- 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:
Randy Heit 2010-09-03 05:08:05 +00:00
parent 092cbfd55b
commit 070ec75785
12 changed files with 344 additions and 202 deletions

View file

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

View file

@ -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:

View file

@ -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__

View file

@ -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)

View file

@ -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();

View file

@ -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);
} }
//========================================================================== //==========================================================================

View file

@ -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)
{ {

View file

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

View file

@ -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);
} }
//========================================================================== //==========================================================================

View file

@ -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);
} }
//========================================================================== //==========================================================================

View file

@ -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)

View file

@ -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"
> >