不同电脑运行同一个录音程序, 结果相差很大. 是声卡的原因还是程序的原因?

sanss2012 2014-08-03 01:13:03
我先说说问题. 本程序在戴尔电脑上运行一切正常, 是High Definition Audio设备. 但在声卡为Realtek的Thinkpad上面运行总出错.

程序介绍: 本程序每1s采集一次麦克风输入的音频数据. 每次只采集很短一段时间即可(约0.2s). 因此每次采集完毕后(缓冲区满后)直接关闭音频设备. 定时器控制每1s重新打开音频设备进行采集.
下面是定时器控制的每1s执行一次的代码,包括从打开音频设备到开始采集的一系列程序.程序主要参考了一个网友博客上面的介绍.
void CNmrView::OnOperateSTART() 
{
m_CountOpen++; //该变量用于统计本函数执行次数

//由于只采集一次即可,所以只需要设置一个缓冲区
pBuffer1=(PBYTE)malloc(INP_BUFFER_SIZE);
if (!pBuffer1) AfxMessageBox(L"Memory erro for pBuffer!");

//这是音频格式设置,可略过
waveform.wFormatTag = WAVE_FORMAT_PCM;
waveform.nChannels = 1;
waveform.nSamplesPerSec = 44100;
waveform.wBitsPerSample = 16;
waveform.nAvgBytesPerSec = waveform.nSamplesPerSec * (waveform.wBitsPerSample / 8);
waveform.nBlockAlign = waveform.nChannels * (waveform.wBitsPerSample / 8);
waveform.cbSize = 0;

//打开音频设备
MMRESULT mmreturn = ::waveInOpen(&hWaveIn, WAVE_MAPPER, &waveform, (DWORD)(UINT)this->m_hWnd, NULL, CALLBACK_WINDOW);
if (mmreturn) AfxMessageBox(L"Audio can not be open!");

//缓冲区设置
pWaveHdr1->lpData = (LPSTR) pBuffer1;
pWaveHdr1->dwBufferLength=INP_BUFFER_SIZE;
pWaveHdr1->dwBytesRecorded=0;

//准备缓冲区
mmreturn = ::waveInPrepareHeader(hWaveIn, pWaveHdr1, sizeof(WAVEHDR));
if (mmreturn) MessageBox(L"error in waveInPrepareHeader()");

pSaveBuffer = (PBYTE)realloc(pSaveBuffer, 1); //用于保存采集到的音频缓冲区

//添加缓冲区
mmreturn = ::waveInAddBuffer(hWaveIn, pWaveHdr1, sizeof (WAVEHDR));
if (mmreturn) MessageBox(L"error in waveInAddBuffer()");

//开始采集
mmreturn = ::waveInStart(hWaveIn);
if (mmreturn) MessageBox(L"error in Start()");
}


下面是每次缓冲区满后执行的消息函数.
LRESULT CNmrView::OnMM_WIM_DATA(WPARAM wParam, LPARAM lParam)
{
m_CountClose++; //该变量统计本函数执行次数

int dwDataLength = ((PWAVEHDR)lParam)->dwBytesRecorded; //缓冲区长度,应该等于INP_BUFFER_SIZE

//为音频数据预置空间
pSaveBuffer = (PBYTE)realloc(pSaveBuffer, dwDataLength);
if (pSaveBuffer == NULL) AfxMessageBox(L"error open memory for pNewBuffer");

//将音频缓冲区的数据放入pSaveBuffer(dwDataLength每次清零,所以没影响,这段是引用的别人博客的代码)
CopyMemory (pSaveBuffer, ((PWAVEHDR) lParam)->lpData, dwDataLength) ;

MMRESULT mmreturn = ::waveInUnprepareHeader (hWaveIn, pWaveHdr1, sizeof (WAVEHDR)) ;;
if (mmreturn) MessageBox(L"error in waveInUnprepareHeader!");

mmreturn = ::waveInReset(hWaveIn);
if (mmreturn) MessageBox(L"error in waveInReset!");

// Sleep(500);

//关闭音频设备
mmreturn = ::waveInClose(hWaveIn);
if (mmreturn) MessageBox(L"waveInClose failed!");
}


在联想笔记本上运行的时候, 通过调试发现这两个函数的执行次数居然不一致. 而且每次运行的时候也不一样. 比如有次OnOperateSTART() 函数执行了16次,而OnMM_WIM_DATA只执行了14次. 而另一次报错退出的时候两个函数都执行三十多次, 但第一个函数总比第二个函数多执行三四次. 而在戴尔电脑上运行的时候却没有这个结果, 两个函数执行次数绝对一致,也不会报错.

报错的地方有两个. 一个是OnOperateSTART() 里面的打开音频设备函数waveInOpen(), 错误代码是4, 代表"指定的资源已被分配".
一个是OnMM_WIM_DATA里面对pSaveBuffer 重分配空间时,dwDataLength的大小为0,导致pSaveBuffer == NULL.

我觉着奇怪的地方主要在于, 为什么第一个函数会比第二个函数多执行几次呢? 似乎有的时候缓冲区满了却没有进入OnMM_WIM_DATA? 但第二个错误的地方又似乎是缓冲区里面没有数据却还是进入了OnMM_WIM_DATA?...
而且最关键在于在戴尔电脑上面一点错都没有....
拜求大神解答啊,也欢迎大家讨论....谢谢~
...全文
475 11 打赏 收藏 转发到动态 举报
写回复
用AI写文章
11 条回复
切换为时间正序
请发表友善的回复…
发表回复
lm_whales 2014-08-13
  • 打赏
  • 举报
回复
试试不动态分配,直接用静态缓冲区,反正是固定大小的。
sanss2012 2014-08-09
  • 打赏
  • 举报
回复
试过了...唉,都不行...
赵4老师 2014-08-07
  • 打赏
  • 举报
回复
检查音量设置
赵4老师 2014-08-07
  • 打赏
  • 举报
回复
引用 7 楼 sanss2012 的回复:
[quote=引用 5 楼 zhao4zhong1 的回复:] 驱动精灵
驱动都装过了的...联想官网的驱动..[/quote] 驱动精灵软件自动搜索本机的各种硬件设备对应的最新驱动,有时比官网的驱动更新更好使。
sanss2012 2014-08-07
  • 打赏
  • 举报
回复
引用 5 楼 zhao4zhong1 的回复:
驱动精灵
驱动都装过了的...联想官网的驱动..
Chivalry 2014-08-07
  • 打赏
  • 举报
回复
太专业,不懂
赵4老师 2014-08-06
  • 打赏
  • 举报
回复
驱动精灵
sanss2012 2014-08-06
  • 打赏
  • 举报
回复
为毛没人回复呢..
sanss2012 2014-08-03
  • 打赏
  • 举报
回复
引用 1 楼 bojie5744 的回复:
这样操作,隔断时间音频有间隔, 不同硬件当然音效也不同。
我不在乎音频有间隔的... 硬件应该会影响音效吧, 但是我用的都是底层函数, 照理说不应该会报错吧?....
sanss2012 2014-08-03
  • 打赏
  • 举报
回复
不好意思,忘了写了,OnMM_WIM_DATA还有一句释放缓冲区的.
free (pBuffer1) ;
  • 打赏
  • 举报
回复
这样操作,隔断时间音频有间隔, 不同硬件当然音效也不同。

1,649

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 非技术类
社区管理员
  • 非技术类社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