mirror of
https://github.com/ZDoom/gzdoom-gles.git
synced 2024-11-28 06:53:40 +00:00
- Cleaned up the ugly MIDI song creating code a little.
- Added a generic Standard MIDI File creator that works with any of the sequencers. mus2midi.cpp is no longer used but is kept around as a reference. SVN r2677 (trunk)
This commit is contained in:
parent
092cbfd55b
commit
070ec75785
12 changed files with 344 additions and 202 deletions
|
@ -661,7 +661,6 @@ add_executable( zdoom WIN32
|
||||||
m_png.cpp
|
m_png.cpp
|
||||||
m_random.cpp
|
m_random.cpp
|
||||||
md5.cpp
|
md5.cpp
|
||||||
mus2midi.cpp
|
|
||||||
name.cpp
|
name.cpp
|
||||||
nodebuild.cpp
|
nodebuild.cpp
|
||||||
nodebuild_classify_nosse2.cpp
|
nodebuild_classify_nosse2.cpp
|
||||||
|
|
|
@ -195,9 +195,9 @@ bool ProduceMIDI (const BYTE *musBuf, int len, TArray<BYTE> &outFile)
|
||||||
switch (event & 0x70)
|
switch (event & 0x70)
|
||||||
{
|
{
|
||||||
case MUS_NOTEOFF:
|
case MUS_NOTEOFF:
|
||||||
midStatus |= MIDI_NOTEOFF;
|
midStatus |= MIDI_NOTEON;
|
||||||
mid1 = t & 127;
|
mid1 = t & 127;
|
||||||
mid2 = 64;
|
mid2 = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MUS_NOTEON:
|
case MUS_NOTEON:
|
||||||
|
|
|
@ -75,7 +75,4 @@ typedef struct
|
||||||
// WORD UsedInstruments[NumInstruments];
|
// WORD UsedInstruments[NumInstruments];
|
||||||
} MUSHeader;
|
} MUSHeader;
|
||||||
|
|
||||||
bool ProduceMIDI (const BYTE *musBuf, int len, TArray<BYTE> &outFile);
|
|
||||||
bool ProduceMIDI (const BYTE *musBuf, int len, FILE *outFile);
|
|
||||||
|
|
||||||
#endif //__MUS2MIDI_H__
|
#endif //__MUS2MIDI_H__
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
** Plays music
|
** Plays music
|
||||||
**
|
**
|
||||||
**---------------------------------------------------------------------------
|
**---------------------------------------------------------------------------
|
||||||
** Copyright 1998-2006 Randy Heit
|
** Copyright 1998-2010 Randy Heit
|
||||||
** All rights reserved.
|
** All rights reserved.
|
||||||
**
|
**
|
||||||
** Redistribution and use in source and binary forms, with or without
|
** Redistribution and use in source and binary forms, with or without
|
||||||
|
@ -84,6 +84,14 @@ extern void ChildSigHandler (int signum);
|
||||||
#define GZIP_FNAME 8
|
#define GZIP_FNAME 8
|
||||||
#define GZIP_FCOMMENT 16
|
#define GZIP_FCOMMENT 16
|
||||||
|
|
||||||
|
enum EMIDIType
|
||||||
|
{
|
||||||
|
MIDI_NOTMIDI,
|
||||||
|
MIDI_MIDI,
|
||||||
|
MIDI_HMI,
|
||||||
|
MIDI_MUS
|
||||||
|
};
|
||||||
|
|
||||||
extern int MUSHeaderSearch(const BYTE *head, int len);
|
extern int MUSHeaderSearch(const BYTE *head, int len);
|
||||||
|
|
||||||
EXTERN_CVAR (Int, snd_samplerate)
|
EXTERN_CVAR (Int, snd_samplerate)
|
||||||
|
@ -305,6 +313,40 @@ MusInfo *I_RegisterURLSong (const char *url)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static MusInfo *CreateMIDISong(FILE *file, const char *filename, BYTE *musiccache, int offset, int len, EMIDIDevice devtype, EMIDIType miditype)
|
||||||
|
{
|
||||||
|
if (devtype == MIDI_Timidity)
|
||||||
|
{
|
||||||
|
assert(miditype == MIDI_MIDI);
|
||||||
|
return new TimiditySong(file, musiccache, len);
|
||||||
|
}
|
||||||
|
else if (devtype >= MIDI_Null)
|
||||||
|
{
|
||||||
|
assert(miditype == MIDI_MIDI);
|
||||||
|
if (musiccache != NULL)
|
||||||
|
{
|
||||||
|
return new StreamSong((char *)musiccache, -1, len);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return new StreamSong(filename, offset, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (miditype == MIDI_MUS)
|
||||||
|
{
|
||||||
|
return new MUSSong2(file, musiccache, len, devtype);
|
||||||
|
}
|
||||||
|
else if (miditype == MIDI_MIDI)
|
||||||
|
{
|
||||||
|
return new MIDISong2(file, musiccache, len, devtype);
|
||||||
|
}
|
||||||
|
else if (miditype == MIDI_HMI)
|
||||||
|
{
|
||||||
|
return new HMISong(file, musiccache, len, devtype);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
MusInfo *I_RegisterSong (const char *filename, BYTE *musiccache, int offset, int len, int device)
|
MusInfo *I_RegisterSong (const char *filename, BYTE *musiccache, int offset, int len, int device)
|
||||||
{
|
{
|
||||||
FILE *file;
|
FILE *file;
|
||||||
|
@ -405,191 +447,147 @@ MusInfo *I_RegisterSong (const char *filename, BYTE *musiccache, int offset, int
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EMIDIType miditype = MIDI_NOTMIDI;
|
||||||
|
|
||||||
// Check for MUS format
|
// Check for MUS format
|
||||||
// Tolerate sloppy wads by searching up to 32 bytes for the header
|
// Tolerate sloppy wads by searching up to 32 bytes for the header
|
||||||
if (MUSHeaderSearch(idstr, sizeof(idstr)) >= 0)
|
if (MUSHeaderSearch(idstr, sizeof(idstr)) >= 0)
|
||||||
{
|
{
|
||||||
/* MUS are played as:
|
miditype = MIDI_MUS;
|
||||||
- OPL:
|
}
|
||||||
- if explicitly selected by $mididevice
|
// Check for HMI format
|
||||||
- when snd_mididevice is -3 and no midi device is set for the song
|
else
|
||||||
|
if (id[0] == MAKE_ID('H','M','I','-') &&
|
||||||
|
id[1] == MAKE_ID('M','I','D','I') &&
|
||||||
|
id[2] == MAKE_ID('S','O','N','G'))
|
||||||
|
{
|
||||||
|
miditype = MIDI_HMI;
|
||||||
|
}
|
||||||
|
// Check for MIDI format
|
||||||
|
else if (id[0] == MAKE_ID('M','T','h','d'))
|
||||||
|
{
|
||||||
|
miditype = MIDI_MIDI;
|
||||||
|
}
|
||||||
|
|
||||||
Timidity:
|
if (miditype != MIDI_NOTMIDI)
|
||||||
- if explicitly selected by $mididevice
|
{
|
||||||
- when snd_mididevice is -2 and no midi device is set for the song
|
TArray<BYTE> midi;
|
||||||
|
/* MIDI are played as:
|
||||||
|
- OPL:
|
||||||
|
- if explicitly selected by $mididevice
|
||||||
|
- when snd_mididevice is -3 and no midi device is set for the song
|
||||||
|
|
||||||
FMod:
|
- Timidity:
|
||||||
- if explicitly selected by $mididevice
|
- if explicitly selected by $mididevice
|
||||||
- when snd_mididevice is -1 and no midi device is set for the song
|
- when snd_mididevice is -2 and no midi device is set for the song
|
||||||
- as fallback when both OPL and Timidity failed unless snd_mididevice is >= 0
|
|
||||||
|
|
||||||
MMAPI (Win32 only):
|
- FMod:
|
||||||
- if explicitly selected by $mididevice (non-Win32 redirects this to FMOD)
|
- if explicitly selected by $mididevice
|
||||||
- when snd_mididevice is >= 0 and no midi device is set for the song
|
- when snd_mididevice is -1 and no midi device is set for the song
|
||||||
- as fallback when both OPL and Timidity failed and snd_mididevice is >= 0
|
- as fallback when both OPL and Timidity failed unless snd_mididevice is >= 0
|
||||||
|
|
||||||
|
- MMAPI (Win32 only):
|
||||||
|
- if explicitly selected by $mididevice (non-Win32 redirects this to FMOD)
|
||||||
|
- when snd_mididevice is >= 0 and no midi device is set for the song
|
||||||
|
- as fallback when both OPL and Timidity failed and snd_mididevice is >= 0
|
||||||
*/
|
*/
|
||||||
if ((snd_mididevice == -3 && device == MDEV_DEFAULT) || device == MDEV_OPL)
|
EMIDIDevice devtype = MIDI_Null;
|
||||||
|
|
||||||
|
// Choose the type of MIDI device we want.
|
||||||
|
if (device == MDEV_FMOD || (snd_mididevice == -1 && device == MDEV_DEFAULT))
|
||||||
{
|
{
|
||||||
info = new MUSSong2 (file, musiccache, len, MIDI_OPL);
|
devtype = MIDI_FMOD;
|
||||||
}
|
}
|
||||||
else if (device == MDEV_TIMIDITY || (device == MDEV_DEFAULT && snd_mididevice == -2))
|
else if (device == MDEV_TIMIDITY || (snd_mididevice == -2 && device == MDEV_DEFAULT))
|
||||||
{
|
{
|
||||||
info = new TimiditySong (file, musiccache, len);
|
devtype = MIDI_Timidity;
|
||||||
|
}
|
||||||
|
else if (device == MDEV_OPL || (snd_mididevice == -3 && device == MDEV_DEFAULT))
|
||||||
|
{
|
||||||
|
devtype = MIDI_OPL;
|
||||||
}
|
}
|
||||||
else if (snd_mididevice == -4 && device == MDEV_DEFAULT)
|
else if (snd_mididevice == -4 && device == MDEV_DEFAULT)
|
||||||
{
|
{
|
||||||
info = new MUSSong2(file, musiccache, len, MIDI_Timidity);
|
devtype = MIDI_GUS;
|
||||||
}
|
}
|
||||||
#ifdef HAVE_FLUIDSYNTH
|
#ifdef HAVE_FLUIDSYNTH
|
||||||
else if (device == MDEV_FLUIDSYNTH || (snd_mididevice == -5 && device == MDEV_DEFAULT))
|
else if (device == MDEV_FLUIDSYNTH || (snd_mididevice == -5 && device == MDEV_DEFAULT))
|
||||||
{
|
{
|
||||||
info = new MUSSong2(file, musiccache, len, MIDI_Fluid);
|
devtype = MIDI_Fluid;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef _WIN32
|
||||||
|
else
|
||||||
|
{
|
||||||
|
devtype = MIDI_Win;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
retry_as_fmod:
|
||||||
|
if (miditype != MIDI_MIDI && devtype >= MIDI_Null)
|
||||||
|
{
|
||||||
|
// Convert to standard MIDI for external sequencers.
|
||||||
|
MIDIStreamer *streamer;
|
||||||
|
|
||||||
|
if (miditype == MIDI_MUS)
|
||||||
|
{
|
||||||
|
streamer = new MUSSong2(file, musiccache, len, MIDI_Null);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
assert(miditype == MIDI_HMI);
|
||||||
|
streamer = new HMISong(file, musiccache, len, MIDI_Null);
|
||||||
|
}
|
||||||
|
if (streamer->IsValid())
|
||||||
|
{
|
||||||
|
streamer->CreateSMF(midi);
|
||||||
|
miditype = MIDI_MIDI;
|
||||||
|
musiccache = &midi[0];
|
||||||
|
len = midi.Size();
|
||||||
|
if (file != NULL)
|
||||||
|
{
|
||||||
|
fclose(file);
|
||||||
|
file = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delete streamer;
|
||||||
|
}
|
||||||
|
info = CreateMIDISong(file, filename, musiccache, offset, len, devtype, miditype);
|
||||||
if (info != NULL && !info->IsValid())
|
if (info != NULL && !info->IsValid())
|
||||||
{
|
{
|
||||||
delete info;
|
delete info;
|
||||||
info = NULL;
|
info = NULL;
|
||||||
device = MDEV_DEFAULT;
|
|
||||||
}
|
}
|
||||||
if (info == NULL && (snd_mididevice == -1 || device == MDEV_FMOD) && device != MDEV_MMAPI)
|
if (info == NULL && devtype != MIDI_FMOD && snd_mididevice < 0)
|
||||||
{
|
{
|
||||||
TArray<BYTE> midi;
|
devtype = MIDI_FMOD;
|
||||||
bool midi_made = false;
|
goto retry_as_fmod;
|
||||||
|
|
||||||
if (file == NULL)
|
|
||||||
{
|
|
||||||
midi_made = ProduceMIDI((BYTE *)musiccache, len, midi);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
BYTE *mus = new BYTE[len];
|
|
||||||
size_t did_read = fread(mus, 1, len, file);
|
|
||||||
if (did_read == (size_t)len)
|
|
||||||
{
|
|
||||||
midi_made = ProduceMIDI(mus, len, midi);
|
|
||||||
}
|
|
||||||
fseek(file, -(long)did_read, SEEK_CUR);
|
|
||||||
delete[] mus;
|
|
||||||
}
|
|
||||||
if (midi_made)
|
|
||||||
{
|
|
||||||
info = new StreamSong((char *)&midi[0], -1, midi.Size());
|
|
||||||
if (!info->IsValid())
|
|
||||||
{
|
|
||||||
delete info;
|
|
||||||
info = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
if (info == NULL)
|
if (info == NULL && devtype != MIDI_Win && snd_mididevice >= 0)
|
||||||
{
|
{
|
||||||
info = new MUSSong2 (file, musiccache, len, MIDI_Win);
|
info = CreateMIDISong(file, filename, musiccache, offset, len, MIDI_Win, miditype);
|
||||||
}
|
}
|
||||||
#endif // _WIN32
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check for various raw OPL formats
|
||||||
|
else if (
|
||||||
|
(id[0] == MAKE_ID('R','A','W','A') && id[1] == MAKE_ID('D','A','T','A')) || // Rdos Raw OPL
|
||||||
|
(id[0] == MAKE_ID('D','B','R','A') && id[1] == MAKE_ID('W','O','P','L')) || // DosBox Raw OPL
|
||||||
|
(id[0] == MAKE_ID('A','D','L','I') && *((BYTE *)id + 4) == 'B')) // Martin Fernandez's modified IMF
|
||||||
|
{
|
||||||
|
info = new OPLMUSSong (file, musiccache, len);
|
||||||
|
}
|
||||||
|
// Check for game music
|
||||||
|
else if ((fmt = GME_CheckFormat(id[0])) != NULL && fmt[0] != '\0')
|
||||||
|
{
|
||||||
|
info = GME_OpenSong(file, musiccache, len, fmt);
|
||||||
|
}
|
||||||
|
// Check for module formats
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Check for HMI format
|
info = MOD_OpenSong(file, musiccache, len);
|
||||||
if (id[0] == MAKE_ID('H','M','I','-') &&
|
|
||||||
id[1] == MAKE_ID('M','I','D','I') &&
|
|
||||||
id[2] == MAKE_ID('S','O','N','G'))
|
|
||||||
{
|
|
||||||
if ((snd_mididevice == -3 && device == MDEV_DEFAULT) || device == MDEV_OPL)
|
|
||||||
{
|
|
||||||
info = new HMISong(file, musiccache, len, MIDI_OPL);
|
|
||||||
}
|
|
||||||
else if (snd_mididevice == -4 && device == MDEV_DEFAULT)
|
|
||||||
{
|
|
||||||
info = new HMISong(file, musiccache, len, MIDI_Timidity);
|
|
||||||
}
|
|
||||||
#ifdef HAVE_FLUIDSYNTH
|
|
||||||
else if (device == MDEV_FLUIDSYNTH || (snd_mididevice == -5 && device == MDEV_DEFAULT))
|
|
||||||
{
|
|
||||||
info = new HMISong(file, musiccache, len, MIDI_Fluid);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#ifdef _WIN32
|
|
||||||
else
|
|
||||||
{
|
|
||||||
info = new HMISong(file, musiccache, len, MIDI_Win);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
// Check for MIDI format
|
|
||||||
else if (id[0] == MAKE_ID('M','T','h','d'))
|
|
||||||
{
|
|
||||||
// This is a midi file
|
|
||||||
|
|
||||||
/* MIDI are played as:
|
|
||||||
OPL:
|
|
||||||
- if explicitly selected by $mididevice
|
|
||||||
- when snd_mididevice is -3 and no midi device is set for the song
|
|
||||||
|
|
||||||
Timidity:
|
|
||||||
- if explicitly selected by $mididevice
|
|
||||||
- when snd_mididevice is -2 and no midi device is set for the song
|
|
||||||
|
|
||||||
FMOD:
|
|
||||||
- if explicitly selected by $mididevice
|
|
||||||
- when snd_mididevice is -1 and no midi device is set for the song
|
|
||||||
- as fallback when Timidity failed unless snd_mididevice is >= 0
|
|
||||||
|
|
||||||
MMAPI (Win32 only):
|
|
||||||
- if explicitly selected by $mididevice (non-Win32 redirects this to FMOD)
|
|
||||||
- when snd_mididevice is >= 0 and no midi device is set for the song
|
|
||||||
- as fallback when Timidity failed and snd_mididevice is >= 0
|
|
||||||
*/
|
|
||||||
if (device == MDEV_OPL || (snd_mididevice == -3 && device == MDEV_DEFAULT))
|
|
||||||
{
|
|
||||||
info = new MIDISong2 (file, musiccache, len, MIDI_OPL);
|
|
||||||
}
|
|
||||||
else if (device == MDEV_TIMIDITY || (snd_mididevice == -2 && device == MDEV_DEFAULT))
|
|
||||||
{
|
|
||||||
info = new TimiditySong (file, musiccache, len);
|
|
||||||
}
|
|
||||||
else if (snd_mididevice == -4 && device == MDEV_DEFAULT)
|
|
||||||
{
|
|
||||||
info = new MIDISong2(file, musiccache, len, MIDI_Timidity);
|
|
||||||
}
|
|
||||||
#ifdef HAVE_FLUIDSYNTH
|
|
||||||
else if (device == MDEV_FLUIDSYNTH || (snd_mididevice == -5 && device == MDEV_DEFAULT))
|
|
||||||
{
|
|
||||||
info = new MIDISong2(file, musiccache, len, MIDI_Fluid);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if (info != NULL && !info->IsValid())
|
|
||||||
{
|
|
||||||
delete info;
|
|
||||||
info = NULL;
|
|
||||||
device = MDEV_DEFAULT;
|
|
||||||
}
|
|
||||||
#ifdef _WIN32
|
|
||||||
if (info == NULL && device != MDEV_FMOD && (snd_mididevice >= 0 || device == MDEV_MMAPI))
|
|
||||||
{
|
|
||||||
info = new MIDISong2 (file, musiccache, len, MIDI_Win);
|
|
||||||
}
|
|
||||||
#endif // _WIN32
|
|
||||||
}
|
|
||||||
// Check for various raw OPL formats
|
|
||||||
else if (
|
|
||||||
(id[0] == MAKE_ID('R','A','W','A') && id[1] == MAKE_ID('D','A','T','A')) || // Rdos Raw OPL
|
|
||||||
(id[0] == MAKE_ID('D','B','R','A') && id[1] == MAKE_ID('W','O','P','L')) || // DosBox Raw OPL
|
|
||||||
(id[0] == MAKE_ID('A','D','L','I') && *((BYTE *)id + 4) == 'B')) // Martin Fernandez's modified IMF
|
|
||||||
{
|
|
||||||
info = new OPLMUSSong (file, musiccache, len);
|
|
||||||
}
|
|
||||||
// Check for game music
|
|
||||||
else if ((fmt = GME_CheckFormat(id[0])) != NULL && fmt[0] != '\0')
|
|
||||||
{
|
|
||||||
info = GME_OpenSong(file, musiccache, len, fmt);
|
|
||||||
}
|
|
||||||
// Check for module formats
|
|
||||||
else
|
|
||||||
{
|
|
||||||
info = MOD_OpenSong(file, musiccache, len);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (info == NULL)
|
if (info == NULL)
|
||||||
|
|
|
@ -333,8 +333,13 @@ enum EMIDIDevice
|
||||||
{
|
{
|
||||||
MIDI_Win,
|
MIDI_Win,
|
||||||
MIDI_OPL,
|
MIDI_OPL,
|
||||||
MIDI_Timidity,
|
MIDI_GUS,
|
||||||
MIDI_Fluid
|
MIDI_Fluid,
|
||||||
|
|
||||||
|
// only used by I_RegisterSong
|
||||||
|
MIDI_Null,
|
||||||
|
MIDI_FMOD,
|
||||||
|
MIDI_Timidity
|
||||||
};
|
};
|
||||||
|
|
||||||
class MIDIStreamer : public MusInfo
|
class MIDIStreamer : public MusInfo
|
||||||
|
@ -357,6 +362,7 @@ public:
|
||||||
void FluidSettingInt(const char *setting, int value);
|
void FluidSettingInt(const char *setting, int value);
|
||||||
void FluidSettingNum(const char *setting, double value);
|
void FluidSettingNum(const char *setting, double value);
|
||||||
void FluidSettingStr(const char *setting, const char *value);
|
void FluidSettingStr(const char *setting, const char *value);
|
||||||
|
void CreateSMF(TArray<BYTE> &file);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
MIDIStreamer(const char *dumpname, EMIDIDevice type);
|
MIDIStreamer(const char *dumpname, EMIDIDevice type);
|
||||||
|
@ -369,7 +375,7 @@ protected:
|
||||||
static void Callback(unsigned int uMsg, void *userdata, DWORD dwParam1, DWORD dwParam2);
|
static void Callback(unsigned int uMsg, void *userdata, DWORD dwParam1, DWORD dwParam2);
|
||||||
|
|
||||||
// Virtuals for subclasses to override
|
// Virtuals for subclasses to override
|
||||||
virtual void CheckCaps();
|
virtual void CheckCaps(int tech);
|
||||||
virtual void DoInitialSetup() = 0;
|
virtual void DoInitialSetup() = 0;
|
||||||
virtual void DoRestart() = 0;
|
virtual void DoRestart() = 0;
|
||||||
virtual bool CheckDone() = 0;
|
virtual bool CheckDone() = 0;
|
||||||
|
@ -457,7 +463,7 @@ public:
|
||||||
protected:
|
protected:
|
||||||
MIDISong2(const MIDISong2 *original, const char *filename, EMIDIDevice type); // file dump constructor
|
MIDISong2(const MIDISong2 *original, const char *filename, EMIDIDevice type); // file dump constructor
|
||||||
|
|
||||||
void CheckCaps();
|
void CheckCaps(int tech);
|
||||||
void DoInitialSetup();
|
void DoInitialSetup();
|
||||||
void DoRestart();
|
void DoRestart();
|
||||||
bool CheckDone();
|
bool CheckDone();
|
||||||
|
@ -494,7 +500,7 @@ public:
|
||||||
protected:
|
protected:
|
||||||
HMISong(const HMISong *original, const char *filename, EMIDIDevice type); // file dump constructor
|
HMISong(const HMISong *original, const char *filename, EMIDIDevice type); // file dump constructor
|
||||||
|
|
||||||
void CheckCaps();
|
void CheckCaps(int tech);
|
||||||
void DoInitialSetup();
|
void DoInitialSetup();
|
||||||
void DoRestart();
|
void DoRestart();
|
||||||
bool CheckDone();
|
bool CheckDone();
|
||||||
|
|
|
@ -273,10 +273,8 @@ HMISong::~HMISong ()
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
void HMISong::CheckCaps()
|
void HMISong::CheckCaps(int tech)
|
||||||
{
|
{
|
||||||
int tech = MIDI->GetTechnology();
|
|
||||||
|
|
||||||
// What's the equivalent HMI device for our technology?
|
// What's the equivalent HMI device for our technology?
|
||||||
if (tech == MOD_FMSYNTH)
|
if (tech == MOD_FMSYNTH)
|
||||||
{
|
{
|
||||||
|
@ -851,7 +849,7 @@ MusInfo *HMISong::GetOPLDumper(const char *filename)
|
||||||
|
|
||||||
MusInfo *HMISong::GetWaveDumper(const char *filename, int rate)
|
MusInfo *HMISong::GetWaveDumper(const char *filename, int rate)
|
||||||
{
|
{
|
||||||
return new HMISong(this, filename, MIDI_Timidity);
|
return new HMISong(this, filename, MIDI_GUS);
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
|
@ -207,7 +207,7 @@ TimiditySong::TimiditySong (FILE *file, BYTE *musiccache, int len)
|
||||||
|
|
||||||
BYTE *buf;
|
BYTE *buf;
|
||||||
|
|
||||||
if (file!=NULL)
|
if (file != NULL)
|
||||||
{
|
{
|
||||||
buf = new BYTE[len];
|
buf = new BYTE[len];
|
||||||
fread (buf, 1, len, file);
|
fread (buf, 1, len, file);
|
||||||
|
@ -217,18 +217,8 @@ TimiditySong::TimiditySong (FILE *file, BYTE *musiccache, int len)
|
||||||
buf = musiccache;
|
buf = musiccache;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Write to temporary file
|
||||||
// The file type has already been checked before this class instance was
|
success = (fwrite (buf, 1, len, f) == (size_t)len);
|
||||||
// created, so we only need to check one character to determine if this
|
|
||||||
// is a MUS or MIDI file and write it to disk as appropriate.
|
|
||||||
if (buf[1] == 'T')
|
|
||||||
{
|
|
||||||
success = (fwrite (buf, 1, len, f) == (size_t)len);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
success = ProduceMIDI (buf, len, f);
|
|
||||||
}
|
|
||||||
fclose (f);
|
fclose (f);
|
||||||
if (file != NULL)
|
if (file != NULL)
|
||||||
{
|
{
|
||||||
|
|
|
@ -49,6 +49,8 @@
|
||||||
|
|
||||||
// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
|
// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
|
||||||
|
|
||||||
|
static void WriteVarLen (TArray<BYTE> &file, DWORD value);
|
||||||
|
|
||||||
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
|
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
|
||||||
|
|
||||||
EXTERN_CVAR(Float, snd_musicvolume)
|
EXTERN_CVAR(Float, snd_musicvolume)
|
||||||
|
@ -57,8 +59,21 @@ EXTERN_CVAR(Float, snd_musicvolume)
|
||||||
extern UINT mididevice;
|
extern UINT mididevice;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
extern char MIDI_EventLengths[7];
|
||||||
|
|
||||||
// PRIVATE DATA DEFINITIONS ------------------------------------------------
|
// PRIVATE DATA DEFINITIONS ------------------------------------------------
|
||||||
|
|
||||||
|
static const BYTE StaticMIDIhead[] =
|
||||||
|
{
|
||||||
|
'M','T','h','d', 0, 0, 0, 6,
|
||||||
|
0, 0, // format 0: only one track
|
||||||
|
0, 1, // yes, there is really only one track
|
||||||
|
0, 0, // divisions (filled in)
|
||||||
|
'M','T','r','k', 0, 0, 0, 0,
|
||||||
|
// The first event sets the tempo (filled in)
|
||||||
|
0, 255, 81, 3, 0, 0, 0
|
||||||
|
};
|
||||||
|
|
||||||
// PUBLIC DATA DEFINITIONS -------------------------------------------------
|
// PUBLIC DATA DEFINITIONS -------------------------------------------------
|
||||||
|
|
||||||
// CODE --------------------------------------------------------------------
|
// CODE --------------------------------------------------------------------
|
||||||
|
@ -172,7 +187,7 @@ bool MIDIStreamer::IsValid() const
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
void MIDIStreamer::CheckCaps()
|
void MIDIStreamer::CheckCaps(int tech)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -200,7 +215,7 @@ void MIDIStreamer::Play(bool looping, int subsong)
|
||||||
{
|
{
|
||||||
MIDI = new OPLDumperMIDIDevice(DumpFilename);
|
MIDI = new OPLDumperMIDIDevice(DumpFilename);
|
||||||
}
|
}
|
||||||
else if (DeviceType == MIDI_Timidity)
|
else if (DeviceType == MIDI_GUS)
|
||||||
{
|
{
|
||||||
MIDI = new TimidityWaveWriterMIDIDevice(DumpFilename, 0);
|
MIDI = new TimidityWaveWriterMIDIDevice(DumpFilename, 0);
|
||||||
}
|
}
|
||||||
|
@ -221,13 +236,17 @@ void MIDIStreamer::Play(bool looping, int subsong)
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
case MIDI_Timidity:
|
case MIDI_GUS:
|
||||||
MIDI = new TimidityMIDIDevice;
|
MIDI = new TimidityMIDIDevice;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MIDI_OPL:
|
case MIDI_OPL:
|
||||||
MIDI = new OPLMIDIDevice;
|
MIDI = new OPLMIDIDevice;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
MIDI = NULL;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
|
@ -240,9 +259,9 @@ void MIDIStreamer::Play(bool looping, int subsong)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
CheckCaps();
|
CheckCaps(MIDI->GetTechnology());
|
||||||
Precache();
|
Precache();
|
||||||
IgnoreLoops = true;
|
IgnoreLoops = false;
|
||||||
|
|
||||||
// Set time division and tempo.
|
// Set time division and tempo.
|
||||||
if (0 != MIDI->SetTimeDiv(Division) ||
|
if (0 != MIDI->SetTimeDiv(Division) ||
|
||||||
|
@ -515,7 +534,7 @@ void MIDIStreamer::OutputVolume (DWORD volume)
|
||||||
int MIDIStreamer::VolumeControllerChange(int channel, int volume)
|
int MIDIStreamer::VolumeControllerChange(int channel, int volume)
|
||||||
{
|
{
|
||||||
ChannelVolumes[channel] = volume;
|
ChannelVolumes[channel] = volume;
|
||||||
return ((volume + 1) * Volume) >> 16;
|
return IgnoreLoops ? volume : ((volume + 1) * Volume) >> 16;
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
@ -834,9 +853,9 @@ int MIDIStreamer::FillBuffer(int buffer_num, int max_events, DWORD max_time)
|
||||||
//
|
//
|
||||||
// MIDIStreamer :: Precache
|
// MIDIStreamer :: Precache
|
||||||
//
|
//
|
||||||
// Generates a list of instruments this song uses them and passes them to
|
// Generates a list of instruments this song uses and passes them to the
|
||||||
// the MIDI device for precaching. The default implementation here pretends
|
// MIDI device for precaching. The default implementation here pretends to
|
||||||
// to play the song and watches for program change events on normal channels
|
// play the song and watches for program change events on normal channels
|
||||||
// and note on events on channel 10.
|
// and note on events on channel 10.
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
@ -933,6 +952,138 @@ void MIDIStreamer::Precache()
|
||||||
MIDI->PrecacheInstruments(&packed[0], packed.Size());
|
MIDI->PrecacheInstruments(&packed[0], packed.Size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// MIDIStreamer :: CreateSMF
|
||||||
|
//
|
||||||
|
// Simulates playback to create a Standard MIDI File.
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
void MIDIStreamer::CreateSMF(TArray<BYTE> &file)
|
||||||
|
{
|
||||||
|
DWORD delay = 0;
|
||||||
|
BYTE running_status = 0;
|
||||||
|
|
||||||
|
// Always create songs aimed at GM devices.
|
||||||
|
CheckCaps(MOD_MIDIPORT);
|
||||||
|
IgnoreLoops = true;
|
||||||
|
DoRestart();
|
||||||
|
|
||||||
|
file.Reserve(sizeof(StaticMIDIhead));
|
||||||
|
memcpy(&file[0], StaticMIDIhead, sizeof(StaticMIDIhead));
|
||||||
|
file[12] = Division >> 8;
|
||||||
|
file[13] = Division & 0xFF;
|
||||||
|
file[26] = InitialTempo >> 16;
|
||||||
|
file[27] = InitialTempo >> 8;
|
||||||
|
file[28] = InitialTempo;
|
||||||
|
|
||||||
|
while (!CheckDone())
|
||||||
|
{
|
||||||
|
DWORD *event_end = MakeEvents(Events[0], &Events[0][MAX_EVENTS*3], 1000000*600);
|
||||||
|
for (DWORD *event = Events[0]; event < event_end; )
|
||||||
|
{
|
||||||
|
delay += event[0];
|
||||||
|
if (MEVT_EVENTTYPE(event[2]) == MEVT_TEMPO)
|
||||||
|
{
|
||||||
|
WriteVarLen(file, delay);
|
||||||
|
delay = 0;
|
||||||
|
DWORD tempo = MEVT_EVENTPARM(event[2]);
|
||||||
|
file.Push(MIDI_META);
|
||||||
|
file.Push(MIDI_META_TEMPO);
|
||||||
|
file.Push(3);
|
||||||
|
file.Push(BYTE(tempo >> 16));
|
||||||
|
file.Push(BYTE(tempo >> 8));
|
||||||
|
file.Push(BYTE(tempo));
|
||||||
|
}
|
||||||
|
else if (MEVT_EVENTTYPE(event[2]) == MEVT_LONGMSG)
|
||||||
|
{
|
||||||
|
WriteVarLen(file, delay);
|
||||||
|
delay = 0;
|
||||||
|
DWORD len = MEVT_EVENTPARM(event[2]);
|
||||||
|
BYTE *bytes = (BYTE *)&event[3];
|
||||||
|
if (bytes[0] == MIDI_SYSEX)
|
||||||
|
{
|
||||||
|
len--;
|
||||||
|
file.Push(MIDI_SYSEX);
|
||||||
|
WriteVarLen(file, len);
|
||||||
|
memcpy(&file[file.Reserve(len - 1)], bytes, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (MEVT_EVENTTYPE(event[2]) == 0)
|
||||||
|
{
|
||||||
|
WriteVarLen(file, delay);
|
||||||
|
delay = 0;
|
||||||
|
BYTE status = BYTE(event[2]);
|
||||||
|
if (status != running_status)
|
||||||
|
{
|
||||||
|
running_status = status;
|
||||||
|
file.Push(status);
|
||||||
|
}
|
||||||
|
file.Push(BYTE((event[2] >> 8) & 0x7F));
|
||||||
|
if (MIDI_EventLengths[(status >> 4) & 7] == 2)
|
||||||
|
{
|
||||||
|
file.Push(BYTE((event[2] >> 16) & 0x7F));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Advance to next event
|
||||||
|
if (event[2] < 0x80000000)
|
||||||
|
{ // short message
|
||||||
|
event += 3;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ // long message
|
||||||
|
event += 3 + ((MEVT_EVENTPARM(event[2]) + 3) >> 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// End track
|
||||||
|
WriteVarLen(file, delay);
|
||||||
|
file.Push(MIDI_META);
|
||||||
|
file.Push(MIDI_META_EOT);
|
||||||
|
file.Push(0);
|
||||||
|
|
||||||
|
// Fill in track length
|
||||||
|
DWORD len = file.Size() - 22;
|
||||||
|
file[18] = BYTE(len >> 24);
|
||||||
|
file[19] = BYTE(len >> 16);
|
||||||
|
file[20] = BYTE(len >> 8);
|
||||||
|
file[21] = BYTE(len & 255);
|
||||||
|
|
||||||
|
IgnoreLoops = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// WriteVarLen
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
static void WriteVarLen (TArray<BYTE> &file, DWORD value)
|
||||||
|
{
|
||||||
|
DWORD buffer = value & 0x7F;
|
||||||
|
|
||||||
|
while ( (value >>= 7) )
|
||||||
|
{
|
||||||
|
buffer <<= 8;
|
||||||
|
buffer |= (value & 0x7F) | 0x80;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
file.Push(BYTE(buffer));
|
||||||
|
if (buffer & 0x80)
|
||||||
|
{
|
||||||
|
buffer >>= 8;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
// MIDIStreamer :: GetStats
|
// MIDIStreamer :: GetStats
|
||||||
|
|
|
@ -283,9 +283,9 @@ DWORD *MUSSong2::MakeEvents(DWORD *events, DWORD *max_event_p, DWORD max_time)
|
||||||
switch (event & 0x70)
|
switch (event & 0x70)
|
||||||
{
|
{
|
||||||
case MUS_NOTEOFF:
|
case MUS_NOTEOFF:
|
||||||
status |= MIDI_NOTEOFF;
|
status |= MIDI_NOTEON;
|
||||||
mid1 = t;
|
mid1 = t;
|
||||||
mid2 = 64;
|
mid2 = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MUS_NOTEON:
|
case MUS_NOTEON:
|
||||||
|
@ -382,7 +382,7 @@ MusInfo *MUSSong2::GetOPLDumper(const char *filename)
|
||||||
|
|
||||||
MusInfo *MUSSong2::GetWaveDumper(const char *filename, int rate)
|
MusInfo *MUSSong2::GetWaveDumper(const char *filename, int rate)
|
||||||
{
|
{
|
||||||
return new MUSSong2(this, filename, MIDI_Timidity);
|
return new MUSSong2(this, filename, MIDI_GUS);
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
|
@ -216,10 +216,8 @@ MIDISong2::~MIDISong2 ()
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
void MIDISong2::CheckCaps()
|
void MIDISong2::CheckCaps(int tech)
|
||||||
{
|
{
|
||||||
int tech = MIDI->GetTechnology();
|
|
||||||
|
|
||||||
DesignationMask = 0xFF0F;
|
DesignationMask = 0xFF0F;
|
||||||
if (tech == MOD_FMSYNTH)
|
if (tech == MOD_FMSYNTH)
|
||||||
{
|
{
|
||||||
|
@ -801,7 +799,7 @@ MusInfo *MIDISong2::GetOPLDumper(const char *filename)
|
||||||
|
|
||||||
MusInfo *MIDISong2::GetWaveDumper(const char *filename, int rate)
|
MusInfo *MIDISong2::GetWaveDumper(const char *filename, int rate)
|
||||||
{
|
{
|
||||||
return new MIDISong2(this, filename, MIDI_Timidity);
|
return new MIDISong2(this, filename, MIDI_GUS);
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
|
@ -141,6 +141,15 @@ public:
|
||||||
::new((void*)&Array[Count]) T(item);
|
::new((void*)&Array[Count]) T(item);
|
||||||
return Count++;
|
return Count++;
|
||||||
}
|
}
|
||||||
|
bool Pop ()
|
||||||
|
{
|
||||||
|
if (Count > 0)
|
||||||
|
{
|
||||||
|
Array[--Count].~T();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
bool Pop (T &item)
|
bool Pop (T &item)
|
||||||
{
|
{
|
||||||
if (Count > 0)
|
if (Count > 0)
|
||||||
|
|
|
@ -712,10 +712,6 @@
|
||||||
RelativePath=".\src\md5.cpp"
|
RelativePath=".\src\md5.cpp"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
|
||||||
RelativePath=".\src\mus2midi.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
<File
|
||||||
RelativePath=".\src\name.cpp"
|
RelativePath=".\src\name.cpp"
|
||||||
>
|
>
|
||||||
|
|
Loading…
Reference in a new issue