Как создать 16-битный файл wav со знаком PCM

0

У меня есть двоичный двоичный файл сырых аудиопотоков. Я хочу создать wav файл со свойствами PCM, подписанный 16-битным монотоном с частотой дискретизации 22050 Гц.

В настоящее время я использую следующий код:

template <typename T>
void write(std::ofstream& stream, const T& t) {
    stream.write((const char*)&t, sizeof(T));
}

template <typename SampleType>
void writeWAVData(const char* outFile, SampleType* buf, size_t bufSize,
                  int sampleRate, short channels)
{
    std::ofstream stream(outFile, std::ios::binary);
    stream.write("RIFF", 4);
    write<int>(stream, 36 + bufSize);
    stream.write("WAVE", 4);
    stream.write("fmt ", 4);
    write<int>(stream, 16);
    write<short>(stream, 1);                                        // Format (1 = PCM)
    write<short>(stream, channels);                                 // Channels //mono/sterio
    write<int>(stream, sampleRate); 

    write<int>(stream, sampleRate * channels * sizeof(SampleType)); // Byterate
    write<short>(stream, channels * sizeof(SampleType));            // Frame size
    write<short>(stream, 16 * sizeof(SampleType));                   // Bits per sample
    stream.write("data", 4);
    stream.write((const char*)&bufSize, 4);
    stream.write((const char*)buf, bufSize);
}


int wmain(int argc,wchar_t **argv)
{
    std::ifstream is("c:\\stream", std::ios_base::binary);
    if (is) {
        // get length of file:
        is.seekg (0, is.end);
        int length = is.tellg();
        is.seekg (0, is.beg);
        char * buffer = new char [length];
        is.read (buffer,length);
        writeWAVData("c:\\audio.wav", buffer, length, 22050, 1);
    }
}

Может ли кто-нибудь помочь мне, что здесь не так?

  • 5
    Что именно идет не так? Ошибка компиляции? Ошибка во время выполнения? Неожиданный вывод?
Теги:
wav

3 ответа

1

Я вижу пару проблем:

  1. buffer должен быть short* или int16_t*, чтобы иметь SampleType 16 бит.

  2. write<short>(stream, 16 * sizeof(SampleType)); должна быть write<short>(stream, 8 * sizeof(SampleType)); при записи битов на образец.

  3. stream.write((const char*)&bufSize, 4); не делает правильной вещи, если size_t не 4 байта (обычно это 8 байт в 64-битных системах), так как вы в основном bufSize первые 4 байта bufSize и записываете их. Сначала нужно static_cast для 32-разрядного целого:

    uint32_t sz = bufSize;
    stream.write((const char*)&sz, 4);
    

Могут быть и другие проблемы, но для меня это вопиющие.

1

char* указатель char* как аргумент buf, тип образца выводится как char. Если образцы на самом деле являются 16 битами, то значения, зависящие от sizeof(SampleType) будут ошибочными.

Вы можете использовать short*; но было бы лучше удалить шаблонность и передать размер выборки в качестве другого параметра времени выполнения. В любом случае вам нужно умножить на 8 (или CHAR_BIT), а не на 16, чтобы получить количество бит.

0

Спасибо, ребята, вы правы. Вот мой окончательный рабочий код

template <typename T>
void write(std::ofstream& stream, const T& t) {
    stream.write((const char*)&t, sizeof(T));
}

template <typename SampleType>
void writeWAVData(const char* outFile, SampleType* buf, size_t bufSize,
                  int sampleRate, short channels)
{
    std::ofstream stream(outFile, std::ios::binary);
    stream.write("RIFF", 4);
    write<int>(stream, 36 + bufSize);
    stream.write("WAVE", 4);
    stream.write("fmt ", 4);
    write<int>(stream, 16);
    write<short>(stream, 1);                                        // Format (1 = PCM)
    write<short>(stream, channels);                                 // Channels //mono/sterio
    write<int>(stream, sampleRate); 

    write<int>(stream, sampleRate * channels * sizeof(SampleType)); // Byterate
    write<short>(stream, channels * sizeof(SampleType));            // Frame size
    write<short>(stream, 8 * sizeof(SampleType));                   // Bits per sample
    stream.write("data", 4);
    uint32_t sz = bufSize;
    stream.write((const char*)&sz, 4);
    stream.write((const char*)buf, bufSize);
}


int wmain(int argc,wchar_t **argv)
{
    FILE *fhandle=fopen("c:\\stream","rb");
    seek(fhandle, 0, SEEK_END); // seek to end of file
    int length ; = ftell(fhandle); // get current file pointer
    fseek(fhandle, 0, SEEK_SET); // seek back to beginning of file
    length = length * 16;
    short* Data=new short [length]; // Create an element for every sample
fread(Data,16/8,length/(16/8),fhandle);//read data
    writeWAVData("c:\\audio.wav", buffer, length, 22050, 1);
  }
}

Ещё вопросы

Сообщество Overcoder
Наверх
Меню