SoundPlayer抛出一个异常,即wave标头已损坏,但事实并非如此

时间:2012-03-06 23:00:02

标签: c# audio .net-4.0 real-time wav

我正在开发一个简单的实时音频库。程序员可以调用可以实时播放音频的方法。此外,程序员可以调用可以在特定频率和持续时间实时播放正弦波的方法。正在播放的音频格式是WAV。问题是,当我调用playSineWave时,它抛出一个内部异常,说PlayerSound.Play不能播放声音,因为它有一个损坏的标题。所以起初我认为我偶然写错了标题。但是我保存了wav文件的实际字节,当然包括标题,它在iTunes中播放时没有错误,听起来像是正确频率的正弦波。所以我做错了什么,因为被抛出的异常是误导性的。

以下是导致问题的代码:

        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中的方法?任何建议都会有所帮助。提前致谢。请不要建议NAudio我想从头开始编写WAV文件,我知道那个很棒的库。

忘记提及如果我在写完后将位置设置为零,那么它会在下面给出这个例外:

尝试读取或写入受保护的内存。这通常表明其他内存已损坏。

2 个答案:

答案 0 :(得分: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);    
    }  
}

答案 1 :(得分:-1)

Stream.Write将流的位置设置为写入数据的末尾。尝试在调用SoundPlayer.Play()之前将流的位置重置为0.