gpt4 book ai didi

c# - 如何防止数字因波动而变大

转载 作者:行者123 更新时间:2023-12-02 23:58:57 25 4
gpt4 key购买 nike

因此,这可能会变得过于复杂,难以解释,但我将尽力使其简单但内容丰富。我的程序是用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的原因。所以我不知道我感到难过。那我为什么有这个问题?我的浪潮是否暗示最大最大值为32,767,并且winmm.dll会知道并且不会超过?并且由于它只是将2个字节的数据转换为短数据,所以它永远不会遇到这个问题吗?请帮忙 :)

最佳答案

对于那些可能正在研究此问题的人,我的解决方案本质上非常简单。一个16位带符号的数字的最大正值是32767。它的最大负数是-32768。如果采用32768的绝对值并尝试将其放入16位数字,则将导致引发溢出异常。因此,解决方案是将短值转换为32位数字,然后再尝试获取绝对值。这是更正的功能

    private int GetMaxSound(short[] wave)
{
int maxSound = 0;
for (int i = 0; i < wave.Length; i++)
{
maxSound = Math.Max(maxSound, Math.Abs((int)wave[i]));
}
return maxSound;
}

我可能也可以通过使用ushort来保留一个无符号数字,但是Math.Abs​​确实可以

关于c# - 如何防止数字因波动而变大,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10621113/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com