鱼C论坛

 找回密码
 立即注册
查看: 275|回复: 3

[已解决]停止之后

[复制链接]
发表于 2023-8-7 15:22:32 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
  1.         // 设置音频格式
  2.         waveform.wFormatTag = WAVE_FORMAT_PCM;
  3.         waveform.nChannels = 1;   // 声道数
  4.         waveform.nSamplesPerSec = 44100;   // 采样频率
  5.         waveform.wBitsPerSample = 16;   // 位深
  6.         waveform.nBlockAlign = waveform.nChannels * (waveform.wBitsPerSample / 8);
  7.         waveform.nAvgBytesPerSec = waveform.nSamplesPerSec * waveform.nBlockAlign;
  8.         waveform.cbSize = 0;

  9.         //创建并准备缓冲区
  10.         waveHeader.lpData = (LPSTR)g_samples;
  11.         waveHeader.dwBufferLength = NUM_SAMPLES * sizeof(short);
  12.         waveHeader.dwBytesRecorded = 0;
  13.         waveHeader.dwUser = 0;
  14.         waveHeader.dwFlags = 0;
  15.         waveHeader.dwLoops = 0;
  16.         pWnd = GetDlgItem(IDC_SOUND);  //获取picture控件句柄
  17.         hWnd = ::GetDlgItem(GetSafeHwnd(), IDC_SOUND);
  18.         hdc = ::GetDC(hWnd);
  19.         hpen = CreatePen(PS_SOLID, 2, RGB(0, 0, 255));//创建画笔
  20.         oldhpen= (HPEN)SelectObject(hdc, hpen);
  21.         ::GetClientRect(hWnd, &rect);//获取picture控件客户区的坐标
  22.         hbr = CreateSolidBrush(RGB(255, 255, 255));
  23.         oldhbr =(HBRUSH)SelectObject(hdc, hbr);
  24.         FillRect(hdc, &rect, hbr);//绘制并填充矩形




  25. void CMFCyinpinDlg::OnBnClickedBtnStart()
  26. {
  27.         MMRESULT mm=waveInOpen(&hWaveIn, WAVE_MAPPER, &waveform, (DWORD)this->m_hWnd, NULL, CALLBACK_WINDOW);//打开录音设备
  28.         if (mm != MMSYSERR_NOERROR) {
  29.                 AfxMessageBox(_T("打开失败"));
  30.                 return;
  31.         }
  32.         waveInPrepareHeader(hWaveIn, &waveHeader, sizeof(WAVEHDR));//准备缓冲区
  33.         waveInAddBuffer(hWaveIn, &waveHeader, sizeof(WAVEHDR));// 添加缓冲区到音频输入设备
  34.         waveInStart(hWaveIn);//启动输入设备

  35. }


  36. void CMFCyinpinDlg::OnBnClickedBtnStop()
  37. {
  38.        
  39.         waveInReset(hWaveIn);//停止录音设备

  40.         ReleaseMutex(mutex);//释放线程控制权

  41. }




  42. UINT func1(LPVOID pParam)   //线程函数
  43. {
  44.        
  45.                
  46.         FillRect(hdc, &rect, hbr);//绘制并填充矩形


  47.         int t = 1;//第一个点不能画直线
  48.         short* g = (short*)pParam;
  49.         DWORD d = WaitForSingleObject(mutex, INFINITE);
  50.                

  51.                 for (int i = 0; i < zong / sizeof(short); i++) {
  52.                         if (t == 1) {
  53.                                 //移到起始点
  54.                                 ::MoveToEx(hdc, i, *(g + i), NULL);
  55.                                 t = 0;
  56.                         }
  57.                         else {
  58.                                 LineTo(hdc, i, *(g + i));//绘制直线
  59.                         }
  60.                 }

  61.        
  62.         return 0;
  63. }


  64. afx_msg LRESULT CMFCyinpinDlg::OnMM_WIM_DATA(WPARAM wParam, LPARAM lParam)
  65. {
  66.         WAVEHDR* pWaveHdr = (WAVEHDR*)lParam;
  67.         memcpy(g_samples, pWaveHdr->lpData, pWaveHdr->dwBytesRecorded);//复制音频数据
  68.         zong = pWaveHdr->dwBytesRecorded;
  69.         CWinThread* pp = AfxBeginThread(func1, (short*)(g_samples), 0, 0, 0, NULL);//创建工作线程
  70.                
  71.         waveInAddBuffer(hWaveIn, pWaveHdr, sizeof(WAVEHDR));  // 继续录制下一段音频数据
  72.                
  73.         return 0;
  74. }


  75. afx_msg LRESULT CMFCyinpinDlg::OnMM_WIM_CLOSE(WPARAM wParam, LPARAM lParam)
  76. {
  77.        
  78.        
  79.         return 0;
  80. }

