Linux麦克风录音实战
在 Linux 上使用麦克风进行录音可以通过多种方式实现,包括使用命令行工具、图形界面应用程序以及编程接口。下面我将介绍几种常见的方法,从简单的命令行工具到使用 PortAudio 库进行编程。
一. 使用arecord命令行工具
arecord 是 ALSA(Advanced Linux Sound Architecture)提供的一个命令行工具,可以用来录制音频。以下是基本步骤:
步骤 1: 检查麦克风设备:首先,确保你的麦克风设备已经被系统识别。你可以使用 arecord -l 命令来列出所有可用的录音设备。
arecord -l
输出示例:
这里card 3和device 0是要使用的麦克风设备。
步骤 2: 录制音频
使用 arecord 命令进行录音,并指定设备和输出文件格式。例如,录制一个 10 秒的音频文件:
arecord -D hw:3,0 -f cd -d 10 output.wav
- -D hw:0,0:指定设备 card 0, device 0。
- -f cd:指定采样格式为 CD 质量(16-bit, 44.1 kHz, stereo)。
- -d 10:录制时间 10 秒。
- output.wav:输出文件名。
二. 使用 PortAudio 编程库
PortAudio 是一个跨平台的音频 I/O 库,支持多种编程语言。以下是一个使用 C++ 和 PortAudio 进行麦克风录音的示例。
步骤一:安装PortAudio
首先,安装PortAudio库
sudo apt-get install portaudio19-dev
或者编译portaudio库的源代码
git clone https://github.com/PortAudio/portaudio.git
cd portaudio
./configure
make
make install
步骤二:编写录音程序
创建一个 C++ 文件(例如 recorder.cc),并编写录音代码。
// 引入portaudio库
#include <portaudio.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 采样频率44100hz
#define SAMPLE_RATE 44100
// 每个缓冲区的帧数
#define FRAMES_PER_BUFFER 1024
// 录制的时间长度
#define RECORD_SECONDS 10
// WAV 文件头结构
typedef struct {
char riff[4]; // "RIFF"
int filesize; // 文件大小减8
char wave[4]; // "WAVE"
char fmt_chunk_marker[4]; // "fmt "
int fmt_chunk_len; // 格式块长度 (16)
short audio_format; // 音频格式 (1 for PCM)
short num_channels; // 声道数 (1 for mono, 2 for stereo)
int sample_rate; // 采样率 (例如 44100)
int byte_rate; // 每秒字节数 (sample_rate * num_channels * (bits_per_sample/8))
short frame_size; // 每个样本的字节数 (num_channels * (bits_per_sample/8))
short bits_per_sample; // 每个样本的位数 (例如 16)
char data_chunk_header[8]; // "data"
int data_bytes; // 数据字节数 (frame_count * frame_size)
} WavHeader;
// 回调函数
// portaudio会在每次有新的音频数据时调用这个函数
int recordCallback(const void *inputBuffer, void *outputBuffer,
unsigned long framesPerBuffer,
const PaStreamCallbackTimeInfo* timeInfo,
PaStreamCallbackFlags statusFlags,
void *userData) {
FILE *file = (FILE *)userData;
fwrite(inputBuffer, sizeof(short), framesPerBuffer, file);
return paContinue;
}
int main() {
PaStream *stream;
PaError err;
FILE *file;
// 初始化 PortAudio
err = Pa_Initialize();
if (err != paNoError) {
fprintf(stderr, "Pa_Initialize: %s\n", Pa_GetErrorText(err));
return 1;
}
// 打开文件
file = fopen("output.wav", "wb");
if (!file) {
fprintf(stderr, "无法打开输出文件\n");
Pa_Terminate();
return 1;
}
// 设置 WAV 文件头
WavHeader header = {0};
strcpy(header.riff, "RIFF");
strcpy(header.wave, "WAVE");
strcpy(header.fmt_chunk_marker, "fmt ");
header.fmt_chunk_len = 16;
header.audio_format = 1;
header.num_channels = 1;
header.sample_rate = SAMPLE_RATE;
header.byte_rate = SAMPLE_RATE * header.num_channels * 2;
header.frame_size = header.num_channels * 2;
header.bits_per_sample = 16;
strcpy(header.data_chunk_header, "data");
header.data_bytes = SAMPLE_RATE * RECORD_SECONDS * header.frame_size;
// 计算文件大小
header.filesize = 36 + header.data_bytes;
// 写入 WAV 文件头
fwrite(&header, sizeof(WavHeader), 1, file);
// 设置输入参数
PaStreamParameters inputParameters;
// 在 PortAudio 中,设备 ID 通常与 arecord 命令列出的 card 编号对应。
inputParameters.device = 3; // 指定设备 ID---对应arecord -l输出的card 3
inputParameters.channelCount = 1;
inputParameters.sampleFormat = paInt16;
inputParameters.suggestedLatency = Pa_GetDeviceInfo(inputParameters.device)->defaultLowInputLatency;
inputParameters.hostApiSpecificStreamInfo = NULL;
// 打开音频流
err = Pa_OpenStream(&stream, &inputParameters, NULL, SAMPLE_RATE, FRAMES_PER_BUFFER, paClipOff, recordCallback, file);
if (err != paNoError) {
fprintf(stderr, "Pa_OpenStream: %s\n", Pa_GetErrorText(err));
fclose(file);
Pa_Terminate();
return 1;
}
// 启动音频流
err = Pa_StartStream(stream);
if (err != paNoError) {
fprintf(stderr, "Pa_StartStream: %s\n", Pa_GetErrorText(err));
Pa_CloseStream(stream);
fclose(file);
Pa_Terminate();
return 1;
}
// 录音
printf("录音中... (按任意键停止)\n");
getchar();
// 停止音频流
err = Pa_StopStream(stream);
if (err != paNoError) {
fprintf(stderr, "Pa_StopStream: %s\n", Pa_GetErrorText(err));
Pa_CloseStream(stream);
fclose(file);
Pa_Terminate();
return 1;
}
// 关闭音频流
Pa_CloseStream(stream);
// 更新 WAV 文件头中的数据大小
header.data_bytes = ftell(file) - 44;
header.filesize = 36 + header.data_bytes;
fseek(file, 0, SEEK_SET);
fwrite(&header, sizeof(WavHeader), 1, file);
// 关闭文件
fclose(file);
// 终止 PortAudio
Pa_Terminate();
printf("录音完成。\n");
return 0;
}
步骤3:编译和运行
使用 g++ 编译代码:
g++ recorder.cc -o recorder -lportaudio
./recorder
使用cmake编译代码
编写 CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
# 项目名称
project(Recorder)
# 查找 PortAudio 库
find_package(PortAudio REQUIRED)
# 添加可执行文件
add_executable(recorder recorder.cc)
# 链接 PortAudio 库
target_link_libraries(recorder PRIVATE ${PORTAUDIO_LIBRARIES})
# 设置可执行文件的输出目录
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin)
编写 CMakeLists.txt后,执行命令
mkdir build
cd build
cmake ..
make
./bin/recorder