CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 3 of 3
  1. #1
    Join Date
    Feb 2018
    Posts
    2

    Sound synchronization error using DirectSound

    Hi everyone !
    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.
    The way I'm doing it : I first get the dsound play cursor,
    and compute the offset to the buffer and the number of bytes to write into it

    Code:
    static void win32_update_soundbuffer(SoundBuffer *source, WIN32SOUNDBUFFER *output) {
    free(source->data);
    
    
    uint32_t play_cursor;
    uint32_t write_cursor;
    output->handle->GetCurrentPosition((LPDWORD)&play_cursor, (LPDWORD)&write_cursor);
    
    static uint32_t last_play_cursor = -1;
    bool play_cursor_moved = last_play_cursor == play_cursor ? false : true;
    
    output->offset = (output->sample_index * output->sample_size) % output->buffer_size;
    
    uint32_t bytes_to_write = 0;
    if (output->offset == play_cursor) {
        if (play_cursor_moved) {
            bytes_to_write = output->buffer_size;
        }
    }
    else if (output->offset < play_cursor) { bytes_to_write = play_cursor - output->offset; }
    else if (output->offset > play_cursor) { bytes_to_write = output->buffer_size - (output->offset - play_cursor); }
    
    last_play_cursor = play_cursor;
    
    source->sample_count = bytes_to_write / output->sample_size;
    source->data = (uint16_t *)malloc(bytes_to_write);  
    }
    Then I lock the buffer and write the sine wave into it.

    Code:
    static void win32_fill_soundbuffer(SoundBuffer *source, WIN32SOUNDBUFFER *output) {
    
    //get the buffer location to write sounds to
    output->handle->Lock(output->offset, source->sample_count * output->sample_size, &output->region1, &output->region1_size,
        &output->region2, &output->region2_size, NULL);
    
    uint16_t *source_sample = source->data;
    uint16_t *out_sample = (uint16_t *)output->region1;
    uint32_t sample_count1 = output->region1_size / output->sample_size;
    for (uint32_t i = 0; i < sample_count1; i++) {
        *out_sample++ = *source_sample++;
        *out_sample++ = *source_sample++;
        output->sample_index++;
    }
    
    out_sample = (uint16_t *)output->region2;
    uint32_t sample_count2 = output->region2_size / output->sample_size;
    for (uint32_t i = 0; i < sample_count2; i++) {
        *out_sample++ = *source_sample++;
        *out_sample++ = *source_sample++;
        output->sample_index++;
    }
    
    output->handle->Unlock(output->region1, output->region1_size, output->region2, output->region2_size);
    }
    (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).

    The implementation look like that :

    Code:
    WIN32SOUNDBUFFER win_soundbuffer = ...
    SoundBuffer soundbuffer = ...
    
    while(running) {
        win32_update_soundbuffer(&soundbuffer, &win_soundbuffer);
        user_process_sound(&soundbuffer);
        do_some_rendering();
        win32_fill_soundbuffer(&soundbuffer, &win_soundbuffer);
        win_soundbuffer.handle->Play(NULL, NULL, DSBPLAY_LOOPING);
    }
    The errors I'm experiencing : it does only work for some buffer length
    (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 work 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 ?

  2. #2
    Arjay's Avatar
    Arjay is offline Moderator / EX MS MVP Power Poster
    Join Date
    Aug 2004
    Posts
    13,490

    Re: Sound synchronization error using DirectSound

    You need to lock/unlock during the read as well.

  3. #3
    Join Date
    Feb 2018
    Posts
    2

    Re: Sound synchronization error using DirectSound

    Quote Originally Posted by Arjay View Post
    You need to lock/unlock during the read as well.
    What do you mean by during the read ? I do think the only time I'm reading something from the buffer is when I call buffer->GetCurrrentPosition(&play_cursor, &write_cursor),
    but I cannot lock the buffer before that, because I need the play and write cursor to know where to lock the buffer.

    EDIT:
    I found something else: changing the sine wave frequency affect the "quality" of the sound : for exemple, raising the frequency up with a buffer of size 1/20s makes the sound cracks. Whereas raising it on a 1/15s buffer removes the cracking. The frequency changes has no effect on buffer bigger than 1/10s

    EDIT:
    Found that it is caused because the write cursor is way before the play cursor, and at the time I get to actually write the data, it has already cross my offset. This mean I am limited to a max length of 1/12s, which mean I need to compute the sound 3 frame in advance... Any idea on how to face it ?
    Last edited by l0w-s3c; February 9th, 2018 at 12:20 PM.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured