首页 > 系统相关 >Linux 下 alsa 库录音并保存为 WAV 格式

Linux 下 alsa 库录音并保存为 WAV 格式

时间:2024-12-24 23:31:29浏览次数:5  
标签:snd int Linux sample header params pcm WAV alsa

麦克风列表:

[jn@jn build]$ arecord -l
**** List of CAPTURE Hardware Devices ****
card 0: AudioPCI [Ensoniq AudioPCI], device 0: ES1371/1 [ES1371 DAC2/ADC]
  Subdevices: 1/1
  Subdevice #0: subdevice #0
card 1: Camera [2K USB Camera], device 0: USB Audio [USB Audio]
  Subdevices: 1/1
  Subdevice #0: subdevice #0
[jn@jn build]$

alsa麦克风录音保存wav代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <alsa/asoundlib.h>

#define PCM_DEVICE "default"
#define FORMAT SND_PCM_FORMAT_S16_LE
#define CHANNELS 2
#define SAMPLE_RATE 44100
#define BITS_PER_SAMPLE 16
#define WAV_HEADER_SIZE 44

// WAV 文件头
typedef struct {
    char riff[4];                // "RIFF"
    unsigned int overall_size;   // 文件大小 - 8
    char wave[4];                // "WAVE"
    char fmt_chunk_marker[4];    // "fmt "
    unsigned int length_of_fmt;  // 格式数据块大小
    unsigned short format_type;  // 格式类别 (PCM = 1)
    unsigned short channels;     // 通道数
    unsigned int sample_rate;    // 采样率
    unsigned int byterate;       // 每秒字节数
    unsigned short block_align;  // 一个样本的字节数
    unsigned short bits_per_sample;  // 每个样本的位数
    char data_chunk_header[4];   // "data"
    unsigned int data_size;      // 音频数据大小
} wav_header_t;

// 生成WAV文件头
void write_wav_header(FILE *file, int channels, int sample_rate, int bits_per_sample, int data_size) {
    wav_header_t header;
    
    // 填写 WAV 文件头
    memcpy(header.riff, "RIFF", 4);
    header.overall_size = data_size + WAV_HEADER_SIZE - 8;
    memcpy(header.wave, "WAVE", 4);
    memcpy(header.fmt_chunk_marker, "fmt ", 4);
    header.length_of_fmt = 16;
    header.format_type = 1;  // PCM
    header.channels = channels;
    header.sample_rate = sample_rate;
    header.byterate = sample_rate * channels * bits_per_sample / 8;
    header.block_align = channels * bits_per_sample / 8;
    header.bits_per_sample = bits_per_sample;
    memcpy(header.data_chunk_header, "data", 4);
    header.data_size = data_size;

    fwrite(&header, 1, sizeof(wav_header_t), file);
}

