我使用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,这应该是不可能的,因为缓冲区不够大,不能持续一帧。 调试时,我可以看到播放光标移动速度不够快,有时它会停留在相同位置几帧,这可能是划痕的原因。 有谁知道如何解决这个问题?谢谢你的帮助。