鱼C论坛

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

[已解决]停止之后

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

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

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

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

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




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

}


void CMFCyinpinDlg::OnBnClickedBtnStop()
{
        
        waveInReset(hWaveIn);//停止录音设备

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

}




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


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

                for (int i = 0; i < zong / sizeof(short); i++) {
                        if (t == 1) {
                                //移到起始点
                                ::MoveToEx(hdc, i, *(g + i), NULL);
                                t = 0;
                        }
                        else {
                                LineTo(hdc, i, *(g + i));//绘制直线
                        }
                }

        
        return 0;
}


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


afx_msg LRESULT CMFCyinpinDlg::OnMM_WIM_CLOSE(WPARAM wParam, LPARAM lParam)
{
        
        
        return 0;
}


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


最佳答案
2023-8-7 15:22:49
这个问题可能是由于您停止录音设备后没有重新准备缓冲区导致的。在停止录音设备后,您需要使用waveInUnprepareHeader函数进行缓冲区的清理工作,然后再次调用waveInPrepareHeaderwaveInAddBuffer函数来准备新的缓冲区。请按照以下方式修改代码:
void CMFCyinpinDlg::OnBnClickedBtnStart() {    MMRESULT mm = waveInOpen(&hWaveIn, WAVE_MAPPER, &waveform, (DWORD)this->m_hWnd, NULL, CALLBACK_WINDOW);    if (mm != MMSYSERR_NOERROR) {        AfxMessageBox(_T("打开失败"));        return;    }    waveInPrepareHeader(hWaveIn, &waveHeader, sizeof(WAVEHDR));    waveInAddBuffer(hWaveIn, &waveHeader, sizeof(WAVEHDR));    waveInStart(hWaveIn);}void CMFCyinpinDlg::OnBnClickedBtnStop() {    waveInReset(hWaveIn);    waveInUnprepareHeader(hWaveIn, &waveHeader, sizeof(WAVEHDR));    ReleaseMutex(mutex);}
另外,您在线程函数func1中使用了HDC对象hdc,但是这个对象在主线程中声明并初始化,无法直接在子线程中访问。您可以将hdc作为参数传递给线程函数,或者使用其他同步机制来确保在子线程中能够正确访问hdc

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

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

使用道具 举报

发表于 2023-8-7 15:22:49 | 显示全部楼层    本楼为最佳答案   
这个问题可能是由于您停止录音设备后没有重新准备缓冲区导致的。在停止录音设备后,您需要使用waveInUnprepareHeader函数进行缓冲区的清理工作,然后再次调用waveInPrepareHeaderwaveInAddBuffer函数来准备新的缓冲区。请按照以下方式修改代码:
void CMFCyinpinDlg::OnBnClickedBtnStart() {    MMRESULT mm = waveInOpen(&hWaveIn, WAVE_MAPPER, &waveform, (DWORD)this->m_hWnd, NULL, CALLBACK_WINDOW);    if (mm != MMSYSERR_NOERROR) {        AfxMessageBox(_T("打开失败"));        return;    }    waveInPrepareHeader(hWaveIn, &waveHeader, sizeof(WAVEHDR));    waveInAddBuffer(hWaveIn, &waveHeader, sizeof(WAVEHDR));    waveInStart(hWaveIn);}void CMFCyinpinDlg::OnBnClickedBtnStop() {    waveInReset(hWaveIn);    waveInUnprepareHeader(hWaveIn, &waveHeader, sizeof(WAVEHDR));    ReleaseMutex(mutex);}
另外,您在线程函数func1中使用了HDC对象hdc,但是这个对象在主线程中声明并初始化,无法直接在子线程中访问。您可以将hdc作为参数传递给线程函数,或者使用其他同步机制来确保在子线程中能够正确访问hdc

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

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

使用道具 举报

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

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

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

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

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

    // 启动输入设备
    waveInAddBuffer(hWaveIn, &waveHeader, sizeof(WAVEHDR));
    waveInStart(hWaveIn);
}

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

使用道具 举报

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

问题解决:
在点击停止按钮后,需要重新创建一个工作线程来绘制波形图。可以在停止按钮的点击事件处理函数中添加以下代码来实现:
void CMFCyinpinDlg::OnBnClickedBtnStop()
{
    waveInReset(hWaveIn); // 停止录音设备
    ReleaseMutex(mutex); // 释放线程控制权

    // 关闭之前的工作线程
    if (pThread != nullptr)
    {
        WaitForSingleObject(pThread->m_hThread, INFINITE);
        delete pThread;
        pThread = nullptr;
    }
}

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

    // 创建新的工作线程
    pThread = AfxBeginThread(func1, (short*)(g_samples), 0, 0, 0, NULL);
}

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

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-12-21 22:10

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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