--- linuxsampler/trunk/src/drivers/midi/MidiInputPort.cpp 2005/02/26 02:01:14 411 +++ linuxsampler/trunk/src/drivers/midi/MidiInputPort.cpp 2005/09/21 14:30:43 775 @@ -23,6 +23,9 @@ #include "MidiInputPort.h" +#include "../../Sampler.h" +#include "../../engines/EngineFactory.h" + namespace LinuxSampler { // *************** ParameterName *************** @@ -70,6 +73,7 @@ this->pDevice = pDevice; this->portNumber = portNumber; Parameters["NAME"] = new ParameterName(this); + pPreviousProgramChangeEngineChannel = NULL; } MidiInputDevice* MidiInputPort::GetDevice() { @@ -145,40 +149,84 @@ } void MidiInputPort::DispatchSysex(void* pData, uint Size) { - // dispatch event for engines listening to the same MIDI channel - { - for (uint MidiChannel = 0; MidiChannel <= 16; MidiChannel++) { - std::set::iterator engineiter = MidiChannelMap[MidiChannel].begin(); - std::set::iterator end = MidiChannelMap[MidiChannel].end(); - for (; engineiter != end; engineiter++) { - Engine* pEngine = (*engineiter)->GetEngine(); - if (pEngine) pEngine->SendSysex(pData, Size); - } - } + // dispatch event to all engine instances + std::set::iterator engineiter = EngineFactory::EngineInstances().begin(); + std::set::iterator end = EngineFactory::EngineInstances().end(); + for (; engineiter != end; engineiter++) (*engineiter)->SendSysex(pData, Size); + } + + void MidiInputPort::DispatchProgramChange(uint8_t Program, uint MidiChannel) { + if (!pDevice || !pDevice->pSampler) { + std::cerr << "MidiInputPort: ERROR, no sampler instance to handle program change." + << "This is a bug, please report it!\n" << std::flush; + return; } - // dispatch event for engines listening to ALL MIDI channels - { - for (uint MidiChannel = 0; MidiChannel <= 16; MidiChannel++) { - std::set::iterator engineiter = MidiChannelMap[midi_chan_all].begin(); - std::set::iterator end = MidiChannelMap[midi_chan_all].end(); - for (; engineiter != end; engineiter++) { - Engine* pEngine = (*engineiter)->GetEngine(); - if (pEngine) pEngine->SendSysex(pData, Size); - } - } + + Sampler* pSampler = (Sampler*) pDevice->pSampler; + SamplerChannel* pSamplerChannel = pSampler->GetSamplerChannel(Program); + if (!pSamplerChannel) return; + + EngineChannel* pEngineChannel = pSamplerChannel->GetEngineChannel(); + if (!pEngineChannel) return; + + // disconnect from the engine channel which was connected by the last PC event + if (pPreviousProgramChangeEngineChannel) + Disconnect(pPreviousProgramChangeEngineChannel); + + // now connect to the new engine channel and remember it + try { + Connect(pEngineChannel, (midi_chan_t) MidiChannel); + pPreviousProgramChangeEngineChannel = pEngineChannel; } + catch (...) { /* NOOP */ } } void MidiInputPort::Connect(EngineChannel* pEngineChannel, midi_chan_t MidiChannel) { if (MidiChannel < 0 || MidiChannel > 16) throw MidiInputException("MIDI channel index out of bounds"); + + // firt check if desired connection is already established + MidiChannelMapMutex.Lock(); + bool bAlreadyDone = MidiChannelMap[MidiChannel].count(pEngineChannel); + MidiChannelMapMutex.Unlock(); + if (bAlreadyDone) return; + + // remove all other connections of that engine channel (if any) Disconnect(pEngineChannel); + + // register engine channel on the desired MIDI channel + MidiChannelMapMutex.Lock(); MidiChannelMap[MidiChannel].insert(pEngineChannel); + MidiChannelMapMutex.Unlock(); + + // inform engine channel about this connection + pEngineChannel->Connect(this, MidiChannel); + + // mark engine channel as changed + pEngineChannel->StatusChanged(true); } void MidiInputPort::Disconnect(EngineChannel* pEngineChannel) { - try { for (int i = 0; i <= 16; i++) MidiChannelMap[i].erase(pEngineChannel); } + if (!pEngineChannel) return; + + bool bChannelFound = false; + + // unregister engine channel from all MIDI channels + MidiChannelMapMutex.Lock(); + try { + for (int i = 0; i <= 16; i++) { + bChannelFound |= MidiChannelMap[i].count(pEngineChannel); + MidiChannelMap[i].erase(pEngineChannel); + } + } catch(...) { /* NOOP */ } + MidiChannelMapMutex.Unlock(); + + // inform engine channel about the disconnection (if there is one) + if (bChannelFound) pEngineChannel->DisconnectMidiInputPort(); + + // mark engine channel as changed + pEngineChannel->StatusChanged(true); } } // namespace LinuxSampler