foxygit / doom Log in
commit 3bde136c60ba10dc080bc1060a6c039f94d7d147
Author:     Simon Howard <fraggle@soulsphere.org>
AuthorDate: Wed Oct 24 20:03:34 2018 -0400
Commit:     Simon Howard <fraggle@soulsphere.org>
CommitDate: Wed Oct 24 20:03:34 2018 -0400

    opl: Use SDL_mixer post-mix hook for OPL output.

    Using Mix_HookMusic() to generate the OPL output stream works fine if
    you only ever play OPL music and don't want to use the normal music
    output functionality of SDL_mixer. However, now that it's possible to
    use substitute music packs with any music output type, this is no longer
    the case. Using Mix_HookMusic() disables normal output from eg. Ogg and
    FLAC playback. As an alternative, use the post-mix hook and mix the
    output from the OPL emulator there.

    Cleanup fix as part of #440.
---
 opl/opl_sdl.c | 47 ++++++++++++++++++++++-------------------------
 1 file changed, 22 insertions(+), 25 deletions(-)

diff --git a/opl/opl_sdl.c b/opl/opl_sdl.c
index 39054978..b1ccb70a 100644
--- a/opl/opl_sdl.c
+++ b/opl/opl_sdl.c
@@ -75,7 +75,7 @@ static int opl_opl3mode;

 // Temporary mixing buffer used by the mixing callback.

-static int32_t *mix_buffer = NULL;
+static uint8_t *mix_buffer = NULL;

 // Register number that was written.

@@ -155,36 +155,32 @@ static void AdvanceTime(unsigned int nsamples)

 // Call the OPL emulator code to fill the specified buffer.

-static void FillBuffer(int16_t *buffer, unsigned int nsamples)
+static void FillBuffer(uint8_t *buffer, unsigned int nsamples)
 {
     // This seems like a reasonable assumption.  mix_buffer is
     // 1 second long, which should always be much longer than the
     // SDL mix buffer.
-
     assert(nsamples < mixing_freq);

-    OPL3_GenerateStream(&opl_chip, buffer, nsamples);
+    // OPL output is generated into temporary buffer and then mixed
+    // (to avoid overflows etc.)
+    OPL3_GenerateStream(&opl_chip, (Bit16s *) mix_buffer, nsamples);
+    SDL_MixAudioFormat(buffer, mix_buffer, AUDIO_S16SYS, nsamples * 4,
+                       SDL_MIX_MAXVOLUME);
 }

 // Callback function to fill a new sound buffer:

-static void OPL_Mix_Callback(void *udata,
-                             Uint8 *byte_buffer,
-                             int buffer_bytes)
+static void OPL_Mix_Callback(void *udata, Uint8 *buffer, int len)
 {
-    int16_t *buffer;
-    unsigned int buffer_len;
-    unsigned int filled = 0;
-
-    // Buffer length in samples (quadrupled, because of 16-bit and stereo)
-
-    buffer = (int16_t *) byte_buffer;
-    buffer_len = buffer_bytes / 4;
+    unsigned int filled, buffer_samples;

     // Repeatedly call the OPL emulator update function until the buffer is
     // full.
+    filled = 0;
+    buffer_samples = len / 4;

-    while (filled < buffer_len)
+    while (filled < buffer_samples)
     {
         uint64_t next_callback_time;
         uint64_t nsamples;
@@ -197,7 +193,7 @@ static void OPL_Mix_Callback(void *udata,

         if (opl_sdl_paused || OPL_Queue_IsEmpty(callback_queue))
         {
-            nsamples = buffer_len - filled;
+            nsamples = buffer_samples - filled;
         }
         else
         {
@@ -206,9 +202,9 @@ static void OPL_Mix_Callback(void *udata,
             nsamples = (next_callback_time - current_time) * mixing_freq;
             nsamples = (nsamples + OPL_SECOND - 1) / OPL_SECOND;

-            if (nsamples > buffer_len - filled)
+            if (nsamples > buffer_samples - filled)
             {
-                nsamples = buffer_len - filled;
+                nsamples = buffer_samples - filled;
             }
         }

@@ -216,7 +212,7 @@ static void OPL_Mix_Callback(void *udata,

         // Add emulator output to buffer.

-        FillBuffer(buffer + filled * 2, nsamples);
+        FillBuffer(buffer + filled * 4, nsamples);
         filled += nsamples;

         // Invoke callbacks for this point in time.
@@ -340,9 +336,8 @@ static int OPL_SDL_Init(unsigned int port_base)
         return 0;
     }

-    // Mix buffer:
-
-    mix_buffer = malloc(mixing_freq * sizeof(uint32_t) * 2);
+    // Mix buffer: four bytes per sample (16 bits * 2 channels):
+    mix_buffer = malloc(mixing_freq * 4);

     // Create the emulator structure:

@@ -352,8 +347,10 @@ static int OPL_SDL_Init(unsigned int port_base)
     callback_mutex = SDL_CreateMutex();
     callback_queue_mutex = SDL_CreateMutex();

-    // TODO: This should be music callback? or-?
-    Mix_HookMusic(OPL_Mix_Callback, NULL);
+    // Set postmix that adds the OPL music. This is deliberately done
+    // as a postmix and not using Mix_HookMusic() as the latter disables
+    // normal SDL_mixer music mixing.
+    Mix_SetPostMix(OPL_Mix_Callback, NULL);

     return 1;
 }