0
votes

I've been use this code to read .wav data in delphi and i've been comparing the result with value i got from matlab function wavread. From which i can say that matlab function can automatically recognize which one is the sample data value, but not with delphi (but both matlab and delphi code result is the same). Since my delphi code cannot recognize the sample data value, i look through the array and found out that the index where sample data value starting were different each .wav file. For an example i test some .wav file and get this:

  1. classic1.wav the sample data value starting on wavedata[].Data[] index number 40
  2. classic2.wav the sample data value starting on wavedata[].Data[] index number 35

i got above conclusion by looking at the result y,[y, Fs, nbits, opts]=wavread('classic1.wav','double'); then i go to the result delphi return in an array checking it value and find the exact same value starting in the index 40 for classic1.wav and 35 for classic2.wav. And i want to know if there is a way i can know the starting index of sample data value of each .wav file?

EDIT : i have corrected the record similar to the reference given, it's perfectly right with the header(from ChunkID to Subchunk2size) but i still got confused by the sample data following it because no change from the previous result.

type
TWaveHeader = packed record

    Marker_RIFF: array [0..3] of char;
    ChunkSize: cardinal;
    Marker_WAVE: array [0..3] of char;


    Marker_fmt: array [0..3] of char;
    SubChunkSize: cardinal;
    FormatTag: word;
    NumChannels: word;
    SampleRate: longint;
    ByteRate: longint;
    BlockAlign:word; 
    BitsPerSample: word;


    Marker_data: array [0..3] of char;
    DataBytes: longint;
  end;

  TChannel = record
  Data : array of smallint;


end;
2
IIRC a simple WAVE file starts with a RIFF chunk descriptor, followed by a RIFF subheader, followed by a WAVEFORMATEX structure. [I've actually written real WAVE encoders/decoders, but that was a few years ago, and I don't remember all the details. All I do know is that it is actually pretty easy.]Andreas Rejbrand
Andreas make a good point, you should revisit your struct declaration and split according the specsOnTheFly
yes i have reconstruct according the specs and it is right at least until the Subchunk2Size but not the data following it.i don't know what i'm doing wrongWawan Ma-chun
A commercial library that does this for you and comes with source code is VC component set from lakesoft. lakeofsoft.com/vc/download.htmlWarren P

2 Answers

4
votes

You're obviously not skipping all of the header fields correctly. Wav files can have some optional header information, so though the actual sample values normally start at byte 44, this is not always the case.

See here for example: https://ccrma.stanford.edu/courses/422/projects/WaveFormat/

One way to skip directly to the sample data (after reading whatever parts of the header you require) is the scan the file (four bytes at a time) for the ascii string of "data" (64 61 74 61 hex) and then read the 4 bytes that immediately follow that, which (as cardinal or longword) represents the total number of bytes to read. The actual samples follow immediately after that cardinal.

Edit:

As expected, looking at the files Classic1.wav and Classic2.wav in a hex editor it's clear that they both have some metadata. At location 36 in each file, instead of finding the SubchunkID of "data" you instead find "LIST". The four bytes following this give the size of this additional data. This is what you have to skip over in order to get to the music sample data.

For example, Classic1.wav has 148 bytes of extra data starting at offset 44. This places Subchunk2ID at offset 192 and Subchunk2Size at offset 196, meaning that the first sample starts at offset 200 in the file.

Classic2.wav has 128 bytes of extra data starting at offset 44. This places Subchunk2ID at offset 172 and Subchunk2Size at offset 176, meaning that the first sample starts at offset 180 in the file.

Here is Classic2.wav in a very basic hex editor: enter image description here

3
votes

Rather than doing all of the file I/O manually, you should use the Win32 Multimedia API functions instead - mmioOpen(), mmioDescend(), mmioAscend(), mmioRead(), etc. Let them do all of the hard work for you. Your code will be easier to manage and read, as you will be able to focus more on the content of the individual chunks while letting the API handle the low-level details of finding each chunk for you.