1 /*************************************************************************** 2 * * 3 * LinuxSampler - modular, streaming capable sampler * 4 * * 5 * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck * 6 * Copyright (C) 2005 - 2016 Christian Schoenebeck * 7 * * 8 * This library is free software; you can redistribute it and/or modify * 9 * it under the terms of the GNU General Public License as published by * 10 * the Free Software Foundation; either version 2 of the License, or * 11 * (at your option) any later version. * 12 * * 13 * This library is distributed in the hope that it will be useful, * 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 16 * GNU General Public License for more details. * 17 * * 18 * You should have received a copy of the GNU General Public License * 19 * along with this library; if not, write to the Free Software * 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * 21 * MA 02111-1307 USA * 22 ***************************************************************************/ 23 24 #include "FxSend.h" 25 26 #include "../common/global_private.h" 27 #include "../drivers/audio/AudioOutputDevice.h" 28 #include "../common/RTMath.h" 29 30 #include <map> 31 32 #define DEFAULT_FX_SEND_LEVEL 0.0f 33 34 namespace LinuxSampler { 35 FxSend(EngineChannel * pEngineChannel,uint8_t MidiCtrl,String Name)36 FxSend::FxSend(EngineChannel* pEngineChannel, uint8_t MidiCtrl, String Name) throw (Exception) 37 : iDestinationEffectChain(-1), iDestinationEffectChainPos(-1), bInfoChanged(false) 38 { 39 this->pEngineChannel = pEngineChannel; 40 AudioOutputDevice* pDevice = pEngineChannel->GetAudioOutputDevice(); 41 const int iChanOffset = (pDevice) ? pDevice->ChannelCount() - pEngineChannel->Channels() : 0; 42 for (int i = 0; i < pEngineChannel->Channels(); i++) { 43 const int iDestination = iChanOffset + i; 44 Routing.push_back(iDestination); 45 } 46 SetMidiController(MidiCtrl); 47 sName = Name; 48 49 // create an EngineChannel unique ID for this FxSend instance 50 if (!pEngineChannel->GetFxSendCount()) iId = 0; 51 else { 52 // get the highest existing map ID 53 uint highestIndex = 0; 54 for (uint i = 0; i < pEngineChannel->GetFxSendCount(); i++) 55 highestIndex = RTMath::Max(highestIndex, pEngineChannel->GetFxSend(i)->Id()); 56 // check if we reached the index limit 57 if (highestIndex + 1 < highestIndex) { 58 // search for an unoccupied map ID starting from 0 59 for (uint i = 0; i < highestIndex; i++) { 60 bool bOccupied = false; 61 for (uint j = 0; j < pEngineChannel->GetFxSendCount(); j++) { 62 if (pEngineChannel->GetFxSend(j)->Id() == i) { 63 bOccupied = true; 64 break; 65 } 66 } 67 if (!bOccupied) { 68 iId = i; 69 goto __done; 70 } 71 } 72 throw Exception("Internal error: could not find unoccupied FxSend ID."); 73 } 74 iId = highestIndex + 1; 75 } 76 __done: 77 78 fLevel = DEFAULT_FX_SEND_LEVEL; 79 } 80 DestinationEffectChain() const81 int FxSend::DestinationEffectChain() const { 82 return iDestinationEffectChain; 83 } 84 DestinationEffectChainPosition() const85 int FxSend::DestinationEffectChainPosition() const { 86 return iDestinationEffectChainPos; 87 } 88 SetDestinationEffect(int iChain,int iChainPos)89 void FxSend::SetDestinationEffect(int iChain, int iChainPos) throw (Exception) { 90 AudioOutputDevice* pDevice = pEngineChannel->GetAudioOutputDevice(); 91 bool chainFound = false; 92 if (iChain != -1) { 93 if (pDevice->SendEffectChainByID(iChain) != NULL) chainFound = true; 94 if (!chainFound) throw Exception( 95 "Could not assign FX Send to send effect chain " + 96 ToString(iChain) + ": effect chain doesn't exist." 97 ); 98 } 99 if (chainFound && (iChainPos < 0 || iChainPos >= pDevice->SendEffectChainByID(iChain)->EffectCount())) 100 throw Exception( 101 "Could not assign FX Send to send effect chain position " + 102 ToString(iChainPos) + " of send effect chain " + ToString(iChain) + 103 ": effect chain position out of bounds." 104 ); 105 iDestinationEffectChain = iChain; 106 iDestinationEffectChainPos = (iChain == -1 ? -1 : iChainPos); 107 } 108 109 // TODO: to be removed DestinationMasterEffectChain() const110 int FxSend::DestinationMasterEffectChain() const { 111 return DestinationEffectChain(); 112 } 113 114 // TODO: to be removed DestinationMasterEffect() const115 int FxSend::DestinationMasterEffect() const { 116 return DestinationEffectChainPosition(); 117 } 118 119 // TODO: to be removed SetDestinationMasterEffect(int iChain,int iChainPos)120 void FxSend::SetDestinationMasterEffect(int iChain, int iChainPos) throw (Exception) { 121 SetDestinationEffect(iChain, iChainPos); 122 } 123 DestinationChannel(int SrcChan)124 int FxSend::DestinationChannel(int SrcChan) { 125 if (SrcChan >= pEngineChannel->Channels()) return -1; 126 return Routing[SrcChan]; 127 } 128 SetDestinationChannel(int SrcChan,int DstChan)129 void FxSend::SetDestinationChannel(int SrcChan, int DstChan) throw (Exception) { 130 if (SrcChan < 0 || SrcChan >= pEngineChannel->Channels()) 131 throw Exception("Cannot alter FxSend routing, source channel out of bounds"); 132 AudioOutputDevice* pDevice = pEngineChannel->GetAudioOutputDevice(); 133 if (pDevice) { 134 if (DstChan < 0 || DstChan >= pDevice->ChannelCount()) 135 throw Exception("Cannot alter FxSend routing, destination channel out of bounds"); 136 } else { // no audio device assigned yet 137 if (DstChan < 0 || DstChan >= pEngineChannel->Channels()) 138 throw Exception( 139 "there is no audio device yet, so you cannot set a " 140 "FxSend destination channel higher than the engine " 141 "channel's amount of channels" 142 ); 143 } 144 Routing[SrcChan] = DstChan; 145 } 146 UpdateChannels()147 void FxSend::UpdateChannels() { 148 if (Routing.size() > pEngineChannel->Channels()) { 149 // add routings with default destinations 150 AudioOutputDevice* pDevice = pEngineChannel->GetAudioOutputDevice(); 151 const int iChanOffset = (pDevice) ? pDevice->ChannelCount() - pEngineChannel->Channels() : 0; 152 for (int i = (int)Routing.size(); i < pEngineChannel->Channels(); i++) { 153 const int iDestination = iChanOffset + i; 154 Routing.push_back(iDestination); 155 } 156 } else if (Routing.size() < pEngineChannel->Channels()) { 157 // shrink routing vector 158 Routing.resize(pEngineChannel->Channels()); 159 } 160 } 161 Level()162 float FxSend::Level() { 163 return fLevel; 164 } 165 SetLevel(float f)166 void FxSend::SetLevel(float f) { 167 if(fLevel == f) return; 168 fLevel = f; 169 SetInfoChanged(true); 170 } 171 SetLevel(uint8_t iMidiValue)172 void FxSend::SetLevel(uint8_t iMidiValue) { 173 fLevel = float(iMidiValue & 0x7f) / 127.0f; 174 SetInfoChanged(true); 175 } 176 Reset()177 void FxSend::Reset() { 178 SetLevel(DEFAULT_FX_SEND_LEVEL); 179 } 180 MidiController()181 uint8_t FxSend::MidiController() { 182 return MidiFxSendController; 183 } 184 SetMidiController(uint8_t MidiCtrl)185 void FxSend::SetMidiController(uint8_t MidiCtrl) throw (Exception) { 186 if (MidiCtrl >> 7) 187 throw Exception("Invalid MIDI controller " + ToString((int)MidiCtrl)); 188 MidiFxSendController = MidiCtrl; 189 } 190 Name()191 String FxSend::Name() { 192 return sName; 193 } 194 SetName(String Name)195 void FxSend::SetName(String Name) { 196 sName = Name; 197 } 198 Id()199 uint FxSend::Id() { 200 return iId; 201 } 202 SetInfoChanged(bool b)203 void FxSend::SetInfoChanged(bool b) { 204 bInfoChanged = b; 205 } 206 IsInfoChanged()207 bool FxSend::IsInfoChanged() { 208 return bInfoChanged; 209 } 210 211 } // namespace LinuxSampler 212