最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C++使用waveIn實(shí)現(xiàn)聲音采集

 更新時(shí)間:2023年10月24日 15:34:35   作者:CodeOfCC  
在Windows上實(shí)現(xiàn)錄音比較簡(jiǎn)單的方法是使用winmm,其中的waveIn模塊就可以打開(kāi)錄音設(shè)備,這篇文章主要為大家介紹了C++如何使用waveIn實(shí)現(xiàn)聲音采集,需要的可以了解下

前言

在Windows上實(shí)現(xiàn)錄音比較簡(jiǎn)單的方法是使用winmm,其中的waveIn模塊就可以打開(kāi)錄音設(shè)備,獲取PCM數(shù)據(jù),進(jìn)行聲音錄制。本文將介紹waveIn錄音的具體實(shí)現(xiàn),以及如何避免死鎖。

一、需要的對(duì)象及方法

需要用到的頭文件

#include"windows.h"
#include <mmsystem.h>
#pragma comment(lib, "winmm.lib ")  

1.對(duì)象

//聲音采集對(duì)象
HWAVEIN _waveIn;
//聲音數(shù)據(jù)的緩存
WAVEHDR  _wavehdrs[2];
//聲音格式
WAVEFORMATEX _waveFormat;

2.方法

//打開(kāi)聲音輸入設(shè)備
waveInOpen
//注冊(cè)緩沖區(qū)
waveInPrepareHeader
//注銷緩沖區(qū)
waveInUnprepareHeader
//緩沖區(qū)加入使用
waveInAddBuffer
//開(kāi)始采集
waveInStart
//停止采集
waveInStop
//停止采集
waveInReset
//關(guān)閉設(shè)備
waveInClose

二、整體流程

整體流程大致如下:

三、關(guān)鍵實(shí)現(xiàn)

1.設(shè)置聲音格式

 WAVEFORMATEX WaveInitFormat(WORD nCh, DWORD  nSampleRate, WORD  bitsPerSample)
{
    WAVEFORMATEX waveFormat;
    waveFormat.wFormatTag = WAVE_FORMAT_PCM;
    waveFormat.nChannels = nCh;
    waveFormat.nSamplesPerSec = nSampleRate;
    waveFormat.nAvgBytesPerSec = nSampleRate * nCh * bitsPerSample / 8;
    waveFormat.nBlockAlign = nCh * bitsPerSample / 8;
    waveFormat.wBitsPerSample = bitsPerSample;
    waveFormat.cbSize = 0;
    return waveFormat;
}

2.子線程中打開(kāi)設(shè)備

使用子線程開(kāi)啟的方式可以有效避免死鎖問(wèn)題。

//子線程,通過(guò)CreateThread啟動(dòng)下列線程
DWORD WINAPI ThreadProc(LPVOID p)
{
MMRESULT result = waveInOpen(&_waveIn, 0, &waveFormat, GetCurrentThreadId(), (DWORD)NULL, CALLBACK_THREAD);
//開(kāi)啟消息循環(huán)
//略
//消息循環(huán)中監(jiān)聽(tīng)3個(gè)消息
switch (msg.message){
case WIM_OPEN:break;
case WIM_DATA:break;
case WIM_CLOSE:break;
}
//開(kāi)啟消息循環(huán)--end
return 0;
}

3.停止采集

通過(guò)發(fā)送WIM_CLOSE消息停止采集。

PostThreadMessage(GetThreadId(_hThread), WIM_CLOSE, 0, 0);

在子線程的消息循環(huán)中:

case WIM_CLOSE:
waveInStop(_waveIn);
waveInReset(_waveIn);
waveInClose(_waveIn);
break;

四、封裝成對(duì)象

將采集功能封裝成一個(gè)通用工具,方便在任意地方使用。

1.接口設(shè)計(jì)

接口設(shè)計(jì)如下:

