shithub: cstory

Download patch

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