Linux麦克风录音实战

news2024/11/26 20:11:53

在 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.coloradmin.cn/o/2248021.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

游戏引擎学习第23天

实时代码编辑功能的回顾 当前实现的实时代码编辑功能已经取得了显著的成功&#xff0c;表现出强大的性能和即时反馈能力。该功能允许开发者在修改代码后几乎立即看到变化在运行中的程序中体现出来&#xff0c;极大提升了开发效率。尽管目前的演示内容较为简单&#xff0c;呈现…

Oracle 数据库 IDENTITY 列

IDENTITY列是Oracle数据库12c推出的新特性。之所以叫IDENTITY列&#xff0c;是由于其支持ANSI SQL 关键字 IDENTITY&#xff0c;其内部实现还是使用SEQUENCE。 不过推出这个新语法也是应该的&#xff0c;毕竟MyQL已经有 AUTO_INCREMENT列&#xff0c;而SQL Server也已经有IDENT…

计算机网络socket编程(2)_UDP网络编程实现网络字典

个人主页&#xff1a;C忠实粉丝 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 C忠实粉丝 原创 计算机网络socket编程(2)_UDP网络编程实现网络字典 收录于专栏【计算机网络】 本专栏旨在分享学习计算机网络的一点学习笔记&#xff0c;欢迎大家在评论区交流讨…

2022年计算机网络408考研真题解析

第一题&#xff1a; 解析&#xff1a;网络体系结构-数据链路层 在ISO网络参考模型中&#xff0c;运输层&#xff0c;网络层和数据链路层都实现了流量的控制功能&#xff0c;其中运输层实现的是端到端的流量控制&#xff0c;网络层实现的是整个网络的流量控制&#xff0c;数据链…

AI Prompt Engineering

AI Prompt Engineering 简介 Prompt Engineering, 提示工程&#xff0c;是人工智能领域的一项技术&#xff0c;它旨在通过设计高效的提示词&#xff08;prompts&#xff09;来优化生成式 AI&#xff08;如 GPT、DALLE 等&#xff09;的输出。提示词是用户与生成式 AI 交互的核…

Windows系统电脑安装TightVNC服务端结合内网穿透实现异地远程桌面

文章目录 前言1. 安装TightVNC服务端2. 局域网VNC远程测试3. Win安装Cpolar工具4. 配置VNC远程地址5. VNC远程桌面连接6. 固定VNC远程地址7. 固定VNC地址测试 前言 在追求高效、便捷的数字化办公与生活的今天&#xff0c;远程桌面服务成为了连接不同地点、不同设备之间的重要桥…

直播实时美颜平台开发详解:基于视频美颜SDK的技术路径

视频美颜SDK作为实现实时美颜的关键技术&#xff0c;为开发者提供了高效、灵活的解决方案。本篇文章&#xff0c;小编将以“基于视频美颜SDK的技术路径”为主题&#xff0c;深入解析直播实时美颜平台的开发要点。 一、视频美颜SDK的作用与优势 视频美颜SDK是一种集成化的开发工…

量子感知机

神经网络类似于人类大脑&#xff0c;是模拟生物神经网络进行信息处理的一种数学模型。它能解决分类、回归等问题&#xff0c;是机器学习的重要组成部分。量子神经网络是将量子理论与神经网络相结合而产生的一种新型计算模式。1995年美国路易斯安那州立大学KAK教授首次提出了量子…

实现在两台宿主机下的docker container 中实现多机器通讯

基于我的实验背景 上位机&#xff1a;ubuntu 20.04 (docker humble 22.04) 下位机&#xff1a;ubuntu 22.04&#xff08;docker noetic 20.04&#xff09; 目标&#xff1a;实现在上位机中的docker container 容器的22.04环境去成功远程访问 非同网段的下位机的20.04的contai…

远程控制软件:探究云计算和人工智能的融合

在数字化时代&#xff0c;远程控制工具已成为我们工作与生活的重要部分。用户能够通过网络远程操作和管理另一台计算机&#xff0c;极大地提升了工作效率和便捷性。随着人工智能&#xff08;AI&#xff09;和云计算技术的飞速发展&#xff0c;远程控制工具也迎来了新的发展机遇…

