diff --git a/docs/rh-log.txt b/docs/rh-log.txt index 096a60e8d..4a67740f1 100644 --- a/docs/rh-log.txt +++ b/docs/rh-log.txt @@ -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. diff --git a/src/files.cpp b/src/files.cpp index 80d966acf..fd017658e 100644 --- a/src/files.cpp +++ b/src/files.cpp @@ -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; } diff --git a/src/files.h b/src/files.h index 578616910..5b9d79433 100644 --- a/src/files.h +++ b/src/files.h @@ -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); diff --git a/src/sound/i_musicinterns.h b/src/sound/i_musicinterns.h index 2a3b24c11..c1f04c385 100644 --- a/src/sound/i_musicinterns.h +++ b/src/sound/i_musicinterns.h @@ -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(); diff --git a/src/sound/music_midistream.cpp b/src/sound/music_midistream.cpp index 8b9bfa864..3f9d454df 100644 --- a/src/sound/music_midistream.cpp +++ b/src/sound/music_midistream.cpp @@ -419,6 +419,15 @@ void MIDIStreamer::MusicVolumeChanged() } } +void MIDIStreamer::TimidityVolumeChanged() +{ + if (MIDI != NULL) + { + MIDI->TimidityVolumeChanged(); + } +} + + //========================================================================== // // MIDIStreamer :: OutputVolume diff --git a/src/sound/music_timidity_mididevice.cpp b/src/sound/music_timidity_mididevice.cpp index 98b7a0907..e20a4ed03 100644 --- a/src/sound/music_timidity_mididevice.cpp +++ b/src/sound/music_timidity_mididevice.cpp @@ -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 diff --git a/src/timidity/common.cpp b/src/timidity/common.cpp index baf74b74a..f306abfb8 100644 --- a/src/timidity/common.cpp +++ b/src/timidity/common.cpp @@ -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 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(); } } diff --git a/src/timidity/instrum.cpp b/src/timidity/instrum.cpp index 700ae7b7e..ee5fdf868 100644 --- a/src/timidity/instrum.cpp +++ b/src/timidity/instrum.cpp @@ -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; } diff --git a/src/timidity/timidity.cpp b/src/timidity/timidity.cpp index 51d6c1ebc..cdc6f5472 100644 --- a/src/timidity/timidity.cpp +++ b/src/timidity/timidity.cpp @@ -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 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); diff --git a/src/timidity/timidity.h b/src/timidity/timidity.h index 2a18aab66..3470b656c 100644 --- a/src/timidity/timidity.h +++ b/src/timidity/timidity.h @@ -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();