SoundPlayer抛出一个异常,即波形标头已损坏,但它没有损坏

本文关键字:已损坏 损坏 波形 SoundPlayer 异常 一个 | 更新日期: 2023-09-27 18:26:53

我正在开发一个简单的实时音频库。程序员可以调用可以实时播放音频的方法。此外,程序员可以调用可以实时播放特定频率和持续时间的正弦波的方法。正在实时播放的音频格式是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;
        }

我是否必须使用Windows API中可以播放WAV文件的方法任何建议都会有帮助。提前感谢。请不要建议NAudio我想从头开始写WAV文件,我知道那个很棒的库。

忘了提一下,如果我在写入后将position设置为零,则会出现以下异常:

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

SoundPlayer抛出一个异常,即波形标头已损坏,但它没有损坏

我通过使用非托管代码解决了这个问题。下面的这个类允许我在内存中播放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);    
    }  
}

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

之前,尝试将流的位置重置为0