title: Sound synchronization error using DirectSound
body: <p>I'm using directsound to play a sine wave. The idea is simple : I have an application running at 30fps, and I create a buffer worth of 1/30sec sound each frame, to be played in the next frame.</p>
  
  <p>The way I'm doing it :
  I first get the dsound play cursor, and compute the offset and the bytes to write out of it.</p>
  
  <pre><code>static void win32_update_soundbuffer(SoundBuffer *source, WIN32SOUNDBUFFER *output) {
  free(source-&gt;data);
  
  
  uint32_t play_cursor;
  uint32_t write_cursor;
  output-&gt;handle-&gt;GetCurrentPosition((LPDWORD)&amp;play_cursor, (LPDWORD)&amp;write_cursor);
  
  static uint32_t last_play_cursor = -1;
  bool play_cursor_moved = last_play_cursor == play_cursor ? false : true;
  
  output-&gt;offset = (output-&gt;sample_index * output-&gt;sample_size) % output-&gt;buffer_size;
  
  uint32_t bytes_to_write = 0;
  if (output-&gt;offset == play_cursor) {
      if (play_cursor_moved) {
          bytes_to_write = output-&gt;buffer_size;
      }
  }
  else if (output-&gt;offset &lt; play_cursor) { bytes_to_write = play_cursor - output-&gt;offset; }
  else if (output-&gt;offset &gt; play_cursor) { bytes_to_write = output-&gt;buffer_size - (output-&gt;offset - play_cursor); }
  
  last_play_cursor = play_cursor;
  
  source-&gt;sample_count = bytes_to_write / output-&gt;sample_size;
  source-&gt;data = (uint16_t *)malloc(bytes_to_write);  //TODO: maybe we don't want to use malloc
  }
  </code></pre>
  
  <p>Then I lock the buffer and write the sine wave into it.</p>
  
  <pre><code>static void win32_fill_soundbuffer(SoundBuffer *source, WIN32SOUNDBUFFER *output) {
  
  //get the buffer location to write sounds to
  output-&gt;handle-&gt;Lock(output-&gt;offset, source-&gt;sample_count * output-&gt;sample_size, &amp;output-&gt;region1, &amp;output-&gt;region1_size,
      &amp;output-&gt;region2, &amp;output-&gt;region2_size, NULL);
  
  uint16_t *source_sample = source-&gt;data;
  uint16_t *out_sample = (uint16_t *)output-&gt;region1;
  uint32_t sample_count1 = output-&gt;region1_size / output-&gt;sample_size;
  for (uint32_t i = 0; i &lt; sample_count1; i++) {
      *out_sample++ = *source_sample++;
      *out_sample++ = *source_sample++;
      output-&gt;sample_index++;
  }
  
  out_sample = (uint16_t *)output-&gt;region2;
  uint32_t sample_count2 = output-&gt;region2_size / output-&gt;sample_size;
  for (uint32_t i = 0; i &lt; sample_count2; i++) {
      *out_sample++ = *source_sample++;
      *out_sample++ = *source_sample++;
      output-&gt;sample_index++;
  }
  
  output-&gt;handle-&gt;Unlock(output-&gt;region1, output-&gt;region1_size, output-&gt;region2, output-&gt;region2_size);
  }
  </code></pre>
  
  <p>(the source buffer is something I first send to the "user" to be filled with the sine wave, and then retrieve to fill the real sound buffer. I'm doing it because the project is multi-platform).</p>
  
  <p>The implementation look like that : </p>
  
  <pre><code>WIN32SOUNDBUFFER win_soundbuffer = ...
  SoundBuffer soundbuffer = ...
  
  while(running) {
      win32_update_soundbuffer(&amp;soundbuffer, &amp;win_soundbuffer);
      user_process_sound(&amp;soundbuffer);
      win32_fill_soundbuffer(&amp;soundbuffer, &amp;win_soundbuffer);
      win_soundbuffer.handle-&gt;Play(NULL, NULL, DSBPLAY_LOOPING);
  }
  </code></pre>
  
  <p>The errors I'm experiencing : it does only work for some buffer size (1s to 1/8s, no problem. 1/9s is scratching a lot. 1/10s, 1/20s are ok too.) The weirder thing is that it also for 1/40s, which should be impossible since the buffer isn't large enough to last for a frame.
  When debugging, I can see that the play cursor isn't moving fast enough, and sometimes it stay at the same place for a few frames, which could be the reason for the scratching.
  Does anyone know how to solve that ? Thanks for the help.</p>