#pragma once 
#include<vector>
#include<string>
#include<functional>
/************************************************************************
* @Project:      AC::SoundCollector
* @Decription:  音頻采集工具
* @Verision:      v1.0.0.1
* @Author:      Xin Nie
* @Create:      2021/12/30 13:34:00
* @LastUpdate:  2021/1/7 23:06:00
************************************************************************
* Copyright @ 2020. All rights reserved.
************************************************************************/
namespace AC {
    /// <summary>
    /// 聲音格式
    /// </summary>
    class SoundFormat {
    public:
        /// <summary>
        /// 聲道數(shù)
        /// </summary>
        int  Channels;
        /// <summary>
        /// 采樣率
        /// </summary>
        int  SampleRate;
        /// <summary>
        /// 位深
        /// </summary>
        int  BitsPerSample;
    };
    /// <summary>
    /// 聲音采集設(shè)備
    /// </summary>
    class  SoundDevice {
    public:
        /// <summary>
        /// 設(shè)備Id
        /// </summary>
        int Id;
        /// <summary>
        /// 設(shè)備名稱
        /// </summary>
        std::string Name;
        /// <summary>
        /// 聲道數(shù)
        /// </summary>
        int Channels;
        /// <summary>
        /// 支持的格式
        /// </summary>
        std::vector<SoundFormat> SupportedFormats;
    };
    /// <summary>
    /// 聲音采集對(duì)象
    /// </summary>
    /// <summary>
    /// 聲音采集對(duì)象
    ///這是一個(gè)功能完整聲音采集對(duì)象,所有接口通過(guò)了測(cè)試。
    ///SoundCollectorTest方法包含了所有接口的測(cè)試,修改代碼后,用其驗(yàn)證功能是否正常。
    ///非線程安全,所有方法需確保在單線程中調(diào)用,即比如:Start和Stop不能在兩個(gè)線程中同時(shí)調(diào)用。
    /// </summary>
    class  SoundCollector {
    public:
        /// <summary>
        /// 采集開(kāi)始事件參數(shù)
        /// </summary>
        class  StartedEventArgs
        {
        public:
            /// <summary>
            /// 采集聲音數(shù)據(jù)的格式
            /// </summary>
            SoundFormat Format;
        };
        /// <summary>
        /// 采集數(shù)據(jù)到達(dá)事件
        /// </summary>
        class  DataArrivedEventArgs :public StartedEventArgs
        {
        public:
            /// <summary>
            /// 聲音數(shù)據(jù)
            /// </summary>
            unsigned char* Data;
            /// <summary>
            /// 數(shù)據(jù)長(zhǎng)度
            /// </summary>
            int DataLength;
        };
        /// <summary>
        /// 錯(cuò)誤事件參數(shù)
        /// </summary>
        class  ErrorEventArgs 
        {
        public:
            /// <summary>
            /// 錯(cuò)誤內(nèi)容
            /// </summary>
            std::string Message;
        };
        /// <summary>
        /// 采集開(kāi)始事件
        /// </summary>
        std::function<void(void*, StartedEventArgs*)> Started;
        /// <summary>
        /// 采集數(shù)據(jù)到達(dá)事件
        /// </summary>
        std::function<void(void*, DataArrivedEventArgs*)> DataArrived;
        /// <summary>
        /// 采集結(jié)束事件
        /// </summary>
        std::function<void(void*, void*)>Stoped;
        /// <summary>
        /// 錯(cuò)誤事件
        /// </summary>
        std::function<void(void*, ErrorEventArgs*)> Error;
        /// <summary>
        /// 構(gòu)造方法
        /// </summary>
        SoundCollector();
        /// <summary>
        /// 構(gòu)造方法
        /// </summary>
        /// <param name="deviceId">聲音設(shè)備Id,0為默認(rèn)設(shè)備</param>
        SoundCollector(int deviceId);
        /// <summary>
        ///  構(gòu)造方法
        /// </summary>
        /// <param name="deviceId">聲音設(shè)備Id,0為默認(rèn)設(shè)備</param>
        /// <param name="channels">采集的聲道數(shù)</param>
        /// <param name="sampleRate">采集的采樣率</param>
        /// <param name="bitsPerSample">采集的位深</param>
        SoundCollector(int deviceId, int channels, int  sampleRate, int  bitsPerSample);
        /// <summary>
        /// 析構(gòu)方法
        /// </summary>
        ~SoundCollector();
        /// <summary>
        /// 開(kāi)始采集
        /// </summary>        
        bool Start(int channels, int sampleRate, int bitsPerSample);
        /// <summary>
        /// 停止采集
        /// </summary>
        void Stop();
        /// <summary>
        /// 異步停止采集
        /// </summary>
        void BeginStop();
        /// <summary>
        /// 設(shè)置采集速率
        /// </summary>
        /// <param name="timesPerSecond">采集速率單位:次/秒</param>
        void SetFrequency(int timesPerSecond);
        /// <summary>
        /// 獲取采集速率,數(shù)據(jù)回調(diào)頻率。
        /// </summary>
        /// <returns>采集速率,單位:次/秒</returns>
        int GetFrequency();
        /// <summary>
        /// 獲取聲道數(shù)
        /// </summary>
        /// <returns>聲道數(shù)</returns>
        int GetChannels();
        /// <summary>
        /// 獲取采樣率
        /// </summary>
        /// <returns>采樣率,單位:hz</returns>
        int GetSampleRate();
        /// <summary>
        /// 獲取位深
        /// </summary>
        /// <returns>位深,單位:bits</returns>
        int GetBitsPerSample();
        /// <summary>
        /// 獲取當(dāng)前是否在采集中
        /// </summary>
        /// <returns>是否已停止</returns>
        bool GetIsStoped();
        /// <summary>
        /// 獲取聲音設(shè)備列表
        /// </summary>
        /// <returns></returns>
        static std::vector<SoundDevice> GetDeives();
    private:
        void* _implement = nullptr;
    };
}

