--- linuxsampler/trunk/src/engines/EngineChannel.cpp 2008/11/01 19:01:27 1789 +++ linuxsampler/trunk/src/engines/EngineChannel.cpp 2010/09/14 17:09:08 2121 @@ -3,7 +3,7 @@ * LinuxSampler - modular, streaming capable sampler * * * * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck * - * Copyright (C) 2005 - 2007 Christian Schoenebeck * + * Copyright (C) 2005 - 20010 Christian Schoenebeck * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * @@ -28,48 +28,78 @@ #include "../Sampler.h" #include "../common/global_private.h" #include "../drivers/midi/MidiInstrumentMapper.h" +#include "../common/atomic.h" #define NO_MIDI_INSTRUMENT_MAP -1 #define DEFAULT_MIDI_INSTRUMENT_MAP -2 namespace LinuxSampler { - EngineChannel::EngineChannel() { - iMute = 0; - bSolo = false; - uiMidiBankMsb = 0; - uiMidiBankLsb = 0; - uiMidiProgram = 0; - bProgramChangeReceived = bMidiBankMsbReceived = bMidiBankLsbReceived = false; - iMidiInstrumentMap = NO_MIDI_INSTRUMENT_MAP; + struct EngineChannel::private_data_t { + int iMute; + bool bSolo; + uint8_t uiMidiProgram; + uint8_t uiMidiBankMsb; + uint8_t uiMidiBankLsb; + uint8_t uiMidiRpnMsb; ///< MIDI Registered Parameter Number (upper 8 bits / coarse) + uint8_t uiMidiRpnLsb; ///< MIDI Registered Parameter Number (lower 8 bits / fine) + uint8_t uiMidiNrpnMsb; ///< MIDI Non-Registered Parameter Number (upper 8 bits / coarse) + uint8_t uiMidiNrpnLsb; ///< MIDI Non-Registered Parameter Number (lower 8 bits / fine) + bool bMidiBankMsbReceived; + bool bMidiBankLsbReceived; + bool bProgramChangeReceived; + bool bMidiRpnReceived; + bool bMidiNrpnReceived; + int iMidiInstrumentMap; + atomic_t voiceCount; + atomic_t diskStreamCount; + SamplerChannel* pSamplerChannel; + ListenerList llFxSendCountListeners; + }; + + EngineChannel::EngineChannel() : p(new private_data_t) { + p->iMute = 0; + p->bSolo = false; + p->uiMidiBankMsb = 0; + p->uiMidiBankLsb = 0; + p->uiMidiProgram = 0; + p->bProgramChangeReceived = + p->bMidiBankMsbReceived = + p->bMidiBankLsbReceived = false; + p->iMidiInstrumentMap = NO_MIDI_INSTRUMENT_MAP; SetVoiceCount(0); SetDiskStreamCount(0); - pSamplerChannel = NULL; + p->pSamplerChannel = NULL; ResetMidiRpnController(); + ResetMidiNrpnController(); + } + + EngineChannel::~EngineChannel() { + delete p; } void EngineChannel::SetMute(int state) throw (Exception) { - if(iMute == state) return; - if(state < -1 || state > 1) + if (p->iMute == state) return; + if (state < -1 || state > 1) throw Exception("Invalid Mute state: " + ToString(state)); - iMute = state; + p->iMute = state; StatusChanged(true); } int EngineChannel::GetMute() { - return iMute; + return p->iMute; } void EngineChannel::SetSolo(bool solo) { - if(bSolo == solo) return; - bSolo = solo; + if (p->bSolo == solo) return; + p->bSolo = solo; StatusChanged(true); } bool EngineChannel::GetSolo() { - return bSolo; + return p->bSolo; } /* @@ -91,46 +121,51 @@ */ uint8_t EngineChannel::GetMidiProgram() { - return uiMidiProgram; // AFAIK atomic on all systems + return p->uiMidiProgram; // AFAIK atomic on all systems } void EngineChannel::SetMidiProgram(uint8_t Program) { - bProgramChangeReceived = true; - uiMidiProgram = Program; // AFAIK atomic on all systems + p->bProgramChangeReceived = true; + p->uiMidiProgram = Program; // AFAIK atomic on all systems } uint8_t EngineChannel::GetMidiBankMsb() { - return (bMidiBankMsbReceived && bMidiBankLsbReceived) ? uiMidiBankMsb : 0; + return (p->bMidiBankMsbReceived && p->bMidiBankLsbReceived) + ? p->uiMidiBankMsb : 0; } void EngineChannel::SetMidiBankMsb(uint8_t BankMSB) { - if (bProgramChangeReceived) - bProgramChangeReceived = bMidiBankLsbReceived = false; - bMidiBankMsbReceived = true; - uiMidiBankMsb = BankMSB; // AFAIK atomic on all systems + if (p->bProgramChangeReceived) { + p->bProgramChangeReceived = + p->bMidiBankLsbReceived = false; + } + p->bMidiBankMsbReceived = true; + p->uiMidiBankMsb = BankMSB; // AFAIK atomic on all systems } uint8_t EngineChannel::GetMidiBankLsb() { - return (!bMidiBankMsbReceived && !bMidiBankLsbReceived) + return (!p->bMidiBankMsbReceived && !p->bMidiBankLsbReceived) ? 0 - : (bMidiBankMsbReceived && !bMidiBankLsbReceived) - ? uiMidiBankMsb - : uiMidiBankLsb; + : (p->bMidiBankMsbReceived && !p->bMidiBankLsbReceived) + ? p->uiMidiBankMsb + : p->uiMidiBankLsb; } void EngineChannel::SetMidiBankLsb(uint8_t BankLSB) { - if (bProgramChangeReceived) - bProgramChangeReceived = bMidiBankMsbReceived = false; - bMidiBankLsbReceived = true; - uiMidiBankLsb = BankLSB; // AFAIK atomic on all systems + if (p->bProgramChangeReceived) { + p->bProgramChangeReceived = + p->bMidiBankMsbReceived = false; + } + p->bMidiBankLsbReceived = true; + p->uiMidiBankLsb = BankLSB; // AFAIK atomic on all systems } bool EngineChannel::UsesNoMidiInstrumentMap() { - return (iMidiInstrumentMap == NO_MIDI_INSTRUMENT_MAP); + return (p->iMidiInstrumentMap == NO_MIDI_INSTRUMENT_MAP); } bool EngineChannel::UsesDefaultMidiInstrumentMap() { - return (iMidiInstrumentMap == DEFAULT_MIDI_INSTRUMENT_MAP); + return (p->iMidiInstrumentMap == DEFAULT_MIDI_INSTRUMENT_MAP); } int EngineChannel::GetMidiInstrumentMap() throw (Exception) { @@ -140,81 +175,106 @@ throw Exception("EngineChannel is using default MIDI instrument map"); // check if the stored map still exists in the MIDI instrument mapper std::vector maps = MidiInstrumentMapper::Maps(); - if (find(maps.begin(), maps.end(), iMidiInstrumentMap) == maps.end()) { + if (find(maps.begin(), maps.end(), p->iMidiInstrumentMap) == maps.end()) { // it doesn't exist anymore, so fall back to NONE and throw an exception - iMidiInstrumentMap = NO_MIDI_INSTRUMENT_MAP; + p->iMidiInstrumentMap = NO_MIDI_INSTRUMENT_MAP; throw Exception("Assigned MIDI instrument map doesn't exist anymore, falling back to NONE"); } - return iMidiInstrumentMap; + return p->iMidiInstrumentMap; } void EngineChannel::SetMidiInstrumentMapToNone() { - if (iMidiInstrumentMap == NO_MIDI_INSTRUMENT_MAP) return; - iMidiInstrumentMap = NO_MIDI_INSTRUMENT_MAP; + if (p->iMidiInstrumentMap == NO_MIDI_INSTRUMENT_MAP) return; + p->iMidiInstrumentMap = NO_MIDI_INSTRUMENT_MAP; StatusChanged(true); } void EngineChannel::SetMidiInstrumentMapToDefault() { - if (iMidiInstrumentMap == DEFAULT_MIDI_INSTRUMENT_MAP) return; - iMidiInstrumentMap = DEFAULT_MIDI_INSTRUMENT_MAP; + if (p->iMidiInstrumentMap == DEFAULT_MIDI_INSTRUMENT_MAP) return; + p->iMidiInstrumentMap = DEFAULT_MIDI_INSTRUMENT_MAP; StatusChanged(true); } void EngineChannel::SetMidiInstrumentMap(int MidiMap) throw (Exception) { - if (iMidiInstrumentMap == MidiMap) return; + if (p->iMidiInstrumentMap == MidiMap) return; // check if given map actually exists in the MIDI instrument mapper std::vector maps = MidiInstrumentMapper::Maps(); if (find(maps.begin(), maps.end(), MidiMap) == maps.end()) throw Exception("MIDI instrument map doesn't exist"); - iMidiInstrumentMap = MidiMap; // assign the new map ID + p->iMidiInstrumentMap = MidiMap; // assign the new map ID StatusChanged(true); } + // RPNs ... + void EngineChannel::SetMidiRpnControllerMsb(uint8_t CtrlMSB) { - uiMidiRpnMsb = CtrlMSB; - bMidiRpnReceived = true; + p->uiMidiRpnMsb = CtrlMSB; + p->bMidiRpnReceived = true; } void EngineChannel::SetMidiRpnControllerLsb(uint8_t CtrlLSB) { - uiMidiRpnLsb = CtrlLSB; - bMidiRpnReceived = true; + p->uiMidiRpnLsb = CtrlLSB; + p->bMidiRpnReceived = true; } void EngineChannel::ResetMidiRpnController() { - uiMidiRpnMsb = uiMidiRpnLsb = 0; - bMidiRpnReceived = false; + p->uiMidiRpnMsb = p->uiMidiRpnLsb = 0; + p->bMidiRpnReceived = false; } int EngineChannel::GetMidiRpnController() { - return (bMidiRpnReceived) ? (uiMidiRpnMsb << 8) | uiMidiRpnLsb : -1; + return (p->bMidiRpnReceived) ? + (p->uiMidiRpnMsb << 8) | p->uiMidiRpnLsb : -1; + } + + // NRPNs ... + + void EngineChannel::SetMidiNrpnControllerMsb(uint8_t CtrlMSB) { + p->uiMidiNrpnMsb = CtrlMSB; + p->bMidiNrpnReceived = true; + } + + void EngineChannel::SetMidiNrpnControllerLsb(uint8_t CtrlLSB) { + p->uiMidiNrpnLsb = CtrlLSB; + p->bMidiNrpnReceived = true; + } + + void EngineChannel::ResetMidiNrpnController() { + p->uiMidiNrpnMsb = p->uiMidiNrpnLsb = 0; + p->bMidiNrpnReceived = false; + } + + int EngineChannel::GetMidiNrpnController() { + return (p->bMidiNrpnReceived) ? + (p->uiMidiNrpnMsb << 8) | p->uiMidiNrpnLsb : -1; } uint EngineChannel::GetVoiceCount() { - return atomic_read(&voiceCount); + return atomic_read(&p->voiceCount); } - + void EngineChannel::SetVoiceCount(uint Voices) { - atomic_set(&voiceCount, Voices); + atomic_set(&p->voiceCount, Voices); } uint EngineChannel::GetDiskStreamCount() { - return atomic_read(&diskStreamCount); + return atomic_read(&p->diskStreamCount); } - + void EngineChannel::SetDiskStreamCount(uint Streams) { - atomic_set(&diskStreamCount, Streams); + atomic_set(&p->diskStreamCount, Streams); } - + SamplerChannel* EngineChannel::GetSamplerChannel() { - if(pSamplerChannel == NULL) { + if (p->pSamplerChannel == NULL) { std::cerr << "EngineChannel::GetSamplerChannel(): pSamplerChannel is NULL, this is a bug!\n" << std::flush; } - return pSamplerChannel; + return p->pSamplerChannel; } void EngineChannel::SetSamplerChannel(SamplerChannel* pChannel) { - pSamplerChannel = pChannel; + p->pSamplerChannel = pChannel; } Sampler* EngineChannel::GetSampler() { @@ -223,20 +283,48 @@ } void EngineChannel::AddFxSendCountListener(FxSendCountListener* l) { - llFxSendCountListeners.AddListener(l); + p->llFxSendCountListeners.AddListener(l); } void EngineChannel::RemoveFxSendCountListener(FxSendCountListener* l) { - llFxSendCountListeners.RemoveListener(l); + p->llFxSendCountListeners.RemoveListener(l); } void EngineChannel::RemoveAllFxSendCountListeners() { - llFxSendCountListeners.RemoveAllListeners(); + p->llFxSendCountListeners.RemoveAllListeners(); } void EngineChannel::fireFxSendCountChanged(int ChannelId, int NewCount) { - for (int i = 0; i < llFxSendCountListeners.GetListenerCount(); i++) { - llFxSendCountListeners.GetListener(i)->FxSendCountChanged(ChannelId, NewCount); + for (int i = 0; i < p->llFxSendCountListeners.GetListenerCount(); i++) { + p->llFxSendCountListeners.GetListener(i)->FxSendCountChanged(ChannelId, NewCount); + } + } + + void EngineChannel::ExecuteProgramChange(uint8_t Program) { + dmsg(1,("Received MIDI program change (prog=%d)\n",Program)); + std::vector maps = MidiInstrumentMapper::Maps(); + if (maps.empty()) return; + + SetMidiProgram(Program); + if (UsesNoMidiInstrumentMap()) return; + if (MidiInstrumentMapper::GetMapCount() == 0) return; + // retrieve the MIDI instrument map this engine channel is assigned to + int iMapID = (UsesDefaultMidiInstrumentMap()) + ? MidiInstrumentMapper::GetDefaultMap() /*default*/ : GetMidiInstrumentMap(); + // is there an entry for this MIDI bank&prog pair in that map? + midi_prog_index_t midiIndex; + midiIndex.midi_bank_msb = GetMidiBankMsb(); + midiIndex.midi_bank_lsb = GetMidiBankLsb(); + midiIndex.midi_prog = GetMidiProgram(); + optional mapping = + MidiInstrumentMapper::GetEntry(iMapID, midiIndex); + if (mapping) { // if mapping exists ... + InstrumentManager::instrument_id_t id; + id.FileName = mapping->InstrumentFile; + id.Index = mapping->InstrumentIndex; + //TODO: we should switch the engine type here + InstrumentManager::LoadInstrumentInBackground(id, this); + Volume(mapping->Volume); } }