【问题标题】:Converting a .wav file to mono (delete right channel)将 .wav 文件转换为单声道(删除右声道)
【发布时间】:2018-11-15 06:18:34
【问题描述】:

我正在尝试从 .wav 文件中删除正确的频道,但无济于事。关于原始标题的一些信息:

NumChannels:2,BlockAlign:4,BitsPerSample:16

从这里我得到样本大小是 4 个字节(2Left + 2Right)所以我正在创建一个新文件,将原始标题写入它,然后一次将 4 个字节从原始文件写入新文件使用 AND 掩码 0xffff0000 将右声道归零。虽然看起来右声道的音量减少了 90%,但我正在寻找一些改进。以下部分代码:

int convertToMono(char *original) {
    Header *header = malloc(sizeof(Header));
    getHeader(header, original);

    FILE *fp = fopen(original, "rb");
    fseek(fp, HEADER_SIZE, 0);// Advance HEADER_SIZE bytes to data section

    // Create new file name
    char *name = malloc((5 + strlen(original)) * sizeof(char));
    strcpy(name, "new-");
    strcat(name, original);

    // Open new file and write the header to it
    FILE *new = fopen(name, "wb");
    fwrite(header, HEADER_SIZE, 1, new);

    u_int sample = 0;// unsigned int, size in bytes == 4
    for (int i = 0; i < header->chunkSize - HEADER_SIZE + 8; i += sizeof(u_int)) {
        fread(&sample, sizeof(u_int), 1, fp);
        sample = (sample & 0xffff0000);
        fwrite(&sample, sizeof(u_int), 1, new);
    }

    fclose(fp);
    fclose(new);
    free(name);
    return 0;
}

编辑:添加了 Audacity 显示的音频图片。

【问题讨论】:

  • HEADER_SIZE 是不是不变的?如果我记得,WAV 文件遵循 RIFF 格式,这意味着它们可以包含可变长度的任意数据。你如何确定你的函数是在音频数据的开头?您如何确定正确的通道减少了 90%?您是否在音频应用程序中加载波形并检查它?如果它真的不为零,那么您很可能会从左通道中流血,这表明您的对齐已关闭。
  • HEADER_SIZE 始终为 44,文件格式应为标题后跟实际数据。关于其余的,我只是通过 Windows 上的 Groove 音乐应用程序播放创建的文件。可能音频驱动程序试图变得聪明并通过两个扬声器播放单声道信号。
  • 它不是单声道信号。这是一个立体声信号,一个通道上没有音频。这是我的一个怀疑:您可能只是在某个混合音频的应用程序中播放它,或者您的音频驱动程序正在运行一些平移/混合,或者一些“环绕”或混响效果。如果您想实际检查 WAV 文件,请在 Audacity 之类的程序中打开它。
  • Audacity 在正确的频道上没有显示任何活动,但我仍然可以听到它。您知道转换为实际单声道信号的方法吗?也许通过更改一些标头数据并将原始数据以不同的方式解析为新文件?我可能已经采取了正确的步骤,但耳机只是搞砸了。
  • 关于转换为真正的单声道:是的,您将通道数更改为 1 并只写出左通道。或者为了正确的单声道转换,您可以将左右混合在一起。您可能还需要调整音频数据的块大小。

标签: c wav


【解决方案1】:

要转换为单声道,首先您必须更改与字段 numChannels 关联的标头信息:

header->numChannels = 1;
header->subchunk2Size /= 2;
header->chunkSize = header->subchunk2Size + 36;
header->byteRate /= 2;
header->blockAlign /= 2;

然后你打开新文件并将修改后的标题写入它:

FILE *fp2 = fopen("new.wav", "wb");
fwrite(header, HEADER_SIZE, 1, fp2);

创建一个可以容纳一半样本的缓冲区:

size_t channel_size = (size_t) (header->bitsPerSample / 8);
char sample[channel_size];

对所有样本读写左通道并忽略右通道。

for (int i = 0; i < header->subchunk2Size; i += channel_size) {
    fread(sample, channel_size, 1, fp1);
    fwrite(sample, channel_size, 1, fp2);

    fread(sample, channel_size, 1, fp1);
}

这将创建一个大小为原始文件一半的文件,并且只会听到左声道。注意:这并不意味着声音只会来自左耳机。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-08
    • 1970-01-01
    • 2011-07-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多