- Changed the internal Timidity player so that it uses timidity_mastervolume

because it has the same sound volume issues as the external one.
- Replaced use of stdio in Timidity with FileReader and added the option to read
  from the lump directory. If the main config file is inside the lump directory
  it will assume that everything else is as well. If it is a real file it will be
  assumed that the rest is real files as well.
- Fixed: None of the error returns in Timidity::read_config_file closed the file being read.


SVN r906 (trunk)
This commit is contained in:
Christoph Oelckers 2008-04-12 21:36:10 +00:00
parent 6b2a7b8b03
commit 96b72f2e33
10 changed files with 214 additions and 114 deletions

View File

@ -1,4 +1,11 @@
April 12, 2008 (Changes by Graf Zahl)
- Changed the internal Timidity player so that it uses timidity_mastervolume
because it has the same sound volume issues as the external one.
- Replaced use of stdio in Timidity with FileReader and added the option to read
from the lump directory. If the main config file is inside the lump directory
it will assume that everything else is as well. If it is a real file it will be
assumed that the rest is real files as well.
- Fixed: None of the error returns in read_config_file closed the file being read.
- Added Martin Howe's morph system update.
- Added support for defining composite textures in HIRESTEX. It is not fully tested
and right now can't do much more than the old TEXTUREx method.

View File

@ -46,7 +46,7 @@
//==========================================================================
FileReader::FileReader ()
: File(NULL), Length(0), CloseOnDestruct(false)
: File(NULL), Length(0), StartPos(0), CloseOnDestruct(false)
{
}
@ -59,13 +59,10 @@ FileReader::FileReader (const FileReader &other, long length)
FileReader::FileReader (const char *filename)
: File(NULL), Length(0), StartPos(0), FilePos(0), CloseOnDestruct(false)
{
File = fopen (filename, "rb");
if (File == NULL)
if (!Open(filename))
{
I_Error ("Could not open %s", filename);
}
CloseOnDestruct = true;
Length = CalcFileLen();
}
FileReader::FileReader (FILE *file)
@ -89,6 +86,16 @@ FileReader::~FileReader ()
}
}
bool FileReader::Open (const char *filename)
{
File = fopen (filename, "rb");
if (File == NULL) return false;
CloseOnDestruct = true;
Length = CalcFileLen();
return true;
}
void FileReader::ResetFilePtr ()
{
FilePos = ftell (File);
@ -150,16 +157,26 @@ char *FileReader::GetsFromBuffer(const char * bufptr, char *strbuf, int len)
if (len <= 0) return NULL;
char *p = strbuf;
while (len > 1 && bufptr[FilePos] != 0)
while (len > 1)
{
if (bufptr[FilePos] == 0)
{
FilePos++;
break;
}
if (bufptr[FilePos] != '\r')
{
*p++ = bufptr[FilePos];
len--;
if (bufptr[FilePos] == '\n') break;
if (bufptr[FilePos] == '\n')
{
FilePos++;
break;
}
}
FilePos++;
}
if (p==strbuf) return NULL;
*p++=0;
return strbuf;
}

View File

@ -9,9 +9,11 @@
class FileReader
{
public:
FileReader ();
FileReader (const char *filename);
FileReader (FILE *file);
FileReader (FILE *file, long length);
bool Open (const char *filename);
virtual ~FileReader ();
virtual long Tell () const;
@ -62,7 +64,6 @@ public:
protected:
FileReader (const FileReader &other, long length);
FileReader ();
char *GetsFromBuffer(const char * bufptr, char *strbuf, int len);

View File

@ -26,6 +26,9 @@ void I_ShutdownMusicWin32 ();
extern float relative_volume;
EXTERN_CVAR (Float, timidity_mastervolume)
// The base music class. Everything is derived from this --------------------
class MusInfo
@ -119,6 +122,7 @@ public:
virtual bool Pause(bool paused) = 0;
virtual bool NeedThreadedCallback() = 0;
virtual void PrecacheInstruments(const WORD *instruments, int count);
virtual void TimidityVolumeChanged() {}
};
// WinMM implementation of a MIDI output device -----------------------------
@ -237,6 +241,7 @@ public:
bool Pause(bool paused);
bool NeedThreadedCallback();
void PrecacheInstruments(const WORD *instruments, int count);
void TimidityVolumeChanged();
protected:
static bool FillStream(SoundStream *stream, void *buff, int len, void *userdata);
@ -277,6 +282,7 @@ public:
~MIDIStreamer();
void MusicVolumeChanged();
void TimidityVolumeChanged();
void Play(bool looping);
void Pause();
void Resume();

