foxygit / doom Log in
commit 7791ace57ee6c238f5f6704eba0970a63e19e424
Author:     Alex Mayfield <alexmax2742@gmail.com>
AuthorDate: Sat Feb 18 22:47:22 2017 -0500
Commit:     Alex Mayfield <alexmax2742@gmail.com>
CommitDate: Sat Feb 18 22:47:22 2017 -0500

    Add server shutdown and music overrides

    - The process will now cut the music and shut down when Chocolate Doom
    does.
    - The process will now peacefully coexist with music overrides, such as
    digital music packs.
---
 midiproc/main.c  | 68 ++++++++++++++++++++++++++++++++++++++++++------------
 src/i_midipipe.c | 29 +++++++++++++++++++++--
 src/i_midipipe.h |  3 ++-
 src/i_sdlmusic.c | 70 +++++++++++++++++++++++++++++++++++++++++++++-----------
 src/net_defs.h   |  1 +
 5 files changed, 141 insertions(+), 30 deletions(-)

diff --git a/midiproc/main.c b/midiproc/main.c
index ac5d80f3..f89ee83e 100644
--- a/midiproc/main.c
+++ b/midiproc/main.c
@@ -41,8 +41,37 @@ static HANDLE    midi_process_in;  // Standard In.
 static HANDLE    midi_process_out; // Standard Out.
 static buffer_t *midi_buffer;      // Data from client.

-// Currently playing music track
-static Mix_Music *music = NULL;
+// Currently playing music track.
+static Mix_Music *music  = NULL;
+
+//=============================================================================
+//
+// Private functions
+//
+
+//
+// Unregisters the currently playing song.  This is never called from the
+// protocol, we simply do this before playing a new song.
+//
+static void UnregisterSong()
+{
+    if (music == NULL)
+    {
+        return;
+    }
+
+    Mix_FreeMusic(music);
+}
+
+//
+// Bookkeeping stuff we need to do when we're shutting off the subprocess.
+//
+static void ShutdownSDL(void)
+{
+    UnregisterSong();
+    Mix_CloseAudio();
+    SDL_Quit();
+}

 //=============================================================================
 //
@@ -53,6 +82,7 @@ static boolean RegisterSong(const char *filename)
 {
     fprintf(stderr, "%s %s\n", __FUNCTION__, filename);

+    UnregisterSong();
     music = Mix_LoadMUS(filename);
     fprintf(stderr, "<-- %p\n", music);

@@ -76,8 +106,19 @@ static void SetVolume(int vol)
 static void PlaySong(int loops)
 {
     fprintf(stderr, "%s %d\n", __FUNCTION__, loops);
+    fprintf(stderr, "%s %d\n", "Playing at volume", Mix_VolumeMusic(-1));

     Mix_PlayMusic(music, loops);
+
+    // [AM] BUG: In my testing, setting the volume of a MIDI track while there
+    //      is no song playing appears to be a no-op.  This can happen when
+    //      you're mixing midiproc with vanilla SDL_Mixer, such as when you
+    //      are alternating between a digital music pack (in the parent
+    //      process) and MIDI (in this process).
+    //
+    //      To work around this bug, we set the volume to itself after the MIDI
+    //      has started playing.
+    Mix_VolumeMusic(Mix_VolumeMusic(-1));
 }

 static void StopSong()
@@ -87,16 +128,6 @@ static void StopSong()
     Mix_HaltMusic();
 }

-//
-// ShutdownSDL
-//
-static void ShutdownSDL()
-{
-    UnregisterSong();
-    Mix_CloseAudio();
-    SDL_Quit();
-}
-
 //=============================================================================
 //
 // Pipe Server Interface
@@ -151,13 +182,18 @@ boolean MidiPipe_PlaySong(buffer_reader_t *reader)
     return true;
 }

-boolean MidiPipe_StopSong(buffer_reader_t *reader)
+boolean MidiPipe_StopSong()
 {
     StopSong();

     return true;
 }

+boolean MidiPipe_Shutdown()
+{
+    exit(EXIT_SUCCESS);
+}
+
 //=============================================================================
 //
 // Server Implementation
