检测声音缓冲区是否充满数据
Detect wheter a sound buffer is filled with data or not
我正在使用WaveAPI进行录制,我想在录制完数据后检测缓冲区中是否有声音,或者它什么都没有录制(只是房间的空隙(。
我写了一个函数,可以得到缓冲区绝对值的平均值,它的工作原理是"Ok",但它有很多问题:
1( 我检测到,当它是空的时,平均值为~860,当我说话时,它为~875,这几乎没有什么不同。怎么可能呢?我正在录制1秒。
2( 有时,我看到平均值约为860,有时约为500,有时甚至约为400。为什么它每次都在变化?我的意思是,它不应该是一样的吗?因为在所有的时候,它都捕捉到了空虚,而没有改变吗?
这是我写的函数:
bool isEmpty(short int *wave)
{
int avg = 0;
for (int i = 0 ; i < NUMPTS ; i++)
{
if (wave[i] < 0)
avg = avg + (wave[i]) * -1;
else
avg = avg + (wave[i]);
}
avg = avg / NUMPTS;
if (avg > avg_voice)
return false;
return true;
}
这个功能还不够好,因为它并不完全正确,我必须不断地将avg_voice
更改为其他内容,有时缓冲区平均只有10个点,声音比空白高,这很难检测它是否有声音。。。。
那么我该怎么办呢?我该如何改进?当我录制语音并填写所有WAVEFORMATEX
和WAVEHDR
设置时,可能有这样的选项?
谢谢!
编辑:wave
是一个包含8000
单元格的短int数组,它将语音存储在内部,看起来如下(示例(:wave[0] = -123;
wave[1] = -205;
wave[2] = -212'
这样。。。
第二次编辑:我记录的数据是这样的:
void StartRecord()
{
short int *waveIn = new short int[NUMPTS];
HWAVEIN hWaveIn;
WAVEHDR WaveInHdr;
MMRESULT result;
HWAVEOUT hWaveOut;
WAVEFORMATEX pFormat;
pFormat.wFormatTag = WAVE_FORMAT_PCM;
pFormat.nChannels = 1;
pFormat.nSamplesPerSec = sampleRate;
pFormat.nAvgBytesPerSec = 2 * sampleRate;
pFormat.nBlockAlign = 2;
pFormat.wBitsPerSample = 16;
pFormat.cbSize = 0;
result = waveInOpen(&hWaveIn, WAVE_MAPPER, &pFormat, 0, 0, WAVE_FORMAT_DIRECT);
if(result)
{
char fault[256];
waveInGetErrorTextA(result, fault, 256);
MessageBoxA(NULL, fault, "Failed to open waveform input device.", MB_OK | MB_ICONEXCLAMATION);
return;
}
WaveInHdr.lpData = (LPSTR)waveIn;
WaveInHdr.dwBufferLength = 2 * NUMPTS;
WaveInHdr.dwBytesRecorded = 0;
WaveInHdr.dwUser = 0;
WaveInHdr.dwFlags = 0;
WaveInHdr.dwLoops = 0;
while (true)
{
waveInPrepareHeader(hWaveIn, &WaveInHdr, sizeof(WAVEHDR));
result = waveInAddBuffer(hWaveIn, &WaveInHdr, sizeof(WAVEHDR));
result = waveInStart(hWaveIn);
if(result)
{
MessageBoxA(NULL, "Failed to start recording", NULL, MB_OK | MB_ICONEXCLAMATION);
return;
}
// Wait until finished recording
Sleep(seconds * 1000); //Sleep for as long as there was recorded
waveInUnprepareHeader(hWaveIn, &WaveInHdr, sizeof(WAVEHDR));
if (isEmpty(waveIn)) // Checks here
.....
}
}
首先,我预测在分析缓冲区时缓冲区尚未填充。与其简单地休眠,不如轮询WaveInHdr.dwFlags以设置WHDR_DONE位。
result = waveInStart(hWaveIn);
if(result)
{
MessageBoxA(NULL, "Failed to start recording", NULL, MB_OK | MB_ICONEXCLAMATION);
return;
}
// Wait until finished recording
while ((WaveInHdr.dwFlags & WHDR_DONE) == 0)
Sleep(100);
其次,我建议用一种更好的方法来测量响度。RMS也许:
double Rms(short int *wave, int length)
{
double sumSquared = 0;
double scaleShortToDouble = 1.0/0x8000;
for (int i = 0 ; i < length; i++)
{
double s = wave[i] * scaleShortToDouble;
sumSquared += s * s;
}
return sqrt(2) * sqrt(sumSquared/length);
}
我已经将短裤转换为-1.0到1.0范围内的双打,因为它更容易计算。额外的sqrt(2(将对结果进行缩放,这样,如果您将正弦波输入a/D转换器,从而产生全刻度数字正弦(-3276382767(,则Rms结果将为1.0。
完成后,您现在可以将Rms值转换为dB,您将得到一个称为dBFS的数字,该数字在谈论数字电平时常用。
转换为:dBFS = 20*log10(rms)
,大致为:
- 0 dBFS=1.0`
- -6 dBFS=0.5
- -12 dBFS=0.25
输入电平的每个减半是另一个-6dBFS下降。
输入信号的每次减半也将需要A/D转换器的少一位。由于你有一个16位的信号,你的理论本底噪声将在-96 dBFS左右。然而,在实践中,由于你连接了麦克风,它会比这个高一些——这在很大程度上取决于你的设置质量。这就是你需要进行实验的地方。
您必须使用RMS,因为正弦曲线的平均值为0,所以如果取平均值,您只会得到麦克风的电压偏移。这就是为什么你会得到不一致但低的值,860/2^15大约是动态范围的2%。
您已使用为waveIn
分配内存
short int *waveIn = new short int[NUMPTS];
但是,这并不能初始化内容。将内容初始化为有意义的内容。然后,你将能够看到哪些地方不起作用。如果0
是有意义的默认值,则使用:
for (int i = 0; i < NUMPTS; ++i )
{
waveIn[i] = 0;
}
- 在 c++ 中解析数据包数据的最佳方法是什么?
- C++:如何通过 curl 调用使用 HTTP post 请求发送二进制数据(protobuf 数据)
- 我无法将数据从数据网格列传输到 C# 中的数组以获取文本框建议收集数据
- 如何用尽可能少的数据将数据缓冲区计算为零校验和值
- 如何将通过TCP发送数据的数据从C++转换为Java
- 从QML ListView中QABStractListModel中的数据操纵数据
- Windivert-修改数据包数据/有效载荷内容
- 如何从C ++的输出中删除垃圾数据(垃圾数据)
- 如何编写循环以通过列表迭代并打印列表中每个元素的数据的数据
- 加入线程后,是访问共享数据的数据竞赛吗?
- 亚类FSTREAM和解密数据即时数据
- 将数据从数据阅读器终端实时获取到GUI
- 将数据从数据读取器终端获取到GUI(QtCreator)
- 使用 libpcap 读取数据包数据
- SDL_net UDP 数据包数据
- 用于插入大部分排序数据的数据结构,这些数据将保持排序顺序
- 从Qt应用程序获取原始数据包数据
- C++:用于高效插入和检索自定义数据的数据结构
- 如何将用户输入的数据从数据网格视图获取到窗口窗体图
- 将libpcap数据包数据从const u_char*复制到另一个const u_car*