所以这可能会变得过于复杂,无法解释,但我会尽量保持简单但信息丰富。我的程序是用 C#.net 编写的,它监视麦克风 2 秒并从样本中返回最大值。我对如何从 winmm.dll 生成声音等不是非常精通,但我的程序大致基于 NAudio 和 CodeProject 的另一个项目来可视化波浪。我使用的波形格式是这个
//WaveIn.cs
private WaveFormat Format= new WaveFormat(8000, 16,1);
//waveFormat.cs
[StructLayout(LayoutKind.Sequential)]
public class WaveFormat
{
public short wFormatTag;
public short nChannels;
public int nSamplesPerSec;
public int nAvgBytesPerSec;
public short nBlockAlign;
public short wBitsPerSample;
public short cbSize;
public WaveFormat(int rate, int bits, short channels)
{
wFormatTag = (short)WaveFormats.Pcm;
nChannels = channels;
nSamplesPerSec = rate;
wBitsPerSample = (short)bits;
cbSize = 0;
nBlockAlign = (short)(nChannels * (wBitsPerSample / 8));
nAvgBytesPerSec = nSamplesPerSec * nBlockAlign;
}
(我想我可能刚刚发现了我的问题,通过发布这个但我仍然要问)
所以然后我在我的wavein文件中设置了一个最大声级事件。如果我正确理解源代码,它会在缓冲区已满时触发。这是那个代码
private void CallBack(IntPtr waveInHandle, WaveMessage message, int userData, ref WaveHeader waveHeader, IntPtr reserved)
{
if (message == WaveMessage.WIM_DATA)
{
GCHandle hBuffer = (GCHandle)waveHeader.dwUser;
WaveInBuffer buffer = (WaveInBuffer)hBuffer.Target;
Exception exception = null;
if (DataAvailable != null)
{
DataAvailable(buffer.Data, buffer.BytesRecorded);
}
if (MaxSoundLevel != null) //FOLLOW THIS ONE
{
byte[] waveStream = new byte[buffer.BytesRecorded];
Marshal.Copy(buffer.Data, waveStream, 0, buffer.BytesRecorded);
MaxSoundLevel(GetMaxSound(GetWaveChannels(waveStream)));
}
if (recording)
{
try
{
buffer.Reuse();
}
catch (Exception e)
{
recording = false;
exception = e;
}
}
}
}
private short[] GetWaveChannels(byte[] waveStream)
{
short[] monoWave = new short[waveStream.Length/2];
int h=0;
for (int i = 0 ; i < waveStream.Length; i += 2)
{
monoWave[h] = BitConverter.ToInt16(waveStream, i);
h++;
}
return monoWave;
}
private int GetMaxSound(short[] wave)
{
int maxSound = 0;
for (int i = 0; i < wave.Length; i++)
{
maxSound = Math.Max(maxSound, Math.Abs(wave[i]));
}
return maxSound;
}
所以当我在这里从这个测试中监控它时,如果我将声级保持在“正常”,它就不会崩溃
[Test]
public void TestSound()
{
var waveIn = new WaveIn();
waveIn.MaxSoundLevel += new WaveIn.MaxSoundHandler(waveIn_MaxSoundLevel);
waveIn.StartRecording();
Console.WriteLine("Starting to record");
Thread.Sleep(4800); //record for 4.8 seconds.
waveIn.StopRecording();
Console.WriteLine("Done Recording");
}
void waveIn_MaxSoundLevel(int MaxSound)
{
Console.WriteLine("MaxSound:{0}", MaxSound);
}
这是我的输出
最大声音:28 最大声音:24 最大声音:31 最大声音:17 最大声音:18760
未处理的异常:System.OverflowException:取反二进制补码的最小值无效。
我曾经得到它给我 MaxSound:32767 (0x7FFF)。
所以我认为我的问题在于它试图将 32 位数字转换为 16 位数字,这就是我将 GetMaxSound 从 short 切换为 int 的原因。所以我不知道。我难住了。那么为什么我会遇到这个问题呢?我的 wave 不是建议它的最大值是 32,767 并且 winmm.dll 会知道并且不会超过那个吗?并且由于它只是将 2 个字节的数据转换为一个短字节,它应该永远不会遇到这个问题吗?请帮忙 :)