当我尝试用 C++ 写入 wav 时,它说文件损坏

When I try to write to wav in c++, it says corrupt file

我正在尝试通过从麦克风输入和其他 headers 获取数据并将其放入 wav 文件来写入 wav。我这样做了,但它仍然说文件损坏。关于代码的一个注意事项是,在具有 headers 的结构中,它的顺序不正确。在 WriteToWav 函数中,我根据块和子块以正确的顺序输入它。这是代码:

struct WavHeaders {
      //Fmt
      char SubChunk1ID[4];
      int SubChunk1Size = 16;
      int AudioFormat = 1;
      int NumChannels = 2;
      int SampleRate = 44100;
      int BitsPerSample = 16;
 
      int ByteRate = SampleRate * NumChannels * BitsPerSample / 8;
      int BlockAlign = NumChannels * BitsPerSample / 8;
 
      //Data
      char SubChunk2ID[4];
      int SubChunk2Size = 1 * NumChannels * BitsPerSample / 8;
 
      //RIFF
      char ChunkID[4];
      int ChunkSize = 4 + (8 + SubChunk1Size) + (8 + SubChunk2Size);
      char Format[4];
    };
 
void _AudioReader::AudioReader::AudioToWav() {
    WAVEFORMATEX wfx = {};
    wfx.wFormatTag = WAVE_FORMAT_PCM;       // PCM is standard
    wfx.nChannels = 2;                      // 2 channels = stereo sound
    wfx.nSamplesPerSec = 44100;             // Samplerate.  44100 Hz
    wfx.wBitsPerSample = 16;                // 16 bit samples
 
    wfx.nBlockAlign = wfx.wBitsPerSample * wfx.nChannels / 8;
    wfx.nAvgBytesPerSec = wfx.nBlockAlign * wfx.nSamplesPerSec;
 
    HWAVEIN wi;
    waveInOpen(
        &wi,         
        WAVE_MAPPER,    
        &wfx,          
        NULL, NULL,     
        CALLBACK_NULL | WAVE_FORMAT_DIRECT  
    );
 
    char buffers[2][44100 * 2 * 2 / 2];   
    WAVEHDR headers[2] = { {},{} };         
    for (int i = 0; i < 2; ++i){
        headers[i].lpData = buffers[i];
        headers[i].dwBufferLength = 44100 * 2 * 2 / 2;      
 
        waveInPrepareHeader(wi, &headers[i], sizeof(headers[i]));
        waveInAddBuffer(wi, &headers[i], sizeof(headers[i]));
    }
 
    //Set Header IDS as char array
    WavHeaders Wav_Headers;
    Wav_Headers.SubChunk1ID[0] = 'f';
    Wav_Headers.SubChunk1ID[1] = 'm';
    Wav_Headers.SubChunk1ID[2] = 't';
    Wav_Headers.SubChunk1ID[3] = ' ';
 
    Wav_Headers.SubChunk2ID[0] = 'd';
    Wav_Headers.SubChunk2ID[1] = 'a';
    Wav_Headers.SubChunk2ID[2] = 't';
    Wav_Headers.SubChunk2ID[3] = 'a';
 
    Wav_Headers.ChunkID[0] = 'R';
    Wav_Headers.ChunkID[1] = 'I';
    Wav_Headers.ChunkID[2] = 'F';
    Wav_Headers.ChunkID[3] = 'F';
 
    Wav_Headers.Format[0] = 'W';
    Wav_Headers.Format[1] = 'A';
    Wav_Headers.Format[2] = 'V';
    Wav_Headers.Format[3] = 'E';
   
    std::ofstream AudioFile("Audio.wav", std::ios_base::out | std::ios_base::binary);
 
    //Write Headers to audio file
    for(int i = 0; i < 4; i++) //RIFF Chunk
        AudioFile << Wav_Headers.ChunkID[i];
    AudioFile << Wav_Headers.ChunkSize << Wav_Headers.Format;
 
    for (int i = 0; i < 4; i++) //fmt(format) sub-chunk
        AudioFile << Wav_Headers.SubChunk1ID[i];
    AudioFile << 
        Wav_Headers.SubChunk1Size <<
        Wav_Headers.AudioFormat <<
        Wav_Headers.NumChannels <<
        Wav_Headers.SampleRate <<
        Wav_Headers.ByteRate << 
        Wav_Headers.BlockAlign <<
        Wav_Headers.BitsPerSample;
 
    for (int i = 0; i < 4; i++) //Data sub-chunk
        AudioFile << Wav_Headers.SubChunk2ID[i];
    AudioFile << Wav_Headers.SubChunk2Size;
 
    std::cout << "Started recording! Press escape when you're ready to stop!\n";
    waveInStart(wi);
  
    while (!(GetAsyncKeyState(VK_ESCAPE) & 0x8000)) {
        for (auto& h : headers) {
            if (h.dwFlags & WHDR_DONE) {
               
                AudioFile.write(h.lpData, h.dwBufferLength); //dump audio binary to wav file
 
                h.dwFlags = 0;        
                h.dwBytesRecorded = 0; 
 
                waveInPrepareHeader(wi, &h, sizeof(h));
                waveInAddBuffer(wi, &h, sizeof(h));
            }
        }
    }
    waveInStop(wi);
    for (auto& h : headers){
        waveInUnprepareHeader(wi, &h, sizeof(h));
    }
    waveInClose(wi);
}```

所以问题是我必须牢记格式和字节顺序。不要使用 << 或 .write,你必须有一个精确的格式。以正确格式写入文件的一种方法是使用我在下面使用的以下函数,并输入相同的 WAV headers.

template <typename T>
    std::ostream& LittleEndianToFile(std::ostream& file, T value, unsigned size = sizeof(T)) {
        for (; size; --size, value >>= 8)
            file.put(static_cast <char> (value & 0xFF));
        return file;
    }

用法:LittleEndianToFile(AudioFile,SampleRate, 4);