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

news2024/9/16 10:03:22

麦克风列表:

[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;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2117037.html

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

相关文章

【硬件知识】关于RAM的“那些事”

文章目录 一、DRAM&#xff08;动态随机存取存储器&#xff09;二、SRAM&#xff08;静态随机存取存储器&#xff09;三、DRAM和SRAM的差异与区别 一、DRAM&#xff08;动态随机存取存储器&#xff09; 工作原理&#xff1a;DRAM使用电容来存储数据。每一位数据通过一个电容和…

【深度学习讲解笔记】第1章-机器学习基础

1.机器学习是什么 机器学习&#xff08;Machine Learning&#xff0c;ML&#xff09;&#xff0c;顾名思义就是让机器学会做一件事情&#xff0c;比如语音识别&#xff0c;机器听一段声音&#xff0c;产生这段声音对应的文字。或是识别图片中有几个人&#xff0c;几辆车。这些…

2024年语音识别转文字工具的崛起

无论是繁忙的会议记录、远程教学的即时笔记&#xff0c;还是日常生活的语音备忘&#xff0c;只需轻轻一说&#xff0c;便能瞬间转化为清晰可编辑的文字&#xff0c;这种便捷与高效无疑为现代生活增添了无限可能。本文将带你深入探索语音识别转文字工具的奥秘。 1.365在线转文字…

【Python篇】matplotlib超详细教程-由入门到精通(上篇)

文章目录 第一部分&#xff1a;基础概念与简单绘图1.1 matplotlib 简介1.2 创建第一个折线图1.3 图表的基本组成元素 第二部分&#xff1a;图表样式与修饰2.1 修改图表样式2.2 添加图例2.3 调整坐标轴与刻度 第三部分&#xff1a;绘制不同类型的图表3.1 散点图 (Scatter Plot)3…

使用 Homebrew 在 macOS 上安装 Conda

Homebrew 是一个流行的 macOS 包管理器&#xff0c;可以帮助你安装和管理各种软件包。 以下是使用 Homebrew 安装 Conda 的步骤&#xff1a; 1. 安装 Homebrew 如果你还没有安装 Homebrew&#xff0c;可以通过以下命令安装&#xff1a; /bin/bash -c "$(curl -fsSL htt…

《机器学习》—— XGBoost(xgb.XGBClassifier) 分类器

文章目录 一、XGBoost 分类器的介绍二、XGBoost&#xff08;xgb.XGBClassifier&#xff09; 分类器与随机森林分类器&#xff08;RandomForestClassifier&#xff09;的区别三、XGBoost&#xff08;xgb.XGBClassifier&#xff09; 分类器代码使用示例 一、XGBoost 分类器的介绍…

微信小程序 自定义组件

1. 微信小程序 自定义组件 微信小程序支持组件化开发&#xff0c;这有助于我们复用代码&#xff0c;提高开发效率。下面我将给出一个简单的微信小程序组件化示例&#xff0c;包括一个自定义组件的创建和使用。 1.1. 创建自定义组件 首先&#xff0c;在项目的 components 目录…

建筑二次供水的基本概念

什么是二次供水&#xff1f; 二次供水是城市供水的主要组成部分&#xff0c;是指集中式供水在入户之前经再度储存、加压和消毒后&#xff0c;通过管道输送给用户的供水方式。 为什么要使用二次供水&#xff1f; 由于市政供水的服务水压通常只能达到较低的楼层&#xff0c;而…

部分库函数及其模拟

前言&#xff1a;当我们学习c/c库函数的时候&#xff0c;我们可以用网站 cplusplus.com - The C Resources Network 来进行查阅&#xff0c;学习。 目录 库函数&#xff1a; 1.字符串函数 1.1求字符串长度 strlen 1.2长度不受限制的字符串函数 1.2.1strcpy 1.2.2strca…

“阡陌云旅”黄河九省文化旅游平台

“阡陌云旅”黄河九省文化旅游平台 GitHub地址&#xff1a;https://github.com/guoJiaQi-123/Yellow-River-Cloud-Journey 项目背景 “阡陌云旅”黄河九省文化旅游平台 “阡陌云旅” 黄河九省文化旅游平台是一个专注于黄河流域九省文化旅游资源整合与推广的项目。 黄河是中…

Spring Framework系统框架

序号表示的是学习顺序 IoC&#xff08;控制反转&#xff09;/DI&#xff08;依赖注入&#xff09;: ioc&#xff1a;思想上是控制反转&#xff0c;spring提供了一个容器&#xff0c;称为IOC容器&#xff0c;用它来充当IOC思想中的外部。 我的理解就是spring把这些对象集中管理…

HomeAssistant添加HACS绑定米家与苹果HomeKit设备并实现远程管理

文章目录 前言1. 下载HACS源码2. 添加HACS商店3. 绑定米家设备 前言 之前介绍过如何实现在群晖NAS使用Docker部署HomeAssistant&#xff0c;通过内网穿透在户外控制家庭智能设备。本文将介绍如何在HA平台安装HACS插件商店&#xff0c;将米家&#xff0c;果家设备接入 Home Ass…

推荐清晖一套不错的讲解沟通的线上讲座

推荐清晖一套不错的讲解沟通的线上讲座&#xff0c;比较实际贴地&#xff0c;听完了推荐给大家&#xff1a; 《项目管理中的沟通策略&#xff0c;听出弦外之音&#xff0c;变身沟通达人》 地址&#xff1a;项目管理中的沟通策略&#xff0c;听出弦外之音&#xff0c;变身沟通达…

数据结构(1):ArrayList和顺序表

数据结构(Data Structure)是计算机存储、组织数据的方式&#xff0c;指相互之间存在一种或多种特定关系的数据元素的集合。 下面我们就开一个新坑&#xff0c;数据结构。数据结构&#xff0c;简单来说就是存放数据的方式&#xff0c;这些方式多种多样&#xff0c;我们来一点一…

Statcounter Global Stats 提供全球统计数据信息

Statcounter Global Stats 提供全球统计数据信息 1. Statcounter Global Stats2. Mobile & Tablet Android Version Market Share WorldwideReferences Statcounter Global Stats https://gs.statcounter.com/ Statcounter Global Stats are brought to you by Statcounte…

C++ 定时器

这是第一次独立设计一个模块&#xff0c;从接口定义&#xff0c;模块组合到多线程并发可能遇到的各种问题&#xff0c;虽然定时挺简单的&#xff0c;但是想设计精度高&#xff0c;并且能应对高并发似乎也不是很容易&#xff0c;当然&#xff0c;最后没有测试定时器的代码&#…

架构模式:MVC

引言 MVC&#xff0c;即 Model&#xff08;模型&#xff09;-View&#xff08;视图&#xff09;-Controller&#xff08;控制器&#xff09;&#xff0c;是广泛应用于交互式系统中的典型架构模式&#xff0c;尤其在 GUI 和 Web 应用中。 MVC 的概念源自 GOF&#xff08;Gang …

JS解密工具之**如何续期 Charles 的 SSL 证书**

本文由 jsjiami加密/一键JS解密 独家赞助 有问题请私聊加密官方客服 Charles 是一款常用的 HTTP 代理工具&#xff0c;用于调试网络请求。然而&#xff0c;Charles 的 SSL 证书会定期过期&#xff0c;如果 SSL 证书失效&#xff0c;你将无法对 HTTPS 请求进行抓包。本文将详细…

SQL语句中in条件超过1000怎么办?

博客主页: 南来_北往 系列专栏&#xff1a;Spring Boot实战 引言 当遇到SQL语句中IN条件超过1000个的情况时&#xff0c;可以采取以下几种策略来有效处理这一问题&#xff1a; 使用临时表&#xff1a;将IN列表中的值存储在临时表中&#xff0c;并将该临时表与查询表进行J…

【Python 千题 —— 算法篇】寻找最长回文子串

Python 千题持续更新中 …… 脑图地址 &#x1f449;&#xff1a;⭐https://twilight-fanyi.gitee.io/mind-map/Python千题.html⭐ 题目背景 回文串是指一个字符串从左到右和从右到左读都是一样的。寻找一个字符串中的最长回文子串是许多经典算法问题之一&#xff0c;广泛应…