Initial import of Red Planet v4.10 Win32 source
Imports the current Win32 source for the pod-racing game 'Red Planet', built on the MUNGA engine and its L4 (Win32/DirectX) platform layer: - MUNGA / MUNGA_L4: cross-platform engine core and Win32 backend - RP / RP_L4: Red Planet game logic and Win32 application - DivLoader, Setup1: asset loader and installer project - lib, MUNGA_L4/openal, MUNGA_L4/sos: third-party audio dependencies Removed stale Subversion metadata and added .gitignore/.gitattributes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,690 @@
|
||||
#include "munga.h"
|
||||
#pragma hdrstop
|
||||
|
||||
#include "audmidi.h"
|
||||
|
||||
//#############################################################################
|
||||
//########################### MidiParse #################################
|
||||
//#############################################################################
|
||||
|
||||
#define NOTEOFF (0x80)
|
||||
#define NOTEON (0x90)
|
||||
#define PRESSURE (0xa0)
|
||||
#define CONTROLLER (0xb0)
|
||||
#define PITCHBEND (0xe0)
|
||||
#define PROGRAM (0xc0)
|
||||
#define CHANPRESSURE (0xd0)
|
||||
|
||||
#define METATEXT "Text Event"
|
||||
#define METACOPYRIGHT "Copyright Notice"
|
||||
#define METASEQUENCE "Sequence/Track Name"
|
||||
#define METAINSTRUMENT "Instrument Name"
|
||||
#define METALYRIC "Lyric"
|
||||
#define METAMARKER "Marker"
|
||||
#define METACUE "Cue Point"
|
||||
#define METAUNRECOGNIZED "Unrecognized"
|
||||
|
||||
#define CHAR_BUFF_SIZE (32)
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
//#############################################################################
|
||||
//
|
||||
MidiParse::MidiParse()
|
||||
{
|
||||
Mf_nomerge = 0; // 1 => continue'ed system exclusives are not collapsed.
|
||||
Mf_currtime = 0L; // current time in delta-time units
|
||||
Mf_skipinit = 0; // 1 if initial garbage should be skipped
|
||||
|
||||
Mf_toberead = 0L;
|
||||
|
||||
Msgbuff = NULL; // message buffer
|
||||
Msgsize = 0; // Size of currently allocated Msg
|
||||
Msgindex = 0; // index of next available location in Msg
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
//#############################################################################
|
||||
//
|
||||
MidiParse::~MidiParse()
|
||||
{
|
||||
if (Msgbuff != NULL)
|
||||
{
|
||||
Unregister_Pointer(Msgbuff);
|
||||
#if 0
|
||||
free(Msgbuff);
|
||||
#else
|
||||
delete[] Msgbuff;
|
||||
#endif
|
||||
Msgbuff = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
//#############################################################################
|
||||
//
|
||||
Logical
|
||||
MidiParse::TestInstance() const
|
||||
{
|
||||
Node::TestInstance();
|
||||
return True;
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
//#############################################################################
|
||||
//
|
||||
MidiParse::SignedLongWord
|
||||
MidiParse::CurTime()
|
||||
{
|
||||
Check(this);
|
||||
return Mf_currtime;
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
//#############################################################################
|
||||
//
|
||||
void
|
||||
MidiParse::Parse()
|
||||
{
|
||||
Check(this);
|
||||
|
||||
SignedWord ntrks;
|
||||
|
||||
ntrks = readheader();
|
||||
Verify(ntrks > 0);
|
||||
while (ntrks-- > 0)
|
||||
readtrack();
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
//#############################################################################
|
||||
//
|
||||
MidiParse::SignedWord
|
||||
MidiParse::readmt(
|
||||
char *s,
|
||||
SignedWord skip
|
||||
)
|
||||
{
|
||||
Check(this);
|
||||
|
||||
SignedWord nread = 0;
|
||||
char b[4];
|
||||
char buff[CHAR_BUFF_SIZE];
|
||||
SignedWord c;
|
||||
char *errmsg = "expecting ";
|
||||
|
||||
// read through the "MThd" or "MTrk" header string
|
||||
// if 1, we attempt to skip initial garbage.
|
||||
|
||||
retry:
|
||||
while ( nread<4 )
|
||||
{
|
||||
c = Mf_getc();
|
||||
if ( c == EOF )
|
||||
{
|
||||
errmsg = "EOF while expecting ";
|
||||
goto err;
|
||||
}
|
||||
b[nread++] = (char)c;
|
||||
}
|
||||
|
||||
// See if we found the 4 characters we're looking for
|
||||
|
||||
if ( s[0]==b[0] && s[1]==b[1] && s[2]==b[2] && s[3]==b[3] )
|
||||
return 0;
|
||||
if ( skip )
|
||||
{
|
||||
|
||||
// If we are supposed to skip initial garbage,
|
||||
// try again with the next character.
|
||||
|
||||
b[0]=b[1];
|
||||
b[1]=b[2];
|
||||
b[2]=b[3];
|
||||
nread = 3;
|
||||
goto retry;
|
||||
}
|
||||
err:
|
||||
Str_Copy(buff, errmsg, CHAR_BUFF_SIZE);
|
||||
Str_Cat(buff, s, CHAR_BUFF_SIZE);
|
||||
mferror(buff);
|
||||
return 0;
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
//#############################################################################
|
||||
//
|
||||
MidiParse::SignedWord
|
||||
MidiParse::egetc()
|
||||
{
|
||||
Check(this);
|
||||
|
||||
// read a single character and abort on EOF
|
||||
|
||||
SignedWord c = Mf_getc();
|
||||
|
||||
if ( c == EOF )
|
||||
mferror("premature EOF");
|
||||
Mf_toberead--;
|
||||
return c;
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
//#############################################################################
|
||||
//
|
||||
MidiParse::SignedWord
|
||||
MidiParse::readheader()
|
||||
{
|
||||
Check(this);
|
||||
|
||||
// read a header chunk
|
||||
|
||||
SignedWord
|
||||
format, ntrks, division;
|
||||
|
||||
if ( readmt("MThd", Mf_skipinit) == EOF )
|
||||
return 0;
|
||||
|
||||
Mf_toberead = read32bit();
|
||||
format = read16bit();
|
||||
ntrks = read16bit();
|
||||
division = read16bit();
|
||||
|
||||
Mf_header(format,ntrks,division);
|
||||
|
||||
// flush any extra stuff, in case the length of header is not 6
|
||||
|
||||
while ( Mf_toberead > 0 )
|
||||
egetc();
|
||||
return ntrks;
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
//#############################################################################
|
||||
//
|
||||
void
|
||||
MidiParse::readtrack()
|
||||
{
|
||||
Check(this);
|
||||
|
||||
// read a track chunk
|
||||
|
||||
// This array is indexed by the high half of a status byte. It's
|
||||
// value is either the number of bytes needed (1 or 2) for a channel
|
||||
// message, or 0 (meaning it's not a channel message).
|
||||
|
||||
static SignedWord chantype[] =
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, // 0x00 through 0x70
|
||||
2, 2, 2, 2, 1, 1, 2, 0 // 0x80 through 0xf0
|
||||
};
|
||||
|
||||
SignedLongWord lookfor, lng;
|
||||
SignedWord c, c1, type;
|
||||
SignedWord sysexcontinue = 0; // 1 if last message was an unfinished sysex
|
||||
SignedWord running; // 1 when running status used
|
||||
SignedWord status = 0; // (possibly running) status byte
|
||||
SignedWord needed;
|
||||
|
||||
if ( readmt("MTrk",0) == EOF )
|
||||
return;
|
||||
|
||||
Mf_toberead = read32bit();
|
||||
Mf_currtime = 0;
|
||||
|
||||
Mf_starttrack();
|
||||
|
||||
while ( Mf_toberead > 0 )
|
||||
{
|
||||
Mf_currtime += readvarinum(); // delta time
|
||||
|
||||
c = egetc();
|
||||
|
||||
if ( sysexcontinue && c != 0xf7 )
|
||||
mferror("didn't find expected continuation of a sysex");
|
||||
|
||||
if ( (c & 0x80) == 0 ) // running status?
|
||||
{
|
||||
if ( status == 0 )
|
||||
mferror("unexpected running status");
|
||||
running = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
status = c;
|
||||
running = 0;
|
||||
}
|
||||
|
||||
needed = chantype[ (status>>4) & 0xf ];
|
||||
|
||||
if ( needed ) // ie. is it a channel message?
|
||||
{
|
||||
if ( running )
|
||||
c1 = c;
|
||||
else
|
||||
c1 = egetc();
|
||||
chanmessage( status, c1, (needed>1) ? egetc() : (SignedWord)0 );
|
||||
continue;
|
||||
}
|
||||
|
||||
switch ( c )
|
||||
{
|
||||
case 0xff: // meta event
|
||||
type = egetc();
|
||||
// watch out - Don't combine the next 2 statements
|
||||
lng = readvarinum();
|
||||
lookfor = Mf_toberead - lng;
|
||||
msginit();
|
||||
|
||||
while ( Mf_toberead > lookfor )
|
||||
msgadd(egetc());
|
||||
|
||||
metaevent(type);
|
||||
break;
|
||||
|
||||
case 0xf0: // start of system exclusive
|
||||
// watch out - Don't combine the next 2 statements
|
||||
lng = readvarinum();
|
||||
lookfor = Mf_toberead - lng;
|
||||
msginit();
|
||||
msgadd(0xf0);
|
||||
|
||||
while ( Mf_toberead > lookfor )
|
||||
msgadd(c=egetc());
|
||||
|
||||
if ( c==0xf7 || Mf_nomerge==0 )
|
||||
sysex();
|
||||
else
|
||||
sysexcontinue = 1; // merge into next msg
|
||||
break;
|
||||
|
||||
case 0xf7: // sysex continuation or arbitrary stuff
|
||||
// watch out - Don't combine the next 2 statements
|
||||
lng = readvarinum();
|
||||
lookfor = Mf_toberead - lng;
|
||||
|
||||
if ( ! sysexcontinue )
|
||||
msginit();
|
||||
|
||||
while ( Mf_toberead > lookfor )
|
||||
msgadd(c=egetc());
|
||||
|
||||
if ( ! sysexcontinue )
|
||||
{
|
||||
Mf_arbitrary(msgleng(),msg());
|
||||
}
|
||||
else if ( c == 0xf7 )
|
||||
{
|
||||
sysex();
|
||||
sysexcontinue = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
badbyte(c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
Mf_endtrack();
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
//#############################################################################
|
||||
//
|
||||
void
|
||||
MidiParse::badbyte(SignedWord c)
|
||||
{
|
||||
Check(this);
|
||||
|
||||
char buff[CHAR_BUFF_SIZE];
|
||||
|
||||
sprintf(buff,"unexpected byte: 0x%02x",c);
|
||||
mferror(buff);
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
//#############################################################################
|
||||
//
|
||||
void
|
||||
MidiParse::metaevent(SignedWord type)
|
||||
{
|
||||
Check(this);
|
||||
|
||||
SignedWord leng = msgleng();
|
||||
char *m = msg();
|
||||
|
||||
switch ( type )
|
||||
{
|
||||
case 0x00:
|
||||
Mf_seqnum(to16bit(m[0],m[1]));
|
||||
break;
|
||||
case 0x01: // Text event
|
||||
case 0x02: // Copyright notice
|
||||
case 0x03: // Sequence/Track name
|
||||
case 0x04: // Instrument name
|
||||
case 0x05: // Lyric
|
||||
case 0x06: // Marker
|
||||
case 0x07: // Cue point
|
||||
case 0x08:
|
||||
case 0x09:
|
||||
case 0x0a:
|
||||
case 0x0b:
|
||||
case 0x0c:
|
||||
case 0x0d:
|
||||
case 0x0e:
|
||||
case 0x0f:
|
||||
// These are all text events
|
||||
Mf_text(type,leng,m);
|
||||
break;
|
||||
case 0x2f: // End of Track
|
||||
Mf_eot();
|
||||
break;
|
||||
case 0x51: // Set tempo
|
||||
Mf_tempo(to32bit((SignedWord)0,m[0],m[1],m[2]));
|
||||
break;
|
||||
case 0x54:
|
||||
Mf_smpte(m[0],m[1],m[2],m[3],m[4]);
|
||||
break;
|
||||
case 0x58:
|
||||
Mf_timesig(m[0],m[1],m[2],m[3]);
|
||||
break;
|
||||
case 0x59:
|
||||
Mf_keysig(m[0],m[1]);
|
||||
break;
|
||||
case 0x7f:
|
||||
Mf_sqspecific(leng,m);
|
||||
break;
|
||||
default:
|
||||
Mf_metamisc(type,leng,m);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
//#############################################################################
|
||||
//
|
||||
void
|
||||
MidiParse::sysex()
|
||||
{
|
||||
Check(this);
|
||||
Mf_sysex(msgleng(),msg());
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
//#############################################################################
|
||||
//
|
||||
void
|
||||
MidiParse::chanmessage(
|
||||
SignedWord status,
|
||||
SignedWord c1,
|
||||
SignedWord c2
|
||||
)
|
||||
{
|
||||
Check(this);
|
||||
|
||||
SignedWord chan = status & (SignedWord)0xf;
|
||||
|
||||
switch ( status & 0xf0 )
|
||||
{
|
||||
case NOTEOFF:
|
||||
Mf_off(chan,c1,c2);
|
||||
break;
|
||||
case NOTEON:
|
||||
Mf_on(chan,c1,c2);
|
||||
break;
|
||||
case PRESSURE:
|
||||
Mf_pressure(chan,c1,c2);
|
||||
break;
|
||||
case CONTROLLER:
|
||||
Mf_controller(chan,c1,c2);
|
||||
break;
|
||||
case PITCHBEND:
|
||||
Mf_pitchbend(chan,c1,c2);
|
||||
break;
|
||||
case PROGRAM:
|
||||
Mf_program(chan,c1);
|
||||
break;
|
||||
case CHANPRESSURE:
|
||||
Mf_chanpressure(chan,c1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
//#############################################################################
|
||||
//
|
||||
MidiParse::SignedLongWord
|
||||
MidiParse::readvarinum()
|
||||
{
|
||||
Check(this);
|
||||
|
||||
// readvarinum - read a varying-length number, and return the
|
||||
// number of characters it took.
|
||||
|
||||
SignedLongWord value;
|
||||
SignedWord c;
|
||||
|
||||
c = egetc();
|
||||
value = c;
|
||||
if (c & 0x80)
|
||||
{
|
||||
value &= 0x7f;
|
||||
do
|
||||
{
|
||||
c = egetc();
|
||||
value <<= 7;
|
||||
value += (c & 0x7f);
|
||||
} while (c & 0x80);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
//#############################################################################
|
||||
//
|
||||
MidiParse::SignedLongWord
|
||||
MidiParse::to32bit(SignedWord c1, SignedWord c2,SignedWord c3, SignedWord c4)
|
||||
{
|
||||
Check(this);
|
||||
|
||||
SignedLongWord value;
|
||||
|
||||
value = (c1 & 0xff);
|
||||
value = (value<<8) + (c2 & 0xff);
|
||||
value = (value<<8) + (c3 & 0xff);
|
||||
value = (value<<8) + (c4 & 0xff);
|
||||
return value;
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
//#############################################################################
|
||||
//
|
||||
MidiParse::SignedWord
|
||||
MidiParse::to16bit(SignedWord c1,SignedWord c2)
|
||||
{
|
||||
Check(this);
|
||||
|
||||
SignedWord value;
|
||||
|
||||
value = (c1 & (SignedWord)0xff);
|
||||
value = (SignedWord)((SignedWord)(value<<8) + (c2 & (SignedWord)0xff));
|
||||
return value;
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
//#############################################################################
|
||||
//
|
||||
MidiParse::SignedLongWord
|
||||
MidiParse::read32bit()
|
||||
{
|
||||
Check(this);
|
||||
|
||||
SignedWord c1, c2, c3, c4;
|
||||
|
||||
c1 = egetc();
|
||||
c2 = egetc();
|
||||
c3 = egetc();
|
||||
c4 = egetc();
|
||||
return to32bit(c1,c2,c3,c4);
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
//#############################################################################
|
||||
//
|
||||
MidiParse::SignedWord
|
||||
MidiParse::read16bit()
|
||||
{
|
||||
Check(this);
|
||||
|
||||
SignedWord c1, c2;
|
||||
|
||||
c1 = egetc();
|
||||
c2 = egetc();
|
||||
return to16bit(c1,c2);
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
//#############################################################################
|
||||
//
|
||||
void
|
||||
MidiParse::mferror(char *s)
|
||||
{
|
||||
Check(this);
|
||||
Mf_error(s);
|
||||
}
|
||||
|
||||
// The code below allows collection of a system exclusive message of
|
||||
// arbitrary length. The Msgbuff is expanded as necessary. The only
|
||||
// visible data/routines are msginit(), msgadd(), msg(), msgleng().
|
||||
|
||||
#define MSGINCREMENT ((SignedWord)128)
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
//#############################################################################
|
||||
//
|
||||
void
|
||||
MidiParse::msginit()
|
||||
{
|
||||
Check(this);
|
||||
Msgindex = 0;
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
//#############################################################################
|
||||
//
|
||||
char*
|
||||
MidiParse::msg()
|
||||
{
|
||||
Check(this);
|
||||
return Msgbuff;
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
//#############################################################################
|
||||
//
|
||||
MidiParse::SignedWord
|
||||
MidiParse::msgleng()
|
||||
{
|
||||
Check(this);
|
||||
return Msgindex;
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
//#############################################################################
|
||||
//
|
||||
void
|
||||
MidiParse::msgadd(SignedWord c)
|
||||
{
|
||||
Check(this);
|
||||
|
||||
// If necessary, allocate larger message buffer.
|
||||
|
||||
if ( Msgindex >= Msgsize )
|
||||
msgenlarge();
|
||||
Msgbuff[Msgindex++] = (char)c;
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
//#############################################################################
|
||||
//
|
||||
void
|
||||
MidiParse::msgenlarge()
|
||||
{
|
||||
Check(this);
|
||||
|
||||
char *newmess;
|
||||
char *oldmess = Msgbuff;
|
||||
SignedWord oldleng = Msgsize;
|
||||
|
||||
Msgsize += MSGINCREMENT;
|
||||
#if 0
|
||||
newmess = (char*)malloc( sizeof(char)*Msgsize );
|
||||
#else
|
||||
newmess = new char[Msgsize];
|
||||
#endif
|
||||
Register_Pointer(newmess);
|
||||
|
||||
// copy old message into larger new one
|
||||
if ( oldmess != 0 )
|
||||
{
|
||||
char *p = newmess;
|
||||
char *q = oldmess;
|
||||
char *endq = &oldmess[oldleng];
|
||||
|
||||
for ( ; q!=endq ; p++,q++ )
|
||||
*p = *q;
|
||||
Unregister_Pointer(oldmess);
|
||||
#if 0
|
||||
free(oldmess);
|
||||
#else
|
||||
delete[] oldmess;
|
||||
#endif
|
||||
}
|
||||
Msgbuff = newmess;
|
||||
}
|
||||
|
||||
// METHODS TO OVERRIDE
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
//#############################################################################
|
||||
//
|
||||
MidiParse::SignedWord
|
||||
MidiParse::Mf_getc()
|
||||
{
|
||||
Fail("MidiParse::Mf_getc - Should never reach here");
|
||||
return 0;
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
//#############################################################################
|
||||
//
|
||||
void
|
||||
MidiParse::Mf_error(char*)
|
||||
{
|
||||
Fail("MidiParse::Mf_error - Should never reach here");
|
||||
}
|
||||
Reference in New Issue
Block a user