View File

@ -419,6 +419,15 @@ void MIDIStreamer::MusicVolumeChanged()
}
}
void MIDIStreamer::TimidityVolumeChanged()
{
if (MIDI != NULL)
{
MIDI->TimidityVolumeChanged();
}
}
//==========================================================================
//
// MIDIStreamer :: OutputVolume

View File

@ -205,7 +205,7 @@ int TimidityMIDIDevice::Resume()
{
if (!Started)
{
if (Stream->Play(true, 1, false))
if (Stream->Play(true, timidity_mastervolume, false))
{
Started = true;
return 0;
@ -326,6 +326,21 @@ bool TimidityMIDIDevice::NeedThreadedCallback()
return false;
}
//==========================================================================
//
// TimidityMIDIDevice :: TimidityVolumeChanged
//
//==========================================================================
void TimidityMIDIDevice::TimidityVolumeChanged()
{
if (Stream != NULL)
{
Stream->SetVolume(timidity_mastervolume);
}
}
//==========================================================================
//
// TimidityMIDIDevice :: Pause

View File

@ -29,34 +29,32 @@
#include "zstring.h"
#include "tarray.h"
#include "i_system.h"
#include "w_wad.h"
#include "files.h"
#include "cmdlib.h"
namespace Timidity
{
/* I guess "rb" should be right for any libc */
#define OPEN_MODE "rb"
FString current_filename;
static TArray<FString> PathList;
/* Try to open a file for reading. */
static FILE *try_to_open(const char *name, int decompress, int noise_mode)
FString BuildPath(FString base, const char *name)
{
FILE *fp;
fp = fopen(name, OPEN_MODE);
if (!fp)
return 0;
return fp;
FString current;
if (base.IsNotEmpty())
{
current = base;
if (current[current.Len() - 1] != '/') current += '/';
}
current += name;
return current;
}
/* This is meant to find and open files for reading. */
FILE *open_file(const char *name, int decompress, int noise_mode)
FileReader *open_filereader(const char *name, int open, int *plumpnum)
{
FILE *fp;
FileReader *fp;
FString current_filename;
if (!name || !(*name))
{
@ -65,64 +63,56 @@ FILE *open_file(const char *name, int decompress, int noise_mode)
/* First try the given name */
current_filename = name;
FixPathSeperator(current_filename);
if ((fp = try_to_open(current_filename, decompress, noise_mode)))
return fp;
int lumpnum = Wads.CheckNumForFullName(current_filename);
#ifdef ENOENT
if (noise_mode && (errno != ENOENT))
if (open != OM_FILE)
{
return 0;
if (lumpnum >= 0)
{
fp = Wads.ReopenLumpNum(lumpnum);
if (plumpnum) *plumpnum = lumpnum;
return fp;
}
if (open == OM_LUMP) // search the path list when not loading the main config
{
for (unsigned int plp = PathList.Size(); plp-- != 0; )
{ /* Try along the path then */
current_filename = BuildPath(PathList[plp], name);
lumpnum = Wads.CheckNumForFullName(current_filename);
if (lumpnum >= 0)
{
fp = Wads.ReopenLumpNum(lumpnum);
if (plumpnum) *plumpnum = lumpnum;
return fp;
}
}
return NULL;
}
}
#endif
if (plumpnum) *plumpnum = -1;
if (name[0] != '/'
#ifdef _WIN32
&& name[0] != '\\'
#endif
)
fp = new FileReader;
if (fp->Open(current_filename)) return fp;
if (name[0] != '/')
{
for (unsigned int plp = PathList.Size(); plp-- != 0; )
{ /* Try along the path then */
current_filename = "";
if (PathList[plp].IsNotEmpty())
{
current_filename = PathList[plp];
if (current_filename[current_filename.Len() - 1] != '/'
#ifdef _WIN32
&& current_filename[current_filename.Len() - 1] != '\\'
#endif
)
{
current_filename += '/';
}
}
current_filename += name;
if ((fp = try_to_open(current_filename, decompress, noise_mode)))
return fp;
if (noise_mode && (errno != ENOENT))
{
return 0;
}
current_filename = BuildPath(PathList[plp], name);
if (fp->Open(current_filename)) return fp;
}
}
delete fp;
/* Nothing could be opened. */
current_filename = "";
return 0;
return NULL;
}
/* This closes files opened with open_file */
void close_file(FILE *fp)
{
fclose(fp);
}
/* This is meant for skipping a few bytes in a file or fifo. */
void skip(FILE *fp, size_t len)
{
fseek(fp, (long)len, SEEK_CUR);
}
/* This'll allocate memory or die. */
void *safe_malloc(size_t count)
@ -146,7 +136,14 @@ void *safe_malloc(size_t count)
/* This adds a directory to the path list */
void add_to_pathlist(const char *s)
{
PathList.Push(s);
FString copy = s;
FixPathSeperator(copy);
PathList.Push(copy);
}
void clear_pathlist()
{
PathList.Clear();
}
}

View File

@ -30,6 +30,7 @@
#include "timidity.h"
#include "m_swap.h"
#include "files.h"
namespace Timidity
{
@ -42,6 +43,7 @@ ToneBank standard_tonebank, standard_drumset;
/* This is only used for tracks that don't specify a program */
int default_program = DEFAULT_PROGRAM;
extern int openmode;
static void free_instrument(Instrument *ip)
@ -200,7 +202,7 @@ static InstrumentLayer *load_instrument(Renderer *song, const char *name, int fo
{
InstrumentLayer *lp, *lastlp, *headlp;
Instrument *ip;
FILE *fp;
FileReader *fp;
BYTE tmp[239];
int i,j;
bool noluck = false;
@ -212,16 +214,16 @@ static InstrumentLayer *load_instrument(Renderer *song, const char *name, int fo
if (!name) return 0;
/* Open patch file */
if ((fp = open_file(name, 1, OF_NORMAL)) == NULL)
if ((fp = open_filereader(name, openmode, NULL)) == NULL)
{
/* Try with various extensions */
FString tmp = name;
tmp += ".pat";
if ((fp = open_file(tmp, 1, OF_NORMAL)) == NULL)
if ((fp = open_filereader(tmp, openmode, NULL)) == NULL)
{
#ifdef unix // Windows isn't case-sensitive.
tmp.ToUpper();
if ((fp = open_file(tmp, 1, OF_NORMAL)) == NULL)
if ((fp = open_filereader(tmp, openmode, NULL)) == NULL)
#endif
{
noluck = true;
@ -240,12 +242,13 @@ static InstrumentLayer *load_instrument(Renderer *song, const char *name, int fo
/* Read some headers and do cursory sanity checks. There are loads
of magic offsets. This could be rewritten... */
if ((239 != fread(tmp, 1, 239, fp)) ||
if ((239 != fp->Read(tmp, 239)) ||
(memcmp(tmp, "GF1PATCH110\0ID#000002", 22) &&
memcmp(tmp, "GF1PATCH100\0ID#000002", 22))) /* don't know what the
differences are */
{
cmsg(CMSG_ERROR, VERB_NORMAL, "%s: not an instrument", name);
delete fp;
return 0;
}
@ -289,12 +292,14 @@ static InstrumentLayer *load_instrument(Renderer *song, const char *name, int fo
if (tmp[82] != 1 && tmp[82] != 0) /* instruments. To some patch makers, 0 means 1 */
{
cmsg(CMSG_ERROR, VERB_NORMAL, "Can't handle patches with %d instruments", tmp[82]);
delete fp;
return 0;
}
if (tmp[151] != 1 && tmp[151] != 0) /* layers. What's a layer? */
{
cmsg(CMSG_ERROR, VERB_NORMAL, "Can't handle instruments with %d layers", tmp[151]);
delete fp;
return 0;
}
@ -394,13 +399,13 @@ static InstrumentLayer *load_instrument(Renderer *song, const char *name, int fo
BYTE sf2delay;
#define READ_CHAR(thing) \
if (1 != fread(&tmpchar, 1, 1, fp)) goto fail; \
if (1 != fp->Read(&tmpchar,1)) goto fail; \
thing = tmpchar;
#define READ_SHORT(thing) \
if (1 != fread(&tmpshort, 2, 1, fp)) goto fail; \
if (2 != fp->Read(&tmpshort, 2)) goto fail; \
thing = LittleShort(tmpshort);
#define READ_LONG(thing) \
if (1 != fread(&tmplong, 4, 1, fp)) goto fail; \
if (4 != fp->Read(&tmplong, 4)) goto fail; \
thing = LittleLong(tmplong);
/*
@ -427,9 +432,9 @@ static InstrumentLayer *load_instrument(Renderer *song, const char *name, int fo
* Now: 1 delay
* 33 reserved
*/
skip(fp, 7); /* Skip the wave name */
fp->Seek(7, SEEK_CUR);
if (1 != fread(&fractions, 1, 1, fp))
if (1 != fp->Read(&fractions, 1))
{
fail:
cmsg(CMSG_ERROR, VERB_NORMAL, "Error reading sample %d", i);
@ -449,6 +454,7 @@ fail:
free(ip->left_sample);
free(ip);
free(lp);
delete fp;
return 0;
}
@ -473,7 +479,7 @@ fail:
READ_LONG(sp->low_freq);
READ_LONG(sp->high_freq);
READ_LONG(sp->root_freq);
skip(fp, 2); /* Unused by GUS: Why have a "root frequency" and then "tuning"?? */
fp->Seek(2, SEEK_CUR); /* Unused by GUS: Why have a "root frequency" and then "tuning"?? */
sp->low_vel = 0;
sp->high_vel = 127;
@ -503,7 +509,7 @@ fail:
}
/* envelope, tremolo, and vibrato */
if (18 != fread(tmp, 1, 18, fp)) goto fail;
if (18 != fp->Read(tmp, 18)) goto fail;
if (!tmp[13] || !tmp[14])
{
@ -551,11 +557,11 @@ fail:
READ_SHORT(sample_volume);
READ_CHAR(sf2delay);
READ_CHAR(sp->exclusiveClass);
skip(fp, 32);
fp->Seek(32, SEEK_CUR);
}
else
{
skip(fp, 36);
fp->Seek(36, SEEK_CUR);
sample_volume = 0;
sf2delay = 0;
@ -658,7 +664,7 @@ fail:
}
sp->data = (sample_t *)safe_malloc(sp->data_length + 1);
if (1 != fread(sp->data, sp->data_length, 1, fp))
if (sp->data_length != fp->Read(sp->data, sp->data_length))
goto fail;
convert_sample_data(sp, sp->data);
@ -737,7 +743,7 @@ fail:
} /* end of vlayer loop */
close_file(fp);
delete fp;
return headlp;
}

View File

@ -29,6 +29,7 @@
#include "cmdlib.h"
#include "c_cvars.h"
#include "i_system.h"
#include "files.h"
CVAR(String, timidity_config, CONFIG_FILE, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
@ -38,17 +39,19 @@ namespace Timidity
ToneBank *tonebank[MAXBANK], *drumset[MAXBANK];
static FString def_instr_name;
int openmode = OM_FILEORLUMP;
#define MAXWORDS 10
static int read_config_file(const char *name)
static int read_config_file(const char *name, bool ismain)
{
FILE *fp;
FileReader *fp;
char tmp[1024], *w[MAXWORDS], *cp;
ToneBank *bank = NULL;
int i, j, k, line = 0, words;
static int rcf_count = 0;
int lumpnum;
if (rcf_count > 50)
{
@ -56,10 +59,25 @@ static int read_config_file(const char *name)
return (-1);
}
if (!(fp = open_file(name, 1, OF_VERBOSE)))
if (ismain) openmode = OM_FILEORLUMP;
if (!(fp = open_filereader(name, openmode, &lumpnum)))
return -1;
while (fgets(tmp, sizeof(tmp), fp))
if (ismain)
{
if (lumpnum > 0)
{
openmode = OM_LUMP;
clear_pathlist(); // when reading from a PK3 we won't want to use any external path
}
else
{
openmode = OM_FILE;
}
}
while (fp->Gets(tmp, sizeof(tmp)))
{
line++;
w[words = 0] = strtok(tmp, " \t\r\n\240");
@ -177,6 +195,7 @@ static int read_config_file(const char *name)
if (words < 2)
{
Printf("%s: line %d: No directory given\n", name, line);
delete fp;
return -2;
}
for (i = 1; i < words; i++)
@ -192,7 +211,7 @@ static int read_config_file(const char *name)
for (i=1; i<words; i++)
{
rcf_count++;
read_config_file(w[i]);
read_config_file(w[i], false);
rcf_count--;
}
}
@ -201,6 +220,7 @@ static int read_config_file(const char *name)
if (words != 2)
{
Printf("%s: line %d: Must specify exactly one patch name\n", name, line);
delete fp;
return -2;
}
def_instr_name = w[1];
@ -210,12 +230,14 @@ static int read_config_file(const char *name)
if (words < 2)
{
Printf("%s: line %d: No drum set number given\n", name, line);
delete fp;
return -2;
}
i = atoi(w[1]);
if (i < 0 || i > 127)
{
Printf("%s: line %d: Drum set must be between 0 and 127\n", name, line);
delete fp;
return -2;
}
if (drumset[i] == NULL)
@ -229,12 +251,14 @@ static int read_config_file(const char *name)
if (words < 2)
{
Printf("%s: line %d: No bank number given\n", name, line);
delete fp;
return -2;
}
i = atoi(w[1]);
if (i < 0 || i > 127)
{
Printf("%s: line %d: Tone bank must be between 0 and 127\n", name, line);
delete fp;
return -2;
}
if (tonebank[i] == NULL)
@ -248,17 +272,20 @@ static int read_config_file(const char *name)
if ((words < 2) || (*w[0] < '0' || *w[0] > '9'))
{
Printf("%s: line %d: syntax error\n", name, line);
delete fp;
return -2;
}
i = atoi(w[0]);
if (i < 0 || i > 127)
{
Printf("%s: line %d: Program must be between 0 and 127\n", name, line);
delete fp;
return -2;
}
if (bank == NULL)
{
Printf("%s: line %d: Must specify tone bank or drum set before assignment\n", name, line);
delete fp;
return -2;
}
bank->tone[i].name = w[1];
@ -271,6 +298,7 @@ static int read_config_file(const char *name)
if (!(cp=strchr(w[j], '=')))
{
Printf("%s: line %d: bad patch option %s\n", name, line, w[j]);
delete fp;
return -2;
}
*cp++ = 0;
@ -280,6 +308,7 @@ static int read_config_file(const char *name)
if ((k < 0 || k > MAX_AMPLIFICATION) || (*cp < '0' || *cp > '9'))
{
Printf("%s: line %d: amplification must be between 0 and %d\n", name, line, MAX_AMPLIFICATION);
delete fp;
return -2;
}
bank->tone[i].amp = k;
@ -290,6 +319,7 @@ static int read_config_file(const char *name)
if ((k < 0 || k > 127) || (*cp < '0' || *cp > '9'))
{
Printf("%s: line %d: note must be between 0 and 127\n", name, line);
delete fp;
return -2;
}
bank->tone[i].note = k;
@ -309,6 +339,7 @@ static int read_config_file(const char *name)
{
Printf("%s: line %d: panning must be left, right, "
"center, or between -100 and 100\n", name, line);
delete fp;
return -2;
}
bank->tone[i].pan = k;
@ -322,6 +353,7 @@ static int read_config_file(const char *name)
else
{
Printf("%s: line %d: keep must be env or loop\n", name, line);
delete fp;
return -2;
}
}
@ -336,24 +368,28 @@ static int read_config_file(const char *name)
else
{
Printf("%s: line %d: strip must be env, loop, or tail\n", name, line);
delete fp;
return -2;
}
}
else
{
Printf("%s: line %d: bad patch option %s\n", name, line, w[j]);
delete fp;
return -2;
}
}
}
}
/*
if (ferror(fp))
{
Printf("Can't read %s: %s\n", name, strerror(errno));
close_file(fp);
return -2;
}
close_file(fp);
*/
delete fp;
return 0;
}
@ -375,22 +411,18 @@ void FreeAll()
}
}
int LoadConfig()
int LoadConfig(const char *filename)
{
static bool set_initial_path = false;
if (!set_initial_path)
{
clear_pathlist();
#ifdef _WIN32
add_to_pathlist("\\TIMIDITY");
add_to_pathlist(progdir);
add_to_pathlist("C:\\TIMIDITY");
add_to_pathlist("\\TIMIDITY");
add_to_pathlist(progdir);
#else
add_to_pathlist("/usr/local/lib/timidity");
add_to_pathlist("/etc/timidity");
add_to_pathlist("/etc");
add_to_pathlist("/usr/local/lib/timidity");
add_to_pathlist("/etc/timidity");
add_to_pathlist("/etc");
#endif
set_initial_path = true;
}
/* Some functions get aggravated if not even the standard banks are available. */
if (tonebank[0] == NULL)
@ -399,7 +431,12 @@ int LoadConfig()
drumset[0] = new ToneBank;
}
return read_config_file(timidity_config);
return read_config_file(filename, true);
}
int LoadConfig()
{
return LoadConfig(timidity_config);
}
Renderer::Renderer(float sample_rate)
@ -508,10 +545,15 @@ void Renderer::MarkInstrument(int banknum, int percussion, int instr)
void cmsg(int type, int verbosity_level, const char *fmt, ...)
{
/*
va_list args;
va_start(args, fmt);
VPrintf(PRINT_HIGH, fmt, args);
msg.VFormat(fmt, args);
*/
#ifdef _WIN32
char buf[1024];
va_list args;
va_start(args, fmt);
vsprintf(buf, fmt, args);
va_end(args);

View File

@ -23,6 +23,8 @@
#include "doomtype.h"
#include "zstring.h"
class FileReader;
namespace Timidity
{
@ -172,19 +174,16 @@ extern __inline__ double pow_x87_inline(double x,double y)
common.h
*/
extern FString current_filename;
#define OM_FILEORLUMP 0
#define OM_LUMP 1
#define OM_FILE 2
/* Noise modes for open_file */
#define OF_SILENT 0
#define OF_NORMAL 1
#define OF_VERBOSE 2
extern FILE *open_file(const char *name, int decompress, int noise_mode);
extern void add_to_pathlist(const char *s);
extern void close_file(FILE *fp);
extern void skip(FILE *fp, size_t len);
extern void clear_pathlist();
extern void *safe_malloc(size_t count);
FileReader *open_filereader(const char *name, int open, int *plumpnum);
/*
controls.h
*/
@ -510,6 +509,7 @@ tables.h
timidity.h
*/
struct DLS_Data;
int LoadConfig(const char *filename);
extern int LoadConfig();
extern void FreeAll();