diff --git a/src/sound/mididevices/music_timiditypp_mididevice.cpp b/src/sound/mididevices/music_timiditypp_mididevice.cpp index 76b3d76bc..066694a52 100644 --- a/src/sound/mididevices/music_timiditypp_mididevice.cpp +++ b/src/sound/mididevices/music_timiditypp_mididevice.cpp @@ -44,6 +44,43 @@ #include "timiditypp/playmidi.h" +//========================================================================== +// +// Error printing override to redirect to the internal console instead of stdout. +// +//========================================================================== + +static void gzdoom_ctl_cmsg(int type, int verbosity_level, const char* fmt, ...) +{ + if (verbosity_level >= TimidityPlus::VERB_DEBUG) return; // Don't waste time on diagnostics. + + va_list args; + va_start(args, fmt); + FString msg; + msg.VFormat(fmt, args); + va_end(args); + + switch (type) + { + case TimidityPlus::CMSG_ERROR: + Printf(TEXTCOLOR_RED "%s\n", msg.GetChars()); + break; + + case TimidityPlus::CMSG_WARNING: + Printf(TEXTCOLOR_YELLOW "%s\n", msg.GetChars()); + break; + + case TimidityPlus::CMSG_INFO: + DPrintf(DMSG_SPAMMY, "%s\n", msg.GetChars()); + break; + } +} + +//========================================================================== +// +// CVar interface to configurable parameters +// +//========================================================================== template void ChangeVarSync(T& var, T value) { @@ -237,11 +274,11 @@ TimidityPPMIDIDevice::TimidityPPMIDIDevice(const char *args, int samplerate) delete instruments; instruments = nullptr; } + TimidityPlus::ctl_cmsg = gzdoom_ctl_cmsg; TimidityPlus::set_playback_rate(SampleRate); if (instruments == nullptr) { - auto sfreader = sfmanager.OpenSoundFont(args, SF_SF2 | SF_GUS); if (sfreader != nullptr) { @@ -367,30 +404,3 @@ void TimidityPP_Shutdown() TimidityPlus::free_gauss_table(); TimidityPlus::free_global_mblock(); } - - -void TimidityPlus::ctl_cmsg(int type, int verbosity_level, const char *fmt, ...) -{ - if (verbosity_level >= VERB_DEBUG) return; // Don't waste time on diagnostics. - - va_list args; - va_start(args, fmt); - FString msg; - msg.VFormat(fmt, args); - va_end(args); - - switch (type) - { - case CMSG_ERROR: - Printf(TEXTCOLOR_RED "%s\n", msg.GetChars()); - break; - - case CMSG_WARNING: - Printf(TEXTCOLOR_YELLOW "%s\n", msg.GetChars()); - break; - - case CMSG_INFO: - DPrintf(DMSG_SPAMMY, "%s\n", msg.GetChars()); - break; - } -} \ No newline at end of file diff --git a/src/sound/timiditypp/common.cpp b/src/sound/timiditypp/common.cpp index 230796d29..87ce4d13e 100644 --- a/src/sound/timiditypp/common.cpp +++ b/src/sound/timiditypp/common.cpp @@ -27,6 +27,7 @@ #include #include #include "common.h" +#include "controls.h" namespace TimidityPlus { @@ -151,5 +152,31 @@ int tf_getc(struct timidity_file *tf) return read == 0 ? EOF : c; } +void default_ctl_cmsg(int type, int verbosity_level, const char* fmt, ...) +{ + if (verbosity_level >= VERB_DEBUG) return; // Don't waste time on diagnostics. + + char buffer[2048]; + va_list args; + va_start(args, fmt); + + switch (type) + { + case CMSG_ERROR: + vprintf("Error: %s\n", args); + break; + + case CMSG_WARNING: + vprintf("Warning: %s\n", args); + break; + + case CMSG_INFO: + vprintf("Info: %s\n", args); + break; + } +} + +// Allow hosting applications to capture the messages and deal with them themselves. +void (*ctl_cmsg)(int type, int verbosity_level, const char* fmt, ...) = default_ctl_cmsg; } diff --git a/src/sound/timiditypp/controls.h b/src/sound/timiditypp/controls.h index d82f0a0ba..b7279c201 100644 --- a/src/sound/timiditypp/controls.h +++ b/src/sound/timiditypp/controls.h @@ -52,7 +52,7 @@ inline bool RC_IS_SKIP_FILE(int rc) } -void ctl_cmsg(int type, int verbosity_level, const char *fmt, ...); +extern void (*ctl_cmsg)(int type, int verbosity_level, const char* fmt, ...); } diff --git a/src/sound/timiditypp/timidity.h b/src/sound/timiditypp/timidity.h index 59f8f529e..31db58ac4 100644 --- a/src/sound/timiditypp/timidity.h +++ b/src/sound/timiditypp/timidity.h @@ -174,5 +174,6 @@ const int max_voices = DEFAULT_VOICES; const int temper_type_mute = 0; const int opt_preserve_silence = 0; const int opt_init_keysig = 8; + } #endif /* TIMIDITY_H_INCLUDED */ diff --git a/src/sound/timiditypp/timidity_file.h b/src/sound/timiditypp/timidity_file.h new file mode 100644 index 000000000..2798f2763 --- /dev/null +++ b/src/sound/timiditypp/timidity_file.h @@ -0,0 +1,133 @@ +/* + TiMidity++ -- File interface for the pure sequencer. + Copyright (C) 2019 Christoph Oelckers + + 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 +*/ + +#pragma once +#include +#include +#include + +namespace TimidityPlus +{ + +struct timidity_file +{ + std::string filename; + + virtual ~timidity_file() {} + virtual char* gets(char* buff, int n) = 0; + virtual long read(void* buff, int32_t size, int32_t nitems) = 0; + virtual long seek(long offset, int whence) = 0; + virtual long tell() = 0; +}; + +class SoundFontReaderInterface +{ +public: + virtual struct timidity_file* open_timidityplus_file(const char* fn) = 0; + virtual void timidityplus_add_path(const char* path) = 0; +}; + + +// A minimalistic sound font reader interface. Normally this should be replaced with something better tied into the host application. +#ifdef USE_BASE_INTERFACE + +// Base version of timidity_file using stdio's FILE. +struct timidity_file_FILE : public timidity_file +{ + FILE* f = nullptr; + + ~timidity_file_FILE() + { + if (f) fclose(f); + } + char* gets(char* buff, int n) override + { + if (!f) return nullptr; + return fgets(buff, n, f); + } + long read(void* buff, int32_t size, int32_t nitems) override + { + if (!f) return 0; + return (long)fread(buff, size, nitems, f); + } + long seek(long offset, int whence) override + { + if (!f) return 0; + return fseek(f, offset, whence); + } + long tell() override + { + if (!f) return 0; + return ftell(f); + } +}; + +class BaseSoundFontReader : public SoundFontReaderInterface +{ + std::vector paths; + + bool IsAbsPath(const char *name) + { + if (name[0] == '/' || name[0] == '\\') return true; + #ifdef _WIN32 + /* [A-Za-z]: (for Windows) */ + if (isalpha(name[0]) && name[1] == ':') return true; + #endif /* _WIN32 */ + return 0; + } + + struct timidity_file* open_timidityplus_file(const char* fn) + { + FILE *f = nullptr; + std::string fullname; + if (!fn) + { + f = fopen("timidity.cfg", "rt"); + fullname = "timidity.cfg"; + } + else + { + if (!IsAbsPath(fn)) + { + for(int i = (int)paths.size()-1; i>=0; i--) + { + fullname = paths[i] + fn; + f = fopen(fullname.c_str(), "rt"); + break; + } + } + if (!f) f = fopen(fn, "rt"); + } + if (!f) return nullptr; + auto tf = new timidity_file_FILE; + tf->f = f; + tf->filename = fullname; + return tf; + } + + void timidityplus_add_path(const char* path) + { + std::string p = path; + if (p.back() != '/' && p.back() != '\\') p += '/'; // always let it end with a slash. + paths.push_back(p); + } +}; +#endif + +}