Sulkyoptimism
Sulkyoptimism

Reputation: 67

Loading Wave File but there is random nonsense at the end of the data rather than the expected samples

I've got a simple wav header reader I found online a long time ago, I've gotten back round to using it but it seems to replace around 1200 samples towards the end of the data chunk with a single random repeated number, eg -126800. At the end of the sample is expected silence so the number should be zero.

Here is the simple program:

void main() {
    WAV_HEADER* wav = loadWav(".\\audio\\test.wav");
    double sample_count = wav->SubChunk2Size * 8 / wav->BitsPerSample;

    printf("Sample count: %i\n", (int)sample_count);

    vector<int16_t> samples = vector<int16_t>();

    for (int i = 0; i < wav->SubChunk2Size; i++)
    {
        int val = ((wav->data[i] & 0xff) << 8) | (wav->data[i + 1] & 0xff);
        samples.push_back(val);
    }
    printf("done\n");
}

And here is the Wav reader:

typedef struct
{
    //riff
    uint32_t Chunk_ID;
    uint32_t ChunkSize;
    uint32_t Format;

    //fmt
    uint32_t SubChunk1ID;
    uint32_t SubChunk1Size;
    uint16_t AudioFormat;
    uint16_t NumberOfChanels;
    uint32_t SampleRate;
    uint32_t ByteRate;

    uint16_t BlockAlignment;
    uint16_t BitsPerSample;

    //data
    uint32_t SubChunk2ID;
    uint32_t SubChunk2Size;

    //Everything else is data. We note it's offset
    char data[];

} WAV_HEADER;
#pragma pack()

inline WAV_HEADER* loadWav(const char* filePath)
{
    long size;
    WAV_HEADER* header;
    void* buffer;

    FILE* file;

    fopen_s(&file,filePath, "r");
    assert(file);

    fseek(file, 0, SEEK_END);
    size = ftell(file);
    rewind(file);

    std::cout << "Size of file: " << size << std::endl;

    buffer = malloc(sizeof(char) * size);
    fread(buffer, 1, size, file);

    header = (WAV_HEADER*)buffer;

    //Assert that data is in correct memory location
    assert((header->data - (char*)header) == sizeof(WAV_HEADER));

    //Extra assert to make sure that the size of our header is actually 44 bytes
    assert((header->data - (char*)header) == 44);

    fclose(file);

    return header;
}

I'm not sure what the problem is, I've confirmed that there is no meta data, nor is there a mismatch between the numbers read from the header of the file and the actual file. I'm assuming it's a size/offset misalignment on my side, but I cannot see it.

Any help welcomed. Sulkyoptimism

Upvotes: 2

Views: 395

Answers (2)

hotpaw2
hotpaw2

Reputation: 70733

Apple (macOS and iOS) software often does not create WAVE/RIFF files with just a canonical Microsoft 44-byte header at the beginning. Those Wave files can instead can use a longer header followed by a padding block.

So you need to use the full WAVE RIFF format parsing specification instead of just reading from a fixed size 44 byte struct.

Upvotes: 0

Marcus M&#252;ller
Marcus M&#252;ller

Reputation: 36442

WAV is just a container for different audio sample formats.

You're making assumptions on a wav file that would have been OK on Windows 3.11 :) These don't hold in 2021.

Instead of rolling your own Wav file reader, simply use one of the available libraries. I personally have good experiences using libsndfile, which has been around roughly forever, is very slim, can deal with all prevalent WAV file formats, and with a lot of other file formats as well, unless you disable that.

This looks like a windows program (one notices by the fact you're using very WIN32API style capital struct names – that's a bit oldschool); so, you can download libsndfile's installer from the github releases and directly use it in your visual studio (another blind guess).

Upvotes: 2

Related Questions