// 主函数
int main() {
    unsigned int sample_rate = SAMPLE_RATE;
    int channels = CHANNELS;
    snd_pcm_uframes_t frames = 32;  // 每次读取32帧

    // 打开 ALSA PCM 设备
    snd_pcm_t *pcm_handle;
    snd_pcm_hw_params_t *params;
    snd_pcm_uframes_t frames_per_period;
    int pcm;

    pcm = snd_pcm_open(&pcm_handle, PCM_DEVICE, SND_PCM_STREAM_CAPTURE, 0);
    if (pcm < 0) {
        fprintf(stderr, "ERROR: Can't open \"%s\" PCM device. %s\n", PCM_DEVICE, snd_strerror(pcm));
        return -1;
    }

    // 设置硬件参数
    snd_pcm_hw_params_malloc(&params);
    snd_pcm_hw_params_any(pcm_handle, params);
    snd_pcm_hw_params_set_access(pcm_handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
    snd_pcm_hw_params_set_format(pcm_handle, params, FORMAT);
    snd_pcm_hw_params_set_channels(pcm_handle, params, channels);
    snd_pcm_hw_params_set_rate_near(pcm_handle, params, &sample_rate, 0);
    snd_pcm_hw_params_set_period_size_near(pcm_handle, params, &frames, 0);
    pcm = snd_pcm_hw_params(pcm_handle, params);
    if (pcm < 0) {
        fprintf(stderr, "ERROR: Can't set hardware parameters. %s\n", snd_strerror(pcm));
        return -1;
    }

    snd_pcm_hw_params_get_period_size(params, &frames_per_period, 0);

    // 打开WAV文件并写入头部
    FILE *file = fopen("output.wav", "wb");
    if (!file) {
        fprintf(stderr, "ERROR: Can't open output file.\n");
        return -1;
    }
    write_wav_header(file, channels, sample_rate, BITS_PER_SAMPLE, 0);  // 先写入空的WAV头

    // 分配缓冲区
    int buffer_size = frames_per_period * channels * BITS_PER_SAMPLE / 8;
    char *buffer = (char *) malloc(buffer_size);

    // 录音循环
    int total_bytes = 0;
    while (total_bytes < SAMPLE_RATE * 5 * channels * BITS_PER_SAMPLE / 8) {  // 录音5秒
        pcm = snd_pcm_readi(pcm_handle, buffer, frames_per_period);
        if (pcm == -EPIPE) {
            fprintf(stderr, "XRUN.\n");
            snd_pcm_prepare(pcm_handle);
        } else if (pcm < 0) {
            fprintf(stderr, "ERROR: Can't read from PCM device. %s\n", snd_strerror(pcm));
        } else {
            fwrite(buffer, 1, buffer_size, file);
            total_bytes += buffer_size;
        }
    }

    // 更新 WAV 头部文件大小信息
    fseek(file, 0, SEEK_SET);
    write_wav_header(file, channels, sample_rate, BITS_PER_SAMPLE, total_bytes);

    // 清理
    free(buffer);
    fclose(file);
    snd_pcm_drain(pcm_handle);
    snd_pcm_close(pcm_handle);

    return 0;
}

标签:snd,int,Linux,sample,header,params,pcm,WAV,alsa
From: https://www.cnblogs.com/dujn/p/18628901

相关文章

  • Linux | scp指令基于WSL在Windows/Ubuntu系统间传输文件
    .背景在Windows系统里,使用WSL连接远程Linux(Ubuntu)服务器是如今一个很常见的操作流程(有利于WFH哈哈)。在使用远程机器的时候,通常需要将本地的文件上传、或将远程的文件下载。问题:如何优雅地将本地文件上传、或将远程的文件下载?.解决方案在网上搜索一番、同时问了GPT,找......
  • Linux 下 mysql 9.1 安装设置初始密码 【附脚本】
    @目录1.下载合适版本2.安装3.初始密码,并允许远程登录4.终极脚本5.其他常用sql概述:本文介绍Linux下如何安装mysql9.1并设置初始密码,不想看步骤内容,安装好后直接到脚本部分,复制脚本到mysql服务器设置即可。1.下载合适版本https://dev.mysql.com/downloads/mysql/例如我的......
  • ArchLinux使用小结
    ArchLinux使用与软件管理小结引言在使用ArchLinux的过程中,我作为新手,遇到了不少问题和挑战。为了帮助自己更好地记录这些经验教训,我决定撰写这篇随笔。虽然内容可能显得随意,但希望能对其他用户有所帮助。1.配置AUR助手ArchUserRepository(AUR)是ArchLinux用户共享......
  • 定制最小linux系统 - 4: 使用vscode单步调试
    内核毕竟是一个很大的工程,有时看得一头雾水,如果能单步调试的话,对于理解可能有亿点帮助.下面一步步搭建qemu+vscode环境对内核进行单步调试.第一步编译内核定制最小linux系统-1:编译linux内核-CSDN博客https://blog.csdn.net/weixin_46766770/article/details/1......
  • Linux之权限管理
    Linux系统之所以更安全,是因为对文件权限有着非常严格的控制。查看文件或目录的权限:ls-al文件权限分别为:读(read),写(write),执行(execute),简写即为(r,w,x),-即无权限。每个文件针对每类访问者定义了三种主要权限。其中,第一位:代表文件类型,后面每3位代表一组权限,分别是:所有者、所属......
  • Linux工具使用指南:从apt管理、gcc编译到makefile构建与gdb调试
    文章目录前言......
  • Linux之用户管理
    Linux用户管理用户&用户组用户:Linux是多用户多任务操作系统,换句话说,Linux、系统支持多个用户在同一时间内登陆,不同用户可以执行不同的任务,并且互不影响。不同用户具有不同的权限,毎个用户在权限允许的范围内完成不同的任务,Linux正是通过这种权限的划分与管理,实现了多用户多......
  • 找到一个linux静态库动态库的好资料.1
    #正文前一篇说找到了这个资料:https://tldp.org/HOWTO/Program-Library-HOWTO/shared-libraries.html;它的首页是https://tldp.org/HOWTO/Program-Library-HOWTO/index.html。原文很好懂,所以我这里算是写一下自己学到的东西,不是翻译,也不按顺序,先整理一下静态库、共享库以及......
  • 嵌入式linux驱动框架 I2C系统驱动程序模型分析
    引言:在嵌入式Linux系统中,I2C(Inter-IntegratedCircuit)是一种常用的通信协议,用于连接低速设备(如传感器、显示器、存储器等)与主控制器。I2C系统驱动程序模型通过层次化的设计,使得I2C总线设备和驱动程序能够高效、灵活地进行通信和管理。本分析旨在详细介绍I2C驱动程序框......
  • RK3568平台开发系列讲解(中断及异常篇)Linux 中断系统中的重要数据结构
    ......