无法使用两个不同的频率填充* .wav文件的缓冲区

时间:2019-04-05 14:57:01

标签: c++ file struct wav

自从我尝试写入8位音频以来,通过将缓冲区从int16_t更改为int8_t来解决了此问题。

我正在尝试为具有两个不同频率的单声道文件填充缓冲区,但失败了。我在Ubuntu 18.04中使用CLion。

我知道,缓冲区大小等于duration*sample_rate,所以我正在创建一个具有该大小的int16_t向量。我尝试先用一个音符填充它。

for(int i = 0; i < frame_total; i++)
    audio[i] = static_cast<int16_t>(128 + 127 * sin(i));

这发出了长鸣。然后我用:

for(int i = 0; i < frame_total; i++)
    audio[i] = static_cast<int16_t>(128 + 127 * sin(i*2));

会产生较高的蜂鸣声,但是在尝试执行以下操作时:

for(int i = 0; i < frame_total/2; i++)
    audio[i] = static_cast<int16_t>(128 + 127 * sin(i*2));

for(int i = frame_total/2; i < frame_total; i++)
    audio[i] = static_cast<int16_t>(128 + 127 * sin(i));

我希望它在音频的前半部分写入较高的蜂鸣声,并用“正常”蜂鸣声填充另一个秋天。 *.wav文件在整个过程中只播放第一音符。

#define FORMAT_AUDIO 1
#define FORMAT_SIZE 16

struct wave_header{
    // Header
    char      riff[4];
    int32_t   file_size;
    char      wave[4];
    // Format
    char      fmt[4];
    int32_t   format_size;
    int16_t   format_audio;
    int16_t   num_channels;
    int32_t   sample_rate;
    int32_t   byte_rate;
    int16_t   block_align;
    int16_t   bits_per_sample;
    // Data
    char      data[4]
    int32_t   data_size;
};

void write_header(ofstream &music_file ,int16_t bits, int32_t samples, int32_t duration){
    wave_header wav_header{};
    int16_t channels_quantity = 1;

    int32_t total_data = duration * samples * channels_quantity * bits/8;
    int32_t file_data = 4 + 8 + FORMAT_SIZE + 8 + total_data;

    wav_header.riff[0] = 'R';
    wav_header.riff[1] = 'I';
    wav_header.riff[2] = 'F';
    wav_header.riff[3] = 'F';

    wav_header.file_size = file_data;

    wav_header.wave[0] = 'W';
    wav_header.wave[1] = 'A';
    wav_header.wave[2] = 'V';
    wav_header.wave[3] = 'E';

    wav_header.fmt[0] = 'f';
    wav_header.fmt[1] = 'm';
    wav_header.fmt[2] = 't';
    wav_header.fmt[3] = ' ';

    wav_header.format_size = FORMAT_SIZE;
    wav_header.format_audio = FORMAT_AUDIO;
    wav_header.num_channels = channels_quantity;
    wav_header.sample_rate = samples;
    wav_header.byte_rate = samples * channels_quantity * bits/8;
    wav_header.block_align = static_cast<int16_t>(channels_quantity * bits / 8);
    wav_header.bits_per_sample = bits;

    wav_header.data[0] = 'd';
    wav_header.data[1] = 'a';
    wav_header.data[2] = 't';
    wav_header.data[3] = 'a';

    wav_header.data_size = total_data;

    music_file.write((char*)&wav_header, sizeof(wave_header));
}

int main(int argc, char const *argv[]) {
    int16_t bits = 8;
    int32_t samples = 44100;
    int32_t duration = 4;
    ofstream music_file("music.wav", ios::out | ios::binary);
    int32_t  frame_total = samples * duration;
    auto* audio = new int16_t[frame_total];

    for(int i = 0; i < frame_total/2; i++)
        audio[i] = static_cast<int16_t>(128 + 127 * sin(i*2));

    for(int i = frame_total/2; i < frame_total; i++)
        audio[i] = static_cast<int16_t>(128 + 127 * sin(i));

    write_header(music_file, bits, samples, duration);
    music_file.write(reinterpret_cast<char*>(audio),sizeof(int16_t)*frame_total);

    return 0;
}

2 个答案:

答案 0 :(得分:2)

您的代码有两个主要问题。


第一个是,根据您的编译器设置和环境,您可能正在编写无效的标头。

原因是wave_header结构未打包在内存中,并且可能在成员之间包含填充。因此,当您这样做时:

music_file.write((char*)&wav_header, sizeof(wave_header));

它可能写的东西不是有效的WAV标头。即使您很幸运地获得了所需的东西,还是要修复它是一个好主意,因为它随时可能更改,并且肯定不是便携式的。


第二个问题是写实际wave的调用:

music_file.write(reinterpret_cast<char*>(audio),sizeof(char)*frame_total);

正在写的数据量恰好是您期望的一半。 audio指向的数据的实际大小为sizeof(int16_t) * frame_total

这说明了为什么您只听到自己编写的wave的第一部分。

答案 1 :(得分:0)

这是通过将缓冲区(音频)从int16_t更改为int8_t来解决的,因为我试图编写8位音频。