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设置为零,则会出现以下异常:
试图读取或写入受保护的内存。这通常表示其他内存已损坏
我通过使用非托管代码解决了这个问题。下面的这个类允许我在内存中播放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().