From 90dd40c58ffb01a510fca82eeba859d8eecdb777 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Sat, 2 Oct 2010 03:36:19 +0000 Subject: [PATCH] - Reimplemented TiMidity++ playback so that it also can handle XMI subsongs. SVN r2874 (trunk) --- src/sound/i_music.cpp | 7 +- src/sound/i_musicinterns.h | 89 ++--- src/sound/music_midi_timidity.cpp | 452 +++++++++++--------------- src/sound/music_midistream.cpp | 8 +- src/sound/music_psuedo_mididevice.cpp | 8 +- 5 files changed, 252 insertions(+), 312 deletions(-) diff --git a/src/sound/i_music.cpp b/src/sound/i_music.cpp index 0ae9af0cf..40fa7f46b 100644 --- a/src/sound/i_music.cpp +++ b/src/sound/i_music.cpp @@ -326,12 +326,7 @@ static MIDIStreamer *CreateMIDIStreamer(FILE *file, BYTE *musiccache, int len, E static MusInfo *CreateMIDISong(FILE *file, const char *filename, BYTE *musiccache, int offset, int len, EMIDIDevice devtype, EMIDIType miditype) { - if (devtype == MIDI_Timidity) - { - assert(miditype == MIDI_MIDI); - return new TimiditySong(file, musiccache, len); - } - else if (devtype >= MIDI_Null) + if (devtype >= MIDI_Null) { assert(miditype == MIDI_MIDI); if (musiccache != NULL) diff --git a/src/sound/i_musicinterns.h b/src/sound/i_musicinterns.h index 6c43cd904..be5a70125 100644 --- a/src/sound/i_musicinterns.h +++ b/src/sound/i_musicinterns.h @@ -100,7 +100,7 @@ public: virtual void FluidSettingInt(const char *setting, int value); virtual void FluidSettingNum(const char *setting, double value); virtual void FluidSettingStr(const char *setting, const char *value); - virtual bool Preprocess(MIDIStreamer *song); + virtual bool Preprocess(MIDIStreamer *song, bool looping); virtual FString GetStats(); }; @@ -165,8 +165,7 @@ public: protected: SoundStream *Stream; bool Started; - int SampleRate; - + bool bLooping; }; // FMOD psuedo-MIDI device -------------------------------------------------- @@ -175,9 +174,51 @@ class FMODMIDIDevice : public PsuedoMIDIDevice { public: int Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata); - bool Preprocess(MIDIStreamer *song); + bool Preprocess(MIDIStreamer *song, bool looping); }; +// MIDI file played with TiMidity++ and possibly streamed through FMOD ------ + +class TimidityPPMIDIDevice : public PsuedoMIDIDevice +{ +public: + TimidityPPMIDIDevice(); + ~TimidityPPMIDIDevice(); + + int Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata); + bool Preprocess(MIDIStreamer *song, bool looping); + bool IsOpen() const; + int Resume(); + + void Stop(); + bool IsOpen(); + void TimidityVolumeChanged(); + +protected: + bool LaunchTimidity(); + + FTempFileName DiskName; +#ifdef _WIN32 + HANDLE ReadWavePipe; + HANDLE WriteWavePipe; + HANDLE KillerEvent; + HANDLE ChildProcess; + bool Validated; + bool ValidateTimidity(); +#else // _WIN32 + int WavePipe[2]; + pid_t ChildProcess; +#endif + FString CommandLine; + size_t LoopPos; + + static bool FillStream(SoundStream *stream, void *buff, int len, void *userdata); +#ifdef _WIN32 + static const char EventName[]; +#endif +}; + + // Base class for software synthesizer MIDI output devices ------------------ class SoftSynthMIDIDevice : public MIDIDevice @@ -371,10 +412,10 @@ enum EMIDIDevice MIDI_GUS, MIDI_Fluid, MIDI_FMOD, + MIDI_Timidity, // only used by I_RegisterSong MIDI_Null, - MIDI_Timidity }; class MIDIStreamer : public MusInfo @@ -651,44 +692,6 @@ protected: SoundStream *m_Stream; }; -// MIDI file played with Timidity and possibly streamed through FMOD -------- - -class TimiditySong : public StreamSong -{ -public: - TimiditySong (FILE *file, BYTE *musiccache, int length); - ~TimiditySong (); - void Play (bool looping, int subsong); - void Stop (); - bool IsPlaying (); - bool IsValid () const { return CommandLine.Len() > 0; } - void TimidityVolumeChanged(); - -protected: - void PrepTimidity (); - bool LaunchTimidity (); - - FTempFileName DiskName; -#ifdef _WIN32 - HANDLE ReadWavePipe; - HANDLE WriteWavePipe; - HANDLE KillerEvent; - HANDLE ChildProcess; - bool Validated; - bool ValidateTimidity (); -#else // _WIN32 - int WavePipe[2]; - pid_t ChildProcess; -#endif - FString CommandLine; - size_t LoopPos; - - static bool FillStream (SoundStream *stream, void *buff, int len, void *userdata); -#ifdef _WIN32 - static const char EventName[]; -#endif -}; - // MUS file played by a software OPL2 synth and streamed through FMOD ------- class OPLMUSSong : public StreamSong diff --git a/src/sound/music_midi_timidity.cpp b/src/sound/music_midi_timidity.cpp index 6e2acb32d..28a77eada 100644 --- a/src/sound/music_midi_timidity.cpp +++ b/src/sound/music_midi_timidity.cpp @@ -3,31 +3,6 @@ #include "cmdlib.h" #include "templates.h" -#if !defined(_WIN32) && 0 -// Under Linux, buffer output from Timidity to try to avoid "bubbles" -// in the sound output. -class FPipeBuffer -{ -public: - FPipeBuffer::FPipeBuffer (int fragSize, int nFrags, int pipe); - ~FPipeBuffer (); - - int ReadFrag (BYTE *Buf); - -private: - int PipeHandle; - int FragSize; - int BuffSize; - int WritePos, ReadPos; - BYTE *Buffer; - bool GotFull; - SDL_mutex *BufferMutex; - SDL_thread *Reader; - - static int ThreadProc (void *data); -}; -#endif - #ifndef _WIN32 #include <unistd.h> @@ -45,7 +20,7 @@ void ChildSigHandler (int signum) #endif #ifdef _WIN32 -const char TimiditySong::EventName[] = "TiMidity Killer"; +const char TimidityPPMIDIDevice::EventName[] = "TiMidity Killer"; static char TimidityTitle[] = "TiMidity (ZDoom Launched)"; CVAR (String, timidity_exe, "timidity.exe", CVAR_ARCHIVE|CVAR_GLOBALCONFIG) @@ -58,6 +33,7 @@ CVAR (String, timidity_reverb, "0", CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CVAR (Bool, timidity_stereo, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CVAR (Bool, timidity_8bit, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CVAR (Bool, timidity_byteswap, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) + // added because Timidity's output is rather loud. CUSTOM_CVAR (Float, timidity_mastervolume, 1.0f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) { @@ -69,8 +45,7 @@ CUSTOM_CVAR (Float, timidity_mastervolume, 1.0f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) currSong->TimidityVolumeChanged(); } - -CUSTOM_CVAR (Int, timidity_pipe, 60, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +CUSTOM_CVAR (Int, timidity_pipe, 90, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) { // pipe size in ms if (timidity_pipe < 0) { // a negative size makes no sense @@ -86,64 +61,42 @@ CUSTOM_CVAR (Int, timidity_frequency, 22050, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) self = 65000; } -void TimiditySong::Play (bool looping, int subsong) -{ - m_Status = STATE_Stopped; - m_Looping = looping; +//========================================================================== +// +// TimidityPPMIDIDevice Constructor +// +//========================================================================== - if (LaunchTimidity ()) - { - if (m_Stream != NULL) - { - if (m_Stream->Play (true, timidity_mastervolume)) - { - m_Status = STATE_Playing; - } - } - else - { // Assume success if not mixing with FMOD - m_Status = STATE_Playing; - } - } -} - -void TimiditySong::Stop () -{ - if (m_Status != STATE_Stopped) - { - if (m_Stream != NULL) - { - m_Stream->Stop (); - } +TimidityPPMIDIDevice::TimidityPPMIDIDevice() + : DiskName("zmid"), #ifdef _WIN32 - if (ChildProcess != INVALID_HANDLE_VALUE) - { - SetEvent (KillerEvent); - if (WaitForSingleObject (ChildProcess, 500) != WAIT_OBJECT_0) - { - TerminateProcess (ChildProcess, 666); - } - CloseHandle (ChildProcess); - ChildProcess = INVALID_HANDLE_VALUE; - } + ReadWavePipe(INVALID_HANDLE_VALUE), WriteWavePipe(INVALID_HANDLE_VALUE), + KillerEvent(INVALID_HANDLE_VALUE), + ChildProcess(INVALID_HANDLE_VALUE), + Validated(false) #else - if (ChildProcess != -1) - { - if (kill (ChildProcess, SIGTERM) != 0) - { - kill (ChildProcess, SIGKILL); - } - waitpid (ChildProcess, NULL, 0); - ChildProcess = -1; - } + ChildProcess(-1) #endif +{ +#ifndef _WIN32 + WavePipe[0] = WavePipe[1] = -1; +#endif + + if (DiskName == NULL) + { + Printf(PRINT_BOLD, "Could not create temp music file\n"); + return; } - m_Status = STATE_Stopped; } -TimiditySong::~TimiditySong () +//========================================================================== +// +// TimidityPPMIDIDevice Destructor +// +//========================================================================== + +TimidityPPMIDIDevice::~TimidityPPMIDIDevice () { - Stop (); #if _WIN32 if (WriteWavePipe != INVALID_HANDLE_VALUE) { @@ -174,68 +127,53 @@ TimiditySong::~TimiditySong () #endif } -TimiditySong::TimiditySong (FILE *file, BYTE *musiccache, int len) - : DiskName ("zmid"), -#ifdef _WIN32 - ReadWavePipe (INVALID_HANDLE_VALUE), WriteWavePipe (INVALID_HANDLE_VALUE), - KillerEvent (INVALID_HANDLE_VALUE), - ChildProcess (INVALID_HANDLE_VALUE), - Validated (false) -#else - ChildProcess (-1) -#endif +//========================================================================== +// +// TimidityPPMIDIDevice :: Preprocess +// +//========================================================================== + +bool TimidityPPMIDIDevice::Preprocess(MIDIStreamer *song, bool looping) { + TArray<BYTE> midi; bool success; FILE *f; -#ifndef _WIN32 - WavePipe[0] = WavePipe[1] = -1; -#endif - - if (DiskName == NULL) + if (CommandLine.IsEmpty()) { - Printf (PRINT_BOLD, "Could not create temp music file\n"); - return; + return false; } - f = fopen (DiskName, "wb"); + // Tell TiMidity++ whether it should loop or not + CommandLine.LockBuffer()[LoopPos] = looping ? 'l' : ' '; + CommandLine.UnlockBuffer(); + + // Write MIDI song to temporary file + song->CreateSMF(midi); + + f = fopen(DiskName, "wb"); if (f == NULL) { - Printf (PRINT_BOLD, "Could not open temp music file\n"); - return; + Printf(PRINT_BOLD, "Could not open temp music file\n"); + return false; } - - BYTE *buf; - - if (file != NULL) - { - buf = new BYTE[len]; - fread (buf, 1, len, file); - } - else - { - buf = musiccache; - } - - // Write to temporary file - success = (fwrite (buf, 1, len, f) == (size_t)len); + success = (fwrite(&midi[0], 1, midi.Size(), f) == (size_t)midi.Size()); fclose (f); - if (file != NULL) - { - delete[] buf; - } - if (success) + if (!success) { - PrepTimidity (); - } - else - { - Printf (PRINT_BOLD, "Could not write temp music file\n"); + Printf(PRINT_BOLD, "Could not write temp music file\n"); } + return false; } -void TimiditySong::PrepTimidity () +//========================================================================== +// +// TimidityPPMIDIDevice :: Open +// +//========================================================================== + +int TimidityPPMIDIDevice::Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata) { int pipeSize; @@ -244,19 +182,19 @@ void TimiditySong::PrepTimidity () if (!Validated && !ValidateTimidity ()) { - return; + return 101; } Validated = true; - KillerEvent = CreateEvent (NULL, FALSE, FALSE, EventName); + KillerEvent = CreateEvent(NULL, FALSE, FALSE, EventName); if (KillerEvent == INVALID_HANDLE_VALUE) { - Printf (PRINT_BOLD, "Could not create TiMidity++ kill event.\n"); - return; + Printf(PRINT_BOLD, "Could not create TiMidity++ kill event.\n"); + return 102; } #endif // WIN32 - CommandLine.Format ("%s %s -EFchorus=%s -EFreverb=%s -s%d ", + CommandLine.Format("%s %s -EFchorus=%s -EFreverb=%s -s%d ", *timidity_exe, *timidity_extargs, *timidity_chorus, *timidity_reverb, *timidity_frequency); @@ -274,31 +212,31 @@ void TimiditySong::PrepTimidity () bitmask <<= 1; pipeSize = bitmask; - if (!CreatePipe (&ReadWavePipe, &WriteWavePipe, &inheritable, pipeSize)) + if (!CreatePipe(&ReadWavePipe, &WriteWavePipe, &inheritable, pipeSize)) #else // WIN32 if (pipe (WavePipe) == -1) #endif { - Printf (PRINT_BOLD, "Could not create a data pipe for TiMidity++.\n"); + Printf(PRINT_BOLD, "Could not create a data pipe for TiMidity++.\n"); pipeSize = 0; } else { - m_Stream = GSnd->CreateStream (FillStream, pipeSize, + Stream = GSnd->CreateStream(FillStream, pipeSize, (timidity_stereo ? 0 : SoundStream::Mono) | (timidity_8bit ? SoundStream::Bits8 : 0), timidity_frequency, this); - if (m_Stream == NULL) + if (Stream == NULL) { - Printf (PRINT_BOLD, "Could not create music stream.\n"); + Printf(PRINT_BOLD, "Could not create music stream.\n"); pipeSize = 0; #ifdef _WIN32 - CloseHandle (WriteWavePipe); - CloseHandle (ReadWavePipe); + CloseHandle(WriteWavePipe); + CloseHandle(ReadWavePipe); ReadWavePipe = WriteWavePipe = INVALID_HANDLE_VALUE; #else - close (WavePipe[1]); - close (WavePipe[0]); + close(WavePipe[1]); + close(WavePipe[0]); WavePipe[0] = WavePipe[1] = -1; #endif } @@ -306,7 +244,7 @@ void TimiditySong::PrepTimidity () if (pipeSize == 0) { - Printf (PRINT_BOLD, "If your soundcard cannot play more than one\n" + Printf(PRINT_BOLD, "If your soundcard cannot play more than one\n" "wave at a time, you will hear no music.\n"); } else @@ -331,14 +269,22 @@ void TimiditySong::PrepTimidity () CommandLine += " -idl "; CommandLine += DiskName.GetName(); + return 0; } -#ifdef _WIN32 +//========================================================================== +// +// TimidityPPMIDIDevice :: ValidateTimidity +// // Check that this TiMidity++ knows about the TiMidity Killer event. // If not, then we can't use it, because Win32 provides no other way // to conveniently signal it to quit. The check is done by simply // searching for the event's name somewhere in the executable. -bool TimiditySong::ValidateTimidity () +// +//========================================================================== + +#ifdef _WIN32 +bool TimidityPPMIDIDevice::ValidateTimidity() { char foundPath[MAX_PATH]; char *filePart; @@ -354,12 +300,12 @@ bool TimiditySong::ValidateTimidity () pathLen = SearchPath (NULL, timidity_exe, NULL, MAX_PATH, foundPath, &filePart); if (pathLen == 0) { - Printf (PRINT_BOLD, "Please set the timidity_exe cvar to the location of TiMidity++\n"); + Printf(PRINT_BOLD, "Please set the timidity_exe cvar to the location of TiMidity++\n"); return false; } if (pathLen > MAX_PATH) { - Printf (PRINT_BOLD, "The path to TiMidity++ is too long\n"); + Printf(PRINT_BOLD, "The path to TiMidity++ is too long\n"); return false; } @@ -367,21 +313,21 @@ bool TimiditySong::ValidateTimidity () OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); if (diskFile == INVALID_HANDLE_VALUE) { - Printf (PRINT_BOLD, "Could not access %s\n", foundPath); + Printf(PRINT_BOLD, "Could not access %s\n", foundPath); return false; } fileLen = GetFileSize (diskFile, NULL); mapping = CreateFileMapping (diskFile, NULL, PAGE_READONLY, 0, 0, NULL); if (mapping == NULL) { - Printf (PRINT_BOLD, "Could not create mapping for %s\n", foundPath); + Printf(PRINT_BOLD, "Could not create mapping for %s\n", foundPath); CloseHandle (diskFile); return false; } exeBase = (const BYTE *)MapViewOfFile (mapping, FILE_MAP_READ, 0, 0, 0); if (exeBase == NULL) { - Printf (PRINT_BOLD, "Could not map %s\n", foundPath); + Printf(PRINT_BOLD, "Could not map %s\n", foundPath); CloseHandle (mapping); CloseHandle (diskFile); return false; @@ -392,12 +338,12 @@ bool TimiditySong::ValidateTimidity () { for (exe = exeBase, exeEnd = exeBase+fileLen; exe < exeEnd; ) { - const char *tSpot = (const char *)memchr (exe, 'T', exeEnd - exe); + const char *tSpot = (const char *)memchr(exe, 'T', exeEnd - exe); if (tSpot == NULL) { break; } - if (memcmp (tSpot+1, EventName+1, sizeof(EventName)-1) == 0) + if (memcmp(tSpot+1, EventName+1, sizeof(EventName)-1) == 0) { good = true; break; @@ -407,32 +353,35 @@ bool TimiditySong::ValidateTimidity () } catch (...) { - Printf (PRINT_BOLD, "Error reading %s\n", foundPath); + Printf(PRINT_BOLD, "Error reading %s\n", foundPath); } if (!good) { - Printf (PRINT_BOLD, "ZDoom requires a special version of TiMidity++\n"); + Printf(PRINT_BOLD, "ZDoom requires a special version of TiMidity++\n"); } - UnmapViewOfFile ((LPVOID)exeBase); - CloseHandle (mapping); - CloseHandle (diskFile); + UnmapViewOfFile((LPVOID)exeBase); + CloseHandle(mapping); + CloseHandle(diskFile); return good; } #endif // _WIN32 -bool TimiditySong::LaunchTimidity () +//========================================================================== +// +// TimidityPPMIDIDevice :: LaunchTimidity +// +//========================================================================== + +bool TimidityPPMIDIDevice::LaunchTimidity () { if (CommandLine.IsEmpty()) { return false; } - // Tell Timidity whether it should loop or not - char *cmdline = CommandLine.LockBuffer(); - cmdline[LoopPos] = m_Looping ? 'l' : ' '; - DPrintf ("cmd: \x1cG%s\n", cmdline); + DPrintf ("cmd: \x1cG%s\n", CommandLine.GetChars()); #ifdef _WIN32 STARTUPINFO startup = { sizeof(startup), }; @@ -448,7 +397,7 @@ bool TimiditySong::LaunchTimidity () startup.lpTitle = TimidityTitle; startup.wShowWindow = SW_SHOWMINNOACTIVE; - if (CreateProcess (NULL, cmdline, NULL, NULL, TRUE, + if (CreateProcess(NULL, CommandLine.LockBuffer(), NULL, NULL, TRUE, /*HIGH_PRIORITY_CLASS|*/DETACHED_PROCESS, NULL, NULL, &startup, &procInfo)) { ChildProcess = procInfo.hProcess; @@ -461,18 +410,18 @@ bool TimiditySong::LaunchTimidity () char hres[9]; LPTSTR msgBuf; - HRESULT err = GetLastError (); + HRESULT err = GetLastError(); if (!FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, err, 0, (LPTSTR)&msgBuf, 0, NULL)) { - mysnprintf (hres, countof(hres), "%08lx", err); + mysnprintf(hres, countof(hres), "%08lx", err); msgBuf = hres; } - Printf (PRINT_BOLD, "Could not run timidity with the command line:\n%s\n" + Printf(PRINT_BOLD, "Could not run timidity with the command line:\n%s\n" "Reason: %s\n", CommandLine.GetChars(), msgBuf); if (msgBuf != hres) { @@ -543,14 +492,20 @@ bool TimiditySong::LaunchTimidity () #endif // _WIN32 } -bool TimiditySong::FillStream (SoundStream *stream, void *buff, int len, void *userdata) +//========================================================================== +// +// TimidityPPMIDIDevice :: FillStream +// +//========================================================================== + +bool TimidityPPMIDIDevice::FillStream(SoundStream *stream, void *buff, int len, void *userdata) { - TimiditySong *song = (TimiditySong *)userdata; + TimidityPPMIDIDevice *song = (TimidityPPMIDIDevice *)userdata; #ifdef _WIN32 DWORD avail, got, didget; - if (!PeekNamedPipe (song->ReadWavePipe, NULL, 0, NULL, &avail, NULL) || avail == 0) + if (!PeekNamedPipe(song->ReadWavePipe, NULL, 0, NULL, &avail, NULL) || avail == 0) { // If nothing is available from the pipe, play silence. memset (buff, 0, len); } @@ -559,14 +514,14 @@ bool TimiditySong::FillStream (SoundStream *stream, void *buff, int len, void *u didget = 0; for (;;) { - ReadFile (song->ReadWavePipe, (BYTE *)buff+didget, len-didget, &got, NULL); + ReadFile(song->ReadWavePipe, (BYTE *)buff+didget, len-didget, &got, NULL); didget += got; if (didget >= (DWORD)len) break; - // Give TiMidity a chance to output something more to the pipe + // Give TiMidity++ a chance to output something more to the pipe Sleep (10); - if (!PeekNamedPipe (song->ReadWavePipe, NULL, 0, NULL, &avail, NULL) || avail == 0) + if (!PeekNamedPipe(song->ReadWavePipe, NULL, 0, NULL, &avail, NULL) || avail == 0) { memset ((BYTE *)buff+didget, 0, len-didget); break; @@ -581,7 +536,7 @@ bool TimiditySong::FillStream (SoundStream *stream, void *buff, int len, void *u if (ChildQuit == song->ChildProcess) { ChildQuit = 0; - fprintf (stderr, "child gone\n"); + fprintf(stderr, "child gone\n"); song->ChildProcess = -1; return false; } @@ -599,32 +554,44 @@ bool TimiditySong::FillStream (SoundStream *stream, void *buff, int len, void *u } // fprintf(stderr,"something\n"); - got = read (song->WavePipe[0], (BYTE *)buff, len); + got = read(song->WavePipe[0], (BYTE *)buff, len); if (got < len) { - memset ((BYTE *)buff+got, 0, len-got); + memset((BYTE *)buff+got, 0, len-got); } #endif return true; } -void TimiditySong::TimidityVolumeChanged() +//========================================================================== +// +// TimidityPPMIDIDevice :: TimidityVolumeChanged +// +//========================================================================== + +void TimidityPPMIDIDevice::TimidityVolumeChanged() { - if (m_Stream != NULL) + if (Stream != NULL) { - m_Stream->SetVolume(timidity_mastervolume); + Stream->SetVolume(timidity_mastervolume); } } -bool TimiditySong::IsPlaying () +//========================================================================== +// +// TimidityPPMIDIDevice :: IsOpen +// +//========================================================================== + +bool TimidityPPMIDIDevice::IsOpen() const { #ifdef _WIN32 if (ChildProcess != INVALID_HANDLE_VALUE) { - if (WaitForSingleObject (ChildProcess, 0) != WAIT_TIMEOUT) - { // Timidity has quit - CloseHandle (ChildProcess); - ChildProcess = INVALID_HANDLE_VALUE; + if (WaitForSingleObject(ChildProcess, 0) != WAIT_TIMEOUT) + { // Timidity++ has quit + CloseHandle(ChildProcess); + const_cast<TimidityPPMIDIDevice *>(this)->ChildProcess = INVALID_HANDLE_VALUE; #else if (ChildProcess != -1) { @@ -632,15 +599,6 @@ bool TimiditySong::IsPlaying () { ChildProcess = -1; #endif - if (m_Looping) - { - if (!LaunchTimidity ()) - { - Stop (); - return false; - } - return true; - } return false; } return true; @@ -648,86 +606,66 @@ bool TimiditySong::IsPlaying () return false; } -#if !defined(_WIN32) && 0 -FPipeBuffer::FPipeBuffer (int fragSize, int nFrags, int pipe) - : PipeHandle (pipe), - FragSize (fragSize), - BuffSize (fragSize * nFrags), - WritePos (0), ReadPos (0), GotFull (false), - Reader (0), PleaseExit (0) +//========================================================================== +// +// TimidityPPMIDIDevice :: Resume +// +//========================================================================== + +int TimidityPPMIDIDevice::Resume() { - Buffer = new BYTE[BuffSize]; - if (Buffer != NULL) + if (!Started) { - BufferMutex = SDL_CreateMutex (); - if (BufferMutex == NULL) + if (LaunchTimidity()) { - Reader = SDL_CreateThread (ThreadProc, (void *)this); + // Assume success if not mixing with FMOD + if (Stream == NULL || Stream->Play(true, timidity_mastervolume)) + { + Started = true; + return 0; + } } + return 1; } + return 0; } -FPipeBuffer::~FPipeBuffer () -{ - if (Reader != NULL) - { // I like the Win32 IPC facilities better than SDL's - // Fortunately, this is a simple thread, so I can cheat - // like this. - SDL_KillThread (ThreadProc); - } - if (BufferMutex != NULL) - { - SDL_DestroyMutex (BufferMutex); - } - if (Buffer != NULL) - { - delete[] Buffer; - } -} +//========================================================================== +// +// TimidityPPMIDIDevice :: Stop +// +//========================================================================== -int FPipeBuffer::ReadFrag (BYTE *buf) +void TimidityPPMIDIDevice::Stop () { - int startavvail; - int avail; - int pos; - int opos; - - if (SDL_mutexP (BufferMutex) == -1) - return 0; - - if (WritePos > ReadPos) + if (Started) { - avail = WritePos - ReadPos; - } - else - { - avail = BuffSize - ReadPos + WritePos; - } - if (avail > FragSize) - avail = FragSize; - - startavail = avali; - pos = ReadPos; - opos = 0; - - while (avail != 0) - { - int thistime; - - thistime = (pos + avail > BuffSize) ? BuffSize - pos : avail; - memcpy (buf + opos, Buffer + pos, thistime); - if (thistime != avail) + if (Stream != NULL) { - pos = 0; - avail -= thistime; + Stream->Stop(); } - opos += thistime; +#ifdef _WIN32 + if (ChildProcess != INVALID_HANDLE_VALUE) + { + SetEvent(KillerEvent); + if (WaitForSingleObject(ChildProcess, 500) != WAIT_OBJECT_0) + { + TerminateProcess(ChildProcess, 666); + } + CloseHandle(ChildProcess); + ChildProcess = INVALID_HANDLE_VALUE; + } +#else + if (ChildProcess != -1) + { + if (kill(ChildProcess, SIGTERM) != 0) + { + kill(ChildProcess, SIGKILL); + } + waitpid(ChildProcess, NULL, 0); + ChildProcess = -1; + } +#endif } - - ReadPos = pos; - - SDL_mutexV (BufferMutex); - - return startavail; + Started = false; } -#endif // !_WIN32 diff --git a/src/sound/music_midistream.cpp b/src/sound/music_midistream.cpp index aa1e3feab..473a9ef75 100644 --- a/src/sound/music_midistream.cpp +++ b/src/sound/music_midistream.cpp @@ -251,6 +251,10 @@ void MIDIStreamer::Play(bool looping, int subsong) MIDI = new OPLMIDIDevice; break; + case MIDI_Timidity: + MIDI = new TimidityPPMIDIDevice; + break; + default: MIDI = NULL; break; @@ -269,7 +273,7 @@ void MIDIStreamer::Play(bool looping, int subsong) SetMIDISubsong(subsong); CheckCaps(MIDI->GetTechnology()); - if (MIDI->Preprocess(this)) + if (MIDI->Preprocess(this, looping)) { StartPlayback(); } @@ -1259,7 +1263,7 @@ void MIDIDevice::PrecacheInstruments(const WORD *instruments, int count) // //========================================================================== -bool MIDIDevice::Preprocess(MIDIStreamer *song) +bool MIDIDevice::Preprocess(MIDIStreamer *song, bool looping) { return true; } diff --git a/src/sound/music_psuedo_mididevice.cpp b/src/sound/music_psuedo_mididevice.cpp index 11ddea63e..ec72794e3 100644 --- a/src/sound/music_psuedo_mididevice.cpp +++ b/src/sound/music_psuedo_mididevice.cpp @@ -67,7 +67,7 @@ PsuedoMIDIDevice::PsuedoMIDIDevice() { Stream = NULL; Started = false; - SampleRate = GSnd != NULL ? (int)GSnd->GetOutputRate() : 44100; + bLooping = true; } //========================================================================== @@ -129,7 +129,7 @@ int PsuedoMIDIDevice::Resume() { if (!Started) { - if (Stream->Play(true, 1)) + if (Stream->Play(bLooping, 1)) { Started = true; return 0; @@ -250,11 +250,11 @@ int FMODMIDIDevice::Open(void (*callback)(unsigned int, void *, DWORD, DWORD), v // //========================================================================== -bool FMODMIDIDevice::Preprocess(MIDIStreamer *song) +bool FMODMIDIDevice::Preprocess(MIDIStreamer *song, bool looping) { TArray<BYTE> midi; song->CreateSMF(midi); - Stream = GSnd->OpenStream((char *)&midi[0], SoundStream::Loop, -1, midi.Size()); + Stream = GSnd->OpenStream((char *)&midi[0], looping ? SoundStream::Loop : 0, -1, midi.Size()); return false; }