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

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

麦克风列表:

[jn@jn build]$ arecord -l
**** List of CAPTURE Hardware Devices ****
card 0: AudioPCI [Ensoniq AudioPCI], device 0: ES1371/1 [ES1371 DAC2/ADC]Subdevices: 1/1Subdevice #0: subdevice #0
card 1: Camera [2K USB Camera], device 0: USB Audio [USB Audio]Subdevices: 1/1Subdevice #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;   // 文件大小 - 8char 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;  // PCMheader.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;
}
http://www.lryc.cn/news/433513.html

相关文章:

  • 使用stripe进行在线支付、退款、订阅、取消订阅功能(uniapp+h5)
  • 深度学习中常见的损失函数
  • 认识Linux及Linux的环境搭建
  • Java之线程篇三
  • Bootstrap动态设置表格title项
  • Arrays.sort()方法在Java中的使用:理论与实践
  • 用AI写论文,千万不要这样用ChatGPT生成参考文献References!!
  • Debian 12如何关闭防火墙
  • windows C++-并行编程-PPL任务并行(二)
  • 快速了解 servlet(SpringMVC 的底层)
  • QT中tr的作用是什么
  • OpenCV结构分析与形状描述符(7)计算轮廓的面积的函数contourArea()的使用
  • 内网环境使用Docker部署Qwen2模型-vLLM篇
  • Rust的常数、作用域与所有权
  • Spring 源码解读:解决循环依赖的三种方式
  • Web3 详解
  • Spring 中依赖注入注解的区别详解
  • PTA求一批整数中出现最多的个位数字
  • 探索国产编程工具:如何实现工作效率翻倍
  • 秒懂:进程相关的操作
  • PDF 软件如何帮助您编辑、转换和保护文件。
  • 蓝桥杯嵌入式国三备赛经验分享
  • AI编程工具合集
  • [网络编程]通过java用TCP实现网络编程
  • Python(TensorFlow)和Java及C++受激发射损耗导图
  • IEEE投稿模板翻译
  • log4j 1.x 日志输出线程以唯一ID的形式配置
  • 宏观学习笔记:GDP分析(二)
  • 两个月冲刺软考——访问位与修改位的题型(淘汰哪一页);内聚的类型;关于码制的知识点;地址映射的相关内容
  • C高级编程 第十六天(树 二叉树)