五、使用示例

采集聲音并保存為wav文件,其中的WavWapper對(duì)象參考《C++ 將音頻PCM數(shù)據(jù)封裝成wav文件

#include"SoundCollector.h"
#include "WavWapper.h"
#include<Windows.h>
int main()
{
    //運(yùn)行測(cè)試程序
    //AC::SoundCollectorTest();
    //獲取設(shè)備列表
    auto devices = AC::SoundCollector::GetDeives();
    if (devices.size() > 0)
    {    
        printf("設(shè)備名稱:%s\n", devices[0].Name.c_str());
        //初始化采集對(duì)象
        AC::SoundCollector sc(devices[0].Id);
        //wav封裝對(duì)象
        AC::WavWapper ww;
        //注冊(cè)事件
        sc.Started = [&](auto s, auto e) {
            printf("開(kāi)始錄制:Channels %d SampleRate %d BitsPerSample %d\n", e->Format.Channels, e->Format.SampleRate, e->Format.BitsPerSample);
            //根據(jù)聲音格式創(chuàng)建wav文件
            ww.CreateWavFile("sound.wav", e->Format.Channels, e->Format.SampleRate, e->Format.BitsPerSample);
        };
        sc.DataArrived = [&](auto s, auto* e) {
            //采集的數(shù)據(jù)寫(xiě)入wav文件
            ww.WriteToFile(e->Data, e->DataLength);
        };
        sc.Stoped = [&](auto s, auto e) {
            //關(guān)閉文件
            ww.CloseFile();
            printf("錄制完成!\n");
        };
        sc.Error = [&](auto s, auto e) {            
            printf("%s\n",e->Message.c_str());
        };
        //開(kāi)始采集
        if (sc.Start(2, 44100, 16))
        {
            Sleep(20000);
            //結(jié)束采集
            sc.Stop();
        }
    }
}

總結(jié)

使用waveIn實(shí)現(xiàn)聲音采集,實(shí)現(xiàn)過(guò)程還是相對(duì)較簡(jiǎn)單的,但還是有些細(xì)節(jié)需要注意,比如使用方法回調(diào)的方式打開(kāi)設(shè)備,關(guān)閉時(shí)很容易造成死鎖,經(jīng)過(guò)一番嘗試發(fā)現(xiàn)子線程中打開(kāi)設(shè)備才是比較好的方式??偟膩?lái)說(shuō),waveIn實(shí)現(xiàn)的聲音采集模塊是能夠支持音頻實(shí)時(shí)流和錄制開(kāi)發(fā)的。

