C++ Reading the Data part of a WAV file

后端 未结 2 938
悲哀的现实
悲哀的现实 2020-12-02 07:52

I plan to create a program that will visualize the audio waveform of a .wav file.

So far, I have started by properly reading the header part of the said wav file. T

相关标签:
2条回答
  • 2020-12-02 08:08

    This image is taken from a Stanford course

    WAV File Format

    So you can see that the audio data occurs immediately after the headers you already read and there will be Subchunk2Size bytes of audio data.

    The pseudocode for this would be

    ReadRIFF();
    ReadFMT();
    int32 chunk2Id = Read32(BigEndian);
    int32 chunk2Size = Read32(LittleEndian);
    for (int i = 0; i < chunk2Size; i++)
    {
        audioData[i] = ReadByte();
    }
    

    If the audio is stereo you'll have two audio streams in data. If the audio is compressed (mp3, aac, etc) you'll have to decompress it first.

    0 讨论(0)
  • 2020-12-02 08:25

    I know this is an old post, but your fread parameters are switched, here is a more correct version (requires g++-4.7 or higher with -std=c++11 flag like this "g++ -std=c++11 WaveReader.cpp -o WaveReader").

    #include <iostream>
    #include <string>
    #include <fstream>
    #include <cstdint>
    
    using std::cin;
    using std::cout;
    using std::endl;
    using std::fstream;
    using std::string;
    
    typedef struct  WAV_HEADER
    {
        /* RIFF Chunk Descriptor */
        uint8_t         RIFF[4];        // RIFF Header Magic header
        uint32_t        ChunkSize;      // RIFF Chunk Size
        uint8_t         WAVE[4];        // WAVE Header
        /* "fmt" sub-chunk */
        uint8_t         fmt[4];         // FMT header
        uint32_t        Subchunk1Size;  // Size of the fmt chunk
        uint16_t        AudioFormat;    // Audio format 1=PCM,6=mulaw,7=alaw,     257=IBM Mu-Law, 258=IBM A-Law, 259=ADPCM
        uint16_t        NumOfChan;      // Number of channels 1=Mono 2=Sterio
        uint32_t        SamplesPerSec;  // Sampling Frequency in Hz
        uint32_t        bytesPerSec;    // bytes per second
        uint16_t        blockAlign;     // 2=16-bit mono, 4=16-bit stereo
        uint16_t        bitsPerSample;  // Number of bits per sample
        /* "data" sub-chunk */
        uint8_t         Subchunk2ID[4]; // "data"  string
        uint32_t        Subchunk2Size;  // Sampled data length
    } wav_hdr;
    
    // Function prototypes
    int getFileSize(FILE* inFile);
    
    int main(int argc, char* argv[])
    {
        wav_hdr wavHeader;
        int headerSize = sizeof(wav_hdr), filelength = 0;
    
        const char* filePath;
        string input;
        if (argc <= 1)
        {
            cout << "Input wave file name: ";
            cin >> input;
            cin.get();
            filePath = input.c_str();
        }
        else
        {
            filePath = argv[1];
            cout << "Input wave file name: " << filePath << endl;
        }
    
        FILE* wavFile = fopen(filePath, "r");
        if (wavFile == nullptr)
        {
            fprintf(stderr, "Unable to open wave file: %s\n", filePath);
            return 1;
        }
    
        //Read the header
        size_t bytesRead = fread(&wavHeader, 1, headerSize, wavFile);
        cout << "Header Read " << bytesRead << " bytes." << endl;
        if (bytesRead > 0)
        {
            //Read the data
            uint16_t bytesPerSample = wavHeader.bitsPerSample / 8;      //Number     of bytes per sample
            uint64_t numSamples = wavHeader.ChunkSize / bytesPerSample; //How many samples are in the wav file?
            static const uint16_t BUFFER_SIZE = 4096;
            int8_t* buffer = new int8_t[BUFFER_SIZE];
            while ((bytesRead = fread(buffer, sizeof buffer[0], BUFFER_SIZE / (sizeof buffer[0]), wavFile)) > 0)
            {
                /** DO SOMETHING WITH THE WAVE DATA HERE **/
                cout << "Read " << bytesRead << " bytes." << endl;
            }
            delete [] buffer;
            buffer = nullptr;
            filelength = getFileSize(wavFile);
    
            cout << "File is                    :" << filelength << " bytes." << endl;
            cout << "RIFF header                :" << wavHeader.RIFF[0] << wavHeader.RIFF[1] << wavHeader.RIFF[2] << wavHeader.RIFF[3] << endl;
            cout << "WAVE header                :" << wavHeader.WAVE[0] << wavHeader.WAVE[1] << wavHeader.WAVE[2] << wavHeader.WAVE[3] << endl;
            cout << "FMT                        :" << wavHeader.fmt[0] << wavHeader.fmt[1] << wavHeader.fmt[2] << wavHeader.fmt[3] << endl;
            cout << "Data size                  :" << wavHeader.ChunkSize << endl;
    
            // Display the sampling Rate from the header
            cout << "Sampling Rate              :" << wavHeader.SamplesPerSec << endl;
            cout << "Number of bits used        :" << wavHeader.bitsPerSample << endl;
            cout << "Number of channels         :" << wavHeader.NumOfChan << endl;
            cout << "Number of bytes per second :" << wavHeader.bytesPerSec << endl;
            cout << "Data length                :" << wavHeader.Subchunk2Size << endl;
            cout << "Audio Format               :" << wavHeader.AudioFormat << endl;
            // Audio format 1=PCM,6=mulaw,7=alaw, 257=IBM Mu-Law, 258=IBM A-Law, 259=ADPCM
    
            cout << "Block align                :" << wavHeader.blockAlign << endl;
            cout << "Data string                :" << wavHeader.Subchunk2ID[0] << wavHeader.Subchunk2ID[1] << wavHeader.Subchunk2ID[2] << wavHeader.Subchunk2ID[3] << endl;
        }
        fclose(wavFile);
        return 0;
    }
    
    // find the file size
    int getFileSize(FILE* inFile)
    {
        int fileSize = 0;
        fseek(inFile, 0, SEEK_END);
    
        fileSize = ftell(inFile);
    
        fseek(inFile, 0, SEEK_SET);
        return fileSize;
    }
    
    0 讨论(0)
提交回复
热议问题