@@ -177,7 +213,9 @@ boolean ParseCommand(buffer_reader_t *reader, uint16_t command)
     case NET_MIDIPIPE_PACKET_TYPE_PLAY_SONG:
         return MidiPipe_PlaySong(reader);
     case NET_MIDIPIPE_PACKET_TYPE_STOP_SONG:
-        return MidiPipe_StopSong(reader);
+        return MidiPipe_StopSong();
+    case NET_MIDIPIPE_PACKET_TYPE_SHUTDOWN:
+        return MidiPipe_Shutdown(reader);
     default:
         return false;
     }
@@ -288,6 +326,8 @@ boolean InitSDL()
         return false;
     }

+    atexit(ShutdownSDL);
+
     return true;
 }

diff --git a/src/i_midipipe.c b/src/i_midipipe.c
index aac43ebb..6390d93e 100644
--- a/src/i_midipipe.c
+++ b/src/i_midipipe.c
@@ -47,7 +47,6 @@ static HANDLE  midi_process_out_reader; // Output stream for midi process.
 static HANDLE  midi_process_out_writer;

 static boolean server_init = false; // if true, server was started
-static boolean client_init = false; // if true, client was bound

 //=============================================================================
 //
@@ -144,7 +143,7 @@ fail:
 // Tells the MIDI subprocess to load a specific filename for playing.  This
 // function blocks until there is an acknowledgement from the server.
 //
-Mix_Music *I_MidiPipe_RegisterSong(const char *filename)
+boolean I_MidiPipe_RegisterSong(const char *filename)
 {
     boolean ok;
     net_packet_t *packet;
@@ -250,6 +249,32 @@ void I_MidiPipe_StopSong()
     DEBUGOUT("I_MidiPipe_StopSong succeeded");
 }

+//
+// I_MidiPipe_StopSong
+//
+// Tells the MIDI subprocess to shutdown.
+//
+void I_MidiPipe_ShutdownServer()
+{
+    boolean ok;
+    net_packet_t *packet;
+
+    packet = NET_NewPacket(2);
+    NET_WriteInt16(packet, NET_MIDIPIPE_PACKET_TYPE_SHUTDOWN);
+    ok = WritePipe(packet);
+    NET_FreePacket(packet);
+
+    server_init = false;
+
+    if (!ok)
+    {
+        DEBUGOUT("I_MidiPipe_ShutdownServer failed");
+        return;
+    }
+
+    DEBUGOUT("I_MidiPipe_ShutdownServer succeeded");
+}
+
 //=============================================================================
 //
 // Public Interface
diff --git a/src/i_midipipe.h b/src/i_midipipe.h
index ae313c52..9bb3db86 100644
--- a/src/i_midipipe.h
+++ b/src/i_midipipe.h
@@ -25,10 +25,11 @@

 #include "doomtype.h"

-Mix_Music *I_MidiPipe_RegisterSong(const char *filename);
+boolean I_MidiPipe_RegisterSong(const char *filename);
 void I_MidiPipe_SetVolume(int vol);
 void I_MidiPipe_PlaySong(int loops);
 void I_MidiPipe_StopSong();
+void I_MidiPipe_ShutdownServer();

 boolean I_MidiPipe_InitServer();

diff --git a/src/i_sdlmusic.c b/src/i_sdlmusic.c
index 156dcb29..5c5d6492 100644
--- a/src/i_sdlmusic.c
+++ b/src/i_sdlmusic.c
@@ -133,6 +133,9 @@ static Mix_Music *current_track_music = NULL;
 // If true, the currently playing track is being played on loop.
 static boolean current_track_loop;

+// If true, the current track is being handled via midiproc.
+static boolean using_midiproc;
+
 // Given a time string (for LOOP_START/LOOP_END), parse it and return
 // the time (in # samples since start of track) it represents.
 static unsigned int ParseVorbisTime(unsigned int samplerate_hz, char *value)
@@ -878,6 +881,9 @@ static void I_SDL_ShutdownMusic(void)
 {
     if (music_initialized)
     {
+#if defined(_WIN32)
+        I_MidiPipe_ShutdownServer();
+#endif
         Mix_HaltMusic();
         music_initialized = false;

@@ -974,7 +980,8 @@ static boolean I_SDL_InitMusic(void)
         LoadSubstituteConfigs();
     }

-#if WIN32
+#if defined(_WIN32)
+    // [AM] Start up midiproc to handle playing MIDI music.
     I_MidiPipe_InitServer();
 #endif

@@ -999,11 +1006,10 @@ static void UpdateMusicVolume(void)
         vol = (current_music_volume * MIX_MAX_VOLUME) / 127;
     }

