【问题标题】:How to change the volume of a .wav file?如何更改 .wav 文件的音量?
【发布时间】:2020-09-30 08:56:08
【问题描述】:

我的代码只是复制标题,但不会在第二个循环中改变音量。

// TODO: Copy header from the input file to the output file

uint8_t header[HEADER_SIZE];
uint8_t* header_p=malloc(HEADER_SIZE * sizeof(uint8_t));
while(fread(&header_p,sizeof(header[HEADER_SIZE]),1,input))
{
    fwrite(&header_p,sizeof(header[HEADER_SIZE]),1,output);
}

// TODO: Read samples from the input file and write updated data to the output file

int16_t buffer;

while(fread(&buffer,sizeof(buffer),1,input))
{
    buffer =(int16_t)(buffer*factor);
    fwrite(&buffer,sizeof(buffer),1,output);
}

【问题讨论】:

  • 我不知道 .wav 文件的格式,但 malloc(sizeof(uint8_t)) 看起来分配的字节很少(一个字节)。
  • 是的,我编辑了它,但没有任何改变,问题在于第二个循环。
  • 1 在十六进制编辑器中打开输出文件并检查数据是否符合您的预期。 2 手工制作示例并检查外观和工作是否符合预期。
  • 你确定这个 WAV 文件是每个样本 16 位的吗?以及为什么要定义大小为HEADER_SIZE 的静态数组,然后为相同大小执行malloc - 我没有看到任何修改。您可以使用header 缓冲区而不是header_p
  • 您希望在一个文件中找到多少个HEADER 元素?您在第一个循环中读取/写入整个文件,直到剩余字节小于 1 个标头。

标签: c audio wav


【解决方案1】:

如果特定的 WAV 文件仅包含一个标头,后跟代表声音数据的 16 位带符号值,则您的错误将出现在第一个 while 循环中。这个循环继续从输入到输出复制sizeof(header[HEADER_SIZE])(实际上是header中一个元素的大小为1)块,直到到达文件末尾,不会进入第二个while循环。

只需复制一次标头,然后使用更合适的缩放算法来解决其他一些问题。例如:

uint8_t header[HEADER_SIZE];
/* There is only one header, so parse it just once */
if (fread(&header[0], sizeof(header), 1, input)) {
    fwrite(&header[0], sizeof(header), 1, output);
}

/* Assuming 16-bit signed integer PCM payload */
int16_t sample;
while(fread(&sample, sizeof(sample), 1, input)) {
    /* Round value to nearest number */
    double scaledValue = floor((sample * factor) + 0.5);

    /* Clamp new value */
    if (scaledValue >= INT16_MAX) {
        sample = INT16_MAX;
    } else if (scaledValue <= INT16_MIN) {
        sample = INT16_MIN;
    } else {
        sample = (int16_t)scaledValue;
    }
    fwrite(&sample, sizeof(sample), 1, output);
}

但是 .wav 文件格式并非如此简单,并且有多种变体,16 位带符号的 PCM 值只是其中之一。示例数据的大小和格式也在标题中给出,您需要仔细解析标题并采取相应措施。有关 .wav 文件格式的更多信息,我想这些是一个很好的起点:

【讨论】:

  • 这应该可以,但我的输出文件显示它已损坏
  • @snowr 我添加了第三个链接,逐字节描述 PCM 16 位 WAVE 文件格式。如果您包含 RIFF 标头部分、WAVE fmt 部分以及块 ID 和大小,您的“标头”应该是大约 44 个字节,但只有当您的文件中只有一个块时它才会起作用。但请正确解析 WAV 数据,至少考虑块 ID 和大小...
  • 它有效,但我也删除了“+ 0.5”-失真以通过测试。非常感谢!
  • 那个 + 0.5 是为了改进舍入,但我忘了这是一个有符号的 int 范围,所以我应该减去 0.5 作为负值。另请参阅stackoverflow.com/questions/9695329/… 我将更新我的答案 - 0.5 表示负值。
  • 是的,我现在明白了。但是因为我的文件,我不得不删除它。抱歉,误会你了。
猜你喜欢
  • 2012-10-31
  • 2011-01-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-30
  • 1970-01-01
相关资源
最近更新 更多