我在C++中很新,我试图解析.wav文件,以便在其上添加一些音频效果。因此,首先我尝试读取和解析输入.wav文件,然后将其写入输出.wav文件。输出文件在资源管理器中具有相同的大小,在音频播放器中具有一定的持续时间,但是在播放时声音是不存在的。它有什么问题?
这是我的密码。
#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
using namespace std;
struct WavHeader
{
char chunkId[4]; // RIFF, FMT, DATA, e.t.c.
unsigned long ChunkSize; // Chunk Size
};
struct RiffHeader : WavHeader
{
char format[4]; // WAVE Header
};
struct FmtHeader : WavHeader
{
unsigned short AudioFormat; // Audio format 1=PCM,6=mulaw,7=alaw, 257=IBM Mu-Law, 258=IBM A-Law, 259=ADPCM
unsigned short NumOfChan; // Number of channels 1=Mono 2=Sterio
unsigned long SamplesPerSec; // Sampling Frequency in Hz
unsigned long bytesPerSec; // bytes per second
unsigned short blockAlign; // 2=16-bit mono, 4=16-bit stereo
unsigned short bitsPerSample; // Number of bits per sample
};
struct DataHeader : WavHeader
{
};
struct Wav
{
RiffHeader RiffHeader;
FmtHeader FmtHeader;
DataHeader DataHeader;
vector<char> Data;
};
/// <summary>
/// Read/write .wav files.
/// </summary>
class WavFileManager
{
public:
/// <summary>
/// Read whole .wav file.
/// </summary>
/// <param name="path">Path to file.</param>
Wav ReadAll(const string& path)
{
ifstream file(path);
if (!file)
{
throw runtime_error("Can't open file: " + path);
}
Wav* wavFile = new Wav();
wavFile->RiffHeader = ReadHeader<RiffHeader>(file);
if (wavFile->RiffHeader.format != "WAVE\0")
{
// throw runtime_error("Wrong format. File: " + path);
}
wavFile->FmtHeader = ReadHeader<FmtHeader>(file);
if (!TrySkipChunksBefore(file, "data"))
{
throw runtime_error("Can't find wav data. File: " + path);
}
wavFile->DataHeader = ReadHeader<DataHeader>(file);
vector<char>& data = wavFile->Data;
data.reserve(wavFile->DataHeader.ChunkSize);
for (int i = 0; i < wavFile->DataHeader.ChunkSize; i++)
{
char buffer;
file.read((char*)&buffer, sizeof(char));
data.push_back(buffer);
}
reverse(data.begin(), data.end());
file.close();
return *wavFile;
}
/// <summary>
/// Read header of .wav file.
/// </summary>
/// <param name="file">File stream.</param>
/// <returns>Header of type T.</returns>
template<typename T>
T ReadHeader(ifstream& file)
{
T header;
int headerSize = sizeof(T);
file.read((char*)&header, headerSize);
return header;
}
/// <summary>
/// Read data chunk of .wav file.
/// </summary>
/// <param name="file">File stream.</param>
/// <param name="size">Chunk size.</param>
/// <returns>Array of bytes.</returns>
char* ReadChunk(ifstream& file, unsigned long size)
{
char* chunk = new char[size];
file.read(chunk, size);
return chunk;
}
/// <summary>
/// Check if .wav header has following chunkId.
/// </summary>
/// <param name="header">.wav header.</param>
/// <param name="chunkId">Id to compare.</param>
bool HasChunkID(const WavHeader& header, const char chunkId[4])
{
return ((header.chunkId[0] == chunkId[0]) &&
(header.chunkId[1] == chunkId[1]) &&
(header.chunkId[2] == chunkId[2]) &&
(header.chunkId[3] == chunkId[3]));
}
/// <summary>
/// Skip all chunks before reqired chunk.
/// </summary>
/// <param name="file">File stream.</param>
/// <param name="chunkId">Id of required chunk.</param>
bool TrySkipChunksBefore(ifstream& file, const char chunkId[4])
{
while (!file.eof())
{
streampos pos = file.tellg();
WavHeader header = ReadHeader<WavHeader>(file);
char* chunk = ReadChunk(file, header.ChunkSize);
if (HasChunkID(header, chunkId))
{
file.clear();
file.seekg(pos);
return true;
}
delete[] chunk;
}
return false;
}
/// <summary>
/// Write all data into file.
/// </summary>
/// <param name="data">Wav to write.</param>
/// <param name="path">Path to output file.</param>
void WriteAll(Wav data, const string& path)
{
ofstream file(path, ios::binary);
file.write((char*)&data.RiffHeader, sizeof(RiffHeader));
file.write((char*)&data.FmtHeader, sizeof(FmtHeader));
file.write((char*)&data.DataHeader, sizeof(DataHeader));
reverse(data.Data.begin(), data.Data.end());
for (int i = 0; i < data.Data.size(); i++)
{
file.write((char*)&data.Data[i], sizeof(char));
}
file.close();
}
};
int main()
try
{
auto* mgr = new WavFileManager();
auto wav = mgr->ReadAll ("input.wav");
mgr->WriteAll(wav, "output.wav");
}
catch (runtime_error& e)
{
cerr << "Error! " << e.what() << '\n';
}发布于 2022-03-09 09:33:39
解决问题很容易。
ifstream file(path, ios::binary);而不是
ifstream file(path);https://stackoverflow.com/questions/71383152
复制相似问题