加载和保存WAV文件

时间:2013-07-31 11:02:16

标签: c++ audio wave

我正在尝试将WAVE文件加载到数据结构中,然后将其作为原始副本保存回磁盘。加载和保存似乎工作正常但复制的WAVE文件不会播放任何声音(尽管它确实打开没有错误)。我想知道这是否与endian-ness有关?

这是我保存WAVE文件的数据结构:

struct WaveFile
{
public:

    static const uint16 NUM_CHARS = 4;

public:

    WaveFile() : Data(nullptr) {}

    ~WaveFile() { delete[] Data; }

    char ChunkID[NUM_CHARS];

    uint32 ChunkSize;

    char Format[NUM_CHARS];

    char SubChunkID[NUM_CHARS];

    uint32 SubChunkSize;

    uint16 AudioFormat;

    uint16 NumChannels;

    uint32 SampleRate;

    uint32 ByteRate;

    uint16 BlockAlign;

    uint16 BitsPerSample;

    char SubChunk2ID[NUM_CHARS];

    uint32 SubChunk2Size;

    byte* Data; 
};

这是我加载它的方式:

std::ifstream file(filename, std::ios::binary);

if (file.good())
{
    file.read(waveFile.ChunkID, WaveFile::NUM_CHARS);
    file.read(reinterpret_cast<char*>(&waveFile.ChunkSize), size_ui32);
    file.read(waveFile.Format, WaveFile::NUM_CHARS);
    file.read(waveFile.SubChunkID, WaveFile::NUM_CHARS);
    file.read(reinterpret_cast<char*>(&waveFile.SubChunkSize), size_ui32);
    file.read(reinterpret_cast<char*>(&waveFile.AudioFormat), size_ui16);
    file.read(reinterpret_cast<char*>(&waveFile.NumChannels), size_ui16);
    file.read(reinterpret_cast<char*>(&waveFile.SampleRate), size_ui32);
    file.read(reinterpret_cast<char*>(&waveFile.ByteRate), size_ui32);
    file.read(reinterpret_cast<char*>(&waveFile.BlockAlign), size_ui16);
    file.read(reinterpret_cast<char*>(&waveFile.BitsPerSample), size_ui16);
    file.read(waveFile.SubChunk2ID, WaveFile::NUM_CHARS);
    file.read(reinterpret_cast<char*>(&waveFile.SubChunk2Size), size_ui32);
    waveFile.Data = new byte[waveFile.SubChunk2Size];
    file.read(reinterpret_cast<char*>(waveFile.Data), sizeof(waveFile.SubChunk2Size));
    file.close();
}

这就是我将数据写回文件的方式:

std::ofstream file(outfile, std::ios::binary);

if (file.good())
{
    file.flush();
    file.write(waveFile.ChunkID, WaveFile::NUM_CHARS);
    file.write(reinterpret_cast<const char*>(&waveFile.ChunkSize), size_ui32);
    file.write(waveFile.Format, WaveFile::NUM_CHARS);
    file.write(waveFile.SubChunkID, WaveFile::NUM_CHARS);
    file.write(reinterpret_cast<const char*>(&waveFile.SubChunkSize), size_ui32);
    file.write(reinterpret_cast<const char*>(&waveFile.AudioFormat), size_ui16);
    file.write(reinterpret_cast<const char*>(&waveFile.NumChannels), size_ui16);
    file.write(reinterpret_cast<const char*>(&waveFile.SampleRate), size_ui32);
    file.write(reinterpret_cast<const char*>(&waveFile.ByteRate), size_ui32);
    file.write(reinterpret_cast<const char*>(&waveFile.BlockAlign), size_ui16);
    file.write(reinterpret_cast<const char*>(&waveFile.BitsPerSample), size_ui16);
    file.write(waveFile.SubChunk2ID, WaveFile::NUM_CHARS);
    file.write(reinterpret_cast<const char*>(&waveFile.SubChunk2Size), size_ui32);
    file.write(reinterpret_cast<const char*>(waveFile.Data), waveFile.SubChunk2Size);
    file.close();   
}

副本的大小也与原始大小相同。如果有人想知道,uint16,uint32和byte只是unsigned short,unsigned int和unsigned char的typedef。 size_ui32变量就是这样的:

static const uint32 size_ui32 = sizeof(uint32);
static const uint32 size_ui16 = sizeof(uint16);

不管怎样,似乎无法找出我出错的地方。

欢呼任何帮助。

2 个答案:

答案 0 :(得分:1)

这适用于大多数wavefiles,但某些标头可能包含特定的用户数据。你可以使用struct WAVEHEADER的sigle写:

struct WAVEFILEHEADER
{
    // don't change the order of attributes
    char m_lpcChunkId[4];
    int m_iChunkSize;
    char m_lpcFormat[4];
    char m_lpcSubChunkFmt[4];
    int m_iSubChunkFmtSize;
    short int m_siAudioFormat;
    short int m_siNumChannels;

    int m_iSampleRate;
    int m_iByteRate;
    short int m_siBlockAlign;
    short int m_siBitsPerSample;

    char m_lpcChunkData[4];
    int m_iSubChunkDataSize;
    // unsigned char * m_data;
};

WAVEFILEHEADER whdr;
FILE* fid = fopen("newaudio.wav","wb"); // important to use binary file

// some inicialization for whdr - RIFF etc.
// You can use only 1 write to save whole header:
fwrite(&whdr, 1, sizeof(WAVEFILEHEADER), fid);

// or you can read wav header
fread(&whdr, 1, sizeof(WAVEFILEHEADER), fid); 
// check chunk size, few headers have aditional 2 bytes (by definition user data, but they was always 0x0000)

答案 1 :(得分:0)

发布此问题后,我刚刚发现了问题。

在阅读数据时,我已经完成了这个:

file.read(reinterpret_cast<char*>(waveFile.Data), sizeof(waveFile.SubChunk2Size));

应该是:

file.read(reinterpret_cast<char*>(waveFile.Data), waveFile.SubChunk2Size);  

删除sizeof()后工作。傻我。