录制成WAV文件

2023-11-29

自从我发帖以来这个问题,我一直在尝试自己从原始 PCM 数据编写一个有效的 WAV 文件。我已经成功编写了 FLAC 转换器(经过测试并且可以工作),但它不会对我一直在编写的 WAV 文件进行编码。

我不确定我做错了什么。我一直在网上搜索其他个人 源代码并将其与我自己的进行比较,但我仍然无法让它工作。

这是精简后的源代码(抱歉,它仍然有点长,需要一些代码才能记录到.wav就我自己而言):

// Compile with "g++ test.ccp -o test -lasound"

// Use the newer ALSA API
#define ALSA_PCM_NEW_HW_PARAMS_API

#include <alsa/asoundlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdint.h>

struct WaveHeader
{
        char RIFF_marker[4];
        uint32_t file_size;
        char filetype_header[4];
        char format_marker[4];
        uint32_t data_header_length;
        uint16_t format_type;
        uint16_t number_of_channels;
        uint32_t sample_rate;
        uint32_t bytes_per_second;
        uint16_t bytes_per_frame;
        uint16_t bits_per_sample;
};

struct WaveHeader *genericWAVHeader(uint32_t sample_rate, uint16_t bit_depth, uint16_t channels)
{
    struct WaveHeader *hdr;
    hdr = (WaveHeader*) malloc(sizeof(*hdr));
    if (!hdr)
        return NULL;

    memcpy(&hdr->RIFF_marker, "RIFF", 4);
    memcpy(&hdr->filetype_header, "WAVE", 4);
    memcpy(&hdr->format_marker, "fmt ", 4);
    hdr->data_header_length = 16;
    hdr->format_type = 1;
    hdr->number_of_channels = channels;
    hdr->sample_rate = sample_rate;
    hdr->bytes_per_second = sample_rate * channels * bit_depth / 8;
    hdr->bytes_per_frame = channels * bit_depth / 8;
    hdr->bits_per_sample = bit_depth;

    return hdr;
}

int writeWAVHeader(int fd, struct WaveHeader *hdr)
{
    if (!hdr)
        return -1;

    write(fd, &hdr->RIFF_marker, 4);
    write(fd, &hdr->file_size, 4);
    write(fd, &hdr->filetype_header, 4);
    write(fd, &hdr->format_marker, 4);
    write(fd, &hdr->data_header_length, 4);
    write(fd, &hdr->format_type, 2);
    write(fd, &hdr->number_of_channels, 2);
    write(fd, &hdr->sample_rate, 4);
    write(fd, &hdr->bytes_per_second, 4);
    write(fd, &hdr->bytes_per_frame, 2);
    write(fd, &hdr->bits_per_sample, 2);
    write(fd, "data", 4);

    uint32_t data_size = hdr->file_size + 8 - 44;
    write(fd, &data_size, 4);

    return 0;
}

