title: WAV File Synthesis From Scratch - C
body: <p>Recently I saw a video lecture in my CS 101 class that inspired me to start playing with the WAV File Format in C. My project today has been creating sounds using a simple mathematical sine function. Despite a couple obstacles, my program can now accept several inputs(frequencies of waves, amplitudes of waves, sampling rate, etc.) and create a wav file containing the specified pitches.</p>
  
  <p>However, when playing these tones on my computer speakers, there is a strange, rhythmic popping sound, which varies with the sampling rate. At higher sampling rates, the frequency of the popping sound increases and turns into an annoying whining sound.</p>
  
  <p>The strange part is that the popping sound is consistent across different computers with the same file.</p>
  
  <p>Below I will post the code that I use to generate the WAV file. Any insights into what might be causing this phenomenon will be appreciated. It's probably just a stupid mistake on my part somewhere. :)</p>
  
  <pre><code>#include &lt;stdio.h&gt;
  #include &lt;sys/types.h&gt;
  #include &lt;sys/ioctl.h&gt;
  #include &lt;fcntl.h&gt;
  #include &lt;string.h&gt;
  #include &lt;math.h&gt;
  
  struct WAVHeader {
      char ChunkID[4];
      uint32_t ChunkSize;
      char RIFFType[4];
  };
  
  struct FormatHeader {
      char ChunkID[4];
      uint32_t ChunkSize;
      uint16_t CompressionCode;
      uint16_t Channels;
      uint32_t SampleRate;
      uint32_t AvgBytesPerSec;
      uint16_t BlockAlign;
      uint16_t SigBitsPerSamp;
  };
  
  struct DataHeader {
      char ChunkID[4];
      uint32_t ChunkSize;
  
  };
  
  
  void main(int argc, char * argv[]) {
  
  //Check for valid number of arguments or display help
  if(argc &lt; 8) {
      printf("Usage:\n./Tone -l [length] -s [frequency] [amplitude] -o [output-file] -r [sample-rate]\n");
      printf("-l length of tone to produce in seconds\n");    
      printf("-s Creates sine wave. Can be used multiple times. Frequency (Hz) and amplitude (0 - 32767) of each tone. \n");  
      printf("-o File to write to\n");
      printf("-r samples per second (kHz). Note: Must be double highest frequency in tone.\n");   
      return;
  }
  
  //Organize arguments
  int length, sinf[10], sina[10], samplerate;
  memset(sinf, 0, sizeof(int) * 10);
  memset(sina, 0, sizeof(int) * 10);
  char * output = NULL;
  int i = 0;
  int count;
  for(count = 1; count &lt; argc; count++){
      char first = *argv[count];
      int second = *(argv[count] + 1);    
      if (first == '-') {
          switch (second) {
              case 's':
                  sinf[i] = atoi(argv[count+1]);
                  sina[i] = atoi(argv[count+2]);
                  i++;
                  break;
              case 'l':
                  length = atoi(argv[count+1]);
                  break;
              case 'o':
                  output = argv[count+1];
                  break;
              case 'r':
                  samplerate = atoi(argv[count+1]) * 1000;
                  break;
          }
      }
  }
  
  //Allocate memory for wav file
  size_t size = sizeof(struct WAVHeader) + sizeof(struct FormatHeader) + sizeof(struct DataHeader) + (length * samplerate * 2);
  void * buffer = malloc(size);
  
  //Fill buffer with headers
  struct WAVHeader * WAV = (struct WAVHeader *)buffer;
  struct FormatHeader * Format = (struct FormatHeader *)(WAV + 1);
  struct DataHeader * Data = (struct DataHeader *)(Format + 1);
  
  strcpy(WAV-&gt;ChunkID, "RIFF");
  WAV-&gt;ChunkSize = (uint32_t)size - 8;
  strcpy(WAV-&gt;RIFFType, "WAVE");
  
  strcpy(Format-&gt;ChunkID, "fmt ");
  Format-&gt;ChunkSize = 16;
  Format-&gt;CompressionCode = 1;
  Format-&gt;Channels = 1;
  Format-&gt;SampleRate = (uint32_t)samplerate;
  Format-&gt;SigBitsPerSamp = 16;
  Format-&gt;BlockAlign = 2;
  Format-&gt;AvgBytesPerSec = Format-&gt;BlockAlign * samplerate;
  
  strcpy(Data-&gt;ChunkID, "data");
  Data-&gt;ChunkSize = length * samplerate * 2;
  
  //Generate Sound
  printf("Generating sound...\n");
  short * sound = (short *)(Data + 1);
  short total;
  float time;
  float increment = 1.0/(float)samplerate;
  for (time = 0; time &lt; length; time += increment){
      total = 0;
      for (i = 0; i &lt; 10; i++) {
          total += sina[i] * sin((float)sinf[i] * time * (2 * 3.1415926));
      }
      *(sound + (int)(time * samplerate)) = total;
      //printf("Time: %f Value: %hd\n", time, total);
  }
  
  //Write buffer to file
  FILE * out = fopen(output, "w");
  fwrite(buffer, size, 1, out);
  printf("Wrote to %s\n", output);
  
  return;
  
  }
  </code></pre>