Files
arcattackandClaude Opus 4.8 7b7d465e5e Initial commit: bt411 -- standalone Windows BattleTech (Tesla 4.10 port)
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>
2026-07-05 21:03:40 -05:00

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 );
}