diff --git a/src/sound/mididevices/music_timiditypp_mididevice.cpp b/src/sound/mididevices/music_timiditypp_mididevice.cpp index 42733ce38..b744e9652 100644 --- a/src/sound/mididevices/music_timiditypp_mididevice.cpp +++ b/src/sound/mididevices/music_timiditypp_mididevice.cpp @@ -45,93 +45,31 @@ #include "tmpfileplus.h" #include "m_misc.h" -#ifndef _WIN32 -#include - -#include -#include -#ifndef __OpenBSD__ -#include -#endif -#include -#include - -int ChildQuit; - -void ChildSigHandler (int signum) -{ - ChildQuit = waitpid (-1, NULL, WNOHANG); -} -#endif - -class TimidityPPMIDIDevice : public PseudoMIDIDevice +class TimidityPPMIDIDevice : public SoftSynthMIDIDevice { + TArray midi; + FString CurrentConfig; public: TimidityPPMIDIDevice(const char *args); ~TimidityPPMIDIDevice(); int Open(MidiCallback, void *userdata); - bool Preprocess(MIDIStreamer *song, bool looping); - bool IsOpen() const; - int Resume(); - - void Stop(); - bool IsOpen(); - void TimidityVolumeChanged(); + void PrecacheInstruments(const uint16_t *instruments, int count); + //FString GetStats(); int GetDeviceType() const override { return MDEV_TIMIDITY; } + bool Preprocess(MIDIStreamer *song, bool looping); + void TimidityVolumeChanged(); protected: - bool LaunchTimidity(); + //TimidityPlus::Player *Renderer; - FString DiskName; -#ifdef _WIN32 - HANDLE ReadWavePipe; - HANDLE WriteWavePipe; - HANDLE ChildProcess; - FString CommandLine; - bool Validated; - bool ValidateTimidity(); -#else // _WIN32 - int WavePipe[2]; - pid_t ChildProcess; -#endif - FString ExeName; - bool Looping; - - static bool FillStream(SoundStream *stream, void *buff, int len, void *userdata); -#ifdef _WIN32 - static const char EventName[]; -#endif + void HandleEvent(int status, int parm1, int parm2); + void HandleLongEvent(const uint8_t *data, int len); + void ComputeOutput(float *buffer, int len); }; - - -#ifdef _WIN32 - - -BOOL SafeTerminateProcess(HANDLE hProcess, UINT uExitCode); - -static char TimidityTitle[] = "TiMidity (" GAMENAME " Launched)"; -const char TimidityPPMIDIDevice::EventName[] = "TiMidity Killer"; - -CUSTOM_CVAR (String, timidity_exe, "timidity.exe", CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -#else -CUSTOM_CVAR(String, timidity_exe, "timidity", CVAR_ARCHIVE | CVAR_GLOBALCONFIG) -#endif -{ - if (currSong != nullptr && currSong->GetDeviceType() == MDEV_TIMIDITY) - { - MIDIDeviceChanged(-1, true); - } -} - -CVAR (String, timidity_extargs, "", CVAR_ARCHIVE|CVAR_GLOBALCONFIG) // extra args to pass to Timidity -CVAR (String, timidity_config, "", CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -CVAR (String, timidity_chorus, "0", CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -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) +// Config file to use +CVAR(String, timidity_config, "", CVAR_ARCHIVE | CVAR_GLOBALCONFIG) // added because Timidity's output is rather loud. CUSTOM_CVAR (Float, timidity_mastervolume, 1.0f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) @@ -144,13 +82,6 @@ CUSTOM_CVAR (Float, timidity_mastervolume, 1.0f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) currSong->TimidityVolumeChanged(); } -CUSTOM_CVAR (Int, timidity_pipe, 90, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -{ // pipe size in ms - if (self < 20) - { // Don't allow pipes less than 20ms - self = 20; - } -} CUSTOM_CVAR (Int, timidity_frequency, 44100, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) { // Clamp frequency to Timidity's limits @@ -166,34 +97,19 @@ CUSTOM_CVAR (Int, timidity_frequency, 44100, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) // //========================================================================== -TimidityPPMIDIDevice::TimidityPPMIDIDevice(const char *args) : -#ifdef _WIN32 - ReadWavePipe(INVALID_HANDLE_VALUE), WriteWavePipe(INVALID_HANDLE_VALUE), - ChildProcess(INVALID_HANDLE_VALUE), - Validated(false), -#else - ChildProcess(-1), -#endif - Looping(false) +TimidityPPMIDIDevice::TimidityPPMIDIDevice(const char *args) { -#ifndef _WIN32 - WavePipe[0] = WavePipe[1] = -1; -#endif + if (args == NULL || *args == 0) args = timidity_config; - if (args == NULL || *args == 0) args = timidity_exe; - ExeName = args; - -#ifdef _WIN32 - CommandLine.Format("%s %s -EFchorus=%s -EFreverb=%s -s%d ", - args, *timidity_extargs, - *timidity_chorus, *timidity_reverb, *timidity_frequency); - if (**timidity_config != '\0') + if (CurrentConfig.CompareNoCase(args) != 0) { - CommandLine += "-c \""; - CommandLine += timidity_config; - CommandLine += "\" "; + // reload instruments + // if (!reload_inst()) CurrentConfig = ""; + } + if (CurrentConfig.IsNotEmpty()) + { + //Renderer = new TimidityPlus::Player(timidity_frequency, args); } -#endif } //========================================================================== @@ -204,34 +120,14 @@ TimidityPPMIDIDevice::TimidityPPMIDIDevice(const char *args) : TimidityPPMIDIDevice::~TimidityPPMIDIDevice () { - if (DiskName.IsNotEmpty()) + Close(); + /* + if (Renderer != nullptr) { - remove(DiskName); + delete Renderer; } + */ -#if _WIN32 - if (WriteWavePipe != INVALID_HANDLE_VALUE) - { - CloseHandle (WriteWavePipe); - WriteWavePipe = INVALID_HANDLE_VALUE; - } - if (ReadWavePipe != INVALID_HANDLE_VALUE) - { - CloseHandle (ReadWavePipe); - ReadWavePipe = INVALID_HANDLE_VALUE; - } -#else - if (WavePipe[1] != -1) - { - close (WavePipe[1]); - WavePipe[1] = -1; - } - if (WavePipe[0] != -1) - { - close (WavePipe[0]); - WavePipe[0] = -1; - } -#endif } //========================================================================== @@ -242,47 +138,9 @@ TimidityPPMIDIDevice::~TimidityPPMIDIDevice () bool TimidityPPMIDIDevice::Preprocess(MIDIStreamer *song, bool looping) { - TArray midi; - bool success; - FILE *f; - - if (ExeName.IsEmpty()) - { - return false; - } - - Looping = looping; - // Write MIDI song to temporary file song->CreateSMF(midi, looping ? 0 : 1); - - FString path = M_GetAppDataPath(false); - path += "/tmp"; - CreatePath(path); - f = tmpfileplus(path, "zmid", &DiskName, 1); - if (f == NULL) - { - Printf(PRINT_BOLD, "Could not open temp music file\n"); - return false; - } - success = (fwrite(&midi[0], 1, midi.Size(), f) == (size_t)midi.Size()); - fclose (f); - - if (!success) - { - Printf(PRINT_BOLD, "Could not write temp music file\n"); - } - -#ifdef _WIN32 - CommandLine.AppendFormat("-o - -Ors%c%c%c -id%c %s", - timidity_stereo ? 'S' : 'M', - timidity_8bit ? '8' : '1', - timidity_byteswap ? 'x' : ' ', - looping ? 'l' : ' ', - DiskName); -#endif - - return false; + return midi.Size() > 0; } //========================================================================== @@ -290,414 +148,79 @@ bool TimidityPPMIDIDevice::Preprocess(MIDIStreamer *song, bool looping) // TimidityPPMIDIDevice :: Open // //========================================================================== +namespace TimidityPlus +{ + int load_midi_file(FileReader *fr); + void run_midi(int samples); + void timidity_close(); +} int TimidityPPMIDIDevice::Open(MidiCallback callback, void *userdata) { - int pipeSize; - -#ifdef _WIN32 - static SECURITY_ATTRIBUTES inheritable = { sizeof(inheritable), NULL, true }; - - if (!Validated && !ValidateTimidity ()) + int ret = OpenStream(2, 0, callback, userdata); + if (ret == 0) { - return 101; + //Renderer->Reset(); + MemoryReader fr((char*)&midi[0], midi.Size()); + return !TimidityPlus::load_midi_file(&fr); } - - Validated = true; -#endif // WIN32 - - pipeSize = (timidity_pipe * timidity_frequency / 1000) - << (timidity_stereo + !timidity_8bit); - - { -#ifdef _WIN32 - // Round pipe size up to nearest power of 2 to try and avoid partial - // buffer reads in FillStream() under NT. This does not seem to be an - // issue under 9x. - int bitmask = pipeSize & -pipeSize; - - while (bitmask < pipeSize) - bitmask <<= 1; - pipeSize = bitmask; - - 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"); - return 1; - } - - Stream = GSnd->CreateStream(FillStream, pipeSize, - (timidity_stereo ? 0 : SoundStream::Mono) | - (timidity_8bit ? SoundStream::Bits8 : 0), - timidity_frequency, this); - if (Stream == NULL) - { - Printf(PRINT_BOLD, "Could not create music stream.\n"); -#ifdef _WIN32 - CloseHandle(WriteWavePipe); - CloseHandle(ReadWavePipe); - ReadWavePipe = WriteWavePipe = INVALID_HANDLE_VALUE; -#else - close(WavePipe[1]); - close(WavePipe[0]); - WavePipe[0] = WavePipe[1] = -1; -#endif - return 1; - } - } - - return 0; + return ret; } //========================================================================== // -// TimidityPPMIDIDevice :: ValidateTimidity +// TimidityPPMIDIDevice :: PrecacheInstruments // -// 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. +// Each entry is packed as follows: +// Bits 0- 6: Instrument number +// Bits 7-13: Bank number +// Bit 14: Select drum set if 1, tone bank if 0 // //========================================================================== -#ifdef _WIN32 -bool TimidityPPMIDIDevice::ValidateTimidity() +void TimidityPPMIDIDevice::PrecacheInstruments(const uint16_t *instruments, int count) { - char foundPath[MAX_PATH]; - char *filePart; - DWORD pathLen; - DWORD fileLen; - HANDLE diskFile; - HANDLE mapping; - const uint8_t *exeBase; - const uint8_t *exeEnd; - const uint8_t *exe; - bool good; - - pathLen = SearchPath (NULL, timidity_exe, NULL, MAX_PATH, foundPath, &filePart); - if (pathLen == 0) + for (int i = 0; i < count; ++i) { - Printf(PRINT_BOLD, "Please set the timidity_exe cvar to the location of TiMidity++\n"); - return false; + //Renderer->MarkInstrument((instruments[i] >> 7) & 127, instruments[i] >> 14, instruments[i] & 127); } - if (pathLen > MAX_PATH) - { - Printf(PRINT_BOLD, "The path to TiMidity++ is too long\n"); - return false; - } - - diskFile = CreateFile (foundPath, GENERIC_READ, FILE_SHARE_READ, NULL, - OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); - if (diskFile == INVALID_HANDLE_VALUE) - { - 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); - CloseHandle (diskFile); - return false; - } - exeBase = (const uint8_t *)MapViewOfFile (mapping, FILE_MAP_READ, 0, 0, 0); - if (exeBase == NULL) - { - Printf(PRINT_BOLD, "Could not map %s\n", foundPath); - CloseHandle (mapping); - CloseHandle (diskFile); - return false; - } - - good = false; - try - { - for (exe = exeBase, exeEnd = exeBase+fileLen; exe < exeEnd; ) - { - const char *tSpot = (const char *)memchr(exe, 'T', exeEnd - exe); - if (tSpot == NULL) - { - break; - } - if (memcmp(tSpot+1, EventName+1, sizeof(EventName)-1) == 0) - { - good = true; - break; - } - exe = (const uint8_t *)tSpot + 1; - } - } - catch (...) - { - Printf(PRINT_BOLD, "Error reading %s\n", foundPath); - } - if (!good) - { - Printf(PRINT_BOLD, GAMENAME " requires a special version of TiMidity++\n"); - } - - UnmapViewOfFile((LPVOID)exeBase); - CloseHandle(mapping); - CloseHandle(diskFile); - - return good; -} -#endif // _WIN32 - -//========================================================================== -// -// TimidityPPMIDIDevice :: LaunchTimidity -// -//========================================================================== - -bool TimidityPPMIDIDevice::LaunchTimidity () -{ - if (ExeName.IsEmpty() || DiskName.IsEmpty()) - { - return false; - } - -#ifdef _WIN32 - DPrintf (DMSG_NOTIFY, "cmd: \x1cG%s\n", CommandLine.GetChars()); - - STARTUPINFO startup = { sizeof(startup), }; - PROCESS_INFORMATION procInfo; - - startup.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; - - startup.hStdInput = INVALID_HANDLE_VALUE; - startup.hStdOutput = WriteWavePipe != INVALID_HANDLE_VALUE ? - WriteWavePipe : GetStdHandle (STD_OUTPUT_HANDLE); - startup.hStdError = GetStdHandle (STD_ERROR_HANDLE); - - startup.lpTitle = TimidityTitle; - startup.wShowWindow = SW_SHOWMINNOACTIVE; - - if (CreateProcess(NULL, CommandLine.LockBuffer(), NULL, NULL, true, - DETACHED_PROCESS, NULL, NULL, &startup, &procInfo)) - { - ChildProcess = procInfo.hProcess; - //SetThreadPriority (procInfo.hThread, THREAD_PRIORITY_HIGHEST); - CloseHandle(procInfo.hThread); // Don't care about the created thread - CommandLine.UnlockBuffer(); - return true; - } - CommandLine.UnlockBuffer(); - - char hres[9]; - LPTSTR msgBuf; - 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); - msgBuf = hres; - } - - Printf(PRINT_BOLD, "Could not run timidity with the command line:\n%s\n" - "Reason: %s\n", CommandLine.GetChars(), msgBuf); - if (msgBuf != hres) - { - LocalFree (msgBuf); - } - return false; -#else - if (WavePipe[0] != -1 && WavePipe[1] == -1 && Stream != NULL) - { - // Timidity was previously launched, so the write end of the pipe - // is closed, and the read end is still open. Close the pipe - // completely and reopen it. - - close (WavePipe[0]); - WavePipe[0] = -1; - delete Stream; - Stream = NULL; - Open (NULL, NULL); - } - - int forkres; -#ifndef __OpenBSD__ - wordexp_t words; -#endif - glob_t glb; - - // Get timidity executable path - const char *exename = "timidity"; // Fallback default - glob(ExeName.GetChars(), 0, NULL, &glb); - if(glb.gl_pathc != 0) - exename = glb.gl_pathv[0]; -#ifndef __OpenBSD__ - // Get user-defined extra args - wordexp(timidity_extargs, &words, WRDE_NOCMD); -#endif - - std::string chorusarg = std::string("-EFchorus=") + *timidity_chorus; - std::string reverbarg = std::string("-EFreverb=") + *timidity_reverb; - std::string sratearg = std::string("-s") + std::to_string(*timidity_frequency); - std::string outfilearg = "-o"; // An extra "-" is added later - std::string outmodearg = "-Or"; - outmodearg += timidity_8bit ? "u8" : "s1"; - outmodearg += timidity_stereo ? "S" : "M"; - if(timidity_byteswap) outmodearg += "x"; - std::string ifacearg = "-id"; - if(Looping) ifacearg += "l"; - - std::vector arglist; - arglist.push_back(exename); -#ifndef __OpenBSD__ - for(size_t i = 0;i < words.we_wordc;i++) - arglist.push_back(words.we_wordv[i]); -#endif - if(**timidity_config != '\0') - { - arglist.push_back("-c"); - arglist.push_back(timidity_config); - } - arglist.push_back(chorusarg.c_str()); - arglist.push_back(reverbarg.c_str()); - arglist.push_back(sratearg.c_str()); - arglist.push_back(outfilearg.c_str()); - arglist.push_back("-"); - arglist.push_back(outmodearg.c_str()); - arglist.push_back(ifacearg.c_str()); - arglist.push_back(DiskName.GetChars()); - - DPrintf(DMSG_NOTIFY, "Timidity EXE: \x1cG%s\n", exename); - int i = 1; - std::for_each(arglist.begin()+1, arglist.end(), - [&i](const char *arg) - { DPrintf(DMSG_NOTIFY, "arg %d: \x1cG%s\n", i++, arg); } - ); - arglist.push_back(nullptr); - - forkres = fork (); - if (forkres == 0) - { - close (WavePipe[0]); - dup2 (WavePipe[1], STDOUT_FILENO); - freopen ("/dev/null", "r", stdin); -// freopen ("/dev/null", "w", stderr); - close (WavePipe[1]); - - execvp (exename, const_cast(arglist.data())); - fprintf(stderr,"execvp failed: %s\n", strerror(errno)); - _exit (0); // if execvp succeeds, we never get here - } - else if (forkres < 0) - { - Printf (PRINT_BOLD, "Could not fork when trying to start timidity\n"); - } - else - { -// printf ("child is %d\n", forkres); - ChildProcess = forkres; - close (WavePipe[1]); - WavePipe[1] = -1; -/* usleep(1000000); - if (waitpid(ChildProcess, NULL, WNOHANG) == ChildProcess) - { - fprintf(stderr,"Launching timidity failed\n"); - }*/ - } - -#ifndef __OpenBSD__ - wordfree(&words); -#endif - globfree (&glb); - return ChildProcess != -1; -#endif // _WIN32 + //Renderer->load_missing_instruments(); } //========================================================================== // -// TimidityPPMIDIDevice :: FillStream +// TimidityPPMIDIDevice :: HandleEvent // //========================================================================== -bool TimidityPPMIDIDevice::FillStream(SoundStream *stream, void *buff, int len, void *userdata) +void TimidityPPMIDIDevice::HandleEvent(int status, int parm1, int parm2) { - TimidityPPMIDIDevice *song = (TimidityPPMIDIDevice *)userdata; + //Renderer->HandleEvent(status, parm1, parm2); +} -#ifdef _WIN32 - DWORD avail, got, didget; +//========================================================================== +// +// TimidityPPMIDIDevice :: HandleLongEvent +// +//========================================================================== - if (!PeekNamedPipe(song->ReadWavePipe, NULL, 0, NULL, &avail, NULL) || avail == 0) - { // If nothing is available from the pipe, play silence. - memset (buff, 0, len); - } - else - { - didget = 0; - for (;;) - { - ReadFile(song->ReadWavePipe, (uint8_t *)buff+didget, len-didget, &got, NULL); - didget += got; - if (didget >= (DWORD)len) - break; +void TimidityPPMIDIDevice::HandleLongEvent(const uint8_t *data, int len) +{ + //Renderer->HandleLongMessage(data, len); +} - // Give TiMidity++ a chance to output something more to the pipe - Sleep (10); - if (!PeekNamedPipe(song->ReadWavePipe, NULL, 0, NULL, &avail, NULL) || avail == 0) - { - memset ((uint8_t *)buff+didget, 0, len-didget); - break; - } - } - } -#else - fd_set rfds; - struct timeval tv; +//========================================================================== +// +// TimidityPPMIDIDevice :: ComputeOutput +// +//========================================================================== - if (ChildQuit == song->ChildProcess) - { - ChildQuit = 0; - fprintf(stderr, "child gone\n"); - song->ChildProcess = -1; - return false; - } +void TimidityPPMIDIDevice::ComputeOutput(float *buffer, int len) +{ + TimidityPlus::run_midi(len / 8); // bytes to samples + memset(buffer, len, 0); // to do - FD_ZERO(&rfds); - FD_SET(song->WavePipe[0], &rfds); - tv.tv_sec = 0; - tv.tv_usec = 50; -// fprintf(stderr,"select\n"); - if (select(1, &rfds, NULL, NULL, &tv) <= 0 && 0) - { // Nothing available, so play silence. -// fprintf(stderr,"nothing\n"); - // memset(buff, 0, len); - return true; - } -// fprintf(stderr,"something\n"); - - ssize_t got = 0; - do { - ssize_t r = read(song->WavePipe[0], (uint8_t*)buff+got, len-got); - if(r < 0) - { - if(errno == EWOULDBLOCK || errno == EAGAIN) - { - FD_ZERO(&rfds); - FD_SET(song->WavePipe[0], &rfds); - tv.tv_sec = 0; - tv.tv_usec = 50; - select(1, &rfds, NULL, NULL, &tv); - continue; - } - break; - } - got += r; - } while(got < len); - if(got < len) - memset((uint8_t*)buff+got, 0, len-got); -#endif - return true; + //Renderer->ComputeOutput(buffer, len); } //========================================================================== @@ -714,162 +237,6 @@ void TimidityPPMIDIDevice::TimidityVolumeChanged() } } -//========================================================================== -// -// TimidityPPMIDIDevice :: IsOpen -// -//========================================================================== - -bool TimidityPPMIDIDevice::IsOpen() const -{ -#ifdef _WIN32 - if (ChildProcess != INVALID_HANDLE_VALUE) - { - if (WaitForSingleObject(ChildProcess, 0) != WAIT_TIMEOUT) - { // Timidity++ has quit - CloseHandle(ChildProcess); - const_cast(this)->ChildProcess = INVALID_HANDLE_VALUE; -#else - if (ChildProcess != -1) - { - if (waitpid (ChildProcess, NULL, WNOHANG) == ChildProcess) - { - const_cast(this)->ChildProcess = -1; -#endif - return false; - } - return true; - } - return false; -} - -//========================================================================== -// -// TimidityPPMIDIDevice :: Resume -// -//========================================================================== - -int TimidityPPMIDIDevice::Resume() -{ - if (!Started) - { - if (LaunchTimidity()) - { - if (Stream != NULL && Stream->Play(true, timidity_mastervolume)) - { - Started = true; - return 0; - } - } - return 1; - } - return 0; -} - -//========================================================================== -// -// TimidityPPMIDIDevice :: Stop -// -//========================================================================== - -void TimidityPPMIDIDevice::Stop () -{ - if (Started) - { - if (Stream != NULL) - { - Stream->Stop(); - } -#ifdef _WIN32 - if (ChildProcess != INVALID_HANDLE_VALUE) - { - if (!SafeTerminateProcess(ChildProcess, 666) && GetLastError() != ERROR_PROCESS_ABORTED) - { - 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 - } - Started = false; -} - -#ifdef _WIN32 -/* - Safely terminate a process by creating a remote thread - in the process that calls ExitProcess - - Source is a Dr Dobbs article circa 1999. -*/ -typedef HANDLE (WINAPI *CreateRemoteThreadProto)(HANDLE,LPSECURITY_ATTRIBUTES,SIZE_T,LPTHREAD_START_ROUTINE,LPVOID,DWORD,LPDWORD); - -BOOL SafeTerminateProcess(HANDLE hProcess, UINT uExitCode) -{ - DWORD dwTID, dwCode; - HRESULT dwErr = 0; - HANDLE hRT = NULL; - HINSTANCE hKernel = GetModuleHandle("Kernel32"); - BOOL bSuccess = FALSE; - - // Detect the special case where the process is already dead... - if ( GetExitCodeProcess(hProcess, &dwCode) && (dwCode == STILL_ACTIVE) ) - { - FARPROC pfnExitProc; - CreateRemoteThreadProto pfCreateRemoteThread; - - pfnExitProc = GetProcAddress(hKernel, "ExitProcess"); - - // CreateRemoteThread does not exist on 9x systems. - pfCreateRemoteThread = (CreateRemoteThreadProto)GetProcAddress(hKernel, "CreateRemoteThread"); - - if (pfCreateRemoteThread == NULL) - { - dwErr = ERROR_INVALID_FUNCTION; - } - else - { - hRT = pfCreateRemoteThread(hProcess, - NULL, - 0, - (LPTHREAD_START_ROUTINE)pfnExitProc, - (PVOID)(UINT_PTR)uExitCode, 0, &dwTID); - - if ( hRT == NULL ) - dwErr = GetLastError(); - } - } - else - { - dwErr = ERROR_PROCESS_ABORTED; - } - - if ( hRT ) - { - // Must wait for process to terminate to guarantee that it has exited... - DWORD res = WaitForSingleObject(hProcess, 1000); - CloseHandle(hRT); - bSuccess = (res == WAIT_OBJECT_0); - dwErr = WAIT_TIMEOUT; - } - - if ( !bSuccess ) - SetLastError(dwErr); - - return bSuccess; -} -#endif - MIDIDevice *CreateTimidityPPMIDIDevice(const char *args) { diff --git a/src/sound/timiditypp/playmidi.h b/src/sound/timiditypp/playmidi.h index 2ce0b6f51..73127059c 100644 --- a/src/sound/timiditypp/playmidi.h +++ b/src/sound/timiditypp/playmidi.h @@ -733,6 +733,8 @@ public: // Only until streaming works. void skip_to(int32_t until_time, MidiEvent *evt_start); + int start_midi(MidiEvent *eventlist, int32_t samples); + void run_midi(int); int play_midi(MidiEvent *eventlist, int32_t samples); friend MidiEvent *groom_list(int32_t divisions, int32_t *eventsp, int32_t *samplesp); diff --git a/src/sound/timiditypp/readmidi.cpp b/src/sound/timiditypp/readmidi.cpp index 5acda6f3c..c90c2326d 100644 --- a/src/sound/timiditypp/readmidi.cpp +++ b/src/sound/timiditypp/readmidi.cpp @@ -18,6 +18,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include #include #include #include @@ -28,6 +29,7 @@ #include "tables.h" #include "reverb.h" #include "aq.h" +#include "tarray.h" #include namespace TimidityPlus @@ -124,10 +126,9 @@ void Player::skip_to(int32_t until_time, MidiEvent *evt_start) } -int Player::play_midi(MidiEvent *eventlist, int32_t samples) +int Player::start_midi(MidiEvent *eventlist, int32_t samples) { int rc; - static int play_count = 0; int i, j; sample_count = samples; @@ -155,29 +156,9 @@ int Player::play_midi(MidiEvent *eventlist, int32_t samples) skip_to(0, eventlist); - rc = RC_OK; - for (;;) - { - rc = play_event(current_event); - if (rc != RC_OK) - break; - current_event++; - } - - if (play_count++ > 3) - { - int cnt; - play_count = 0; - cnt = free_global_mblock(); /* free unused memory */ - if (cnt > 0) - ctl_cmsg(CMSG_INFO, VERB_VERBOSE, - "%d memory blocks are free", cnt); - } - return rc; + return RC_OK; } - - static MidiEventList *alloc_midi_event() { return (MidiEventList *)new_segment(&mempool, sizeof(MidiEventList)); @@ -1491,23 +1472,7 @@ static MidiEvent *read_midi_file(struct timidity_file *tf, int32_t *count, int32 //////////////////////////////////////// MID file player -// temporary crutch -static struct timidity_file *open_file(char *name, int decompress, int noise_mode) -{ - FileReader *fr = new FileReader; - if (!fr->Open(name)) - { - delete fr; - return nullptr; - } - auto tf = new timidity_file; - tf->url = fr; - tf->filename = name; - return tf; -} - - -static int play_midi_load_file(char *fn, +static int play_midi_load_file(FileReader *fr, MidiEvent **event, int32_t *nsamples) { @@ -1517,16 +1482,14 @@ static int play_midi_load_file(char *fn, *event = NULL; - ctl_cmsg(CMSG_INFO, VERB_VERBOSE, "MIDI file: %s", fn); - if ((tf = open_file(fn, 1, OF_VERBOSE)) == NULL) - { - return RC_ERROR; - } + tf = new timidity_file; + tf->filename = "zdoom"; + tf->url = fr; *event = NULL; rc = RC_OK; - *event = read_midi_file(tf, &nevents, nsamples, fn); + *event = read_midi_file(tf, &nevents, nsamples, "zdoom"); close_file(tf); if (*event == NULL) @@ -1564,15 +1527,35 @@ static int play_midi_load_file(char *fn, } -int play_midi_file(char *fn) + +Instruments *instruments; +CRITICAL_SECTION critSect; + + +int load_midi_file(FileReader *fr) { int rc; static int last_rc = RC_OK; MidiEvent *event; int32_t nsamples; + InitializeCriticalSection(&critSect); + if (play_mode->open_output() < 0) + { + return RC_ERROR; + } + + instruments = new Instruments; + if (instruments->load("timidity.cfg")) + { + return RC_ERROR; + } + + gplayer = new Player; + + /* Set current file information */ - auto current_file_info = gplayer->get_midi_file_info(fn, 1); + auto current_file_info = gplayer->get_midi_file_info("zdoom", 1); rc = RC_OK; @@ -1581,31 +1564,39 @@ int play_midi_file(char *fn) midi_restart_time = 0; - rc = play_midi_load_file(fn, &event, &nsamples); + rc = play_midi_load_file(fr, &event, &nsamples); if (RC_IS_SKIP_FILE(rc)) - goto play_end; /* skip playing */ + return RC_ERROR; /* skip playing */ - rc = gplayer->play_midi(event, nsamples); - -play_end: - - instruments->free_special_patch(-1); - - if (event != NULL) - free(event); - - last_rc = rc; - return rc; + return gplayer->start_midi(event, nsamples); } -int dumb_pass_playing_list(int number_of_files, char *list_of_files[]) + +void Player::run_midi(int samples) { - gplayer = new Player; - for (;;) + auto time = current_event->time + samples; + while (current_event->time < samples) { - if (play_midi_file(list_of_files[0]) == RC_QUIT) return 0; + if (play_event(current_event) != RC_OK) + return; + current_event++; } - delete gplayer; } +void run_midi(int msec) +{ + gplayer->run_midi(msec); +} + + +void timidity_close() +{ + delete gplayer; + delete instruments; + play_mode->close_output(); + DeleteCriticalSection(&critSect); + free_global_mblock(); +} + + } \ No newline at end of file diff --git a/src/sound/timiditypp/timidity.cpp b/src/sound/timiditypp/timidity.cpp deleted file mode 100644 index 4212564b3..000000000 --- a/src/sound/timiditypp/timidity.cpp +++ /dev/null @@ -1,149 +0,0 @@ -/* - TiMidity++ -- MIDI to WAVE converter and player - Copyright (C) 1999-2008 Masanao Izumo - Copyright (C) 1995 Tuukka Toivonen - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include -#include - -#ifdef _WIN32 -#include -#include -#include -#endif -#include - -#include - -#include "timidity.h" -#include "common.h" -#include "instrum.h" -#include "playmidi.h" -#include "tables.h" -#include "reverb.h" -#include "resample.h" -#include "recache.h" -#include "aq.h" -#include "mix.h" -#include "quantity.h" -#include "c_cvars.h" - -namespace TimidityPlus -{ - Instruments *instruments; - -/* main interfaces (To be used another main) */ - -int timidity_pre_load_configuration(void); -void timidity_init_player(void); -int timidity_play_main(int nfiles, char **files); -int got_a_configuration; - - -CRITICAL_SECTION critSect; - -/* -------- functions for getopt_long ends here --------- */ - - - -int timidity_pre_load_configuration(void) -{ - /* Windows */ - char *strp; - char local[1024]; - - - /* First, try read configuration file which is in the - * TiMidity directory. - */ - if(GetModuleFileNameA(NULL, local, 1023)) - { - local[1023] = '\0'; - if (strp = strrchr(local, '\\')) - { - *(++strp) = '\0'; - strncat(local, "TIMIDITY.CFG", sizeof(local) - strlen(local) - 1); - if (true) - { - if (!instruments->load("timidity.cfg")) - { - got_a_configuration = 1; - return 0; - } - } - } - } - - return 0; -} - - -int dumb_pass_playing_list(int number_of_files, char *list_of_files[]); - -int timidity_play_main(int nfiles, char **files) -{ - int need_stdin = 0, need_stdout = 0; - int output_fail = 0; - int retval; - - -#ifdef _WIN32 - - - InitializeCriticalSection(&critSect); - -#endif - - /* Open output device */ - - if(play_mode->open_output() < 0) - { - output_fail = 1; - return 2; - } - - retval=dumb_pass_playing_list(nfiles, files); - - - play_mode->close_output(); -#ifdef _WIN32 - DeleteCriticalSection (&critSect); -#endif - - return retval; -} - -} - -using namespace TimidityPlus; - -void main(int argc, char **argv) -{ - int err; - char *files_nbuf = NULL; - int main_ret; - instruments = new Instruments; - - if ((err = timidity_pre_load_configuration()) != 0) - return; - - main_ret = timidity_play_main(1, &argv[1]); - //free_readmidi(); - free_global_mblock(); -} -