- 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.
This commit is contained in:
Christoph Oelckers 2018-02-23 00:48:03 +01:00
parent c12c068355
commit d6fe1fb39f
9 changed files with 131 additions and 159 deletions

View file

@ -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<FileReader *, FString> 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<FileReader *, FString> 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<FString> &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<FString> &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<FString> &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<FString> 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

View file

@ -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.
@ -38,20 +35,13 @@ protected:
TArray<FString> 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<FileReader *, FString> 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<FSoundFontInfo> soundfonts;
FWadCollection soundfontcollection;
void ProcessOneFile(const FString & fn, TArray<FString> &sffiles);
void ProcessOneFile(const FString & fn);
public:
void CollectSoundfonts();

View file

@ -27,16 +27,21 @@
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <memory>
#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<FSoundFontReader> 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;

View file

@ -1,6 +1,7 @@
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <memory>
#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<FSoundFontReader> 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)
{

View file

@ -2,6 +2,7 @@
#include <string.h>
#include <errno.h>
#include <math.h>
#include <memory>
#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<FSoundFontReader> 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)

View file

@ -22,6 +22,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <memory>
#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<FSoundFontReader> 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;

View file

@ -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];

View file

@ -34,6 +34,7 @@
*/
#include <errno.h>
#include <memory>
#include "files.h"
#include "wm_error.h"

View file

@ -42,6 +42,7 @@
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <memory>
#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.
}
}