Неспособность заполнить буфер для файла * .wav, используя две разные частоты - PullRequest
1 голос
/ 05 апреля 2019

Это было решено путем изменения буфера с int16_t на int8_t, так как я пытался записать 8-битное аудио.

Я пытаюсь заполнить буфер для моноволнового файла с двумя разными частотами, но мне это не удается,Я использую CLion в Ubuntu 18.04.

Я знаю, размер буфера равен 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 ]

2 голосов
/ 05 апреля 2019

С вашим кодом есть две основные проблемы.


Во-первых, вы можете писать недопустимый заголовок в зависимости от настроек компилятора и среды.

Причина в том, что структура wave_header не упакована в память и может содержать отступы между членами. Поэтому, когда вы делаете:

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

Он может написать что-то, что не является допустимым WAV-заголовком. Даже если вам посчастливилось получить именно то, что вы хотели, это хорошая идея, чтобы исправить это, потому что он может измениться в любой момент и, конечно, он не переносим.


Вторая проблема заключается в том, что призыв написать актуальную волну:

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

Записывает ровно половину ожидаемого объема данных. Фактический размер данных, указанных audio, равен sizeof(int16_t) * frame_total.

Это объясняет, почему вы слышите только первую часть волны, которую вы написали.

0 голосов
/ 05 апреля 2019

Это было решено путем изменения буфера (аудио) с int16_t на int8_t, так как я пытался записать 8-битное аудио.

...