int recordWAV(const char *fileName, struct WaveHeader *hdr, uint32_t duration)
{
    int err;
    int size;
    snd_pcm_t *handle;
    snd_pcm_hw_params_t *params;
    unsigned int sampleRate = hdr->sample_rate;
    int dir;
    snd_pcm_uframes_t frames = 32;
    char *device = (char*) "plughw:1,0";
    char *buffer;
    int filedesc;

    printf("Capture device is %s\n", device);

    /* Open PCM device for recording (capture). */
    err = snd_pcm_open(&handle, device, SND_PCM_STREAM_CAPTURE, 0);
    if (err)
    {
        fprintf(stderr, "Unable to open PCM device: %s\n", snd_strerror(err));
        return err;
    }

    /* Allocate a hardware parameters object. */
    snd_pcm_hw_params_alloca(&params);

    /* Fill it in with default values. */
    snd_pcm_hw_params_any(handle, params);

    /* ### Set the desired hardware parameters. ### */

    /* Interleaved mode */
    err = snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
    if (err)
    {
        fprintf(stderr, "Error setting interleaved mode: %s\n", snd_strerror(err));
        snd_pcm_close(handle);
        return err;
    }
    /* Signed 16-bit little-endian format */
    if (hdr->bits_per_sample == 16) err = snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE);
    else err = snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_U8);
    if (err)
    {
        fprintf(stderr, "Error setting format: %s\n", snd_strerror(err));
        snd_pcm_close(handle);
        return err;
    }
    /* Two channels (stereo) */
    err = snd_pcm_hw_params_set_channels(handle, params, hdr->number_of_channels);
    if (err)
    {
        fprintf(stderr, "Error setting channels: %s\n", snd_strerror(err));
        snd_pcm_close(handle);
        return err;
    }
    /* 44100 bits/second sampling rate (CD quality) */
    sampleRate = hdr->sample_rate;
    err = snd_pcm_hw_params_set_rate_near(handle, params, &sampleRate, &dir);
    if (err)
    {
        fprintf(stderr, "Error setting sampling rate (%d): %s\n", sampleRate, snd_strerror(err));
        snd_pcm_close(handle);
        return err;
    }
    hdr->sample_rate = sampleRate;
    /* Set period size*/
    err = snd_pcm_hw_params_set_period_size_near(handle, params, &frames, &dir);
    if (err)
    {
        fprintf(stderr, "Error setting period size: %s\n", snd_strerror(err));
        snd_pcm_close(handle);
        return err;
    }
    /* Write the parameters to the driver */
    err = snd_pcm_hw_params(handle, params);
    if (err < 0)
    {
        fprintf(stderr, "Unable to set HW parameters: %s\n", snd_strerror(err));
        snd_pcm_close(handle);
        return err;
    }

    /* Use a buffer large enough to hold one period */
    err = snd_pcm_hw_params_get_period_size(params, &frames, &dir);
    if (err)
    {
        fprintf(stderr, "Error retrieving period size: %s\n", snd_strerror(err));
        snd_pcm_close(handle);
        return err;
    }

    size = frames * hdr->bits_per_sample / 8 * hdr->number_of_channels; /* 2 bytes/sample, 2 channels */
    buffer = (char *) malloc(size);
    if (!buffer)
    {
        fprintf(stdout, "Buffer error.\n");
        snd_pcm_close(handle);
        return -1;
    }

    err = snd_pcm_hw_params_get_period_time(params, &sampleRate, &dir);
    if (err)
    {
        fprintf(stderr, "Error retrieving period time: %s\n", snd_strerror(err));
        snd_pcm_close(handle);
        free(buffer);
        return err;
    }

    uint32_t pcm_data_size = hdr->sample_rate * hdr->bytes_per_frame * duration / 1000;
    hdr->file_size = pcm_data_size + 44 - 8;

    filedesc = open(fileName, O_WRONLY | O_CREAT, 0644);
    err = writeWAVHeader(filedesc, hdr);
    if (err)
    {
        fprintf(stderr, "Error writing .wav header.");
        snd_pcm_close(handle);
        free(buffer);
        close(filedesc);
        return err;
    }
    fprintf(stdout, "Channels: %d\n", hdr->number_of_channels);
    for(int i = duration * 1000 / sampleRate; i > 0; i--)
    {
        err = snd_pcm_readi(handle, buffer, frames);
        if (err == -EPIPE) fprintf(stderr, "Overrun occurred: %d\n", err);
        if (err) err = snd_pcm_recover(handle, err, 0);
        // Still an error, need to exit.
        if (err)
        {
            fprintf(stderr, "Error occured while recording: %s\n", snd_strerror(err));
            snd_pcm_close(handle);
            free(buffer);
            close(filedesc);
            return err;
        }
        write(filedesc, buffer, size);
    }

    close(filedesc);
    snd_pcm_drain(handle);
    snd_pcm_close(handle);
    free(buffer);

    printf("Finished writing to %s\n", fileName);
    return 0;
}

int main(int argc, char *argv[]) {

    if(argc != 2)
    {
        fprintf(stderr, "Usage: %s (record duration)\n", argv[0]);
        return -1;
    }

    int err;
    struct WaveHeader *hdr;

    // Creates a temporary file in /tmp

    char wavFile[L_tmpnam + 5];
    char *tempFilenameStub = tmpnam(NULL);
    sprintf(wavFile, "%s.wav", tempFilenameStub);
    hdr = genericWAVHeader(44000, 16, 2);
    if (!hdr)
    {
        fprintf(stderr, "Error allocating WAV header.\n");
        return -1;
    }

    err = recordWAV(wavFile, hdr, 1000 * strtod(argv[1], NULL));
    if (err)
    {
            fprintf(stderr, "Error recording WAV file: %d\n", err);
            return err;
    }

    free(hdr);
    return 0;
}

