#include "mungal4.h" #pragma hdrstop #include "l4audhdw.h" //#if defined(AUDIO_HARDWARE) // #include "sos\bc4\sosmawe.h" //#endif #if defined(TRACE_AUDIO_RENDERER_MIDI) BitTrace Audio_Renderer_MIDI("Audio Renderer MIDI"); #endif //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ MPU Emulation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #define _inp inportb #define _outp outportb #define MPUPort(x) ((x)+mpuAddx) #define SBCPort(x) ((x)+srcAddx) /* DSP defines */ #define MPU_ACK_OK 0xfe #define MPU_RESET_CMD 0xff #define MPU_ENTER_UART 0x3f //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ MIDIMessage ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // //############################################################################# // TestInstance //############################################################################# // Logical MIDIMessage::TestInstance() const { return True; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // std::ostream& operator << ( std::ostream &strm, const MIDIMessage &midi_message ) { Check(&midi_message); strm << "["; strm << (int)(midi_message.message[0] & 0x0F) << ","; strm << (int)(midi_message.message[0] >> 4) << ","; strm << (int)midi_message.message[1] << ","; strm << (int)midi_message.message[2] << "]"; return strm; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ AudioChannel ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // //############################################################################# //############################################################################# // /*AudioChannel::AudioChannel( AudioChannelType audio_channel_type, MIDIChannel midi_channel, AudioCard *audio_card ) { audioChannelType = audio_channel_type; midiChannel = midi_channel; voicesUsed = 0; Check(audio_card); audioCard = audio_card; } // //############################################################################# //############################################################################# // AudioChannel::~AudioChannel() { Verify(voicesUsed == 0); } // //############################################################################# // TestInstance //############################################################################# // Logical AudioChannel::TestInstance() const { Plug::TestInstance(); Verify(voicesUsed >=0 && voicesUsed <= AWE_VOICE_COUNT); Check(audioCard); return True; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ AudioCard ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // //############################################################################# // AudioCard //############################################################################# // AudioCard::AudioCard(): idleChannelSocket(NULL), percussionChannelSocket(NULL) { MIDIChannel channel; idleVoices = AWE_VOICE_COUNT; for (channel = 0; channel < AWE_CHANNEL_COUNT; channel++) { AudioChannel *audio_channel; if (channel == AWE_PERCUSSIVE_CHANNEL) { audio_channel = new AudioChannel( PercussionAudioChannelType, channel, this ); Register_Object(audio_channel); Check(&percussionChannelSocket); percussionChannelSocket.Add(audio_channel); } else { audio_channel = new AudioChannel( InstrumentAudioChannelType, channel, this ); Register_Object(audio_channel); Check(&idleChannelSocket); idleChannelSocket.Add(audio_channel); } } } // //############################################################################# // ~AudioCard //############################################################################# // AudioCard::~AudioCard() { // // Delete the idle channels // { ChainIteratorOf iterator(&idleChannelSocket); Check(&iterator); Verify(idleVoices == AWE_VOICE_COUNT); Verify(iterator.GetSize() == AWE_CHANNEL_COUNT - 1); iterator.DeletePlugs(); } // // Delete the percussive channel // { ChainIteratorOf iterator(&percussionChannelSocket); Check(&iterator); Verify(idleVoices == AWE_VOICE_COUNT); Verify(iterator.GetSize() == 1); iterator.DeletePlugs(); } } // //############################################################################# // TestInstance //############################################################################# // Logical AudioCard::TestInstance() const { Node::TestInstance(); Verify(idleVoices >= 0 && idleVoices <= AWE_VOICE_COUNT); Check(&idleChannelSocket); return True; } // //############################################################################# // Initialize //############################################################################# // void AudioCard::Initialize() { #ifdef AUDIO_HARDWARE Tell("AudioCard::Initialize - Start\n"); WORD wError; // // Set the selector of the pointer to the driver memory for the // MIDI driver to _NULL. this will tell the load driver routine // to allocate new memory for the MIDI driver // #if defined(__BCPLUSPLUS__) sSOSMIDIInitDriver.lpDriverMemory.sel = _NULL; #else sSOSMIDIInitDriver.lpDriverMemory = _NULL; #endif // // Setup the port for the MIDI driver to use // // sSOSMIDIHardware.wPort = _MIDI_DRIVER_PORT; sSOSMIDIHardware.wPort = emuAddx; // // Load and initialize the MIDI driver // wError = sosMIDIInitDriver( _MIDI_DRIVER_TYPE, &sSOSMIDIHardware, &sSOSMIDIInitDriver, &wDriverHandle ); if (wError) { std::cout << sosGetErrorString(wError); Fail("AudioCard::Initialize - sosMIDIInitDriver failed\n"); } Tell("AudioCard::Initialize - Finish\n"); #endif } // //############################################################################# // Close //############################################################################# // void AudioCard::Close() { #ifdef AUDIO_HARDWARE Check(this); sosMIDIAWE32ReleaseSBKFiles(wDriverHandle); // // Reset the midi driver // sosMIDIResetDriver(wDriverHandle); // // Uninitialize the midi driver and tell it to free the memory allocated // for the driver // sosMIDIUnInitDriver(wDriverHandle, _TRUE); #endif } // //############################################################################# // GetEnvironmentSettings //############################################################################# // void AudioCard::GetEnvironmentSettings(char *env_str) { WORD src_addx = 0xffff; WORD irq_interrupt = 0xffff; WORD dma_channel = 0xffff; WORD mpu_addx = 0xffff; WORD emu_addx = 0xffff; const char *sz_blaster; sz_blaster = getenv(env_str); Check_Pointer(sz_blaster); while (*sz_blaster) { if (*sz_blaster == 'a' || *sz_blaster == 'A') { ++sz_blaster; if (*sz_blaster) { if (*sz_blaster == ':') ++sz_blaster; src_addx = GetHexWord(&sz_blaster); } } if (*sz_blaster == 'i' || *sz_blaster == 'I') { ++sz_blaster; if (*sz_blaster) { if (*sz_blaster == ':') ++sz_blaster; irq_interrupt = GetHexWord(&sz_blaster); } } if (*sz_blaster == 'd' || *sz_blaster == 'D') { ++sz_blaster; if (*sz_blaster) { if (*sz_blaster == ':') ++sz_blaster; dma_channel = GetHexWord(&sz_blaster); } } if (*sz_blaster == 'e' || *sz_blaster == 'E') { ++sz_blaster; if (*sz_blaster) { if (*sz_blaster == ':') ++sz_blaster; emu_addx = GetHexWord(&sz_blaster); } } if (*sz_blaster == 'p' || *sz_blaster == 'P') { ++sz_blaster; if (*sz_blaster) { if (*sz_blaster == ':') ++sz_blaster; mpu_addx = GetHexWord(&sz_blaster); } } // // Skip until blank or end of string // while (*sz_blaster && *sz_blaster != ' ') ++sz_blaster; while (*sz_blaster == ' ') ++sz_blaster; } if (emu_addx == 0xffff) emu_addx = (WORD)(src_addx + 0x400); srcAddx = src_addx; irqInterrupt = irq_interrupt; dmaChannel = dma_channel; mpuAddx = mpu_addx; emuAddx = emu_addx; #if DEBUG_LEVEL>0 Tell("AudioCard::GetEnvironmentSettings: " << env_str << "\n"); #if 0 Dump(srcAddx); Dump(irqInterrupt); Dump(dmaChannel); Dump(mpuAddx); Dump(emuAddx); #endif printf(" srcAddx = %x\n", (unsigned)srcAddx); printf(" irqInterrupt = %x\n", (unsigned)irqInterrupt); printf(" dmaChannel = %x\n", (unsigned)dmaChannel); printf(" mpuAddx = %x\n", (unsigned)mpuAddx); printf(" emuAddx = %x\n", (unsigned)emuAddx); #endif } // //############################################################################# // InitMIDIReceive // Initializes Sound Blaster to ready to receive data state. //############################################################################# // Logical AudioCard::InitMIDIReceive() { #if 0 volatile DWORD dwCount; for (dwCount=0; dwCount<0x2000; dwCount++) ; dwCount = 0x2000; while (dwCount && _inp(MPUPort(1)) & 0x40) --dwCount; _outp(MPUPort(1), MPU_RESET_CMD); for (dwCount=0; dwCount<0x2000; dwCount++) ; dwCount = 0x2000; while (dwCount && _inp(MPUPort(1)) & 0x80) --dwCount; _inp(MPUPort(0)); for (dwCount=0; dwCount<0x2000; dwCount++) ; dwCount = 0x2000; while (dwCount && _inp(MPUPort(1)) & 0x40) --dwCount; _outp(MPUPort(1), MPU_RESET_CMD); for (dwCount=0; dwCount<0x2000; dwCount++) ; dwCount = 0x2000; while (dwCount && _inp(MPUPort(1)) & 0x80) --dwCount; _inp(MPUPort(0)); for (dwCount=0; dwCount<0x2000; dwCount++) ; dwCount = 0x2000; while (dwCount && _inp(MPUPort(1)) & 0x40) --dwCount; _outp(MPUPort(1), MPU_ENTER_UART); for (dwCount=0; dwCount<0x2000; dwCount++) ; dwCount = 0x2000; while (dwCount && _inp(MPUPort(1)) & 0x80) --dwCount; if (!dwCount) return True; if (_inp(MPUPort(0)) != MPU_ACK_OK) return True; // mask MPU-401 interrupt _outp(SBCPort(0x4), 0x83); _outp(SBCPort(0x5), _inp(SBCPort(0x5)) & ~0x04); #endif return False; } // //############################################################################# // CloseMIDIReceive //############################################################################# // void AudioCard::CloseMIDIReceive() { #if 0 volatile DWORD dwCount; for (dwCount=0; dwCount<0x2000; dwCount++) ; dwCount = 0x2000; while (dwCount && _inp(MPUPort(1)) & 0x40) --dwCount; _outp(MPUPort(1), MPU_RESET_CMD); for (dwCount=0; dwCount<0x2000; dwCount++) ; _inp(MPUPort(0)); for (dwCount=0; dwCount<0x2000; dwCount++) ; dwCount = 0x2000; while (dwCount && _inp(MPUPort(1)) & 0x40) --dwCount; _outp(MPUPort(1), MPU_RESET_CMD); for (dwCount=0; dwCount<0x2000; dwCount++) ; _inp(MPUPort(0)); #endif } // //############################################################################# // IsMIDIAvailable //############################################################################# // Logical AudioCard::IsMIDIAvailable() { #if 0 return ((_inp(MPUPort(1)) & 0x80) == 0); #endif return False; } // //############################################################################# // GetMIDIByte //############################################################################# // MIDIValue AudioCard::GetMIDIByte() { #if 0 return (_inp(MPUPort(0))); #endif return (MIDIValue)0; } // //############################################################################# // InitializeChannels //############################################################################# // void AudioCard::InitializeChannels() { Check(this); // // Initialize idle channels // { ChainIteratorOf iterator(&idleChannelSocket); AudioChannel *channel; Check(&iterator); Verify(iterator.GetSize() == (AWE_CHANNEL_COUNT-1)); while ((channel = iterator.ReadAndNext()) != NULL) { Check(channel); channel->SendPitchBendRange(MIDI_PITCH_BEND_RANGE); } } // // Initialize percussive channels // { ChainIteratorOf iterator(&percussionChannelSocket); AudioChannel *channel; Check(&iterator); Verify(iterator.GetSize() == 1); channel = iterator.GetCurrent(); Check(channel); channel->SendPitchBendRange(MIDI_PITCH_BEND_RANGE); } } // //############################################################################# // LoadSBK //############################################################################# // int AudioCard::LoadSBK(const char *file_name) { #ifdef AUDIO_HARDWARE Check(this); Check_Pointer(file_name); int ret; Tell("AudioCard::LoadSBK - " << file_name << "\n"); ret = sosMIDIAWE32SetSBKFile(wDriverHandle, file_name); Verify_And_Dump(ret >= 0, ret); Tell("AudioCard::LoadSBK - Finished\n"); return ret; #else return 1; #endif } // //############################################################################# // ReleaseAllBanks //############################################################################# // void AudioCard::ReleaseAllBanks() { #ifdef AUDIO_HARDWARE Check(this); sosMIDIAWE32ReleaseSBKFiles(wDriverHandle); #endif } // //############################################################################# // MIDI methods //############################################################################# // // //############################################################################# //############################################################################# // void AudioCard::SendPitchBend( MIDIChannel channel, MIDIPitchBend pitch_bend ) { MIDIMessage message( MIDI_PITCH_BEND_STATUS, channel, (MIDIValue)((pitch_bend+8192)%128), (MIDIValue)((pitch_bend+8192)/128) ); SendMIDIMessage(&message, 3); } // //############################################################################# //############################################################################# // void AudioCard::SendPitchBendRange( MIDIChannel channel, MIDIValue sensitivity ) { SendController(channel, (MIDIValue)101, (MIDIValue)0); SendController(channel, (MIDIValue)100, (MIDIValue)0); SendController(channel, (MIDIValue)6, sensitivity); } // //############################################################################# //############################################################################# // void AudioCard::SendNRPN( MIDIChannel channel, MIDIValue param_number, MIDINRPNValue value ) { // // Set sound parameter // SendController(channel, (MIDIValue)99, (MIDIValue)127); SendController(channel, (MIDIValue)98, param_number); // // Set parameter value // SendController(channel, (MIDIValue)6, (MIDIValue)((value+8192)/128) ); SendController(channel, (MIDIValue)38, (MIDIValue)((value+8192)%128) ); } // //############################################################################# //############################################################################# // #define SYSEX_MACRO_LENGTH 11 Byte chorus_sysex[SYSEX_MACRO_LENGTH] = { 0xF0, 0x41, 0x10, 0x42, 0x12, 0x40, 0x01, 0x38, 0x00, 0x00, 0xF7 }; Byte reverb_sysex[SYSEX_MACRO_LENGTH] = { 0xF0, 0x41, 0x10, 0x42, 0x12, 0x40, 0x01, 0x30, 0x00, 0x00, 0xF7 }; void AudioCard::SelectEffect( MIDIEffectType type, MIDIValue effect ) { switch (type) { case ChorusMIDIEffectType: chorus_sysex[8] = effect; SendSysex(chorus_sysex, SYSEX_MACRO_LENGTH); break; case ReverbMIDIEffectType: reverb_sysex[8] = effect; SendSysex(reverb_sysex, SYSEX_MACRO_LENGTH); break; } } // //############################################################################# //############################################################################# // void AudioCard::SendSysex( void *data, size_t length ) { #ifdef AUDIO_HARDWARE WORD wError; // // Note - HMI can specify sysex channel via F0, F1, ..., FF // #if defined(__BCPLUSPLUS__) wError = sosMIDISendMIDIData( wDriverHandle, (char*)data, length ); #else wError = sosMIDISendMIDIData( wDriverHandle, (Byte*)data, length ); #endif if (wError != _ERR_NO_ERROR) { Fail("AudioCard::SendSysex - wError != _ERR_NO_ERROR"); } #endif } #if 0 // //############################################################################# //############################################################################# // void AudioCard::SendMIDIMessage(MIDIMessage *midi_message) { #ifdef AUDIO_HARDWARE SET_AUDIO_RENDERER_MIDI(); Check(midi_message); #if 0 long now = Now(); Tell(now << "\t" << (int)srcAddx << "\t" << *midi_message << "\t"); Tell(idleVoices << "\n"); #endif 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: #if DEBUG_LEVEL>0 { Word wError = sosMIDISendMIDIData( wDriverHandle, (char*)midi_message->message, 3 ); Verify(wError == _ERR_NO_ERROR); } #else sosMIDISendMIDIData( wDriverHandle, (char*)midi_message->message, 3 ); #endif break; case MIDI_PROGRAM_CHANGE_STATUS: case MIDI_CHANNEL_PRESSURE_STATUS: #if DEBUG_LEVEL>0 { Word wError = sosMIDISendMIDIData( wDriverHandle, (char*)midi_message->message, 2 ); Verify(wError == _ERR_NO_ERROR); } #else sosMIDISendMIDIData( wDriverHandle, (char*)midi_message->message, 2 ); #endif break; default: // // Should never reach here // Fail("Should never reach here"); break; } CLEAR_AUDIO_RENDERER_MIDI(); #endif } #endif // //############################################################################# // Channel methods //############################################################################# // // //############################################################################# //############################################################################# // AudioChannel* AudioCard::RequestAudioChannel(AudioVoiceCount voice_count) { Check(this); // // Monitor resource usage // #if 0 #if DEBUG_LEVEL>0 { ChainIteratorOf iterator(&idleChannelSocket); if (voice_count > idleVoices || iterator.GetSize() == 0) { Tell("RequestAudioChannel - voices: " << idleVoices); Tell(" channels: " << iterator.GetSize()); Tell("\n"); } } #endif #endif // // Are there enough voices to allocate // if (voice_count > idleVoices) return NULL; // // Allocate a channel // ChainIteratorOf iterator(&idleChannelSocket); AudioChannel *audio_channel; Check(&iterator); if ((audio_channel = iterator.GetCurrent()) != NULL) { Check(audio_channel); iterator.Remove(); idleVoices -= voice_count; audio_channel->SetVoicesUsed(voice_count); return audio_channel; } return NULL; } // //############################################################################# //############################################################################# // void AudioCard::ReleaseAudioChannel(AudioChannel *audio_channel) { Check(this); Check(audio_channel); #if 0 Tell("AudioCard::ReleaseAudioChannel - Released channel\n"); Tell(" "); Dump((int)audio_channel->GetChannelNumber()); #endif // // Add to idle list // idleVoices += audio_channel->GetVoicesUsed(); Verify(idleVoices > 0 && idleVoices <= AWE_VOICE_COUNT); audio_channel->SetVoicesUsed(0); idleChannelSocket.Add(audio_channel); } // //############################################################################# // GetHexWord //############################################################################# // WORD AudioCard::GetHexWord(const char ** s) { WORD n = 0; while (**s) { if (**s >= '0' && **s <= '9') n = (WORD)(n * 16 + (*(*s)++ - '0')); else if (**s >= 'a' && **s <= 'f') n = (WORD)(n * 16 + (*(*s)++ - 'a') + 10); else if (**s >= 'A' && **s <= 'F') n = (WORD)(n * 16 + (*(*s)++ - 'A') + 10); else break; } return n; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ AudioHardware ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // //############################################################################# // AudioHardware //############################################################################# // AudioHardware::AudioHardware() { } // //############################################################################# // ~AudioHardware //############################################################################# // AudioHardware::~AudioHardware() { } // //############################################################################# // TestInstance //############################################################################# // Logical AudioHardware::TestInstance() const { Node::TestInstance(); Check(&frontCard); Check(&rearCard); return True; } // //############################################################################# // Initialize //############################################################################# // void AudioHardware::Initialize() { #ifdef AUDIO_HARDWARE Tell("AudioHardware::Initialize - Start\n"); #if 0 // // initialize the TIMER system and tell it to call the DOS timer // at a rate of 19 times/second. the actual rate is 18.2, but // 19 is a good approximation. // if (getenv(TIMER_ENV) == NULL) // L4Time is not setting up timer { sosTIMERInitSystem(_TIMER_DOS_RATE, _SOS_DEBUG_NORMAL); } #endif // // initialize the MIDI system // sosMIDIInitSystem((PSTR)_SOS_DRIVER_PATH, _SOS_DEBUG_NORMAL); // // initialize the cards // frontCard.GetEnvironmentSettings(FRONT_CARD_ENV_VAR); rearCard.GetEnvironmentSettings(REAR_CARD_ENV_VAR); frontCard.Initialize(); rearCard.Initialize(); // // Setup standard channel attributes // frontCard.InitializeChannels(); rearCard.InitializeChannels(); Tell("AudioHardware::Initialize - Finish\n"); #endif } // //############################################################################# // Close //############################################################################# // void AudioHardware::Close() { #ifdef AUDIO_HARDWARE Check(this); // // Close the cards // frontCard.Close(); rearCard.Close(); #if 0 // // Uninitialize the TIMER system and pass it the value to write to the // timer chip to reset the timer, 0 is equivalent to 18.2 times/second // which is the DOS clock rate. the calculation for the value to pass // is 1193180/RATE. // if (getenv(TIMER_ENV) == NULL) // L4Time is not setting up timer { sosTIMERUnInitSystem(0); } sosTIMERUnInitSystem(0); #endif // // Uninitialize the MIDI system // sosMIDIUnInitSystem(); #endif }*/ #ifdef TEST_CLASS # include "l4audhdw.tcp" #endif