ISUP协议视频平台EasyCVR萤石设备视频接入平台银行营业网点安全防范系统解决方案

在金融行业&#xff0c;银行营业厅的安全保卫工作至关重要&#xff0c;它不仅关系到客户资金的安全&#xff0c;也关系到整个银行的信誉和运营效率。随着科技的发展&#xff0c;传统的安全防护措施已经无法满足现代银行对于高效、智能化安全管理的需求。 EasyCVR视频汇聚平台以…

C#基础上机练习题

21.计算500-800区间内素数的个数cn&#xff0c;并按所求素数的值从大到小的顺序排列&#xff0c;再计算其间隔加、减之和&#xff0c;即第1个素数-第2个素数第3个素数-第4个素数第5个素数……的值sum。请编写函数实现程序的要求&#xff0c;把结果cn和sum输出。 22.在三位整数…

ubuntu24挂载硬盘记录

1、显示硬盘及所属分区情况。在终端窗口中输入如下命令&#xff1a; sudo fdisk -l 找到自己硬盘的分区 我的地址/dev/sda 2、显示硬盘及所属分区情况。在终端窗口中输入如下命令&#xff0c;格式化自己硬盘&#xff1a; sudo mkfs -t ext4 /dev/sda 3、在终端窗口中输入如下…

函数类型注释和Union联合类型注释

函数类型注释格式&#xff08;调用时提示输入参数的类型&#xff09;: )def 函数名(形参名:类型&#xff0c;形参名:类型&#xff09;->函数返回值类型: 函数体 Union联合类型注释&#xff08;可注释多种类型混合的变量&#xff09;格式: #先导入模块 from typing import…

【Python】分割秘籍!掌握split()方法,让你的字符串处理轻松无敌!

在Python开发中&#xff0c;字符串处理是最常见也是最基础的任务之一。而在众多字符串操作方法中&#xff0c;split()函数无疑是最为重要和常用的一个。无论你是Python新手&#xff0c;还是经验丰富的开发者&#xff0c;深入理解并熟练运用split()方法&#xff0c;都将大大提升…

DICOM图像深入解析:为何部分DR/CR图像默认显示为反色?

概述 在数字医学影像处理中,CR(Computed Radiography,计算机放射摄影)和DR(Digital Radiography,数字放射摄影)技术广泛应用于医疗影像获取与分析。然而,临床实践中常常遇到这样一个问题:部分CR/DR图像在默认打开时呈现为反色(即负片效果),需手动反色后才能正常阅片…

正则表达式灾难:重新认识“KISS原则”的意义

RSS Feed 文章标题整理 微积分在生活中的应用与思维启发 捕鹿到瞬时速度的趣味探索 微积分是一扇通往更广阔世界的门&#xff0c;从生活中学习思维的工具。 数据库才是最强架构 你还在被“复杂架构”误导吗&#xff1f; 把业务逻辑写入数据库&#xff0c;重新定义简单与效率。…

详解 【AVL树】

AVL树实现 1. AVL的概念AVL树的实现2.1 AVL树的结点结构2.2 AVL树的插入2.2.1 AVL树的插入的一个大概操作&#xff1a;2.2.2 AVL树的平衡因子更新2.2.3 平衡因子的停止条件2.2.4 再不考虑旋转的角度上实现AVL树的插入 2.3 旋转2.3.1 旋转的原则2.3.2 右单旋2.2.3 右单旋代码实现…

go语言range的高级用法-使用range来接收通道里面的数据

在 Go 语言中&#xff0c;可以使用 for ... range 循环来遍历通道&#xff08;channel&#xff09;。for ... range 循环会一直从通道中接收值&#xff0c;直到通道关闭并且所有值都被接收完毕。 使用 for ... range 遍历通道 示例代码 下面是一个使用 for ... range 遍历通…

计算机网络 | 7.网络安全

1.网络安全问题概述 &#xff08;1&#xff09;计算机网络面临的安全性威胁 <1>计算机网络面临的完全性威胁 计算机网络面临的两大类安全威胁&#xff1a;被动攻击和主动攻击 被动攻击 截获&#xff1a;从网络上窃听他人的通信内容。主动攻击 篡改&#xff1a;故意篡改…