程序运行时得到的输出:

$ ./capture 5
Capture device is plughw:1,0
Channels: 2
Error occured while recording: Channel number out of range
Error recording WAV file: -44

有什么建议么?我已经为此烦恼了一段时间了。


返回的错误代码snd_* 函数为负数。 有些函数可以返回正值来指示成功(例如,snd_pcm_readi返回帧数)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

录制成WAV文件 的相关文章

  • C修改printf()输出到文件

    有没有办法修改printf为了将字符串输出到文件而不是控制台 我尝试在互联网上查找一些内容 发现了类似的电话dup dup2 and fflush这可能与此有关 EDIT 也许我不清楚 问题是这是C考试问题 问题如下 解释一个通常将字符串输
  • 为什么假设 send 可能返回的数据少于在阻塞套接字上传输的请求数据?

    在流套接字上发送数据的标准方法始终是调用 send 并写入一大块数据 检查返回值以查看是否发送了所有数据 然后再次调用 send 直到整个消息被接受 例如 这是一个常见方案的简单示例 int send all int sock unsign
  • 如何将字节块读入结构体

    我有一个需要处理的资源文件 它包含一组文件 首先 资源文件列出了其中包含的所有文件 以及一些其他数据 例如在此结构中 struct FileEntry byte Value1 char Filename 12 byte Value2 byt
  • 错误:“rjags”的包或命名空间加载失败

    在终端的 conda 环境之一中 我能够成功安装包 rjags 但是 当我在该环境中运行 R 并运行库 rjags 时 出现以下错误 加载所需的包 coda 错误 rjags 的包或命名空间加载失败 rjags 的 loadNamespac
  • 将 C# 反射代码移植到 Metro-Ui

    我正在尝试移植使用反射的现有 C 类 通用工厂 但我无法编译这段代码 Type types Assembly GetAssembly typeof TProduct GetTypes foreach Type type in types i
  • 特定设备的不同字体大小

    我目前正在开发通用应用程序 我需要分别处理移动设备和桌面的文本框字体大小 我找到了一些方法 但都不能解决问题 使用 VisualStateManager 和 StateTrigger 为例
  • 用 C# 制作 Vista 风格的应用程序

    我正在运行 Windows Vista 并且希望外观看起来像常规 Vista 程序 有没有关于如何构建 Vista 风格应用程序的真正好的教程 文章 我还想学习如何使用本机代码并将其转换为 C 如this http bartdesmet n
  • 如何使用泛型类型的 DataContractSerializer 编写自定义序列化器?

    我想编写一个自定义序列化器 用于将会话状态存储到Azure 缓存 预览版 这意味着这个自定义序列化器必须实现IDataCacheObjectSerializer 如果我错了 请告诉我 我需要编写这个自定义序列化程序的原因是我需要序列化一些包
  • 在“using”语句中使用各种类型 (C#)

    自从C usingstatements只是try finally dispose 的语法糖 为什么它接受多个对象仅当它们属于同一类型时 我不明白 因为它们需要的只是 IDisposable 如果它们都实现 IDisposable 应该没问题
  • 数据损坏 C++ 和 Python 之间的管道

    我正在编写一些代码 从 Python 获取二进制数据 将其通过管道传输到 C 对数据进行一些处理 在本例中计算互信息度量 然后将结果通过管道传输回 Python 在测试时 我发现如果我发送的数据是一组尺寸小于 1500 X 1500 的 2
  • 不要声明只读可变引用类型 - 为什么不呢?

    我一直在阅读这个问题 https stackoverflow com questions 2274412 immutable readonly reference types fxcop violation do not declare r
  • 在生产服务器上使用 Subversion 使文件生效的最佳方法是什么?

    目前我已经设置了 subversion 这样当我在 Eclipse PDT 中进行更改时 我可以提交更改 它们将保存在 home administrator 中项目文件 该文件具有 subversion 推荐的 branches tags
  • 当在 Repository/UnitOrWork 之上使用 Service 类时,我应该在哪里放置逻辑不适合 Repository 的常用数据访问代码?

    In my 先前的问题 https stackoverflow com questions 24906548 using the generic repository unit of work pattern in large projec
  • 如何查找哪个 Yocto 项目配方填充图像根文件系统上的特定文件

    我经常与 Yocto 项目合作 一个常见的挑战是确定文件为何 或来自什么配方 包含在 rootfs 中 这有望从构建系统的环境 日志和元数据中得出 理想情况下 一组命令将允许将文件链接回源 即配方 我通常的策略是对元数据执行搜索 例如gre
  • 如何在 *nix 中登录时运行脚本?

    我知道我曾经知道如何做到这一点 但是 如何在 unix 中登录时运行脚本 bash 可以 From 维基百科 Bash http en wikipedia org wiki Bash 28Unix shell 29 当 Bash 启动时 它
  • 将 bignum 类型结构转换为人类可读字符串的有效方法是什么?

    我有一点问题 为了增长我的 C 知识 我决定尝试实现一个基本的 bigint 库 bigint 结构的核心将是一个 32 位整数数组 选择它们是因为它们适合寄存器 这将允许我在数字之间进行操作 这些操作将在 64 位整数中溢出 这也将适合寄
  • 为什么C语言中可以使用多个分号?

    在 C 中我可以执行以下操作 int main printf HELLO WORLD 它有效 这是为什么 我个人的想法 分号是一个 NO OPERATION 来自维基百科 指示符 拥有一大串分号与拥有一个分号并告诉 C 语句已结束具有相同的
  • 如何强制执行特定的 UserControl 设计

    我正在编写一个基本用户控件 它将由一堆其他用户控件继承 我需要对所有这些后代控件强制执行某种设计 例如 顶部必须有几个按钮以及一个或两个标签 后代用户控件区域的其余部分可以自由放置任何内容 最初 我认为我可以将一个面板放到 Base Use
  • 创建带有部分的选项卡式侧边栏 WPF

    我正在尝试创建一个带有部分的选项卡式侧边栏 如 WPF 中的以下内容 我考虑过几种方法 但是有没有更简单 更优雅的方法呢 方法一 列表框 Using a ListBox并将 SelectedItem 绑定到右侧内容控件所绑定的值 为了区分标
  • 使用剪贴板 SetText 换行

    如何使用 SetText 方法添加换行符 I tried Clipboard SetText eee n xxxx 但当我将剪贴板数据粘贴到记事本中时 它没有给我预期的结果 预期结果 eee xxxx 我怎样才能做到这一点 Windows

随机推荐

  • 折线图的“输入”选择可以设置动画吗?

    我有一个更新得非常好的折线图 直到新数据进入问题 此时 更新 选择会按应有的方式向下动画 但新数据不会 很难解释发生了什么 但一张 gif 胜过一千个单词 注意它何时转换 down 我已将图形包装在具有更新和渲染方法的类中 这是我写的渲染方
  • 如何在 IIS7 中托管 WCF 数据服务 (OData)?

    有谁知道如何在 IIS7 中托管 WCF 数据服务 或 OData 我看到很多有关托管 WCF 的文章 但没有一篇专门针对 WCF 数据服务 非常感谢 主持一个WCF数据服务在 IIS 中实际上是默认选项 这是一个非常简单的 3 步过程 创
  • SPNEGO:成功协商和身份验证后的后续调用

    在过去的几天里 我使用以下方法构建了一个概念验证演示GSS API and SPNEGO 目的是让用户通过 Http RESTful Web 服务单点登录访问我们的自定义应用程序服务器提供的服务 持有有效 Kerberos 票证授予票证 T
  • 在 git clone 命令中使用密码克隆 BitBucket 存储库会导致问题

    我正在尝试使用我的密码git clone命令克隆存储库 但总是会出现以下错误 remote Login failed due to incorrect login credentials or method remote If you ar
  • 我的 Android 应用程序可以在隐身选项卡中打开 URL 吗?

    我们都知道如何在 Android 的浏览器中打开 URL 做这样的事情 Intent browserIntent new Intent android intent action VIEW Uri parse url context sta
  • 在mysql中创建触发器时出现错误“1064”?

    在 mysql 中创建触发器时 我收到错误 1046 我的查询是 CREATE TABLE test Employee id int first name VARCHAR 30 last name VARCHAR 15 start date
  • extjs:加载时如何设置组合框的值

    我正在寻找一个load侦听器 当组合框启动时 load将被调用并向服务器执行 ajax 以获得组合框的正确显示值 但是 加载函数永远不会被调用 我该如何修复它 我想在组合框之前显示文本 所以我添加了属性fieldLabel Save log
  • 量角器未知错误,从 DOM 中删除属性

    我是量角器新手 试图从 DOM 中删除属性 但收到 未知错误 我不确定可能是什么问题 我有一个带有自定义指令的简单 HTML 我正在尝试删除它以使我的测试用例通过
  • 在 Google Colaboratory 上使用 GPU 运行 LightGBM/ LGBM

    我经常在 Google Colabatory 上运行 LGBM 我刚刚发现这个页面说 LGBM 默认设置为 CPU 所以你需要先设置 https medium com am sharma lgbm on colab with gpu c1c
  • Clearcase 7.1.2,VOB 分割

    我们当前设置了 VOB 源代码和文档驻留在同一个 VOB 中 为了减少 VOB 下载时间 我们现在希望将文档移动到新的 VOB 以便只有代码部分保留在旧的 VOB 中 由于有很多文件夹和文件 因此不可能手动重新定位每个文件 文件夹 为此 我
  • 使用框在同一文件上绘制不同的列

    我有一个看起来像这样的文件 cat myfile dat 1 8 32 19230 1 186 3 985 1 8 64 9620 0 600 7 877 1 8 128 4810 0 312 15 136 1 8 256 2410 0 2
  • 同步和可见范围

    我一直在阅读 Java 并发性 但忘记了这样一个事实 使用同一锁的两个线程中的同步块也会影响变量的可见性 即使它们没有定义为 易失性 如果我有这样的代码 Object lock new Object boolean a false b fa
  • PHP MD5 与 C# MD5 不匹配

    我在 C 中有一个哈希方法 如下所示 MD5CryptoServiceProvider md5 new MD5CryptoServiceProvider byte raw input Encoding UTF32 GetBytes hell
  • r 在数据表上的行式迭代

    library quantmod library PerformanceAnalytics getSymbols YHOO src google stock dat data table PerformanceAnalytics Calcu
  • 在 Excel 中复制和重命名未打开的工作簿

    我正在尝试复制位于一个文件路径的整个未打开的工作簿 将其重命名并将其保存到新目录 我在重命名和保存时遇到问题 这是迄今为止我的代码 Private Sub new file Click Dim ActBook As Workbook New
  • 用于初始化列表列表的简洁语法

    C 中是否有用于初始化列表列表的简洁语法 I tried new List
  • 使用 setAttribute 方法() 的 Aurelia 自定义属性

    当我在 javascript 中创建和附加元素并设置自定义属性时 Aurelia 似乎并不知道 除非我做错了什么 例如 const e document createElement div e setAttribute custom att
  • 如何将 iScroll4 与 SwipeView 结合使用?

    我正在使用 iScroll4 在移动网站内的图像上创建水平滚动效果 iScroll 工作得非常好 但问题是 iScroll 包装器中包含的图像禁用了本机垂直滚动 换句话说 用户通过手指滑动来导航页面的操作在 iScroll 包裹图像内的任何
  • 在php中获取图像src

    如何使用 php 函数从 img 标签获取图像源 或者 您可以使用内置 DOM 函数 如果您使用 PHP 5 doc new DOMDocument doc gt loadHTMLFile url xpath new DOMXpath do
  • 录制成WAV文件

    自从我发帖以来这个问题 我一直在尝试自己从原始 PCM 数据编写一个有效的 WAV 文件 我已经成功编写了 FLAC 转换器 经过测试并且可以工作 但它不会对我一直在编写的 WAV 文件进行编码 我不确定我做错了什么 我一直在网上搜索其他个