diff --git a/src/menu/menu.cpp b/src/menu/menu.cpp index 65a5d5a99..db0fd2efb 100644 --- a/src/menu/menu.cpp +++ b/src/menu/menu.cpp @@ -65,7 +65,7 @@ CVAR (Float, mouse_sensitivity, 1.f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CVAR (Bool, show_messages, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CVAR (Bool, show_obituaries, true, CVAR_ARCHIVE) -CVAR(Bool, m_showinputgrid, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +CVAR (Int, m_showinputgrid, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) CVAR(Bool, m_blockcontrollers, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) diff --git a/src/menu/menudef.cpp b/src/menu/menudef.cpp index e7818d849..d97705b34 100644 --- a/src/menu/menudef.cpp +++ b/src/menu/menudef.cpp @@ -1386,6 +1386,7 @@ static void InitMusicMenus() DMenuDescriptor **gusmenu = MenuDescriptors.CheckKey("GusConfigMenu"); DMenuDescriptor **timiditymenu = MenuDescriptors.CheckKey("TimidityExeMenu"); DMenuDescriptor **wildmidimenu = MenuDescriptors.CheckKey("WildMidiConfigMenu"); + DMenuDescriptor **timiditycfgmenu = MenuDescriptors.CheckKey("TimidityConfigMenu"); DMenuDescriptor **fluidmenu = MenuDescriptors.CheckKey("FluidPatchsetMenu"); const char *key, *value; @@ -1426,6 +1427,11 @@ static void InitMusicMenus() auto it = CreateOptionMenuItemCommand(key, FStringf("wildmidi_config %s", NicePath(value).GetChars()), true); static_cast(*wildmidimenu)->mItems.Push(it); } + if (timiditycfgmenu != nullptr) + { + auto it = CreateOptionMenuItemCommand(key, FStringf("timidity_config \"%s\"", NicePath(value).GetChars()), true); + static_cast(*timiditycfgmenu)->mItems.Push(it); + } } } } @@ -1437,6 +1443,8 @@ static void InitMusicMenus() if (it != nullptr) d->mItems.Delete(d->mItems.Find(it)); it = d->GetItem("WildMidiConfigMenu"); if (it != nullptr) d->mItems.Delete(d->mItems.Find(it)); + it = d->GetItem("TimidityConfigMenu"); + if (it != nullptr) d->mItems.Delete(d->mItems.Find(it)); } #ifdef _WIN32 // Different Timidity paths only make sense if they can be stored in arbitrary paths with local configs (i.e. not if things are done the Linux way) if (GameConfig->SetSection("TimidityExes")) diff --git a/src/sound/mididevices/music_timiditypp_mididevice.cpp b/src/sound/mididevices/music_timiditypp_mididevice.cpp index fb30192d7..335265326 100644 --- a/src/sound/mididevices/music_timiditypp_mididevice.cpp +++ b/src/sound/mididevices/music_timiditypp_mididevice.cpp @@ -34,6 +34,8 @@ #include "i_midi_win32.h" +#include +#include #include "i_musicinterns.h" #include "c_cvars.h" @@ -46,6 +48,7 @@ #include #include +#include #include #include @@ -81,14 +84,16 @@ protected: HANDLE ReadWavePipe; HANDLE WriteWavePipe; HANDLE ChildProcess; + FString CommandLine; + size_t LoopPos; bool Validated; bool ValidateTimidity(); #else // _WIN32 int WavePipe[2]; pid_t ChildProcess; #endif - FString CommandLine; - size_t LoopPos; + FString ExeName; + bool Looping; static bool FillStream(SoundStream *stream, void *buff, int len, void *userdata); #ifdef _WIN32 @@ -118,6 +123,7 @@ CUSTOM_CVAR(String, timidity_exe, "timidity", CVAR_ARCHIVE | CVAR_GLOBALCONFIG) } 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) @@ -137,9 +143,9 @@ CUSTOM_CVAR (Float, timidity_mastervolume, 1.0f, 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 - timidity_pipe = 0; + if (self < 20) + { // Don't allow pipes less than 20ms + self = 20; } } @@ -162,20 +168,30 @@ TimidityPPMIDIDevice::TimidityPPMIDIDevice(const char *args) #ifdef _WIN32 ReadWavePipe(INVALID_HANDLE_VALUE), WriteWavePipe(INVALID_HANDLE_VALUE), ChildProcess(INVALID_HANDLE_VALUE), - Validated(false) + Validated(false), #else - ChildProcess(-1) + ChildProcess(-1), #endif + Looping(false) { #ifndef _WIN32 WavePipe[0] = WavePipe[1] = -1; #endif 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') + { + CommandLine += "-c \""; + CommandLine += timidity_config; + CommandLine += "\" "; + } +#endif if (DiskName == NULL) { @@ -229,14 +245,17 @@ bool TimidityPPMIDIDevice::Preprocess(MIDIStreamer *song, bool looping) bool success; FILE *f; - if (CommandLine.IsEmpty()) + if (ExeName.IsEmpty()) { return false; } // Tell TiMidity++ whether it should loop or not +#ifdef _WIN32 CommandLine.LockBuffer()[LoopPos] = looping ? 'l' : ' '; CommandLine.UnlockBuffer(); +#endif + Looping = looping; // Write MIDI song to temporary file song->CreateSMF(midi, looping ? 0 : 1); @@ -298,46 +317,31 @@ int TimidityPPMIDIDevice::Open(MidiCallback callback, void *userdata) #endif { Printf(PRINT_BOLD, "Could not create a data pipe for TiMidity++.\n"); - pipeSize = 0; + return 1; } - else + + Stream = GSnd->CreateStream(FillStream, pipeSize, + (timidity_stereo ? 0 : SoundStream::Mono) | + (timidity_8bit ? SoundStream::Bits8 : 0), + timidity_frequency, this); + if (Stream == NULL) { - 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"); - pipeSize = 0; + Printf(PRINT_BOLD, "Could not create music stream.\n"); #ifdef _WIN32 - CloseHandle(WriteWavePipe); - CloseHandle(ReadWavePipe); - ReadWavePipe = WriteWavePipe = INVALID_HANDLE_VALUE; + CloseHandle(WriteWavePipe); + CloseHandle(ReadWavePipe); + ReadWavePipe = WriteWavePipe = INVALID_HANDLE_VALUE; #else - close(WavePipe[1]); - close(WavePipe[0]); - WavePipe[0] = WavePipe[1] = -1; + close(WavePipe[1]); + close(WavePipe[0]); + WavePipe[0] = WavePipe[1] = -1; #endif - } - } - - if (pipeSize == 0) - { - Printf(PRINT_BOLD, "If your soundcard cannot play more than one\n" - "wave at a time, you will hear no music.\n"); - } - else - { - CommandLine += "-o - -Ors"; + return 1; } } - if (pipeSize == 0) - { - CommandLine += "-Od"; - } - +#ifdef _WIN32 + CommandLine += "-o - -Ors"; CommandLine += timidity_stereo ? 'S' : 'M'; CommandLine += timidity_8bit ? '8' : '1'; if (timidity_byteswap) @@ -349,6 +353,7 @@ int TimidityPPMIDIDevice::Open(MidiCallback callback, void *userdata) CommandLine += " -idl "; CommandLine += DiskName.GetName(); +#endif return 0; } @@ -456,6 +461,7 @@ bool TimidityPPMIDIDevice::ValidateTimidity() bool TimidityPPMIDIDevice::LaunchTimidity () { +#ifdef _WIN32 if (CommandLine.IsEmpty()) { return false; @@ -463,7 +469,6 @@ bool TimidityPPMIDIDevice::LaunchTimidity () DPrintf (DMSG_NOTIFY, "cmd: \x1cG%s\n", CommandLine.GetChars()); -#ifdef _WIN32 STARTUPINFO startup = { sizeof(startup), }; PROCESS_INFORMATION procInfo; @@ -509,6 +514,11 @@ bool TimidityPPMIDIDevice::LaunchTimidity () } return false; #else + if (ExeName.IsEmpty()) + { + return false; + } + if (WavePipe[0] != -1 && WavePipe[1] == -1 && Stream != NULL) { // Timidity was previously launched, so the write end of the pipe @@ -523,78 +533,55 @@ bool TimidityPPMIDIDevice::LaunchTimidity () } int forkres; + wordexp_t words; glob_t glb; // Get timidity executable path - int spaceIdx = 0; - int spaceInExePathCount = -1; - FString TimidityExe; - do + const char *exename = "timidity"; // Fallback default + glob(ExeName.GetChars(), 0, NULL, &glb); + if(glb.gl_pathc != 0) + exename = glb.gl_pathv[0]; + // Get user-defined extra args + wordexp(timidity_extargs, &words, WRDE_NOCMD); + + 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); + for(size_t i = 0;i < words.we_wordc;i++) + arglist.push_back(words.we_wordv[i]); + if(**timidity_config != '\0') { - spaceIdx = CommandLine.IndexOf(' ', spaceIdx); - TimidityExe = CommandLine.Left(spaceIdx); - glob(TimidityExe.GetChars(), 0, NULL, &glb); - spaceIdx += 1; - spaceInExePathCount += 1; - } while (spaceIdx != 0 && glb.gl_pathc == 0); - if (spaceIdx == 0) - { - TimidityExe = FString("timidity"); // Maybe it's in your PATH? - spaceInExePathCount = 0; + arglist.push_back("-c"); + arglist.push_back(timidity_config); } - globfree(&glb); + 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.GetName()); - int strCount = 1; - for (spaceIdx = 0; spaceIdx < static_cast(CommandLine.Len()); spaceIdx++) - { - if (CommandLine[spaceIdx] == ' ') - { - ++strCount; - if (CommandLine[spaceIdx+1] == ' ') - { - --strCount; - } - } - } - strCount -= spaceInExePathCount; - - char** TimidityArgs = new char*[strCount + 1]; - TimidityArgs[strCount] = NULL; - - spaceIdx = CommandLine.IndexOf(' '); - int curSpace = spaceIdx, i = 1; - - TimidityArgs[0] = new char[TimidityExe.Len() + 1]; - TimidityArgs[0][TimidityExe.Len()] = 0; - strcpy(TimidityArgs[0], TimidityExe.GetChars()); - - int argLen; - while (curSpace != -1) - { - curSpace = CommandLine.IndexOf(' ', spaceIdx); - if (curSpace != spaceIdx) - { - argLen = curSpace - spaceIdx + 1; - if (argLen < 0) - { - argLen = CommandLine.Len() - curSpace; - } - TimidityArgs[i] = new char[argLen]; - TimidityArgs[i][argLen-1] = 0; - strcpy(TimidityArgs[i], CommandLine.Mid(spaceIdx, curSpace - spaceIdx).GetChars()); - i += 1; - } - spaceIdx = curSpace + 1; - } - - DPrintf(DMSG_NOTIFY, "Timidity EXE: \x1cG%s\n", TimidityExe.GetChars()); - for (i = 0; i < strCount; i++) - { - DPrintf(DMSG_NOTIFY, "arg %d: \x1cG%s\n", i, TimidityArgs[i]); - } + 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]); @@ -603,7 +590,7 @@ bool TimidityPPMIDIDevice::LaunchTimidity () // freopen ("/dev/null", "w", stderr); close (WavePipe[1]); - execvp (TimidityExe.GetChars(), TimidityArgs); + execvp (exename, const_cast(arglist.data())); fprintf(stderr,"execvp failed: %s\n", strerror(errno)); _exit (0); // if execvp succeeds, we never get here } @@ -624,12 +611,7 @@ bool TimidityPPMIDIDevice::LaunchTimidity () }*/ } - for (i = 0; i < strCount; i++) - { - delete [] TimidityArgs[i]; - } - - delete [] TimidityArgs; + wordfree(&words); globfree (&glb); return ChildProcess != -1; #endif // _WIN32 @@ -672,7 +654,6 @@ bool TimidityPPMIDIDevice::FillStream(SoundStream *stream, void *buff, int len, } } #else - ssize_t got; fd_set rfds; struct timeval tv; @@ -697,11 +678,26 @@ bool TimidityPPMIDIDevice::FillStream(SoundStream *stream, void *buff, int len, } // fprintf(stderr,"something\n"); - got = read(song->WavePipe[0], (uint8_t *)buff, len); - if (got < len) - { - memset((uint8_t *)buff+got, 0, len-got); - } + 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; } @@ -761,8 +757,7 @@ int TimidityPPMIDIDevice::Resume() { if (LaunchTimidity()) { - // Assume success if not mixing with the sound system - if (Stream == NULL || Stream->Play(true, timidity_mastervolume)) + if (Stream != NULL && Stream->Play(true, timidity_mastervolume)) { Started = true; return 0; diff --git a/wadsrc/static/language.enu b/wadsrc/static/language.enu index 1edd84500..3c20a7bfd 100644 --- a/wadsrc/static/language.enu +++ b/wadsrc/static/language.enu @@ -2163,6 +2163,7 @@ ADVSNDMNU_REVERB = "Reverb"; ADVSNDMNU_FLUIDVOICES = "MIDI voices"; ADVSNDMNU_TIMIDITY = "Timidity++"; ADVSNDMNU_TIMIDITYEXE = "Path for executable"; +ADVSNDMNU_TIMIDITYCONFIG = "Timidity config file"; ADVSNDMNU_TIMIDITYCHORUS = "Chorus"; ADVSNDMNU_TIMIDITYVOLUME = "Relative volume"; ADVSNDMNU_WILDMIDI = "WildMidi"; diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt index 978774c4c..b95d53852 100644 --- a/wadsrc/static/menudef.txt +++ b/wadsrc/static/menudef.txt @@ -1680,6 +1680,8 @@ OptionMenu AdvSoundOptions protected { SubMenu "$ADVSNDMNU_SELCONFIG", "TimidityExeMenu" } + TextField "$ADVSNDMNU_TIMIDITYCONFIG", "timidity_config" + SubMenu "$ADVSNDMNU_SELCONFIG", "TimidityConfigMenu" Option "$ADVSNDMNU_REVERB", "timidity_reverb", "OnOff" Option "$ADVSNDMNU_TIMIDITYCHORUS", "timidity_chorus", "OnOff" Slider "$ADVSNDMNU_TIMIDITYVOLUME", "timidity_mastervolume", 0, 4, 0.2, 1 @@ -1705,6 +1707,11 @@ OptionMenu TimidityExeMenu protected Title "$ADVSNDMNU_SELCONFIG" } +OptionMenu TimidityConfigMenu protected +{ + Title "$ADVSNDMNU_SELCONFIG" +} + OptionMenu FluidPatchsetMenu protected { Title "$ADVSNDMNU_SELCONFIG" diff --git a/wadsrc/static/zscript/menu/textentermenu.txt b/wadsrc/static/zscript/menu/textentermenu.txt index 69a6694f3..db38896b3 100644 --- a/wadsrc/static/zscript/menu/textentermenu.txt +++ b/wadsrc/static/zscript/menu/textentermenu.txt @@ -63,7 +63,7 @@ class TextEnterMenu : Menu mEnterString = textbuffer; mEnterSize = maxlen < 0 ? 0x7fffffff : maxlen; mSizeMode = sizemode; - mInputGridOkay = showgrid || m_showinputgrid; + mInputGridOkay = (showgrid && (m_showinputgrid == 0)) || (m_showinputgrid >= 1); if (mEnterString.Length() > 0) { InputGridX = INPUTGRID_WIDTH - 1;