mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-24 13:01:48 +00:00
- Added Gez's HMI/XMI division fixes, and partially the XMI tempo fix (not currently used).
SVN r3377 (trunk)
This commit is contained in:
parent
91ba2ec404
commit
170284ad57
3 changed files with 47 additions and 7 deletions
|
@ -637,6 +637,7 @@ protected:
|
||||||
|
|
||||||
int FindXMIDforms(const BYTE *chunk, int len, TrackInfo *songs) const;
|
int FindXMIDforms(const BYTE *chunk, int len, TrackInfo *songs) const;
|
||||||
void FoundXMID(const BYTE *chunk, int len, TrackInfo *song) const;
|
void FoundXMID(const BYTE *chunk, int len, TrackInfo *song) const;
|
||||||
|
void ScanForTempo(const TrackInfo *song);
|
||||||
bool SetMIDISubsong(int subsong);
|
bool SetMIDISubsong(int subsong);
|
||||||
void DoInitialSetup();
|
void DoInitialSetup();
|
||||||
void DoRestart();
|
void DoRestart();
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
** music_midi_midiout.cpp
|
** music_hmi_midiout.cpp
|
||||||
** Code to let ZDoom play HMI MIDI music through the MIDI streaming API.
|
** Code to let ZDoom play HMI MIDI music through the MIDI streaming API.
|
||||||
**
|
**
|
||||||
**---------------------------------------------------------------------------
|
**---------------------------------------------------------------------------
|
||||||
|
@ -54,7 +54,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
// In song header
|
// In song header
|
||||||
#define HMI_DIVISION_OFFSET 0xD2
|
#define HMI_DIVISION_OFFSET 0xD4
|
||||||
#define HMI_TRACK_COUNT_OFFSET 0xE4
|
#define HMI_TRACK_COUNT_OFFSET 0xE4
|
||||||
#define HMI_TRACK_DIR_PTR_OFFSET 0xE8
|
#define HMI_TRACK_DIR_PTR_OFFSET 0xE8
|
||||||
|
|
||||||
|
@ -202,7 +202,10 @@ void HMISong::SetupForHMI(int len)
|
||||||
}
|
}
|
||||||
|
|
||||||
// The division is the number of pulses per quarter note (PPQN).
|
// The division is the number of pulses per quarter note (PPQN).
|
||||||
Division = GetShort(MusHeader + HMI_DIVISION_OFFSET);
|
// HMI files have two values here, a full value and a quarter value. Some games,
|
||||||
|
// notably Quarantines, have identical values for some reason, so it's safer to
|
||||||
|
// use the quarter value and multiply it by four than to trust the full value.
|
||||||
|
Division = GetShort(MusHeader + HMI_DIVISION_OFFSET) << 2;
|
||||||
InitialTempo = 4000000;
|
InitialTempo = 4000000;
|
||||||
|
|
||||||
Tracks = new TrackInfo[NumTracks + 1];
|
Tracks = new TrackInfo[NumTracks + 1];
|
||||||
|
|
|
@ -134,14 +134,16 @@ XMISong::XMISong (FILE *file, BYTE *musiccache, int len, EMidiDevice type)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// The division is the number of pulses per quarter note (PPQN).
|
||||||
|
// It is set by a specific MIDI event, but just in case these aren't used,
|
||||||
|
// set a default value. Specs indicate it should be 120.
|
||||||
|
Division = 120;
|
||||||
Songs = new TrackInfo[NumSongs];
|
Songs = new TrackInfo[NumSongs];
|
||||||
memset(Songs, 0, sizeof(*Songs) * NumSongs);
|
memset(Songs, 0, sizeof(*Songs) * NumSongs);
|
||||||
FindXMIDforms(MusHeader, len, Songs);
|
FindXMIDforms(MusHeader, len, Songs);
|
||||||
CurrSong = Songs;
|
CurrSong = Songs;
|
||||||
DPrintf("XMI song count: %d\n", NumSongs);
|
DPrintf("XMI song count: %d\n", NumSongs);
|
||||||
|
DPrintf("Divisions: %d\n", Division);
|
||||||
// The division is the number of pulses per quarter note (PPQN).
|
|
||||||
Division = 60;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
@ -198,6 +200,8 @@ int XMISong::FindXMIDforms(const BYTE *chunk, int len, TrackInfo *songs) const
|
||||||
// IFF chunks are padded to even byte boundaries to avoid
|
// IFF chunks are padded to even byte boundaries to avoid
|
||||||
// unaligned reads on 68k processors.
|
// unaligned reads on 68k processors.
|
||||||
p += 8 + chunklen + (chunklen & 1);
|
p += 8 + chunklen + (chunklen & 1);
|
||||||
|
// Avoid crashes from corrupt chunks which indicate a negative size.
|
||||||
|
if (chunklen < 0) p = len;
|
||||||
}
|
}
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
@ -233,6 +237,37 @@ void XMISong::FoundXMID(const BYTE *chunk, int len, TrackInfo *song) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// XMISong :: ScanForTempo
|
||||||
|
//
|
||||||
|
// Look through events chunk to find one that sets the tempo.
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
void XMISong::ScanForTempo(const TrackInfo *song)
|
||||||
|
{
|
||||||
|
const BYTE *chunk = song->EventChunk;
|
||||||
|
|
||||||
|
for (size_t q = 0; q < song->EventLen - 3; )
|
||||||
|
{
|
||||||
|
int r = q;
|
||||||
|
int evmark = chunk[r];
|
||||||
|
int evtype = chunk[r + 1];
|
||||||
|
int evlen = chunk[r + 2];
|
||||||
|
// Is it a tempo event? If so, length should be 3.
|
||||||
|
if (evmark == MIDI_META && evtype == MIDI_META_TEMPO && evlen == 3)
|
||||||
|
{
|
||||||
|
// Tempo is given in microseconds per quarter notes, so for a base of
|
||||||
|
// 120 per second, we have to divide by a million a multiply by 120 to
|
||||||
|
// get the PPQN. This is simplified by 40 to manipulate smaller values.
|
||||||
|
Tempo = (chunk[r + 3] << 16) | (chunk[r + 4] << 8) | chunk[r + 5];
|
||||||
|
Division = Tempo * 3 / 25000;
|
||||||
|
}
|
||||||
|
q += 3 + evlen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
// XMISong :: SetMIDISubsong
|
// XMISong :: SetMIDISubsong
|
||||||
|
@ -304,7 +339,7 @@ bool XMISong::CheckDone()
|
||||||
//
|
//
|
||||||
// XMISong :: MakeEvents
|
// XMISong :: MakeEvents
|
||||||
//
|
//
|
||||||
// Copies MIDI events from the SMF and puts them into a MIDI stream
|
// Copies MIDI events from the XMI and puts them into a MIDI stream
|
||||||
// buffer. Returns the new position in the buffer.
|
// buffer. Returns the new position in the buffer.
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
@ -542,6 +577,7 @@ DWORD *XMISong::SendCommand (DWORD *events, EventSource due, DWORD delay)
|
||||||
events[1] = 0;
|
events[1] = 0;
|
||||||
events[2] = (MEVT_TEMPO << 24) | Tempo;
|
events[2] = (MEVT_TEMPO << 24) | Tempo;
|
||||||
events += 3;
|
events += 3;
|
||||||
|
Division = Tempo * 3 / 25000;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
track->EventP += len;
|
track->EventP += len;
|
||||||
|
|
Loading…
Reference in a new issue