2012-03-06 1 views
1

간단한 실시간 오디오 라이브러리를 개발 중입니다. 프로그래머는 실시간으로 오디오를 재생할 수있는 메서드를 호출 할 수 있습니다. 또한 프로그래머는 특정 주파수와 지속 시간으로 사인파를 실시간으로 재생할 수있는 메서드를 호출 할 수 있습니다. 실시간으로 재생되는 오디오 형식은 WAV입니다. 문제는 PlayerSound.Play가 사운드를 재생할 수 없다는 내부 예외를 throw하는 playSineWave를 호출 할 때 손상된 헤더가 있기 때문입니다. 그래서 처음에는 실수로 우물을 잘못 작성했다고 믿었습니다. 그러나 물론 헤더를 포함하여 wav 파일의 실제 바이트를 저장했는데 오류없이 iTunes에서 재생했고 올바른 주파수의 사인파처럼 들립니다. 그래서 던져지고있는 예외가 오도 된 것이므로 잘못된 것은 무엇입니까.SoundPlayer는 웨이브 헤더가 손상되었지만 그렇지 않은 예외를 throw합니다.

 public void playSineWave(int frequency, int totalSampleLength) 
     { 
      if (frequency <= 0) 
      { 
       throw new InvalidDataException("frequency cannot be zero or negative."); 
      } 
      List<byte> data = new List<byte>(); 
      byte[] header = getWavHeader(totalSampleLength); 
      data.AddRange(header); 
      for(int x = 0; x < (totalSampleLength); x++) 
      { 
       data.Add((byte)(127 * Math.Sin(2 * (Math.PI/sampleRate) * frequency * (x/2)))); 
      } 



      using(MemoryStream stream = new MemoryStream()) 
      { 
       using (SoundPlayer player = new SoundPlayer(stream)) 
       { 


        stream.Write(data.ToArray(), 0, data.Count); 
        player.Play(); 



       } 
      } 



     } 


     public int secondsToSampleLength(int seconds) 
     { 
      /* 
      * x sample 2 byte  60 second 
      * -------- * -------- * --------------- = total in samples 
      * 1 second 1 second  1 second 
      */ 
      return sampleRate * seconds * 2; 

     } 
     private byte[] getWavHeader(int totalSamples) 
     { 
      MemoryStream stream = new MemoryStream(); 
      byte[] wavHeader; 
      using (BinaryWriter writer = new BinaryWriter(stream, Encoding.BigEndianUnicode)) 
      { 

       writer.Write(new byte[] { 0x52, 0x49, 0x46, 0x46 }); // 4 
       int bitsPerSample = 16; 
       writer.Write(36 + (totalSamples * numberOfChannels * (bitsPerSample/8))); // 4 
       writer.Write(new byte[] { 0x57, 0x41, 0x56, 0x45 }); // 4 
       writer.Write(new byte[] { 0x66, 0x6d, 0x74, 0x20 }); // 4 
       writer.Write(16); // 4 
       writer.Write((short)1); // 2 
       writer.Write((short)numberOfChannels); // 2 
       writer.Write(sampleRate); // 4 
       writer.Write(sampleRate * numberOfChannels * (bitsPerSample/8)); // 4 
       writer.Write((short)(numberOfChannels * (bitsPerSample/8))); // 2 
       writer.Write((short)(bitsPerSample)); // 2 
       writer.Write(new byte[] { 0x64, 0x61, 0x74, 0x61 }); // 4 
       writer.Write((totalSamples * numberOfChannels * (bitsPerSample/8))); // 4 
       wavHeader = stream.ToArray(); 
      } 
      return wavHeader; 
     } 

내가 WAV 파일을 재생할 수있는 Windows API의 방법을 사용해야합니다 : 여기

는 문제의 원인이되는 코드는? 어떤 제안도 도움이 될 것입니다. 고맙습니다. WAV 파일을 처음부터 작성하고 싶습니다. 훌륭한 라이브러리를 알고 있습니다.

보호 된 메모리를 읽거나 쓰려고 시도 :

내가 다음 작성 후 제로로 높은 게재 순위를 설정하면 그 아래에이 예외를 제공한다는 얘기를 깜빡 했네요. 이것은 종종 다른 메모리가 손상되었다는 표시입니다.

+0

WAV 파일은 * byte *가 아니며 RIFF 표준 (Resource Interchange File Format)에 의해 지정된 구조를 가진 파일 형식입니다. SoundPlayer는 원시 샘플 데이터 (일명 PCM)를 재생하는 방법을 알지 못합니다 *. NAudio를 사용하지 않으려면 wav 스트림 작성기를 직접 만들어야합니다. –

답변

-1

Stream.Write는 스트림의 위치를 ​​기록 된 데이터의 끝으로 설정합니다. SoundPlayer.Play()를 호출하기 전에 스트림의 위치를 ​​0으로 재설정 해보십시오.

+0

내가 그랬다는 사실을 잊어 버렸지 만 다른 예외가있다. 내 질문에 게시 할 것입니다. –

+0

Write – allonym

+0

을 호출하는 대신 데이터 버퍼를 MemoryStream 생성자에 전달하여 스트림을 초기화 해보십시오. 동일한 예외가 발생합니다. –

0

음, 비 관리 코드를 사용하여 해결했습니다. 아래의이 클래스는 메모리에서 wav 파일을 재생할 수있게 해줍니다. 바이트 배열을 쓰기 변환 방법을 사용하여 문자열로 변환하면 wav 파일과 심지어는 사인파를 실시간으로 재생할 수 있습니다.

class UnManagedSoundPlayer 
{  
    [DllImport("WinMM.dll")]  
    public static extern bool PlaySound(string data, int Mod, int flag);  // these are the SoundFlags we are using here, check mmsystem.h for more  
    public const int SND_ASYNC = 0x0001;  // play asynchronously  
    public const int SND_FILENAME = 0x00020000; // use file name  
    public const int SND_PURGE = 0x0040;  // purge non-static events  
    public const int SND_NODEFAULT = 0x00002; 
    public const int SND_SYNC = 0x00000; 
    public const int SND_MEMORY = 0x00004; 
    public static bool Play(string data, int SoundFlags = (SND_ASYNC | SND_MEMORY | SND_NODEFAULT | SND_SYNC))  
    {  
     return PlaySound(data, 0, SoundFlags);  
    }  
    public static void StopPlay()  
    {  
     PlaySound(null, 0, SND_PURGE);  
    } 
} 
관련 문제