C++使用alsa庫(kù)實(shí)現(xiàn)播放聲音文件
前言
平常讀麥克風(fēng)的場(chǎng)景居多,有時(shí)候也需要播放一個(gè)聲音文件,這里就介紹怎么處理。
一、命令行
1.ffmpeg
ffmpeg -i <filename.wav> -f alsa default
2.aplay
aplay -i <filename.wav>
如果提示找不到aplay就安裝工具:
sudo apt install alsa-utils
二、代碼實(shí)現(xiàn)
main.cpp
#include <alsa/asoundlib.h> #include <iostream> #include <fstream> #define PCM_DEVICE "default"http://默認(rèn)的播放設(shè)備,你可以在settings里面調(diào)換 int main(int argc, char *argv[]) { const char *audioFilename = "../wakeup.wav"; // 配置ALSA參數(shù) snd_pcm_t *pcmHandle; if (snd_pcm_open(&pcmHandle, PCM_DEVICE, SND_PCM_STREAM_PLAYBACK, 0) < 0) { std::cerr << "Error: Failed to open PCM device" << std::endl; return 1; } snd_pcm_hw_params_t *params; snd_pcm_hw_params_alloca(¶ms); snd_pcm_hw_params_any(pcmHandle, params); snd_pcm_hw_params_set_access(pcmHandle, params, SND_PCM_ACCESS_RW_INTERLEAVED); snd_pcm_hw_params_set_format(pcmHandle, params, SND_PCM_FORMAT_S16_LE); snd_pcm_hw_params_set_channels(pcmHandle, params, 2); unsigned int sampleRate = 48000; snd_pcm_hw_params_set_rate_near(pcmHandle, params, &sampleRate, nullptr); snd_pcm_uframes_t bufferSize = 512; snd_pcm_hw_params_set_buffer_size_near(pcmHandle, params, &bufferSize); snd_pcm_hw_params(pcmHandle, params); std::ifstream ifs("../wakeup.wav"); if (ifs.is_open()) { std::string data; size_t size; char buffer[8192]; while ((size = ifs.readsome(buffer, 8192)) > 0) { data.append(buffer, size); } snd_pcm_sframes_t err = snd_pcm_writei(pcmHandle, (const void *) data.c_str(), data.size()); if (err < 0) { std::cerr << "Error: Failed to write PCM device" << std::endl; } ifs.close(); } // 關(guān)閉PCM設(shè)備和文件 snd_pcm_close(pcmHandle); return 0; }
CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
project(write_speaker)
set(CMAKE_CXX_STANDARD 11)
add_executable(${PROJECT_NAME} main.cpp)
target_link_libraries(${PROJECT_NAME} asound)
三、知識(shí)補(bǔ)充
C++使用Alsa采集linux音頻
1、運(yùn)行時(shí)前先裝庫(kù),sudo apt-get install libalsa
2遍tab自動(dòng)提示出庫(kù)文件,選擇庫(kù),alsa-ocaml-dev,最終的命令行為:sudo apt-get install libalsa-ocaml-dev
2、編譯執(zhí)行腳本,gcc -o main main.c -lasound;
3、執(zhí)行 ./main
以下是代碼
#include <stdlib.h> #include <stdio.h> #include <alsa/asoundlib.h> #include <signal.h> static int recording; void stop_record(int param) { recording = 0; } void InitCapture(snd_pcm_t ** handle,snd_pcm_hw_params_t ** params,snd_pcm_uframes_t* frames,char ** buffer,int* size) { int ret; unsigned int val; int dir; //打開(kāi)設(shè)備 ret = snd_pcm_open(handle, “default”, SND_PCM_STREAM_CAPTURE, 0); printf(“after open file\n”); if (ret < 0) { fprintf(stderr, “unable to open device:%s\n”, snd_strerror(ret)); exit(1); } //分配一個(gè)硬件參數(shù)結(jié)構(gòu)體 snd_pcm_hw_params_alloca(params); //使用默認(rèn)參數(shù) snd_pcm_hw_params_any(*handle, *params); //翻譯 snd_pcm_hw_params_set_access(*handle, *params, SND_PCM_ACCESS_RW_INTERLEAVED); //S16小端 snd_pcm_hw_params_set_format(*handle, *params, SND_PCM_FORMAT_S16_LE); //雙通道,立體聲 snd_pcm_hw_params_set_channels(*handle, *params, 2); //采樣率 val = 44100; snd_pcm_hw_params_set_rate_near(*handle, *params,&val,&dir); *frames = 32; snd_pcm_hw_params_set_period_size_near(*handle, *params,frames,&dir); //參數(shù)生效 ret = snd_pcm_hw_params(*handle, *params); if (ret<0) { fprintf(stderr, "unable to set hw parameters:%s\n", snd_strerror(ret)); exit(1); } //得到一個(gè)周期的數(shù)據(jù)大小 snd_pcm_hw_params_get_period_size(*params, frames, &dir); //16位雙通道,16位為2字節(jié),2字節(jié)*2通道=4,假如frames=1024,則size是1024*4 = 4096 *size = *frames * 4; *buffer = (char*)malloc(*size); //設(shè)置一個(gè)周期的時(shí)間長(zhǎng)度 snd_pcm_hw_params_get_period_time(*params, &val, &dir); } void CaptureAudio(snd_pcm_t ** handle,snd_pcm_uframes_t* frames,char ** buffer,int* size,FILE ** pFile) { int ret; recording = 1; while (recording) { ret = snd_pcm_readi(*handle, *buffer,*frames); if (ret == -EPIPE ) { fprintf(stderr, "overrun occurred\n"); snd_pcm_prepare(*handle); } else if (ret < 0) { fprintf(stderr, "error from read\n"); snd_strerror(ret); } else if (ret != (int)(*frames)) { fprintf(stderr, "short read %d frames\n",ret); } printf("write to file......%d\n", *size); //寫(xiě)到標(biāo)準(zhǔn)輸出中去 ret = fwrite(*buffer, sizeof(char), *size, *pFile); if (ret != *size) { fprintf(stderr, "short write :write %d bytes\n", ret); } if (signal(SIGINT, stop_record)==SIG_ERR) { fprintf(stderr, "signal failed\n"); } } } void CloseCaptureDevice(FILE ** pFile,snd_pcm_t ** handle,char ** buffer) { printf(“write file exit\n”); snd_pcm_drain(*handle); snd_pcm_close(*handle); free(*buffer); fclose(*pFile); } int main() { FILE * pFile; pFile = fopen(“test.pcm”, “wb”); int size; //給文件操作分配一個(gè)句柄 snd_pcm_t * handle; //硬件參數(shù) snd_pcm_hw_params_t * params; // snd_pcm_uframes_t frames; char * buffer; printf(“before open file\n”); InitCapture(&handle,¶ms,&frames,&buffer,&size); CaptureAudio(&handle,&frames,&buffer,&size,&pFile); CloseCaptureDevice(&pFile,&handle,&buffer); printf(“write file exit\n”); return 0; }
到此這篇關(guān)于C++使用alsa庫(kù)實(shí)現(xiàn)播放聲音文件的文章就介紹到這了,更多相關(guān)C++ alsa播放聲音文件內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C語(yǔ)言動(dòng)態(tài)分配二維字符串?dāng)?shù)組的方法
小編最近忙里偷閑,給大家整理一份教程關(guān)于C語(yǔ)言動(dòng)態(tài)分配二維字符串?dāng)?shù)組的方法,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2021-10-10C語(yǔ)言實(shí)現(xiàn)猜數(shù)字小游戲的示例代碼
猜數(shù)字小游戲是我們小時(shí)候喜歡我們一個(gè)經(jīng)典小游戲。本文將用C語(yǔ)言實(shí)現(xiàn)這一經(jīng)典游戲,文中的示例代碼講解詳細(xì),感興趣的可以了解一下2022-08-08c語(yǔ)言實(shí)現(xiàn)MD5算法的項(xiàng)目實(shí)踐
MD5用于確保信息傳輸完整一致,是計(jì)算機(jī)廣泛使用的雜湊算法之一,本文主要介紹了c語(yǔ)言實(shí)現(xiàn)MD5算法,具有一定的參考價(jià)值,感興趣的可以了解一下2023-08-08win32 api實(shí)現(xiàn)簡(jiǎn)單的消息窗口示例
這篇文章主要介紹了使用win32 api實(shí)現(xiàn)簡(jiǎn)單的消息窗口示例,需要的朋友可以參考下2014-03-03C++中function的實(shí)現(xiàn)原理詳解
類(lèi)模版std::function是一種通用、多態(tài)的函數(shù)封裝。function的實(shí)例可以對(duì)任何可以調(diào)用的目標(biāo)實(shí)體進(jìn)行存儲(chǔ)、復(fù)制、和調(diào)用操作。本文主要聊聊它的實(shí)現(xiàn)原理,需要的可以參考一下2022-12-12