复制代码



我的问题:点击 开始 按钮后,画出麦克风的波形图
可是我按了 停止 按钮后,再按开始按钮   就不画波形图 了,也就是说线程函数没有执行  ??


最佳答案
2023-8-7 15:22:49
这个问题可能是由于您停止录音设备后没有重新准备缓冲区导致的。在停止录音设备后,您需要使用waveInUnprepareHeader函数进行缓冲区的清理工作,然后再次调用waveInPrepareHeaderwaveInAddBuffer函数来准备新的缓冲区。请按照以下方式修改代码:
  1. void CMFCyinpinDlg::OnBnClickedBtnStart() {
  2.     MMRESULT mm = waveInOpen(&hWaveIn, WAVE_MAPPER, &waveform, (DWORD)this->m_hWnd, NULL, CALLBACK_WINDOW);
  3.     if (mm != MMSYSERR_NOERROR) {
  4.         AfxMessageBox(_T("打开失败"));
  5.         return;
  6.     }
  7.     waveInPrepareHeader(hWaveIn, &waveHeader, sizeof(WAVEHDR));
  8.     waveInAddBuffer(hWaveIn, &waveHeader, sizeof(WAVEHDR));
  9.     waveInStart(hWaveIn);
  10. }
  11. void CMFCyinpinDlg::OnBnClickedBtnStop() {
  12.     waveInReset(hWaveIn);
  13.     waveInUnprepareHeader(hWaveIn, &waveHeader, sizeof(WAVEHDR));
  14.     ReleaseMutex(mutex);
  15. }
复制代码

另外,您在线程函数func1中使用了HDC对象hdc,但是这个对象在主线程中声明并初始化,无法直接在子线程中访问。您可以将hdc作为参数传递给线程函数,或者使用其他同步机制来确保在子线程中能够正确访问hdc

希望这些修改对您有帮助!如果还有其他问题,请随时提问。

如果回答对你有帮助,请给我一个最佳答案!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2023-8-7 15:22:49 | 显示全部楼层    本楼为最佳答案   
这个问题可能是由于您停止录音设备后没有重新准备缓冲区导致的。在停止录音设备后,您需要使用waveInUnprepareHeader函数进行缓冲区的清理工作,然后再次调用waveInPrepareHeaderwaveInAddBuffer函数来准备新的缓冲区。请按照以下方式修改代码:
  1. void CMFCyinpinDlg::OnBnClickedBtnStart() {
  2.     MMRESULT mm = waveInOpen(&hWaveIn, WAVE_MAPPER, &waveform, (DWORD)this->m_hWnd, NULL, CALLBACK_WINDOW);
  3.     if (mm != MMSYSERR_NOERROR) {
  4.         AfxMessageBox(_T("打开失败"));
  5.         return;
  6.     }
  7.     waveInPrepareHeader(hWaveIn, &waveHeader, sizeof(WAVEHDR));
  8.     waveInAddBuffer(hWaveIn, &waveHeader, sizeof(WAVEHDR));
  9.     waveInStart(hWaveIn);
  10. }
  11. void CMFCyinpinDlg::OnBnClickedBtnStop() {
  12.     waveInReset(hWaveIn);
  13.     waveInUnprepareHeader(hWaveIn, &waveHeader, sizeof(WAVEHDR));
  14.     ReleaseMutex(mutex);
  15. }
复制代码

