Files
CydandClaude Fable 5 fdd9ac9d97 Initial import: Tesla Release 4.10 (Tesla:BattleTech & Tesla:Red Planet)
Archival snapshot of the Virtual World Entertainment Tesla cockpit
software, 1994-1996: MUNGA engine and L4 pod layer source (Borland
C++ 5.0), BT/RP game code, and game content (models, audio, maps,
gauges, Division renderer data). Includes third-party libraries:
Division dVS/DPL graphics, HMI SOS audio, WATTCP networking.

Files are preserved byte-for-byte (.gitattributes disables all
line-ending conversion). README.md documents the layout, target
hardware, and toolchain.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-02 13:21:58 -05:00

822 lines
18 KiB
C++

//===========================================================================//
// File: l4audhdw.hh //
// Project: MUNGA Brick: Audio Manager //
// Contents: Spec for audio manager //
//---------------------------------------------------------------------------//
// Date Who Modification //
// -------- --- ---------------------------------------------------------- //
// 01/25/95 ECH Initial coding. //
//---------------------------------------------------------------------------//
// Copyright (C) 1994, Virtual World Entertainment, Inc. //
// All Rights reserved worldwide //
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL //
//===========================================================================//
#if !defined(L4AUDHDW_HPP)
# define L4AUDHDW_HPP
# define AUDIO_HARDWARE
# if !defined(STYLE_HPP)
# include <style.hpp>
# endif
# ifdef AUDIO_HARDWARE
# ifndef _SOS_MIDI_DEFINED
# include <sosm.h>
# endif
# else
typedef Byte BYTE;
typedef Word WORD;
# endif
# if !defined(NODE_HPP)
# include <node.hpp>
# endif
# if !defined(SCHAIN_HPP)
# include <schain.hpp>
# endif
# if !defined(AUDIO_HPP)
# include <audio.hpp>
# endif
#if defined(TRACE_AUDIO_RENDERER_MIDI)
extern BitTrace Audio_Renderer_MIDI("Audio Renderer MIDI");
#define SET_AUDIO_RENDERER_MIDI() Audio_Renderer_MIDI.Set()
#define CLEAR_AUDIO_RENDERER_MIDI() Audio_Renderer_MIDI.Clear()
#else
#define SET_AUDIO_RENDERER_MIDI()
#define CLEAR_AUDIO_RENDERER_MIDI()
#endif
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ MIDI types ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
typedef unsigned char MIDIStatus;
typedef unsigned char MIDIChannel;
typedef unsigned char MIDIValue;
typedef int MIDIPitchBend;
typedef int MIDINRPNValue;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~ MIDI status ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#define MIDI_CHANNEL_COUNT (16)
#define MIDI_NOTE_OFF_STATUS ((MIDIValue)0x8) // 8
#define MIDI_NOTE_ON_STATUS ((MIDIValue)0x9) // 9
#define MIDI_POLYKEY_STATUS ((MIDIValue)0xa) // 10
#define MIDI_CONTROLLER_STATUS ((MIDIValue)0xb) // 11
#define MIDI_PROGRAM_CHANGE_STATUS ((MIDIValue)0xc) // 12
#define MIDI_CHANNEL_PRESSURE_STATUS ((MIDIValue)0xd) // 13
#define MIDI_PITCH_BEND_STATUS ((MIDIValue)0xe) // 14
//~~~~~~~~~~~~~~~~~~~~~~~~~~ MIDI controllers ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#define MIDI_MAX_CONTROL_VALUE ((MIDIValue)127)
#define MIDI_MIN_CONTROL_VALUE ((MIDIValue)0)
#define MIDI_LEFT_PAN_VALUE ((MIDIValue)0)
#define MIDI_CENTER_PAN_VALUE ((MIDIValue)63)
#define MIDI_RIGHT_PAN_VALUE ((MIDIValue)127)
#define MIDI_VOLUME_CONTROL ((MIDIValue)7)
#define MIDI_PAN_CONTROL ((MIDIValue)10)
#define MIDI_REVERB_CONTROL ((MIDIValue)91)
#define MIDI_CHORUS_CONTROL ((MIDIValue)93)
#define MIDI_CONTROL_RESET ((MIDIValue)121)
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ MIDI notes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#define MIDI_DEFAULT_NOTE ((MIDIValue)60)
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ MIDI pitch ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#define MIDI_PITCH_BEND_MAX ((MIDIPitchBend)8191)
#define MIDI_PITCH_BEND_RANGE ((MIDIValue)24)
#define MIDI_PITCH_BEND_CENTS (24*100)
#define MIDI_PITCH_PER_CENTS ((Scalar)MIDI_PITCH_BEND_MAX / \
(Scalar)MIDI_PITCH_BEND_CENTS)
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ AWE NRPN ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#define AWE_VOL_ATTACK_TIME_NRPN ((MIDIValue)11)
#define AWE_PITCH_NRPN ((MIDIValue)16)
#define AWE_FILTER_CUTOFF_NRPN ((MIDIValue)21)
#define AWE_VOL_ATTACK_TIME_RANGE ((MIDINRPNValue)5940) // 0...5.9 secs
#define AWE_FILTER_CUTOFF_RANGE ((MIDINRPNValue)127) // 100...8000 Hz
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~ AWE effects ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
typedef enum {
ChorusMIDIEffectType,
ReverbMIDIEffectType
} MIDIEffectType;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~ AWE resources ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#define AWE_VOICE_COUNT (32)
#define AWE_CHANNEL_COUNT (16)
#define AWE_PERCUSSIVE_CHANNEL (9)
//
// Driver type to use
//
#define _MIDI_DRIVER_TYPE _MIDI_AWE32
//
// Path to the driver file
//
#define _SOS_DRIVER_PATH _NULL
//
// AWE environment variables
//
#define FRONT_CARD_ENV_VAR "AWE_FRONT"
#define REAR_CARD_ENV_VAR "AWE_REAR"
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ MIDIMessage ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#define MIDI_MESSAGE_SIZE (3)
class MIDIMessage SIGNATURED
{
friend class AudioCard;
friend ostream&
operator << (
ostream &strm,
const MIDIMessage &midi_message
);
public:
MIDIMessage(
MIDIStatus status,
MIDIChannel channel,
MIDIValue byte1,
MIDIValue byte2 = 0
);
~MIDIMessage() {}
Logical
TestInstance() const;
private:
MIDIValue
message[MIDI_MESSAGE_SIZE];
};
inline MIDIMessage::MIDIMessage(
MIDIStatus status,
MIDIChannel channel,
MIDIValue byte1,
MIDIValue byte2
)
{
message[0] = (MIDIValue)((status << 4) | channel);
message[1] = byte1;
message[2] = byte2;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ AudioChannel ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
typedef enum
{
InstrumentAudioChannelType = 0,
PercussionAudioChannelType
} AudioChannelType;
class AudioCard;
class AudioChannel:
public Plug
{
public:
//
//--------------------------------------------------------------------
// Constructor, Destructor, Testing
//--------------------------------------------------------------------
//
AudioChannel(
AudioChannelType audio_channel_type,
MIDIChannel midi_channel,
AudioCard *audio_card
);
~AudioChannel();
Logical
TestInstance() const;
//
//--------------------------------------------------------------------
// Accessors
//--------------------------------------------------------------------
//
AudioChannelType
GetAudioChannelType()
{return audioChannelType;}
MIDIChannel
GetChannelNumber()
{return midiChannel;}
void
SetVoicesUsed(AudioVoiceCount voices_used)
{voicesUsed = voices_used;}
AudioVoiceCount
GetVoicesUsed()
{return voicesUsed;}
//
//--------------------------------------------------------------------
// MIDI methods
//--------------------------------------------------------------------
//
void
SendNoteOn(
MIDIValue key,
MIDIValue velocity
);
void
SendNoteOff(
MIDIValue key,
MIDIValue velocity
);
void
SendProgramChange(
MIDIValue program
);
void
SendController(
MIDIValue controller,
MIDIValue value
);
void
SendPolyKeyPressure(
MIDIValue key,
MIDIValue value
);
void
SendChannelPressure(
MIDIValue value
);
void
SendPitchBend(
MIDIPitchBend pitch_bend
);
void
SendPitchBendRange(
MIDIValue sensitivity
);
void
SendNRPN(
MIDIValue paramNumber,
MIDINRPNValue value
);
void
SelectEffect(
MIDIEffectType type,
MIDIValue effect
);
void
SelectBank(
MIDIValue bank
);
//
//--------------------------------------------------------------------
// Release
//--------------------------------------------------------------------
//
void
Release();
private:
//
//--------------------------------------------------------------------
// Private data
//--------------------------------------------------------------------
//
AudioChannelType
audioChannelType;
MIDIChannel
midiChannel;
AudioVoiceCount
voicesUsed;
AudioCard
*audioCard;
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ AudioCard ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class AudioCard:
public Node
{
friend class AudioHardware;
public:
//
//--------------------------------------------------------------------
// Constructor, Destructor, Testing
//--------------------------------------------------------------------
//
AudioCard();
~AudioCard();
Logical
TestInstance() const;
//
//--------------------------------------------------------------------
// Public methods
//--------------------------------------------------------------------
//
void
Initialize();
void
Close();
void
GetEnvironmentSettings(char *env_str);
Logical
InitMIDIReceive();
void
CloseMIDIReceive();
Logical
IsMIDIAvailable();
MIDIValue
GetMIDIByte();
void
InitializeChannels();
int
LoadSBK(const char *file_name);
void
ReleaseAllBanks();
//
//--------------------------------------------------------------------
// MIDI methods
//--------------------------------------------------------------------
//
void
SendNoteOn(
MIDIChannel channel,
MIDIValue key,
MIDIValue velocity
);
void
SendNoteOff(
MIDIChannel channel,
MIDIValue key,
MIDIValue velocity
);
void
SendProgramChange(
MIDIChannel channel,
MIDIValue program
);
void
SendController(
MIDIChannel channel,
MIDIValue controller,
MIDIValue value
);
void
SendPolyKeyPressure(
MIDIChannel channel,
MIDIValue key,
MIDIValue value
);
void
SendChannelPressure(
MIDIChannel channel,
MIDIValue value
);
void
SendPitchBendRange(
MIDIChannel channel,
MIDIValue sensitivity
);
void
SendPitchBend(
MIDIChannel channel,
MIDIPitchBend pitch_bend
);
void
SendSysex(
void *data,
size_t length
);
void
SendNRPN(
MIDIChannel channel,
MIDIValue paramNumber,
MIDINRPNValue value
);
void
SelectEffect(
MIDIEffectType type,
MIDIValue effect
);
void
SelectBank(
MIDIChannel channel,
MIDIValue bank
);
void
SendMIDIMessage(
MIDIMessage *midi_message,
Word length
);
//
//--------------------------------------------------------------------
// Channel methods
//--------------------------------------------------------------------
//
AudioChannel*
RequestAudioChannel(AudioVoiceCount voice_count);
void
ReleaseAudioChannel(AudioChannel *audio_channel);
private:
//
//--------------------------------------------------------------------
// Private methods
//--------------------------------------------------------------------
//
WORD
GetHexWord(const char ** s);
//
//--------------------------------------------------------------------
// Private data
//--------------------------------------------------------------------
//
//
// Card addresses
//
WORD srcAddx;
WORD irqInterrupt;
WORD dmaChannel;
WORD mpuAddx;
WORD emuAddx;
//
// Structure for the MIDI driver initialization function
// Structure for the MIDI driver hardware
//
#ifdef AUDIO_HARDWARE
_SOS_MIDI_INIT_DRIVER sSOSMIDIInitDriver;
_SOS_MIDI_HARDWARE sSOSMIDIHardware;
#endif
//
// Handle for the loaded MIDI driver
//
WORD wDriverHandle;
//
// Number of free voices
//
AudioVoiceCount
idleVoices;
//
// Idle channels
//
ChainOf<AudioChannel*>
idleChannelSocket;
ChainOf<AudioChannel*>
percussionChannelSocket;
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ AudioHardware ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class AudioHardware:
public Node
{
public:
//
//--------------------------------------------------------------------
// Constructor, Destructor, Testing
//--------------------------------------------------------------------
//
AudioHardware();
~AudioHardware();
Logical
TestInstance() const;
static Logical
TestClass();
static Logical
ProfileClass();
//
//--------------------------------------------------------------------
// Public methods
//--------------------------------------------------------------------
//
void
Initialize();
void
Close();
//
//--------------------------------------------------------------------
// Card Access
//--------------------------------------------------------------------
//
AudioCard*
GetFrontCard();
AudioCard*
GetRearCard();
private:
//
//--------------------------------------------------------------------
// Private methods
//--------------------------------------------------------------------
//
//
//--------------------------------------------------------------------
// Private data
//--------------------------------------------------------------------
//
AudioCard
frontCard;
AudioCard
rearCard;
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~ AudioCard inlines ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
inline void
AudioCard::SendMIDIMessage(
MIDIMessage *midi_message,
Word length
)
{
#ifdef AUDIO_HARDWARE
SET_AUDIO_RENDERER_MIDI();
Check_Signature(midi_message);
#if DEBUG_LEVEL>0
switch (midi_message->message[0] >> 4)
{
case MIDI_NOTE_ON_STATUS:
case MIDI_NOTE_OFF_STATUS:
case MIDI_POLYKEY_STATUS:
case MIDI_CONTROLLER_STATUS:
case MIDI_PITCH_BEND_STATUS:
Verify(length == 3);
break;
case MIDI_PROGRAM_CHANGE_STATUS:
case MIDI_CHANNEL_PRESSURE_STATUS:
Verify(length == 2);
break;
default:
Fail("Should never reach here");
break;
}
#endif
#if DEBUG_LEVEL>0
{
Word wError = sosMIDISendMIDIData(
wDriverHandle,
(char*)midi_message->message,
length
);
Verify(wError == _ERR_NO_ERROR);
}
#else
sosMIDISendMIDIData(
wDriverHandle,
(char*)midi_message->message,
length
);
#endif
CLEAR_AUDIO_RENDERER_MIDI();
#endif
}
//
//--------------------------------------------------------------------
// MIDI methods
//--------------------------------------------------------------------
//
inline void
AudioCard::SendNoteOn(
MIDIChannel channel,
MIDIValue key,
MIDIValue velocity
)
{
MIDIMessage message(MIDI_NOTE_ON_STATUS, channel, key, velocity);
SendMIDIMessage(&message, 3);
}
inline void
AudioCard::SendNoteOff(
MIDIChannel channel,
MIDIValue key,
MIDIValue velocity
)
{
MIDIMessage message(MIDI_NOTE_OFF_STATUS, channel, key, velocity);
SendMIDIMessage(&message, 3);
}
inline void
AudioCard::SendProgramChange(
MIDIChannel channel,
MIDIValue program
)
{
MIDIMessage message(MIDI_PROGRAM_CHANGE_STATUS, channel, program);
SendMIDIMessage(&message, 2);
}
inline void
AudioCard::SendController(
MIDIChannel channel,
MIDIValue controller,
MIDIValue value
)
{
MIDIMessage message(MIDI_CONTROLLER_STATUS, channel, controller, value);
SendMIDIMessage(&message, 3);
}
inline void
AudioCard::SendPolyKeyPressure(
MIDIChannel channel,
MIDIValue key,
MIDIValue value
)
{
MIDIMessage message(MIDI_POLYKEY_STATUS, channel, key, value);
SendMIDIMessage(&message, 3);
}
inline void
AudioCard::SendChannelPressure(
MIDIChannel channel,
MIDIValue value
)
{
MIDIMessage message(MIDI_CHANNEL_PRESSURE_STATUS, channel, value);
SendMIDIMessage(&message, 2);
}
inline void
AudioCard::SelectBank(
MIDIChannel channel,
MIDIValue bank
)
{
SendController(channel, (MIDIValue)0, bank);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~ AudioChannel inlines ~~~~~~~~~~~~~~~~~~~~~~~~~~
//
//--------------------------------------------------------------------
// MIDI methods
//--------------------------------------------------------------------
//
inline void
AudioChannel::SendNoteOn(
MIDIValue key,
MIDIValue velocity
)
{
Check(audioCard);
audioCard->SendNoteOn(midiChannel,key,velocity);
}
inline void
AudioChannel::SendNoteOff(
MIDIValue key,
MIDIValue velocity
)
{
Check(audioCard);
audioCard->SendNoteOff(midiChannel,key,velocity);
}
inline void
AudioChannel::SendProgramChange(
MIDIValue program
)
{
Check(audioCard);
audioCard->SendProgramChange(midiChannel,program);
}
inline void
AudioChannel::SendController(
MIDIValue controller,
MIDIValue value
)
{
Check(audioCard);
audioCard->SendController(midiChannel,controller,value);
}
inline void
AudioChannel::SendPolyKeyPressure(
MIDIValue key,
MIDIValue value
)
{
Check(audioCard);
audioCard->SendPolyKeyPressure(midiChannel,key,value);
}
inline void
AudioChannel::SendChannelPressure(
MIDIValue value
)
{
Check(audioCard);
audioCard->SendChannelPressure(midiChannel,value);
}
inline void
AudioChannel::SendPitchBend(
MIDIPitchBend pitch_bend
)
{
Check(audioCard);
audioCard->SendPitchBend(midiChannel,pitch_bend);
}
inline void
AudioChannel::SendPitchBendRange(
MIDIValue sensitivity
)
{
Check(audioCard);
audioCard->SendPitchBendRange(midiChannel,sensitivity);
}
inline void
AudioChannel::SelectEffect(
MIDIEffectType type,
MIDIValue effect
)
{
Check(audioCard);
audioCard->SelectEffect(type,effect);
}
inline void
AudioChannel::SendNRPN(
MIDIValue paramNumber,
MIDINRPNValue value
)
{
Check(audioCard);
audioCard->SendNRPN(midiChannel,paramNumber,value);
}
inline void
AudioChannel::SelectBank(
MIDIValue bank
)
{
Check(audioCard);
audioCard->SelectBank(midiChannel,bank);
}
inline void
AudioChannel::Release()
{
Check(audioCard);
audioCard->ReleaseAudioChannel(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~ AudioHardware inlines ~~~~~~~~~~~~~~~~~~~~~~~~~~
inline AudioCard*
AudioHardware::GetFrontCard()
{
Check(this);
return &frontCard;
}
inline AudioCard*
AudioHardware::GetRearCard()
{
Check(this);
return &rearCard;
}
#endif