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

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

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

前言

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

一、需要的對象及方法

需要用到的頭文件

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

1.對象

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

2.方法

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

二、整體流程

整體流程大致如下:

三、關鍵實現(xiàn)

1.設置聲音格式

 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.子線程中打開設備

使用子線程開啟的方式可以有效避免死鎖問題。

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

3.停止采集

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

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

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

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

四、封裝成對象

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

1.接口設計

接口設計如下:

#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>
    /// 聲音采集設備
    /// </summary>
    class  SoundDevice {
    public:
        /// <summary>
        /// 設備Id
        /// </summary>
        int Id;
        /// <summary>
        /// 設備名稱
        /// </summary>
        std::string Name;
        /// <summary>
        /// 聲道數(shù)
        /// </summary>
        int Channels;
        /// <summary>
        /// 支持的格式
        /// </summary>
        std::vector<SoundFormat> SupportedFormats;
    };
    /// <summary>
    /// 聲音采集對象
    /// </summary>
    /// <summary>
    /// 聲音采集對象
    ///這是一個功能完整聲音采集對象,所有接口通過了測試。
    ///SoundCollectorTest方法包含了所有接口的測試,修改代碼后,用其驗證功能是否正常。
    ///非線程安全,所有方法需確保在單線程中調用,即比如:Start和Stop不能在兩個線程中同時調用。
    /// </summary>
    class  SoundCollector {
    public:
        /// <summary>
        /// 采集開始事件參數(shù)
        /// </summary>
        class  StartedEventArgs
        {
        public:
            /// <summary>
            /// 采集聲音數(shù)據(jù)的格式
            /// </summary>
            SoundFormat Format;
        };
        /// <summary>
        /// 采集數(shù)據(jù)到達事件
        /// </summary>
        class  DataArrivedEventArgs :public StartedEventArgs
        {
        public:
            /// <summary>
            /// 聲音數(shù)據(jù)
            /// </summary>
            unsigned char* Data;
            /// <summary>
            /// 數(shù)據(jù)長度
            /// </summary>
            int DataLength;
        };
        /// <summary>
        /// 錯誤事件參數(shù)
        /// </summary>
        class  ErrorEventArgs 
        {
        public:
            /// <summary>
            /// 錯誤內容
            /// </summary>
            std::string Message;
        };
        /// <summary>
        /// 采集開始事件
        /// </summary>
        std::function<void(void*, StartedEventArgs*)> Started;
        /// <summary>
        /// 采集數(shù)據(jù)到達事件
        /// </summary>
        std::function<void(void*, DataArrivedEventArgs*)> DataArrived;
        /// <summary>
        /// 采集結束事件
        /// </summary>
        std::function<void(void*, void*)>Stoped;
        /// <summary>
        /// 錯誤事件
        /// </summary>
        std::function<void(void*, ErrorEventArgs*)> Error;
        /// <summary>
        /// 構造方法
        /// </summary>
        SoundCollector();
        /// <summary>
        /// 構造方法
        /// </summary>
        /// <param name="deviceId">聲音設備Id,0為默認設備</param>
        SoundCollector(int deviceId);
        /// <summary>
        ///  構造方法
        /// </summary>
        /// <param name="deviceId">聲音設備Id,0為默認設備</param>
        /// <param name="channels">采集的聲道數(shù)</param>
        /// <param name="sampleRate">采集的采樣率</param>
        /// <param name="bitsPerSample">采集的位深</param>
        SoundCollector(int deviceId, int channels, int  sampleRate, int  bitsPerSample);
        /// <summary>
        /// 析構方法
        /// </summary>
        ~SoundCollector();
        /// <summary>
        /// 開始采集
        /// </summary>        
        bool Start(int channels, int sampleRate, int bitsPerSample);
        /// <summary>
        /// 停止采集
        /// </summary>
        void Stop();
        /// <summary>
        /// 異步停止采集
        /// </summary>
        void BeginStop();
        /// <summary>
        /// 設置采集速率
        /// </summary>
        /// <param name="timesPerSecond">采集速率單位:次/秒</param>
        void SetFrequency(int timesPerSecond);
        /// <summary>
        /// 獲取采集速率,數(shù)據(jù)回調頻率。
        /// </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>
        /// 獲取當前是否在采集中
        /// </summary>
        /// <returns>是否已停止</returns>
        bool GetIsStoped();
        /// <summary>
        /// 獲取聲音設備列表
        /// </summary>
        /// <returns></returns>
        static std::vector<SoundDevice> GetDeives();
    private:
        void* _implement = nullptr;
    };
}

五、使用示例

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

#include"SoundCollector.h"
#include "WavWapper.h"
#include<Windows.h>
int main()
{
    //運行測試程序
    //AC::SoundCollectorTest();
    //獲取設備列表
    auto devices = AC::SoundCollector::GetDeives();
    if (devices.size() > 0)
    {    
        printf("設備名稱:%s\n", devices[0].Name.c_str());
        //初始化采集對象
        AC::SoundCollector sc(devices[0].Id);
        //wav封裝對象
        AC::WavWapper ww;
        //注冊事件
        sc.Started = [&](auto s, auto e) {
            printf("開始錄制: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ù)寫入wav文件
            ww.WriteToFile(e->Data, e->DataLength);
        };
        sc.Stoped = [&](auto s, auto e) {
            //關閉文件
            ww.CloseFile();
            printf("錄制完成!\n");
        };
        sc.Error = [&](auto s, auto e) {            
            printf("%s\n",e->Message.c_str());
        };
        //開始采集
        if (sc.Start(2, 44100, 16))
        {
            Sleep(20000);
            //結束采集
            sc.Stop();
        }
    }
}

總結

使用waveIn實現(xiàn)聲音采集,實現(xiàn)過程還是相對較簡單的,但還是有些細節(jié)需要注意,比如使用方法回調的方式打開設備,關閉時很容易造成死鎖,經過一番嘗試發(fā)現(xiàn)子線程中打開設備才是比較好的方式。總的來說,waveIn實現(xiàn)的聲音采集模塊是能夠支持音頻實時流和錄制開發(fā)的。

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

相關文章

  • C語言學習筆記之VS2022安裝使用教程

    C語言學習筆記之VS2022安裝使用教程

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

    C語言排序之?堆排序

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

    C++使用遞歸方法求n階勒讓德多項式完整實例

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

    基于C++編寫一個Json解析器

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

    C語言練習題:求1到10的階乘之和簡單實例

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

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

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

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

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

    OpenCV實現(xiàn)圖像細化算法

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

    C++之談談構造函數(shù)的初始化列表

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

    詳解C++中的常量

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

最新評論

绥滨县| 阳谷县| 彝良县| 巫山县| 耿马| 镇康县| 吉安县| 芷江| 莆田市| 信宜市| 修武县| 清苑县| 吴旗县| 共和县| 苏尼特右旗| 甘肃省| 女性| 米易县| 南通市| 桦甸市| 白水县| 淮阳县| 涟水县| 大新县| 鄂州市| 平谷区| 贵溪市| 富源县| 天峻县| 崇文区| 华池县| 宜宾市| 鄯善县| 望谟县| 天津市| 五莲县| 晴隆县| 玛曲县| 吴旗县| 德兴市| 池州市|