From d6fe1fb39f16b74b25500583b52bcf54f55fb971 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 23 Feb 2018 00:48:03 +0100 Subject: [PATCH] - simplified the sound font manager a bit. - allow the GUS to change sound fonts at run time. - implemented sound font manager support in the GUS synth. This works but also made me realize that the SF2 support of this synth has been rather broken, apparently forever. --- src/sound/i_soundfont.cpp | 118 +++++++--------------------- src/sound/i_soundfont.h | 27 +++---- src/sound/timidity/instrum.cpp | 14 +++- src/sound/timidity/instrum_font.cpp | 5 +- src/sound/timidity/instrum_sf2.cpp | 9 ++- src/sound/timidity/timidity.cpp | 112 +++++++++++++++----------- src/sound/timidity/timidity.h | 1 - src/sound/wildmidi/file_io.cpp | 1 + src/sound/wildmidi/wildmidi_lib.cpp | 3 +- 9 files changed, 131 insertions(+), 159 deletions(-) diff --git a/src/sound/i_soundfont.cpp b/src/sound/i_soundfont.cpp index bb35204352..634b6448bd 100644 --- a/src/sound/i_soundfont.cpp +++ b/src/sound/i_soundfont.cpp @@ -44,78 +44,6 @@ FSoundFontManager sfmanager; -//========================================================================== -// -// -// -//========================================================================== - -FSoundFontReader::FSoundFontReader(FWadCollection *coll, const FSoundFontInfo *sfi) -{ - collection = coll; - if (sfi->type == SF_SF2) - { - mMainConfigForSF2.Format("soundfont %s", sfi->mFilename.GetChars()); - } - if (coll != nullptr) - { - auto num = coll->GetNumWads(); - for(int i = 0; i < num; i++) - { - auto wadname = ExtractFileBase(coll->GetWadFullName(i), false); - if (sfi->mName.CompareNoCase(wadname) == 0) - { - // For the given sound font we may only read from this file and no other. - // This is to avoid conflicts with duplicate patches between patch sets. - // For SF2 fonts it's just an added precaution in cause some zipped patch set - // contains extraneous data that gets in the way. - mFindInfile = i; - break; - } - } - } -} - -//========================================================================== -// -// -// -//========================================================================== - -FileReader *FSoundFontReader::OpenMainConfigFile() -{ - if (mMainConfigForSF2.IsNotEmpty()) - { - return new MemoryReader(mMainConfigForSF2.GetChars(), (long)mMainConfigForSF2.Len()); - } - else - { - auto lump = collection->CheckNumForFullName("timidity.cfg", mFindInfile); - return lump < 0? nullptr : collection->ReopenLumpNum(lump); - } -} - -//========================================================================== -// -// -// -//========================================================================== - -FileReader *FSoundFontReader::OpenFile(const char *name) -{ - auto lump = collection->CheckNumForFullName(name, mFindInfile); - if (lump >= 0) - { - // For SF2 files return a streaming reader to avoid loading the entire file into memory. - if (collection->GetLumpCount(mFindInfile) == 1) - { - return collection->ReopenLumpNumNewFile(lump); - } - return collection->ReopenLumpNum(lump); - } - return nullptr; -} - //========================================================================== // // returns both a file reader and the full name of the looked up file @@ -124,12 +52,7 @@ FileReader *FSoundFontReader::OpenFile(const char *name) std::pair FSoundFontReader::LookupFile(const char *name) { - if (IsAbsPath(name)) - { - auto fr = OpenFile(name); - if (fr != nullptr) return std::make_pair(fr, name); - } - else + if (!IsAbsPath(name)) { for(int i = mPaths.Size()-1; i>=0; i--) { @@ -138,6 +61,8 @@ std::pair FSoundFontReader::LookupFile(const char *name) if (fr != nullptr) return std::make_pair(fr, fullname); } } + auto fr = OpenFile(name); + if (fr != nullptr) return std::make_pair(fr, name); return std::make_pair(nullptr, FString()); } @@ -182,10 +107,25 @@ int FSoundFontReader::pathcmp(const char *p1, const char *p2) FSF2Reader::FSF2Reader(const char *fn) { - mMainConfigForSF2.Format("soundfont %s", fn); + mMainConfigForSF2.Format("soundfont %s\n", fn); mFilename = fn; } +//========================================================================== +// +// +// +//========================================================================== + +FileReader *FSF2Reader::OpenMainConfigFile() +{ + if (mMainConfigForSF2.IsNotEmpty()) + { + return new MemoryReader(mMainConfigForSF2.GetChars(), (long)mMainConfigForSF2.Len()); + } + return nullptr; +} + FileReader *FSF2Reader::OpenFile(const char *name) { if (mFilename.CompareNoCase(name) == 0) @@ -278,6 +218,12 @@ FPatchSetReader::FPatchSetReader(const char *filename) } } +FPatchSetReader::FPatchSetReader() +{ + // This constructor is for reading DMXGUS + mAllowAbsolutePaths = true; +} + FileReader *FPatchSetReader::OpenMainConfigFile() { auto fr = new FileReader; @@ -339,7 +285,7 @@ FileReader *FLumpPatchSetReader::OpenFile(const char *name) // //========================================================================== -void FSoundFontManager::ProcessOneFile(const FString &fn, TArray &sffiles) +void FSoundFontManager::ProcessOneFile(const FString &fn) { auto fb = ExtractFileBase(fn, false); auto fbe = ExtractFileBase(fn, true); @@ -357,7 +303,6 @@ void FSoundFontManager::ProcessOneFile(const FString &fn, TArray &sffil fr.Read(head, 16); if (!memcmp(head, "RIFF", 4) && !memcmp(head+8, "sfbkLIST", 8)) { - sffiles.Push(fn); FSoundFontInfo sft = { fb, fbe, fn, SF_SF2 }; soundfonts.Push(sft); } @@ -372,7 +317,6 @@ void FSoundFontManager::ProcessOneFile(const FString &fn, TArray &sffil if (zipl != nullptr) { // It seems like this is what we are looking for - sffiles.Push(fn); FSoundFontInfo sft = { fb, fbe, fn, SF_GUS }; soundfonts.Push(sft); } @@ -393,7 +337,6 @@ void FSoundFontManager::CollectSoundfonts() { findstate_t c_file; void *file; - TArray sffiles; if (GameConfig != NULL && GameConfig->SetSection ("FileSearch.Directories")) @@ -420,7 +363,7 @@ void FSoundFontManager::CollectSoundfonts() if (!(I_FindAttr(&c_file) & FA_DIREC)) { FStringf name("%s%s", path.GetChars(), I_FindName(&c_file)); - ProcessOneFile(name, sffiles); + ProcessOneFile(name); } } while (I_FindNext(file, &c_file) == 0); I_FindClose(file); @@ -429,10 +372,6 @@ void FSoundFontManager::CollectSoundfonts() } } } - - - if (sffiles.Size() > 0) - soundfontcollection.InitMultipleFiles(sffiles); } //========================================================================== @@ -478,7 +417,8 @@ FSoundFontReader *FSoundFontManager::OpenSoundFont(const char *name, int allowed auto sfi = FindSoundFont(name, allowed); if (sfi != nullptr) { - return new FSoundFontReader(&soundfontcollection, sfi); + if (sfi->type == SF_SF2) return new FSF2Reader(sfi->mFilename); + else return new FZipPatReader(sfi->mFilename); } // The sound font collection did not yield any good results. // Next check if the file is a .sf file diff --git a/src/sound/i_soundfont.h b/src/sound/i_soundfont.h index 3b161621a9..de1967950e 100644 --- a/src/sound/i_soundfont.h +++ b/src/sound/i_soundfont.h @@ -27,9 +27,6 @@ struct FSoundFontInfo class FSoundFontReader { protected: - FWadCollection *collection; - FString mMainConfigForSF2; - int mFindInfile; // This is only doable for loose config files that get set as sound fonts. All other cases read from a contained environment where this does not apply. bool mAllowAbsolutePaths = false; // This has only meaning if being run on a platform with a case sensitive file system and loose files. @@ -37,21 +34,14 @@ protected: bool mCaseSensitivePaths = false; TArray mPaths; - - FSoundFontReader() - { - collection = nullptr; - mFindInfile = -1; - } - + int pathcmp(const char *p1, const char *p2); - + public: - FSoundFontReader(FWadCollection *coll, const FSoundFontInfo *sfi); - virtual FileReader *OpenMainConfigFile(); // this is special because it needs to be synthesized for .sf files and set some restrictions for patch sets - virtual FileReader *OpenFile(const char *name); + virtual FileReader *OpenMainConfigFile() = 0; // this is special because it needs to be synthesized for .sf files and set some restrictions for patch sets + virtual FileReader *OpenFile(const char *name) = 0; std::pair LookupFile(const char *name); void AddPath(const char *str); virtual FString basePath() const @@ -68,9 +58,11 @@ public: class FSF2Reader : public FSoundFontReader { - FString mFilename; + FString mMainConfigForSF2; + FString mFilename; public: FSF2Reader(const char *filename); + virtual FileReader *FSF2Reader::OpenMainConfigFile() override; virtual FileReader *OpenFile(const char *name) override; }; @@ -126,6 +118,7 @@ class FPatchSetReader : public FSoundFontReader FString mFullPathToConfig; public: + FPatchSetReader(); FPatchSetReader(const char *filename); ~FPatchSetReader(); virtual FileReader *OpenMainConfigFile() override; @@ -145,10 +138,8 @@ public: class FSoundFontManager { TArray soundfonts; - FWadCollection soundfontcollection; - - void ProcessOneFile(const FString & fn, TArray &sffiles); + void ProcessOneFile(const FString & fn); public: void CollectSoundfonts(); diff --git a/src/sound/timidity/instrum.cpp b/src/sound/timidity/instrum.cpp index 0b88f39bc0..b804433bd7 100644 --- a/src/sound/timidity/instrum.cpp +++ b/src/sound/timidity/instrum.cpp @@ -27,16 +27,21 @@ #include #include #include +#include #include "timidity.h" #include "m_swap.h" #include "files.h" #include "templates.h" #include "gf1patch.h" +#include "i_soundfont.h" namespace Timidity { + extern std::unique_ptr gus_sfreader; + + extern Instrument *load_instrument_dls(Renderer *song, int drum, int bank, int instrument); Instrument::Instrument() @@ -159,16 +164,19 @@ static Instrument *load_instrument(Renderer *song, const char *name, int percuss if (!name) return 0; /* Open patch file */ - if ((fp = pathExpander.openFileReader(name, NULL)) == NULL) + fp = gus_sfreader->LookupFile(name).first; + if (fp == NULL) { /* Try with various extensions */ FString tmp = name; tmp += ".pat"; - if ((fp = pathExpander.openFileReader(tmp, NULL)) == NULL) + fp = gus_sfreader->LookupFile(tmp).first; + if (fp == NULL) { #ifdef __unix__ // Windows isn't case-sensitive. tmp.ToUpper(); - if ((fp = pathExpander.openFileReader(tmp, NULL)) == NULL) + fp = gus_sfreader->LookupFile(tmp).first; + if (fp == NULL) #endif { noluck = true; diff --git a/src/sound/timidity/instrum_font.cpp b/src/sound/timidity/instrum_font.cpp index 227a6f78c7..41709809c9 100644 --- a/src/sound/timidity/instrum_font.cpp +++ b/src/sound/timidity/instrum_font.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include "doomdef.h" #include "m_swap.h" @@ -8,11 +9,13 @@ #include "timidity.h" #include "sf2.h" #include "files.h" +#include "i_soundfont.h" namespace Timidity { FontFile *Fonts; +extern std::unique_ptr gus_sfreader; FontFile *ReadDLS(const char *filename, FileReader *f) { @@ -54,7 +57,7 @@ void font_add(const char *filename, int load_order) } else { - FileReader *fp = pathExpander.openFileReader(filename, NULL); + FileReader *fp = gus_sfreader->LookupFile(filename).first; if (fp != NULL) { diff --git a/src/sound/timidity/instrum_sf2.cpp b/src/sound/timidity/instrum_sf2.cpp index a2d747b927..dccbf53ac0 100644 --- a/src/sound/timidity/instrum_sf2.cpp +++ b/src/sound/timidity/instrum_sf2.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include "doomdef.h" #include "m_swap.h" @@ -9,6 +10,12 @@ #include "timidity.h" #include "sf2.h" #include "files.h" +#include "i_soundfont.h" + +namespace Timidity +{ + extern std::unique_ptr gus_sfreader; +} using namespace Timidity; @@ -1501,7 +1508,7 @@ void SFFile::ApplyGeneratorsToRegion(SFGenComposite *gen, SFSample *sfsamp, Rend void SFFile::LoadSample(SFSample *sample) { - FileReader *fp = pathExpander.openFileReader(Filename, NULL); + FileReader *fp = gus_sfreader->LookupFile(Filename).first; uint32_t i; if (fp == NULL) diff --git a/src/sound/timidity/timidity.cpp b/src/sound/timidity/timidity.cpp index d37c0e1a7b..6a53112c75 100644 --- a/src/sound/timidity/timidity.cpp +++ b/src/sound/timidity/timidity.cpp @@ -22,6 +22,7 @@ #include #include +#include #include "timidity.h" #include "templates.h" @@ -32,21 +33,52 @@ #include "files.h" #include "w_wad.h" #include "i_soundfont.h" +#include "i_musicinterns.h" +#include "v_text.h" + +CUSTOM_CVAR(String, midi_config, CONFIG_FILE, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +{ + Timidity::FreeAll(); + if (currSong != nullptr && currSong->GetDeviceType() == MDEV_GUS) + { + MIDIDeviceChanged(-1, true); + } +} -// Unlike the other softsynths, this one cannot change its config data at run time. -CVAR(String, midi_config, CONFIG_FILE, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CVAR(Int, midi_voices, 32, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CVAR(String, gus_patchdir, "", CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -CVAR(Bool, midi_dmxgus, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +CUSTOM_CVAR(Bool, midi_dmxgus, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) // This was 'true' but since it requires special setup that's not such a good idea. +{ + Timidity::FreeAll(); + if (currSong != nullptr && currSong->GetDeviceType() == MDEV_GUS) + { + MIDIDeviceChanged(-1, true); + } +} + CVAR(Int, gus_memsize, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) namespace Timidity { -PathExpander pathExpander; ToneBank *tonebank[MAXBANK], *drumset[MAXBANK]; static FString def_instr_name; +std::unique_ptr gus_sfreader; + +static bool InitReader(const char *config_file) +{ + auto reader = sfmanager.OpenSoundFont(config_file, SF_GUS|SF_SF2); + if (reader == nullptr) + { + Printf(TEXTCOLOR_RED "%s: Unable to load sound font", config_file); + return false; // No sound font could be opened. + } + gus_sfreader.reset(reader); + //config_name = config_file; + return true; +} + static int read_config_file(const char *name, bool ismain) { @@ -55,32 +87,25 @@ static int read_config_file(const char *name, bool ismain) ToneBank *bank = NULL; int i, j, k, line = 0, words; static int rcf_count = 0; - int lumpnum; if (rcf_count > 50) { Printf("Timidity: Probable source loop in configuration files\n"); return (-1); } - - if (ismain) pathExpander.openmode = PathExpander::OM_FILEORLUMP; - - if (!(fp = pathExpander.openFileReader(name, &lumpnum))) - return -1; - - FreeAll(); - if (ismain) { - if (lumpnum > 0) - { - pathExpander.openmode = PathExpander::OM_LUMP; - pathExpander.clearPathlist(); // when reading from a PK3 we don't want to use any external path - } - else - { - pathExpander.openmode = PathExpander::OM_FILE; - } + if (!InitReader(name)) return -1; + fp = gus_sfreader->OpenMainConfigFile(); + FreeAll(); + } + else + { + fp = gus_sfreader->LookupFile(name).first; + } + if (fp == nullptr) + { + return -1; } while (fp->Gets(tmp, sizeof(tmp))) @@ -291,7 +316,10 @@ static int read_config_file(const char *name, bool ismain) return -2; } for (i = 1; i < words; i++) - pathExpander.addToPathlist(w[i]); + { + // Q: How does this deal with relative paths? In this form it just does not work. + gus_sfreader->AddPath(w[i]); + } } else if (!strcmp(w[0], "source")) { @@ -531,17 +559,6 @@ int LoadConfig(const char *filename) * that needs to be added to the search path. */ if (currentConfig.CompareNoCase(filename) == 0) return 0; - currentConfig = filename; - pathExpander.clearPathlist(); -#ifdef _WIN32 - pathExpander.addToPathlist("C:\\TIMIDITY"); - pathExpander.addToPathlist("\\TIMIDITY"); - pathExpander.addToPathlist(progdir); -#else - pathExpander.addToPathlist("/usr/local/lib/timidity"); - pathExpander.addToPathlist("/etc/timidity"); - pathExpander.addToPathlist("/etc"); -#endif /* Some functions get aggravated if not even the standard banks are available. */ if (tonebank[0] == NULL) @@ -576,18 +593,24 @@ int LoadDMXGUS() FWadLump data = Wads.OpenLumpNum(lump); if (data.GetLength() == 0) return LoadConfig(midi_config); + // Check if we got some GUS data before using it. + FString ultradir = getenv("ULTRADIR"); + if (ultradir.IsEmpty() && *(*gus_patchdir) == 0) return LoadConfig(midi_config); + currentConfig = "DMXGUS"; FreeAll(); + auto psreader = new FPatchSetReader; + // The GUS put its patches in %ULTRADIR%/MIDI so we can try that - FString ultradir = getenv("ULTRADIR"); if (ultradir.IsNotEmpty()) { ultradir += "/midi"; - pathExpander.addToPathlist(ultradir.GetChars()); + psreader->AddPath(ultradir); } // Load DMXGUS lump and patches from gus_patchdir - pathExpander.addToPathlist(gus_patchdir); + if (*(*gus_patchdir) != 0) psreader->AddPath(gus_patchdir); + gus_sfreader.reset(psreader); char readbuffer[1024]; long size = data.GetLength(); @@ -700,16 +723,15 @@ Renderer::Renderer(float sample_rate, const char *args) // Load explicitly stated sound font if so desired. if (args != nullptr && *args != 0) { - int ret; - FreeAll(); - if (!stricmp(args, "DMXGUS")) ret = LoadDMXGUS(); - ret = LoadConfig(args); - if (ret != 0) - { - } + if (!stricmp(args, "DMXGUS")) LoadDMXGUS(); + LoadConfig(args); + } + else if (tonebank[0] == nullptr) + { + LoadConfig(); } - // + // These can be left empty here if an error occured during sound font initialization. if (tonebank[0] == NULL) { tonebank[0] = new ToneBank; diff --git a/src/sound/timidity/timidity.h b/src/sound/timidity/timidity.h index 1c73b3dc68..b44927f596 100644 --- a/src/sound/timidity/timidity.h +++ b/src/sound/timidity/timidity.h @@ -608,7 +608,6 @@ int LoadConfig(const char *filename); int LoadDMXGUS(); extern int LoadConfig(); extern void FreeAll(); -extern PathExpander pathExpander; extern ToneBank *tonebank[MAXBANK]; extern ToneBank *drumset[MAXBANK]; diff --git a/src/sound/wildmidi/file_io.cpp b/src/sound/wildmidi/file_io.cpp index c2baafd171..6e8b9628c0 100644 --- a/src/sound/wildmidi/file_io.cpp +++ b/src/sound/wildmidi/file_io.cpp @@ -34,6 +34,7 @@ */ #include +#include #include "files.h" #include "wm_error.h" diff --git a/src/sound/wildmidi/wildmidi_lib.cpp b/src/sound/wildmidi/wildmidi_lib.cpp index 547b7dd9cc..87afc16ded 100644 --- a/src/sound/wildmidi/wildmidi_lib.cpp +++ b/src/sound/wildmidi/wildmidi_lib.cpp @@ -42,6 +42,7 @@ #include #include #include +#include #include "common.h" #include "wm_error.h" @@ -2942,7 +2943,7 @@ void WildMidi_Renderer::ComputeOutput(float *fbuffer, int len) } for (; buffer < newbuf; ++buffer) { - *(float *)buffer = (float)*buffer * (2. / 32768.f); // boost the volume because Wildmidi is far more quiet than the other synths and therefore hard to balance. + *(float *)buffer = (float)*buffer * (2.f / 32768.f); // boost the volume because Wildmidi is far more quiet than the other synths and therefore hard to balance. } }