当我尝试用 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);
我正在尝试通过从麦克风输入和其他 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);