Creating a .WAV file header

Can someone adjust the below .WAV file header for me? Once correct, I'll be able to use it "as is" in all my .WAV files from now on.

It came from the article:
Arduino (Mega) Audio Recording

But I plan to use it with the higher bitrate in the sketch at:
Arduino Audio Input

The best instructions I've found are at:
Wav (RIFF) File Format Tutorial

My main concern is how to split the bit rate of 38,500 into the two bytes provided for that info. And of course, I'll still be creating a mono file with one byte per sample.

Also, I'm wondering if the bit rate of 38,500 can be understood by players reading my file? I'm not sure since the standard for CD's is 44,100. Evidently the ATmega328 interrupt timers can't easily be set for 44,100 since the sketch is set to 38,500 instead.

// wavheader setup
// little endian (lowest byte 1st)
wavheader[0]='R';
wavheader[1]='I';
wavheader[2]='F';
wavheader[3]='F';
//wavheader[4] to wavheader[7] size of data + header -8
wavheader[8]='W';
wavheader[9]='A';
wavheader[10]='V';
wavheader[11]='E';
wavheader[12]='f';
wavheader[13]='m';
wavheader[14]='t';
wavheader[15]=' ';
wavheader[16]=16;
wavheader[17]=0;
wavheader[18]=0;
wavheader[19]=0;
wavheader[20]=1;
wavheader[21]=0;
wavheader[22]=1;
wavheader[23]=0;
// wavheader[24] to wavheader[27] samplerate hz
// wavheader[28] to wavheader[31] samplerate*1*1
// optional bytes can be added here
wavheader[32]=1;
wavheader[33]=0;
wavheader[34]=8;
wavheader[35]=0;
wavheader[36]='d';
wavheader[37]='a';
wavheader[38]='t';
wavheader[39]='a';
//wavheader[40] to wavheader[43] sample number

There isn't a field for bit rate in the WAV header. There is a 32-bit field for sample rate which will easily hold 38500.
There is also a 32-bit field for byte rate which is simply the sampling rate multiplied by the number of bytes per sample (which is also a field in the header). In your case this will also be 38500.

Pete

Thanks Pete. That helps a lot.

Combining what you said with the below web page I just found, I think I now have the answer.
Big and Little Endian (the sample I gave saying "Little Endian" at the top)

I can't test it yet to be sure, but I believe this will work:

  1. I opened the windows calculator program in "programmer" mode, set it to "Dec", and entered 38500.
  2. I changed from "Dec" to "Hex", which changed the number to 9664.
  3. I entered just the high byte "96", changed back to "Dec, and got "100".
  4. I changed to "Hex" again, and entered the low byte "64".
  5. I changed this back to "Dec", and got "150".
  6. So I've entered those two numbers -- "100" and "150" -- in my sketch as shown:
// wavheader[24] to wavheader[27]  (samplerate hz)
wavheader[24]=100;
wavheader[25]=150;
wavheader[26]=0;
wavheader[27]=0;
// wavheader[28] to wavheader[31]  (samplerate * 1 chanel * 1 byte)
wavheader[28]=100;
wavheader[29]=150;
wavheader[30]=0;
wavheader[31]=0;

Again, thank you Pete, for filling in the missing pieces and pointing me in the right direction.

Your code would be easier to read, especially when you come back to it after a few weeks, if you defined a structure for the WAV header and filled in each of the named fields. Something like this:

struct soundhdr {
  char  riff[4];        /* "RIFF"                                  */
  long  flength;        /* file length in bytes                    */
  char  wave[4];        /* "WAVE"                                  */
  char  fmt[4];         /* "fmt "                                  */
  long  chunk_size;     /* size of FMT chunk in bytes (usually 16) */
  short format_tag;     /* 1=PCM, 257=Mu-Law, 258=A-Law, 259=ADPCM */
  short num_chans;      /* 1=mono, 2=stereo                        */
  long  srate;          /* Sampling rate in samples per second     */
  long  bytes_per_sec;  /* bytes per second = srate*bytes_per_samp */
  short bytes_per_samp; /* 2=16-bit mono, 4=16-bit stereo          */
  short bits_per_samp;  /* Number of bits per sample               */
  char  data[4];        /* "data"                                  */
  long  dlength;        /* data length in bytes (filelength - 44)  */
} wavh;

// ......

  // It's easy enough to initialize the strings
  strncpy(wavh.riff,"RIFF",4);
  strncpy(wavh.wave,"WAVE",4);
  strncpy(wavh.fmt,"fmt ",4);
  strncpy(wavh.data,"data",4);
  
  // size of FMT chunk in bytes
  wavh.block_size = 16;
  wavh.format_tag = 1; // PCM
  wavh.num_chans = 1; // mono
  // This is easier than converting to hex and then to bytes :)
  wavh.srate = 38500;
  wavh.bits_per_samp = 8;
  // etc.

Pete

I didn't know I could do that, Pete. Besides being easier to read, entering the data -- without all the above switching between DEC and HEX on a calculator first -- is SO much easier.

Thank you! :slight_smile:

Woops! Pete, your "struct" didn't work when it came time to save it to the SD Card.

The line:

myFile.write(wavheader, 44);

worked fine when it was a simple string of bytes, but now that its a complex structure containing several types, you have to explicitly tell it to save it as a string of bytes anyway; using:

myFile.write((byte *)&wavheader,44);

I found this solution at:
Copy a STRUCT record to SD ?