以上就是C++使用waveIn實(shí)現(xiàn)聲音采集的詳細(xì)內(nèi)容,更多關(guān)于C++ waveIn聲音采集的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • C語(yǔ)言學(xué)習(xí)筆記之VS2022安裝使用教程

    C語(yǔ)言學(xué)習(xí)筆記之VS2022安裝使用教程

    這篇文章主要介紹了C語(yǔ)言學(xué)習(xí)筆記之VS2022安裝使用教程,在VS2022中,在使用scanf函數(shù)編譯出錯(cuò),本文給大家提到了解決方法,需要的朋友可以參考下
    2022-05-05
  • C語(yǔ)言排序之?堆排序

    C語(yǔ)言排序之?堆排序

    這篇文章主要介紹了C語(yǔ)言排序之堆排序,文章基于C語(yǔ)言的相關(guān)資料展開(kāi)詳細(xì)內(nèi)容,具有一定的參考資料,需要的小伙伴可以參考一下
    2022-04-04
  • C++使用遞歸方法求n階勒讓德多項(xiàng)式完整實(shí)例

    C++使用遞歸方法求n階勒讓德多項(xiàng)式完整實(shí)例

    這篇文章主要介紹了C++使用遞歸方法求n階勒讓德多項(xiàng)式,涉及C++遞歸算法與浮點(diǎn)數(shù)運(yùn)算的相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2016-05-05
  • 基于C++編寫(xiě)一個(gè)Json解析器

    基于C++編寫(xiě)一個(gè)Json解析器

    這篇文章主要為大家詳細(xì)介紹了如何基于C++編寫(xiě)一個(gè)Json解析器,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,感興趣的小伙伴可以了解一下
    2023-03-03
  • C語(yǔ)言練習(xí)題:求1到10的階乘之和簡(jiǎn)單實(shí)例

    C語(yǔ)言練習(xí)題:求1到10的階乘之和簡(jiǎn)單實(shí)例

    下面小編就為大家?guī)?lái)一篇C語(yǔ)言練習(xí)題:求1到10的階乘之和簡(jiǎn)單實(shí)例。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2016-05-05
  • C/C++實(shí)現(xiàn)HTTP協(xié)議解析的示例代碼

    C/C++實(shí)現(xiàn)HTTP協(xié)議解析的示例代碼

    基本上,HTTP?是一種基于?TCP/IP?的通信協(xié)議,用于通過(guò)?Web?傳遞?HTML?文件、圖像文件、查詢結(jié)果等數(shù)據(jù)。本文將用C/C++實(shí)現(xiàn)HTTP協(xié)議解析,感興趣的可以了解一下
    2022-07-07
  • C語(yǔ)言實(shí)現(xiàn)Fibonacci數(shù)列遞歸

    C語(yǔ)言實(shí)現(xiàn)Fibonacci數(shù)列遞歸

    這篇文章主要介紹了C語(yǔ)言實(shí)現(xiàn)Fibonacci數(shù)列遞歸,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-02-02
  • OpenCV實(shí)現(xiàn)圖像細(xì)化算法

    OpenCV實(shí)現(xiàn)圖像細(xì)化算法

    本文主要介紹了OpenCV實(shí)現(xiàn)圖像細(xì)化算法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-08-08
  • C++之談?wù)剺?gòu)造函數(shù)的初始化列表

    C++之談?wù)剺?gòu)造函數(shù)的初始化列表

    構(gòu)造函數(shù)主要作用在于創(chuàng)建對(duì)象時(shí)為對(duì)象的成員屬性賦值,構(gòu)造函數(shù)由編譯器自動(dòng)調(diào)用,無(wú)須手動(dòng)調(diào)用,這篇文章詳細(xì)介紹了構(gòu)造函數(shù)的初始化列表,文章中有詳細(xì)的示例代碼,感興趣的同學(xué)可以參考閱讀
    2023-04-04
  • 詳解C++中的常量

    詳解C++中的常量

    這篇文章主要介紹了C++中的常量的相關(guān)資料,文中示例代碼非常詳細(xì),幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下
    2020-07-07

最新評(píng)論

辛集市| 乌拉特前旗| 思茅市| 闽侯县| 潞西市| 呼伦贝尔市| 谷城县| 嘉义县| 昌平区| 屏东县| 洛南县| 德保县| 望江县| 施甸县| 巴南区| 建宁县| 磴口县| 达日县| 临西县| 岗巴县| 义马市| 宁都县| 常熟市| 阿克| 阜康市| 孝义市| 南木林县| 永丰县| 蒲城县| 庆元县| 太和县| 阿拉尔市| 乌海市| 桂平市| 巴楚县| 罗甸县| 东城区| 蚌埠市| 灵川县| 峨眉山市| 安平县|