当前位置: 首页 > article >正文

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

http://www.kler.cn/a/405547.html

相关文章:

  • 【电路笔记 TMS320F28335DSP】时钟+看门狗+相关寄存器(功能模块使能、时钟频率配置、看门狗配置)
  • sql注入报错分享(mssql+mysql)
  • C++:类和对象(三)
  • 实际开发中的协变与逆变案例:数据处理流水线
  • 关于一次开源java spring快速开发平台项目RuoYi部署的记录
  • 【gitlab】部署
  • ##继承##
  • Flink 常用问题及常用配置(有用)
  • [ 应急响应进阶篇-1 ] Windows 创建后门并进行应急处置-6:windows轻松访问后门
  • Java-07 深入浅出 MyBatis - 一对多模型 SqlMapConfig 与 Mapper 详细讲解测试
  • 前端知识点---rest(javascript)
  • 【代码随想录day38】【C++复健】322. 零钱兑换;279.完全平方数;139.单词拆分;卡码网56. 携带矿石资源
  • 力扣 LeetCode 257. 二叉树的所有路径(Day8:二叉树)
  • 泷羽sec-星河飞雪-shell-7
  • 演讲回顾丨杭州悦数 CTO 叶小萌:图数据库发展新航向——拥抱 GQL,融合 HTAP,携手 AI
  • git config 指令详解
  • C#开发基础之借用dotnet CLI命令行参数的设计了解命令行构建用法
  • Android 在Android.bp或Android.mk文件移除原生内置应用
  • 服务器数据恢复—raid5阵列热备盘上线失败导致EXT3文件系统不可用的数据恢复案例
  • Lumerical脚本——创建基本结构
  • comprehension
  • python文件对象方法
  • @PermitAll注解和@PreAuthorize注解
  • Next.js 开发教程(三):CSS 样式的完整指南
  • VLAN资源池(Java Python JS C++ C )
  • 如何在 React 项目中应用 TypeScript?应该注意那些点?结合实际项目示例及代码进行讲解!