//===========================================================================// // 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 # endif # ifdef AUDIO_HARDWARE # ifndef _SOS_MIDI_DEFINED # include # endif # else typedef Byte BYTE; typedef Word WORD; # endif # if !defined(NODE_HPP) # include # endif # if !defined(SCHAIN_HPP) # include # endif # if !defined(AUDIO_HPP) # include # 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 idleChannelSocket; ChainOf 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