Clean, self-contained extraction of the BattleTech-specific work from the
reverse-engineering workspace -- engine + game + content + build, with nothing
from Red Planet or the raw archive dumps. Builds green (Win32) and runs the
single-player drive->animate->target->fire->damage->destroy loop out of the box.
Layout:
engine/ MUNGA + MUNGA_L4 shared 2007 engine, carrying our BT render/loader
work (bgfload/L4D3D/L4VIDEO: BSL bit-slice decode, LOD/ground/shadow
models) + image codec; the minimal rp/ headers the audio HAL needs
game/ reconstructed BT logic + surviving-original BT source + fwd shims
+ WinMain launcher
content/ full runtime tree (BTL4.RES, VIDEO/, GAUGE/, AUDIO/, eggs, BTDPL.INI)
docs/ format specs + reconstruction ledgers
reference/ raw Ghidra pseudocode (recon source-of-truth) + decomp exporter
tools/ MP console emulator + map/resource scanners
One top-level CMake builds munga_engine lib + bt410_l4 game lib + btl4.exe.
All paths relativized (186 fwd shims + ~437 CMake abs paths -> repo-relative);
DXSDK is the one external, overridable via -DDXSDK. Verified: builds to a
byte-identical 2.27MB exe and runs combat (TARGET DESTROYED, 0 crashes) against
the bundled content.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
444 lines
12 KiB
C++
444 lines
12 KiB
C++
/****************************************************************************
|
|
|
|
File : sosmawe.c
|
|
|
|
Purpose : Module to handle AWE32 .SBK file uploads
|
|
|
|
Date : 1-20-95
|
|
|
|
Programmer(s) : Don Fowler
|
|
|
|
Last Updated : 1-29-95
|
|
|
|
****************************************************************************
|
|
Copyright(c) 1992,1995 Human Machine Interfaces
|
|
All Rights Reserved
|
|
****************************************************************************/
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <dos.h>
|
|
#include <fcntl.h>
|
|
#include <bios.h>
|
|
#include <io.h>
|
|
#include <malloc.h>
|
|
#include <conio.h>
|
|
#include <ctype.h>
|
|
#include "sosm.h"
|
|
|
|
WORD sosMIDIAWE32SetSBKFile( WORD, PSTR );
|
|
WORD sosMIDIAWE32ReleaseSBKFiles( WORD );
|
|
WORD sosMIDIAWE32NoteOn( WORD, WORD, WORD, WORD, WORD, WORD );
|
|
WORD sosMIDIAWE32NoteOff( WORD, WORD, WORD );
|
|
|
|
// maximum number of .SBK files that can be set on the chip
|
|
#define _MAX_SBKS 0x10
|
|
|
|
// offset into slot list for .SBK files to start
|
|
#define _SBK_SLOT_OFFSET 0x01
|
|
|
|
// size of buffer needed to read in a chunk of .SBK file
|
|
#define _READ_BUFFER_SIZE 0x2000
|
|
|
|
// pointer to preset data for awe32
|
|
#ifdef BORLAND
|
|
PSTR _lpSOSMIDIAwe32PresetBuffer[ _SOS_MIDI_MAX_DRIVERS ][ _MAX_SBKS ] = {
|
|
#else
|
|
LPSTR _lpSOSMIDIAwe32PresetBuffer[ _SOS_MIDI_MAX_DRIVERS ][ _MAX_SBKS ] = {
|
|
#endif
|
|
|
|
{ _NULL, _NULL, _NULL, _NULL, _NULL, _NULL, _NULL, _NULL,
|
|
_NULL, _NULL, _NULL, _NULL, _NULL, _NULL, _NULL, _NULL },
|
|
{ _NULL, _NULL, _NULL, _NULL, _NULL, _NULL, _NULL, _NULL,
|
|
_NULL, _NULL, _NULL, _NULL, _NULL, _NULL, _NULL, _NULL },
|
|
{ _NULL, _NULL, _NULL, _NULL, _NULL, _NULL, _NULL, _NULL,
|
|
_NULL, _NULL, _NULL, _NULL, _NULL, _NULL, _NULL, _NULL },
|
|
{ _NULL, _NULL, _NULL, _NULL, _NULL, _NULL, _NULL, _NULL,
|
|
_NULL, _NULL, _NULL, _NULL, _NULL, _NULL, _NULL, _NULL },
|
|
{ _NULL, _NULL, _NULL, _NULL, _NULL, _NULL, _NULL, _NULL,
|
|
_NULL, _NULL, _NULL, _NULL, _NULL, _NULL, _NULL, _NULL }
|
|
|
|
};
|
|
|
|
// index into list of presets to the currently available slot,
|
|
// start the index at 0 to leave slot 0 open for general midi
|
|
// rom on the AWE32
|
|
WORD _wSOSMIDIAwe32PresetIndex[ _SOS_MIDI_MAX_DRIVERS ] = {
|
|
|
|
_SBK_SLOT_OFFSET, _SBK_SLOT_OFFSET, _SBK_SLOT_OFFSET,
|
|
_SBK_SLOT_OFFSET, _SBK_SLOT_OFFSET
|
|
};
|
|
|
|
/***************************************************************************
|
|
|
|
Function : WORD sosMIDIAWE32SetSBKFile
|
|
|
|
Parameters : WORD hDriver
|
|
Handle of SOS driver to set SBK file on.
|
|
PSTR szFileName
|
|
Name of .SBK file to set.
|
|
|
|
Returns : -1 if error; otherwise, slot that the .SBK file was
|
|
assigned to on the AWE32.
|
|
|
|
Description : Stream a .SBK file onto the awe32 and return the slot
|
|
streamed to.
|
|
|
|
****************************************************************************/
|
|
|
|
WORD sosMIDIAWE32SetSBKFile( WORD hDriver, PSTR szFileName )
|
|
{
|
|
WORD wIndex;
|
|
WORD hFile;
|
|
WORD wReadSize;
|
|
PSTR pDataPtr;
|
|
#ifdef BORLAND
|
|
SFAR lpTemp;
|
|
#endif
|
|
|
|
// attempt to find a slot to use for the .SBK file
|
|
if( _wSOSMIDIAwe32PresetIndex[ hDriver ] == ( _MAX_SBKS - 1 ) )
|
|
return( -1 );
|
|
|
|
// attempt to open the sbk file
|
|
if( ( hFile = open( ( const char * )szFileName, O_RDONLY | O_BINARY ) ) == -1 )
|
|
return( -1 );
|
|
|
|
// attempt to allocate a buffer to use for transfer
|
|
if( !( pDataPtr = ( PSTR )malloc( _READ_BUFFER_SIZE ) ) )
|
|
{
|
|
// close the file
|
|
close( hFile );
|
|
|
|
// return an error
|
|
return( -1 );
|
|
}
|
|
|
|
// open the awe32 stream
|
|
#ifdef BORLAND
|
|
if( ( wReadSize = sosMIDIDRVCall32Func( _lpSOSMIDIDrvFunction[ hDriver ][ 5 ],
|
|
lpTemp, _wSOSMIDIAwe32PresetIndex[ hDriver ], 0x00 ) ) == -1 )
|
|
#else
|
|
if( ( wReadSize = _lpSOSMIDIDrvFunction[ hDriver ][ 5 ]( _NULL,
|
|
_wSOSMIDIAwe32PresetIndex[ hDriver ], 0x00 ) ) == -1 )
|
|
#endif
|
|
{
|
|
// free the previously allocated memory
|
|
free( pDataPtr );
|
|
|
|
// close the file
|
|
close( hFile );
|
|
|
|
// return error
|
|
return( -1 );
|
|
}
|
|
|
|
// read in a chunk of data from the file
|
|
if( read( hFile, pDataPtr, wReadSize ) == -1 )
|
|
return( -1 );
|
|
|
|
// get the sample data seek location
|
|
#ifdef BORLAND
|
|
lpTemp.sel = getDS();
|
|
lpTemp.off = pDataPtr;
|
|
if( ( wIndex = sosMIDIDRVCall32Func( _lpSOSMIDIDrvFunction[ hDriver ][ 8 ],
|
|
lpTemp, _wSOSMIDIAwe32PresetIndex[ hDriver ], 0x00 ) ) == -1 )
|
|
#else
|
|
if( ( wIndex = _lpSOSMIDIDrvFunction[ hDriver ][ 8 ]( ( LPSTR )pDataPtr,
|
|
_wSOSMIDIAwe32PresetIndex[ hDriver ], 0x00 ) ) == -1 )
|
|
#endif
|
|
{
|
|
// free the previously allocated memory
|
|
free( pDataPtr );
|
|
|
|
// close the file
|
|
close( hFile );
|
|
|
|
// return error
|
|
return( -1 );
|
|
}
|
|
|
|
// seek the file to the sample location
|
|
if( lseek( hFile, wIndex, SEEK_SET ) == -1 )
|
|
{
|
|
// close the file
|
|
close( hFile );
|
|
|
|
// free the preset memory
|
|
free( ( PSTR )_lpSOSMIDIAwe32PresetBuffer[ hDriver ][ _wSOSMIDIAwe32PresetIndex[ hDriver ] ] );
|
|
|
|
// return an error
|
|
return( -1 );
|
|
}
|
|
|
|
// send chunks of data to the driver
|
|
do
|
|
{
|
|
// read in a chunk of data from the file
|
|
if( read( hFile, pDataPtr, wReadSize ) == -1 )
|
|
return( -1 );
|
|
|
|
// send the data to the driver
|
|
#ifdef BORLAND
|
|
lpTemp.sel = getDS();
|
|
lpTemp.off = pDataPtr;
|
|
if( ( wReadSize = sosMIDIDRVCall32Func( _lpSOSMIDIDrvFunction[ hDriver ]
|
|
[ 6 ], lpTemp, _wSOSMIDIAwe32PresetIndex[ hDriver ], 0x00 ) ) == -1 )
|
|
#else
|
|
if( ( wReadSize = _lpSOSMIDIDrvFunction[ hDriver ][ 6 ](
|
|
( LPSTR )pDataPtr, _wSOSMIDIAwe32PresetIndex[ hDriver ], 0x00 ) ) == -1 )
|
|
#endif
|
|
{
|
|
// close the file
|
|
close( hFile );
|
|
|
|
// free the memory
|
|
free( pDataPtr );
|
|
|
|
// return an error
|
|
return( -1 );
|
|
}
|
|
} while( wReadSize );
|
|
|
|
// free the temporary memory buffer
|
|
free( pDataPtr );
|
|
|
|
// get the preset data size
|
|
#ifdef BORLAND
|
|
wReadSize = sosMIDIDRVCall32Func( _lpSOSMIDIDrvFunction[ hDriver ][ 7 ],
|
|
lpTemp, 0x00, 0x00 );
|
|
#else
|
|
wReadSize = _lpSOSMIDIDrvFunction[ hDriver ][ 7 ]( _NULL, 0x00, 0x00 );
|
|
#endif
|
|
|
|
// get the preset location in the file
|
|
#ifdef BORLAND
|
|
lpTemp.sel = getDS();
|
|
lpTemp.off = &wIndex;
|
|
sosMIDIDRVCall32Func( _lpSOSMIDIDrvFunction[ hDriver ][ 9 ], lpTemp,
|
|
0x00, 0x00 );
|
|
#else
|
|
_lpSOSMIDIDrvFunction[ hDriver ][ 9 ]( ( LPSTR )&wIndex, 0x00, 0x00 );
|
|
#endif
|
|
|
|
// allocate the memory for the preset information
|
|
#ifdef BORLAND
|
|
if( !( _lpSOSMIDIAwe32PresetBuffer[ hDriver ][ _wSOSMIDIAwe32PresetIndex[ hDriver ] ] =
|
|
( PSTR )malloc( wReadSize ) ) )
|
|
#else
|
|
if( !( _lpSOSMIDIAwe32PresetBuffer[ hDriver ][ _wSOSMIDIAwe32PresetIndex[ hDriver ] ] =
|
|
( LPSTR )malloc( wReadSize ) ) )
|
|
#endif
|
|
{
|
|
// close the file
|
|
close( hFile );
|
|
|
|
// return an error
|
|
return( -1 );
|
|
}
|
|
|
|
// seek the file to the preset location
|
|
if( lseek( hFile, wIndex, SEEK_SET ) == -1 )
|
|
{
|
|
// close the file
|
|
close( hFile );
|
|
|
|
// free the preset memory
|
|
free( ( PSTR )_lpSOSMIDIAwe32PresetBuffer[ hDriver ][ _wSOSMIDIAwe32PresetIndex[ hDriver ] ] );
|
|
|
|
// return an error
|
|
return( -1 );
|
|
}
|
|
|
|
// read in the preset information
|
|
if( read( hFile, ( PSTR )_lpSOSMIDIAwe32PresetBuffer[ hDriver ][
|
|
_wSOSMIDIAwe32PresetIndex[ hDriver ] ], wReadSize ) == -1 )
|
|
{
|
|
// close the file
|
|
close( hFile );
|
|
|
|
// free the preset memory
|
|
free( ( PSTR )_lpSOSMIDIAwe32PresetBuffer[ hDriver ][ _wSOSMIDIAwe32PresetIndex[ hDriver ] ] );
|
|
|
|
// return an error
|
|
return( -1 );
|
|
}
|
|
|
|
// send the preset information to the driver
|
|
#ifdef BORLAND
|
|
lpTemp.sel = getDS();
|
|
lpTemp.off = _lpSOSMIDIAwe32PresetBuffer[ hDriver ][ _wSOSMIDIAwe32PresetIndex[ hDriver ] ];
|
|
if( ( sosMIDIDRVCall32Func( _lpSOSMIDIDrvFunction[ hDriver ][ 10 ],
|
|
lpTemp, 0x00, 0x00 ) ) == -1 )
|
|
#else
|
|
if( ( _lpSOSMIDIDrvFunction[ hDriver ][ 10 ]( ( LPSTR )
|
|
_lpSOSMIDIAwe32PresetBuffer[ hDriver ][ _wSOSMIDIAwe32PresetIndex[ hDriver ] ], 0x00, 0x00 ) ) == -1 )
|
|
#endif
|
|
{
|
|
// free the preset memory
|
|
free( ( PSTR )_lpSOSMIDIAwe32PresetBuffer[ hDriver ][ _wSOSMIDIAwe32PresetIndex[ hDriver ] ] );
|
|
|
|
// close the file
|
|
close( hFile );
|
|
|
|
// return an error
|
|
return( -1 );
|
|
}
|
|
|
|
// close the SBK file
|
|
close( hFile );
|
|
|
|
// increment the preset buffer index to the next available slot
|
|
_wSOSMIDIAwe32PresetIndex[ hDriver ]++;
|
|
|
|
// return no error
|
|
return( _wSOSMIDIAwe32PresetIndex[ hDriver ] );
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
Function : WORD sosMIDIAWE32ReleaseAllSBKFiles
|
|
|
|
Parameters : WORD hDriver
|
|
Handle of SOS driver to release .SBK files from
|
|
|
|
Returns : -1 if error; otherwise, _ERR_NO_ERROR
|
|
|
|
Description : Release all of the memory associated to the .SBK files
|
|
uploaded to the awe32.
|
|
|
|
****************************************************************************/
|
|
|
|
WORD sosMIDIAWE32ReleaseSBKFiles( WORD hDriver )
|
|
{
|
|
WORD wIndex;
|
|
#ifdef BORLAND
|
|
SFAR lpTemp;
|
|
#endif
|
|
|
|
// call the driver to release all of the .SBK files
|
|
#ifdef BORLAND
|
|
if( sosMIDIDRVCall32Func( _lpSOSMIDIDrvFunction[ hDriver ][ 9 ], lpTemp,
|
|
0x01, 0x00 ) == -1 )
|
|
#else
|
|
if( _lpSOSMIDIDrvFunction[ hDriver ][ 9 ]( ( LPSTR )_NULL, 0x01, 0x00 )
|
|
== -1 )
|
|
#endif
|
|
return( -1 );
|
|
|
|
// free the memory allocated for the awe32 preset information
|
|
for( wIndex = _SBK_SLOT_OFFSET; wIndex < _wSOSMIDIAwe32PresetIndex[ hDriver ];
|
|
wIndex++ )
|
|
free( ( PSTR )_lpSOSMIDIAwe32PresetBuffer[ hDriver ][ wIndex ] );
|
|
|
|
// reset the available slot index
|
|
_wSOSMIDIAwe32PresetIndex[ hDriver ] = _SBK_SLOT_OFFSET;
|
|
|
|
// return no error
|
|
return( _ERR_NO_ERROR );
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
Function : WORD sosMIDIAWE32NoteOn
|
|
|
|
Parameters : WORD hDriver
|
|
Handle of SOS driver
|
|
WORD wSlot
|
|
.SBK file slot to associate patch to
|
|
WORD wChannel
|
|
Channel to use
|
|
WORD wPatch
|
|
Patch to use
|
|
WORD wNote
|
|
MIDI relative pitch to use
|
|
WORD wVelocity
|
|
Velocity to use
|
|
|
|
Returns : -1 if error; otherwise, _ERR_NO_ERROR
|
|
|
|
Description : Turn a note on
|
|
|
|
****************************************************************************/
|
|
|
|
WORD sosMIDIAWE32NoteOn( WORD hDriver, WORD wSlot, WORD wChannel,
|
|
WORD wPatch, WORD wNote, WORD wVelocity )
|
|
{
|
|
BYTE szMIDIData[ 0x10 ];
|
|
|
|
// setup the midi data structure to associate a slot to a channel
|
|
szMIDIData[ 0 ] = 0xb0 | wChannel;
|
|
szMIDIData[ 1 ] = 0x00;
|
|
szMIDIData[ 2 ] = wSlot;
|
|
#ifdef BORLAND
|
|
sosMIDISendMIDIData( hDriver, ( PSTR )szMIDIData, 0x03 );
|
|
#else
|
|
sosMIDISendMIDIData( hDriver, ( LPSTR )szMIDIData, 0x03 );
|
|
#endif
|
|
|
|
// select the patch for the channel
|
|
szMIDIData[ 0 ] = 0xc0 | wChannel;
|
|
szMIDIData[ 1 ] = wPatch;
|
|
#ifdef BORLAND
|
|
sosMIDISendMIDIData( hDriver, ( PSTR )szMIDIData, 0x02 );
|
|
#else
|
|
sosMIDISendMIDIData( hDriver, ( LPSTR )szMIDIData, 0x02 );
|
|
#endif
|
|
|
|
// turn the note on with the correct pitch and attack
|
|
szMIDIData[ 0 ] = 0x90 | wChannel;
|
|
szMIDIData[ 1 ] = wNote;
|
|
szMIDIData[ 2 ] = wVelocity;
|
|
#ifdef BORLAND
|
|
sosMIDISendMIDIData( hDriver, ( PSTR )szMIDIData, 0x02 );
|
|
#else
|
|
sosMIDISendMIDIData( hDriver, ( LPSTR )szMIDIData, 0x02 );
|
|
#endif
|
|
|
|
// return no error
|
|
return( _ERR_NO_ERROR );
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
Function : WORD sosMIDIAWE32NoteOff
|
|
|
|
Parameters : WORD hDriver
|
|
Handle of SOS driver
|
|
WORD wChannel
|
|
Channel to use
|
|
WORD wNote
|
|
MIDI relative pitch to use
|
|
|
|
Returns : -1 if error; otherwise, _ERR_NO_ERROR
|
|
|
|
Description : Turn a note on
|
|
|
|
****************************************************************************/
|
|
|
|
WORD sosMIDIAWE32NoteOff( WORD hDriver, WORD wChannel, WORD wNote )
|
|
{
|
|
BYTE szMIDIData[ 0x10 ];
|
|
|
|
// turn the note off
|
|
szMIDIData[ 0 ] = 0x90 | wChannel;
|
|
szMIDIData[ 1 ] = wNote;
|
|
szMIDIData[ 2 ] = 0x00;
|
|
#ifdef BORLAND
|
|
sosMIDISendMIDIData( hDriver, ( PSTR )szMIDIData, 0x03 );
|
|
#else
|
|
sosMIDISendMIDIData( hDriver, ( LPSTR )szMIDIData, 0x03 );
|
|
#endif
|
|
|
|
// return no error
|
|
return( _ERR_NO_ERROR );
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|