另外,您在线程函数func1中使用了HDC对象hdc,但是这个对象在主线程中声明并初始化,无法直接在子线程中访问。您可以将hdc作为参数传递给线程函数,或者使用其他同步机制来确保在子线程中能够正确访问hdc

希望这些修改对您有帮助!如果还有其他问题,请随时提问。

如果回答对你有帮助,请给我一个最佳答案!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-8-7 15:22:49 | 显示全部楼层
根据你提供的代码,停止录音后并没有重新准备缓冲区、启动输入设备和创建线程。为了解决这个问题,你可以在停止按钮的点击事件处理函数中添加下面的代码:

  1. void CMFCyinpinDlg::OnBnClickedBtnStop(){
  2.     waveInReset(hWaveIn);  // 停止录音设备
  3.     waveInUnprepareHeader(hWaveIn, &waveHeader, sizeof(WAVEHDR));  // 取消准备缓冲区
  4.     waveInClose(hWaveIn);  // 关闭录音设备

  5.     ReleaseMutex(mutex);  // 释放线程控制权

  6.     // 清空缓冲区
  7.     memset(g_samples, 0, NUM_SAMPLES * sizeof(short));
  8.     zong = 0;

  9.     Invalidate();  // 刷新窗口,清空波形图

  10.     // 重新准备缓冲区
  11.     waveHeader.lpData = (LPSTR)g_samples;
  12.     waveHeader.dwBufferLength = NUM_SAMPLES * sizeof(short);
  13.     waveInPrepareHeader(hWaveIn, &waveHeader, sizeof(WAVEHDR));

  14.     // 启动输入设备
  15.     waveInAddBuffer(hWaveIn, &waveHeader, sizeof(WAVEHDR));
  16.     waveInStart(hWaveIn);
  17. }
复制代码


这样,在停止录音后再次点击开始按钮时,会重新准备缓冲区、启动输入设备,并创建新的线程来绘制波形图。
如果问题已经解决,请设置最佳答案
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-8-7 15:22:54 | 显示全部楼层
问题分析:
根据提供的代码,当点击开始按钮时,会启动录音设备并启动一个工作线程来绘制麦克风的波形图。当点击停止按钮时,会停止录音设备并释放线程控制权。然后再次点击开始按钮时,线程函数不再执行,导致波形图不再绘制。

问题解决:
在点击停止按钮后,需要重新创建一个工作线程来绘制波形图。可以在停止按钮的点击事件处理函数中添加以下代码来实现:

  1. void CMFCyinpinDlg::OnBnClickedBtnStop()
  2. {
  3.     waveInReset(hWaveIn); // 停止录音设备
  4.     ReleaseMutex(mutex); // 释放线程控制权

  5.     // 关闭之前的工作线程
  6.     if (pThread != nullptr)
  7.     {
  8.         WaitForSingleObject(pThread->m_hThread, INFINITE);
  9.         delete pThread;
  10.         pThread = nullptr;
  11.     }
  12. }

  13. void CMFCyinpinDlg::OnBnClickedBtnStart()
  14. {
  15.     MMRESULT mm = waveInOpen(&hWaveIn, WAVE_MAPPER, &waveform, (DWORD)this->m_hWnd, NULL, CALLBACK_WINDOW); // 打开录音设备
  16.     if (mm != MMSYSERR_NOERROR) {
  17.         AfxMessageBox(_T("打开失败"));
  18.         return;
  19.     }
  20.     waveInPrepareHeader(hWaveIn, &waveHeader, sizeof(WAVEHDR)); // 准备缓冲区
  21.     waveInAddBuffer(hWaveIn, &waveHeader, sizeof(WAVEHDR)); // 添加缓冲区到音频输入设备
  22.     waveInStart(hWaveIn); // 启动输入设备

  23.     // 创建新的工作线程
  24.     pThread = AfxBeginThread(func1, (short*)(g_samples), 0, 0, 0, NULL);
  25. }
复制代码


在停止按钮的点击事件处理函数中,先关闭之前的工作线程,然后在开始按钮的点击事件处理函数中,重新创建一个新的工作线程来绘制波形图。这样就可以实现再次点击开始按钮后绘制波形图的功能。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-4-27 14:42

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表