我正在尝试为具有两个不同频率的单声道文件填充缓冲区,但失败了。我在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;
}
答案 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位音频。