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