mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-11 07:11:54 +00:00
Framework for context independent sounffont management
Not tested yet!
This commit is contained in:
parent
3d08c1fbc7
commit
a6fa906764
9 changed files with 612 additions and 52 deletions
|
@ -1137,6 +1137,7 @@ set (PCH_SOURCES
|
||||||
sfmt/SFMT.cpp
|
sfmt/SFMT.cpp
|
||||||
sound/i_music.cpp
|
sound/i_music.cpp
|
||||||
sound/i_sound.cpp
|
sound/i_sound.cpp
|
||||||
|
sound/i_soundfont.cpp
|
||||||
sound/mididevices/music_opldumper_mididevice.cpp
|
sound/mididevices/music_opldumper_mididevice.cpp
|
||||||
sound/mididevices/music_opl_mididevice.cpp
|
sound/mididevices/music_opl_mididevice.cpp
|
||||||
sound/mididevices/music_pseudo_mididevice.cpp
|
sound/mididevices/music_pseudo_mididevice.cpp
|
||||||
|
|
|
@ -1061,3 +1061,20 @@ void ScanDirectory(TArray<FFileList> &list, const char *dirpath)
|
||||||
delete[] argv[0];
|
delete[] argv[0];
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
bool IsAbsPath(const char *name)
|
||||||
|
{
|
||||||
|
if (IsSeperator(name[0])) return true;
|
||||||
|
#ifdef _WIN32
|
||||||
|
/* [A-Za-z]: (for Windows) */
|
||||||
|
if (isalpha(name[0]) && name[1] == ':') return true;
|
||||||
|
#endif /* _WIN32 */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
@ -62,6 +62,7 @@ struct FFileList
|
||||||
};
|
};
|
||||||
|
|
||||||
void ScanDirectory(TArray<FFileList> &list, const char *dirpath);
|
void ScanDirectory(TArray<FFileList> &list, const char *dirpath);
|
||||||
|
bool IsAbsPath(const char*);
|
||||||
|
|
||||||
|
|
||||||
inline int Tics2Seconds(int tics)
|
inline int Tics2Seconds(int tics)
|
||||||
|
|
|
@ -65,6 +65,8 @@ extern void ChildSigHandler (int signum);
|
||||||
#include "timidity/timidity.h"
|
#include "timidity/timidity.h"
|
||||||
#include "vm.h"
|
#include "vm.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#define GZIP_ID1 31
|
#define GZIP_ID1 31
|
||||||
#define GZIP_ID2 139
|
#define GZIP_ID2 139
|
||||||
#define GZIP_CM 8
|
#define GZIP_CM 8
|
||||||
|
@ -664,43 +666,6 @@ void I_SetMusicVolume (float factor)
|
||||||
snd_musicvolume.Callback();
|
snd_musicvolume.Callback();
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//==========================================================================
|
|
||||||
|
|
||||||
void I_CollectSoundfonts()
|
|
||||||
{
|
|
||||||
FString path = M_GetDocumentsPath();
|
|
||||||
TArray<FString> sffiles;
|
|
||||||
const char *match;
|
|
||||||
findstate_t c_file;
|
|
||||||
void *file;
|
|
||||||
|
|
||||||
path << "/soundfonts/*";
|
|
||||||
|
|
||||||
if ((file = I_FindFirst(path, &c_file)) == ((void *)(-1)))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
path.StripRight("*");
|
|
||||||
do
|
|
||||||
{
|
|
||||||
if (!I_FindAttr(&c_file) & FA_DIREC)
|
|
||||||
{
|
|
||||||
FStringf name("%s%s", path.GetChars(), I_FindName(&c_file));
|
|
||||||
sffiles.Push(name);
|
|
||||||
}
|
|
||||||
} while (I_FindNext(file, &c_file) == 0);
|
|
||||||
I_FindClose(file);
|
|
||||||
|
|
||||||
auto soundfonts = new FWadCollection;
|
|
||||||
soundfonts->InitMultipleFiles(sffiles);
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
DEFINE_ACTION_FUNCTION(DObject, SetMusicVolume)
|
DEFINE_ACTION_FUNCTION(DObject, SetMusicVolume)
|
||||||
{
|
{
|
||||||
PARAM_PROLOGUE;
|
PARAM_PROLOGUE;
|
||||||
|
|
572
src/sound/i_soundfont.cpp
Normal file
572
src/sound/i_soundfont.cpp
Normal file
|
@ -0,0 +1,572 @@
|
||||||
|
/*
|
||||||
|
** i_soundfont.cpp
|
||||||
|
** The sound font manager for the MIDI synths
|
||||||
|
**
|
||||||
|
**---------------------------------------------------------------------------
|
||||||
|
** Copyright 2018 Christoph Oelckers
|
||||||
|
** All rights reserved.
|
||||||
|
**
|
||||||
|
** Redistribution and use in source and binary forms, with or without
|
||||||
|
** modification, are permitted provided that the following conditions
|
||||||
|
** are met:
|
||||||
|
**
|
||||||
|
** 1. Redistributions of source code must retain the above copyright
|
||||||
|
** notice, this list of conditions and the following disclaimer.
|
||||||
|
** 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
** notice, this list of conditions and the following disclaimer in the
|
||||||
|
** documentation and/or other materials provided with the distribution.
|
||||||
|
** 3. The name of the author may not be used to endorse or promote products
|
||||||
|
** derived from this software without specific prior written permission.
|
||||||
|
**
|
||||||
|
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
**---------------------------------------------------------------------------
|
||||||
|
**
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "i_musicinterns.h"
|
||||||
|
#include "doomtype.h"
|
||||||
|
#include "m_argv.h"
|
||||||
|
#include "i_music.h"
|
||||||
|
#include "w_wad.h"
|
||||||
|
#include "cmdlib.h"
|
||||||
|
#include "files.h"
|
||||||
|
|
||||||
|
#include "gameconfigfile.h"
|
||||||
|
#include "resourcefiles/resourcefile.h"
|
||||||
|
#include "pathexpander.h"
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
SF_SF2 = 1,
|
||||||
|
SF_GUS = 2
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FSoundFontInfo
|
||||||
|
{
|
||||||
|
FString mName; // This is what the sounfont is identified with. It's the extension-less base file name
|
||||||
|
FString mFilename; // Full path to the backing file - this is needed by FluidSynth to load the sound font.
|
||||||
|
int type;
|
||||||
|
};
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
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.
|
||||||
|
// When reading from an archive it will always be case insensitive, just like the lump manager (since it repurposes the same implementation.)
|
||||||
|
bool mCaseSensitivePaths = false;
|
||||||
|
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);
|
||||||
|
std::pair<FileReader *, FString> LookupFile(const char *name);
|
||||||
|
void AddPath(const char *str);
|
||||||
|
};
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
class FSF2Reader : FSoundFontReader
|
||||||
|
{
|
||||||
|
FString mFilename;
|
||||||
|
public:
|
||||||
|
FSF2Reader(const char *filename);
|
||||||
|
virtual FileReader *OpenFile(const char *name) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
class FZipPatReader : FSoundFontReader
|
||||||
|
{
|
||||||
|
FResourceFile *resf;
|
||||||
|
public:
|
||||||
|
FZipPatReader(const char *filename);
|
||||||
|
~FZipPatReader();
|
||||||
|
virtual FileReader *OpenFile(const char *name) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// This one gets ugly...
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
class FPatchSetReader : FSoundFontReader
|
||||||
|
{
|
||||||
|
FString mBasePath;
|
||||||
|
FString mFullPathToConfig;
|
||||||
|
|
||||||
|
public:
|
||||||
|
FPatchSetReader(const char *filename);
|
||||||
|
~FPatchSetReader();
|
||||||
|
virtual FileReader *OpenMainConfigFile() override;
|
||||||
|
virtual FileReader *OpenFile(const char *name) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
class FSoundFontManager
|
||||||
|
{
|
||||||
|
TArray<FSoundFontInfo> soundfonts;
|
||||||
|
FWadCollection soundfontcollection;
|
||||||
|
|
||||||
|
|
||||||
|
void ProcessOneFile(const FString & fn, TArray<FString> &sffiles);
|
||||||
|
|
||||||
|
public:
|
||||||
|
void CollectSoundfonts();
|
||||||
|
const FSoundFontInfo *FindSoundFont(const char *name, int allowedtypes) const;
|
||||||
|
FSoundFontReader *OpenSoundFont(const char *name, int allowedtypes);
|
||||||
|
const auto &GetList() const { return soundfonts; } // This is for the menu
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
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(), 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 the backing file reader to avoid reopening the file.
|
||||||
|
// Note that there is no possibility of a non-SF2 resource file having only one lump due to the check in the init code.
|
||||||
|
if (collection->GetLumpCount(mFindInfile) == 1)
|
||||||
|
{
|
||||||
|
auto fr = collection->GetFileReader(mFindInfile);
|
||||||
|
fr->Seek(0, SEEK_SET);
|
||||||
|
return fr;
|
||||||
|
}
|
||||||
|
return collection->ReopenLumpNum(lump);
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// returns both a file reader and the full name of the looked up file
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
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
|
||||||
|
{
|
||||||
|
for(int i = mPaths.Size()-1; i>=0; i--)
|
||||||
|
{
|
||||||
|
FString fullname = mPaths[i] + name;
|
||||||
|
auto fr = OpenFile(fullname);
|
||||||
|
if (fr != nullptr) return std::make_pair(fr, fullname);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return std::make_pair(nullptr, FString());
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// This adds a directory to the path list
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
void FSoundFontReader::AddPath(const char *strp)
|
||||||
|
{
|
||||||
|
if (*strp == 0) return;
|
||||||
|
if (!mAllowAbsolutePaths && IsAbsPath(strp)) return; // of no use so we may just discard it right away
|
||||||
|
int i = 0;
|
||||||
|
FString str = strp;
|
||||||
|
FixPathSeperator(str);
|
||||||
|
if (str.Back() != '/') str += '/'; // always let it end with a slash.
|
||||||
|
for (auto &s : mPaths)
|
||||||
|
{
|
||||||
|
if (pathcmp(s.GetChars(), str) == 0)
|
||||||
|
{
|
||||||
|
// move string to the back.
|
||||||
|
mPaths.Delete(i);
|
||||||
|
mPaths.Push(str);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
mPaths.Push(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
int FSoundFontReader::pathcmp(const char *p1, const char *p2)
|
||||||
|
{
|
||||||
|
return mCaseSensitivePaths? strcmp(p1, p2) : stricmp(p1, p2);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// Note that the file type has already been checked
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
FSF2Reader::FSF2Reader(const char *fn)
|
||||||
|
{
|
||||||
|
mMainConfigForSF2.Format("soundfont %s", fn);
|
||||||
|
mFilename = fn;
|
||||||
|
}
|
||||||
|
|
||||||
|
FileReader *FSF2Reader::OpenFile(const char *name)
|
||||||
|
{
|
||||||
|
if (mFilename.CompareNoCase(name) == 0)
|
||||||
|
{
|
||||||
|
auto fr = new FileReader;
|
||||||
|
if (fr->Open(name)) return fr;
|
||||||
|
delete fr;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
FZipPatReader::FZipPatReader(const char *filename)
|
||||||
|
{
|
||||||
|
resf = FResourceFile::OpenResourceFile(filename, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
FZipPatReader::~FZipPatReader()
|
||||||
|
{
|
||||||
|
if (resf != nullptr) delete resf;
|
||||||
|
}
|
||||||
|
|
||||||
|
FileReader *FZipPatReader::OpenFile(const char *name)
|
||||||
|
{
|
||||||
|
if (resf != nullptr)
|
||||||
|
{
|
||||||
|
auto lump = resf->FindLump(name);
|
||||||
|
if (lump != nullptr)
|
||||||
|
{
|
||||||
|
return lump->NewReader();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
FPatchSetReader::FPatchSetReader(const char *filename)
|
||||||
|
{
|
||||||
|
#ifndef _WIN32
|
||||||
|
mCaseSensitivePaths = true;
|
||||||
|
const char *paths[] = {
|
||||||
|
"/usr/local/lib/timidity",
|
||||||
|
"/etc/timidity",
|
||||||
|
"/etc"
|
||||||
|
};
|
||||||
|
#else
|
||||||
|
const char *paths[] = {
|
||||||
|
"C:/TIMIDITY",
|
||||||
|
"/TIMIDITY",
|
||||||
|
progdir
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
mAllowAbsolutePaths = true;
|
||||||
|
FileReader *fr = new FileReader;
|
||||||
|
if (fr->Open(filename))
|
||||||
|
{
|
||||||
|
mFullPathToConfig = filename;
|
||||||
|
}
|
||||||
|
else if (!IsAbsPath(filename))
|
||||||
|
{
|
||||||
|
for(auto c : paths)
|
||||||
|
{
|
||||||
|
FStringf fullname("%s/%s", c, filename);
|
||||||
|
if (fr->Open(fullname))
|
||||||
|
{
|
||||||
|
mFullPathToConfig = fullname;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (mFullPathToConfig.Len() > 0)
|
||||||
|
{
|
||||||
|
FixPathSeperator(mFullPathToConfig);
|
||||||
|
mBasePath = ExtractFilePath(mFullPathToConfig);
|
||||||
|
if (mBasePath.Len() > 0 && mBasePath.Back() != '/') mBasePath += '/';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FileReader *FPatchSetReader::OpenMainConfigFile()
|
||||||
|
{
|
||||||
|
auto fr = new FileReader;
|
||||||
|
if (fr->Open(mBasePath)) return fr;
|
||||||
|
delete fr;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
FileReader *FPatchSetReader::OpenFile(const char *name)
|
||||||
|
{
|
||||||
|
FString path;
|
||||||
|
if (IsAbsPath(name)) path = name;
|
||||||
|
else path = mBasePath + name;
|
||||||
|
auto fr = new FileReader;
|
||||||
|
if (fr->Open(path)) return fr;
|
||||||
|
delete fr;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// collects everything out of the soundfonts directory.
|
||||||
|
// This may either be .sf2 files or zipped GUS patch sets with a
|
||||||
|
// 'timidity.cfg' in the root directory.
|
||||||
|
// Other compression types are not supported, in particular not 7z because
|
||||||
|
// due to the solid nature of its archives would be too slow.
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
void FSoundFontManager::ProcessOneFile(const FString &fn, TArray<FString> &sffiles)
|
||||||
|
{
|
||||||
|
auto fb = ExtractFileBase(fn, false);
|
||||||
|
for (auto &sfi : soundfonts)
|
||||||
|
{
|
||||||
|
// We already got a soundfont with this name. Do not add again.
|
||||||
|
if (!sfi.mName.CompareNoCase(fb)) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
FileReader fr;
|
||||||
|
if (fr.Open(fn))
|
||||||
|
{
|
||||||
|
// Try to identify. We only accept .sf2 and .zip by content. All other archives are intentionally ignored.
|
||||||
|
char head[16] = { 0};
|
||||||
|
fr.Read(head, 16);
|
||||||
|
if (!memcmp(head, "RIFF", 4) && !memcmp(head+8, "sfbkLIST", 8))
|
||||||
|
{
|
||||||
|
sffiles.Push(fn);
|
||||||
|
FSoundFontInfo sft = { fb, fn, SF_SF2 };
|
||||||
|
soundfonts.Push(sft);
|
||||||
|
}
|
||||||
|
else if (!memcmp(head, "PK", 2))
|
||||||
|
{
|
||||||
|
auto zip = FResourceFile::OpenResourceFile(fn, &fr);
|
||||||
|
if (zip != nullptr && zip->LumpCount() > 1) // Anything with just one lump cannot possibly be a packed GUS patch set so skip it right away and simplify the lookup code
|
||||||
|
{
|
||||||
|
auto zipl = zip->FindLump("timidity.cfg");
|
||||||
|
if (zipl != nullptr)
|
||||||
|
{
|
||||||
|
// It seems like this is what we are looking for
|
||||||
|
sffiles.Push(fn);
|
||||||
|
FSoundFontInfo sft = { fb, fn, SF_GUS };
|
||||||
|
soundfonts.Push(sft);
|
||||||
|
}
|
||||||
|
delete zip;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
void FSoundFontManager::CollectSoundfonts()
|
||||||
|
{
|
||||||
|
findstate_t c_file;
|
||||||
|
void *file;
|
||||||
|
TArray<FString> sffiles;
|
||||||
|
|
||||||
|
|
||||||
|
if (GameConfig != NULL && GameConfig->SetSection ("FileSearch.Directories"))
|
||||||
|
{
|
||||||
|
const char *key;
|
||||||
|
const char *value;
|
||||||
|
|
||||||
|
while (GameConfig->NextInSection (key, value))
|
||||||
|
{
|
||||||
|
if (stricmp (key, "Path") == 0)
|
||||||
|
{
|
||||||
|
FString dir;
|
||||||
|
|
||||||
|
dir = NicePath(value);
|
||||||
|
if (dir.IsNotEmpty())
|
||||||
|
{
|
||||||
|
if (dir.Back() != '/') dir += '/';
|
||||||
|
FString path = dir + '*';
|
||||||
|
if ((file = I_FindFirst(path, &c_file)) != ((void *)(-1)))
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (!(I_FindAttr(&c_file) & FA_DIREC))
|
||||||
|
{
|
||||||
|
FStringf name("%s%s", path.GetChars(), I_FindName(&c_file));
|
||||||
|
ProcessOneFile(name, sffiles);
|
||||||
|
}
|
||||||
|
} while (I_FindNext(file, &c_file) == 0);
|
||||||
|
I_FindClose(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
soundfontcollection.InitMultipleFiles(sffiles);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
const FSoundFontInfo *FSoundFontManager::FindSoundFont(const char *name, int allowed) const
|
||||||
|
{
|
||||||
|
for(auto &sfi : soundfonts)
|
||||||
|
{
|
||||||
|
if (allowed & sfi.type && !sfi.mFilename.CompareNoCase(name))
|
||||||
|
{
|
||||||
|
return &sfi;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
FSoundFontReader *FSoundFontManager::OpenSoundFont(const char *name, int allowed)
|
||||||
|
{
|
||||||
|
auto sfi = FindSoundFont(name, allowed);
|
||||||
|
if (sfi != nullptr)
|
||||||
|
{
|
||||||
|
return new FSoundFontReader(&soundfontcollection, sfi);
|
||||||
|
}
|
||||||
|
// The sound font collection did not yield any good results.
|
||||||
|
// Next check if the file is a .sf file
|
||||||
|
if (allowed & SF_SF2)
|
||||||
|
{
|
||||||
|
FileReader fr;
|
||||||
|
if (fr.Open(name))
|
||||||
|
{
|
||||||
|
char head[16] = { 0};
|
||||||
|
fr.Read(head, 16);
|
||||||
|
if (!memcmp(head, "RIFF", 4) && !memcmp(head+8, "sfbkLIST", 8))
|
||||||
|
{
|
||||||
|
FSoundFontInfo sft = { name, name, SF_SF2 };
|
||||||
|
soundfonts.Push(sft);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -222,7 +222,7 @@ std::pair<FileReader *, std::string> PathList::openFile(const char *name, bool i
|
||||||
{
|
{
|
||||||
/* First try the given name */
|
/* First try the given name */
|
||||||
|
|
||||||
if (!isAbsPath(name))
|
if (!IsAbsPath(name))
|
||||||
{
|
{
|
||||||
for (int i = (int)paths.size() - 1; i >= 0; i--)
|
for (int i = (int)paths.size() - 1; i >= 0; i--)
|
||||||
{
|
{
|
||||||
|
@ -253,18 +253,6 @@ std::pair<FileReader *, std::string> PathList::openFile(const char *name, bool i
|
||||||
return std::make_pair(nullptr, std::string());
|
return std::make_pair(nullptr, std::string());
|
||||||
}
|
}
|
||||||
|
|
||||||
int PathList::isAbsPath(const char *name)
|
|
||||||
{
|
|
||||||
if (name[0] == '/') return 1;
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
/* [A-Za-z]: (for Windows) */
|
|
||||||
if (isalpha(name[0]) && name[1] == ':') return 1;
|
|
||||||
#endif /* _WIN32 */
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
struct timidity_file *open_file(const char *name, bool ismainfile, PathList &pathList)
|
struct timidity_file *open_file(const char *name, bool ismainfile, PathList &pathList)
|
||||||
{
|
{
|
||||||
auto file = pathList.openFile(name, ismainfile);
|
auto file = pathList.openFile(name, ismainfile);
|
||||||
|
|
|
@ -36,7 +36,6 @@ class PathList
|
||||||
{
|
{
|
||||||
std::vector<std::string> paths;
|
std::vector<std::string> paths;
|
||||||
|
|
||||||
int isAbsPath(const char *name);
|
|
||||||
FileReader *tryOpenPath(const char *name, bool ismain);
|
FileReader *tryOpenPath(const char *name, bool ismain);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -1423,6 +1423,22 @@ int FWadCollection::GetLastLump (int wadnum) const
|
||||||
return Files[wadnum]->GetFirstLump() + Files[wadnum]->LumpCount() - 1;
|
return Files[wadnum]->GetFirstLump() + Files[wadnum]->LumpCount() - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
int FWadCollection::GetLumpCount (int wadnum) const
|
||||||
|
{
|
||||||
|
if ((uint32_t)wadnum >= Files.Size())
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Files[wadnum]->LumpCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
// W_GetWadFullName
|
// W_GetWadFullName
|
||||||
|
|
|
@ -146,6 +146,7 @@ public:
|
||||||
|
|
||||||
int GetFirstLump(int wadnum) const;
|
int GetFirstLump(int wadnum) const;
|
||||||
int GetLastLump(int wadnum) const;
|
int GetLastLump(int wadnum) const;
|
||||||
|
int GetLumpCount(int wadnum) const;
|
||||||
|
|
||||||
int CheckNumForName (const char *name, int namespc);
|
int CheckNumForName (const char *name, int namespc);
|
||||||
int CheckNumForName (const char *name, int namespc, int wadfile, bool exact = true);
|
int CheckNumForName (const char *name, int namespc, int wadfile, bool exact = true);
|
||||||
|
|
Loading…
Reference in a new issue