-
February 8th, 2018, 02:30 PM
#1
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 ?
-
February 8th, 2018, 07:10 PM
#2
Re: Sound synchronization error using DirectSound
You need to lock/unlock during the read as well.
-
February 9th, 2018, 11:30 AM
#3
Re: Sound synchronization error using DirectSound
Originally Posted by Arjay
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
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|