-#if WIN32
+#if defined(_WIN32)
     I_MidiPipe_SetVolume(vol);
-#else
-    Mix_VolumeMusic(vol);
 #endif
+    Mix_VolumeMusic(vol);
 }

 // Set music volume (0 - 127)
@@ -1027,7 +1033,7 @@ static void I_SDL_PlaySong(void *handle, boolean looping)
         return;
     }

-    if (handle == NULL)
+    if (handle == NULL && !using_midiproc)
     {
         return;
     }
@@ -1055,7 +1061,14 @@ static void I_SDL_PlaySong(void *handle, boolean looping)
     }

 #if defined(_WIN32)
-    I_MidiPipe_PlaySong(loops);
+    if (using_midiproc)
+    {
+        I_MidiPipe_PlaySong(loops);
+    }
+    else
+    {
+        Mix_PlayMusic(current_track_music, loops);
+    }
 #else
     Mix_PlayMusic(current_track_music, loops);
 #endif
@@ -1093,7 +1106,15 @@ static void I_SDL_StopSong(void)
     }

 #if defined(_WIN32)
-    I_MidiPipe_StopSong();
+    if (using_midiproc)
+    {
+        I_MidiPipe_StopSong();
+        using_midiproc = false;
+    }
+    else
+    {
+        Mix_HaltMusic();
+    }
 #else
     Mix_HaltMusic();
 #endif
@@ -1116,9 +1137,7 @@ static void I_SDL_UnRegisterSong(void *handle)
         return;
     }

-#if !defined(_WIN32)
     Mix_FreeMusic(music);
-#endif
 }

 // Determine whether memory block is a .mid file
@@ -1182,6 +1201,9 @@ static void *I_SDL_RegisterSong(void *data, int len)
         }
         else
         {
+            // [AM] Substitute music never uses midiproc.
+            using_midiproc = false;
+
             // Read loop point metadata from the file so that we know where
             // to loop the music.
             playing_substitute = true;
@@ -1211,17 +1233,39 @@ static void *I_SDL_RegisterSong(void *data, int len)
     // we have to generate a temporary file.

 #if defined(_WIN32)
-    music = I_MidiPipe_RegisterSong(filename);
+    // [AM] If we do not have an external music command defined, play
+    //      music with midiproc.exe.
+    if (strlen(snd_musiccmd) == 0)
+    {
+        music = NULL;
+        if (I_MidiPipe_RegisterSong(filename))
+        {
+            using_midiproc = true;
+        }
+        else
+        {
+            fprintf(stderr, "Error loading midi: %s\n",
+                "Could not communicate with midiproc.");
+        }
+    }
+    else
+    {
+        using_midiproc = false;
+        music = Mix_LoadMUS(filename);
+        if (music == NULL)
+        {
+            // Failed to load
+            fprintf(stderr, "Error loading midi: %s\n", Mix_GetError());
+        }
+    }
 #else
     music = Mix_LoadMUS(filename);
-#endif
-
     if (music == NULL)
     {
         // Failed to load
-
         fprintf(stderr, "Error loading midi: %s\n", Mix_GetError());
     }
+#endif

     // Remove the temporary MIDI file; however, when using an external
     // MIDI program we can't delete the file. Otherwise, the program
diff --git a/src/net_defs.h b/src/net_defs.h
index 7273004a..c55c7bbc 100644
--- a/src/net_defs.h
+++ b/src/net_defs.h
@@ -148,6 +148,7 @@ typedef enum {
     NET_MIDIPIPE_PACKET_TYPE_SET_VOLUME,
     NET_MIDIPIPE_PACKET_TYPE_PLAY_SONG,
     NET_MIDIPIPE_PACKET_TYPE_STOP_SONG,
+    NET_MIDIPIPE_PACKET_TYPE_SHUTDOWN
 } net_midipipe_packet_type_t;

 // Settings specified when the client connects to the server.