使用DirectSound声音同步错误

时间:2018-02-07 20:07:17

标签: c winapi directsound

我使用directsound播放正弦波。这个想法很简单:我有一个运行速度为30fps的应用程序,每帧创建一个价值1 / 30sec的缓冲区,在下一帧播放。

我这样做的方式: 我首先得到dsound播放光标,并计算偏移量和要写出的字节数。

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);  //TODO: maybe we don't want to use malloc
}

然后我锁定缓冲区并将正弦波写入其中。

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);
}

(源缓冲区是我首先发送给&#34;用户&#34;用正弦波填充,然后检索以填充真实的声音缓冲区。我这样做是因为项目是多平台的。)

实现看起来像这样:

WIN32SOUNDBUFFER win_soundbuffer = ...
SoundBuffer soundbuffer = ...

while(running) {
    win32_update_soundbuffer(&soundbuffer, &win_soundbuffer);
    user_process_sound(&soundbuffer);
    win32_fill_soundbuffer(&soundbuffer, &win_soundbuffer);
    win_soundbuffer.handle->Play(NULL, NULL, DSBPLAY_LOOPING);
}

我遇到的错误:它只适用于某些缓冲区大小(1s到1 / 8s,没问题.1 / 9s很多.1 / 10s,1 / 20s也可以。)更奇怪的是,它也是1 / 40s,这应该是不可能的,因为缓冲区不够大,不能持续一帧。 调试时,我可以看到播放光标移动速度不够快,有时它会停留在相同位置几帧,这可能是划痕的原因。 有谁知道如何解决这个问题?谢谢你的帮助。

0 个答案:

没有答案