ref: 3eb346ce103380998a7780cb81479a84062377b0
parent: a07627486484a9909da0e11eed6e23173b1db52e
author: Clownacy <Clownacy@users.noreply.github.com>
date: Mon Sep 9 17:43:33 EDT 2019
Synchronise the audio callback with Organya This is the 'perfect' Organya playback I mentioned in the commit message for 5ea356a3bd46a96604d5f2dadd00fcf0d418ccdb
--- a/src/Backends/Audio/SDL2.cpp
+++ b/src/Backends/Audio/SDL2.cpp
@@ -64,32 +64,8 @@
sound->volume_r = sound->pan_r * sound->volume;
}
-static void Callback(void *user_data, Uint8 *stream_uint8, int len)
+static void MixSounds(float *stream, size_t frames_total)
{
- (void)user_data;
-
- float *stream = (float*)stream_uint8;
- unsigned int frames_total = len / sizeof(float) / 2;
-
- for (unsigned int i = 0; i < frames_total * 2; ++i)
- stream[i] = 0.0f;
-
- if (organya_timer != 0)
- {
- static int timer_countdown;
-
- timer_countdown -= frames_total * 1000;
-
- if (timer_countdown <= 0)
- {
- do
- {
- timer_countdown += organya_timer * 44100;
- UpdateOrganya();
- } while (timer_countdown <= 0);
- }
- }
-
for (AudioBackend_Sound *sound = sound_list_head; sound != NULL; sound = sound->next)
{
if (sound->playing)
@@ -142,6 +118,49 @@
}
}
+static void Callback(void *user_data, Uint8 *stream_uint8, int len)
+{
+ (void)user_data;
+
+ float *stream = (float*)stream_uint8;
+ unsigned int frames_total = len / sizeof(float) / 2;
+
+ for (unsigned int i = 0; i < frames_total * 2; ++i)
+ stream[i] = 0.0f;
+
+ if (organya_timer == 0)
+ {
+ MixSounds(stream, frames_total);
+ }
+ else
+ {
+ // Synchronise audio generation with Organya.
+ // In the original game, Organya ran asynchronously in a separate thread,
+ // firing off commands to DirectSound in realtime. To match that, we'd
+ // need a very low-latency buffer, otherwise we'd get mistimed instruments.
+ // Instead, we can just do this.
+ unsigned int frames_done = 0;
+
+ while (frames_done != frames_total)
+ {
+ static unsigned long organya_countdown;
+
+ if (organya_countdown == 0)
+ {
+ organya_countdown = (organya_timer * 44100) / 1000; // organya_timer is in milliseconds, so convert it to audio frames
+ UpdateOrganya();
+ }
+
+ const unsigned int frames_to_do = MIN(organya_countdown, frames_total - frames_done);
+
+ MixSounds(stream + frames_done * 2, frames_to_do);
+
+ frames_done += frames_to_do;
+ organya_countdown -= frames_to_do;
+ }
+ }
+}
+
BOOL AudioBackend_Init(void)
{
if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
@@ -151,7 +170,7 @@
specification.freq = 44100;
specification.format = AUDIO_F32;
specification.channels = 2;
- specification.samples = 0x200;
+ specification.samples = 0x400; // Roughly 10 milliseconds
specification.callback = Callback;
specification.userdata = NULL;
--
⑨