1 /***************************************************************************
2  *                                                                         *
3  *   LinuxSampler - modular, streaming capable sampler                     *
4  *                                                                         *
5  *   Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck   *
6  *   Copyright (C) 2005 - 2020 Christian Schoenebeck                       *
7  *                                                                         *
8  *   This program 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 program 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 program; 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 "EngineChannel.h"
25 
26 #include <algorithm>
27 
28 #include "../Sampler.h"
29 #include "../common/global_private.h"
30 #include "../drivers/midi/MidiInstrumentMapper.h"
31 #include "../common/atomic.h"
32 
33 #define NO_MIDI_INSTRUMENT_MAP		-1
34 #define DEFAULT_MIDI_INSTRUMENT_MAP	-2
35 
36 namespace LinuxSampler {
37 
38     struct EngineChannel::private_data_t {
39         int     iMute;
40         bool    bSolo;
41         uint8_t uiMidiProgram;
42         uint8_t uiMidiBankMsb;
43         uint8_t uiMidiBankLsb;
44         uint8_t uiMidiRpnMsb; ///< MIDI Registered Parameter Number (upper 7 bits / coarse)
45         uint8_t uiMidiRpnLsb; ///< MIDI Registered Parameter Number (lower 7 bits / fine)
46         uint8_t uiMidiRpnDataMsb; ///< New MIDI RPN Parameter Value (upper 7 bits / coarse)
47         uint8_t uiMidiRpnDataLsb; ///< New MIDI RPN Parameter Value (lower 7 bits / fine)
48         uint8_t uiMidiNrpnMsb; ///< MIDI Non-Registered Parameter Number (upper 7 bits / coarse)
49         uint8_t uiMidiNrpnLsb; ///< MIDI Non-Registered Parameter Number (lower 7 bits / fine)
50         uint8_t uiMidiNrpnDataMsb; ///< New MIDI NRPN Parameter Value (upper 7 bits / coarse)
51         uint8_t uiMidiNrpnDataLsb; ///< New MIDI NRPN Parameter Value (lower 7 bits / fine)
52         bool    bMidiBankMsbReceived;
53         bool    bMidiBankLsbReceived;
54         bool    bProgramChangeReceived;
55         bool    bMidiRpnReceived;
56         bool    bMidiNrpnReceived;
57         int     iMidiInstrumentMap;
58         atomic_t voiceCount;
59         atomic_t diskStreamCount;
60         SamplerChannel* pSamplerChannel;
61         ListenerList<FxSendCountListener*> llFxSendCountListeners;
62     };
63 
EngineChannel()64     EngineChannel::EngineChannel() : p(new private_data_t) {
65         p->iMute = 0;
66         p->bSolo = false;
67         p->uiMidiBankMsb = 0;
68         p->uiMidiBankLsb = 0;
69         p->uiMidiProgram = 0;
70         p->bProgramChangeReceived =
71         p->bMidiBankMsbReceived =
72         p->bMidiBankLsbReceived = false;
73         p->iMidiInstrumentMap = NO_MIDI_INSTRUMENT_MAP;
74         SetVoiceCount(0);
75         SetDiskStreamCount(0);
76         p->pSamplerChannel = NULL;
77         ResetMidiRpnParameter();
78         ResetMidiNrpnParameter();
79     }
80 
~EngineChannel()81     EngineChannel::~EngineChannel() {
82         delete p;
83     }
84 
85     /**
86      * Sometimes an instrument is splitted over several files. For example
87      * the GigaStudio format may split an instrument over a certain amount
88      * of files like: "Foo.gig", "Foo.gx01", "Foo.gx02", ...
89      * This method allows to retrieve the whole list of files that is used
90      * for the currently loaded instrument on this engine channel.
91      * Calling this method with index 0 is equivalent as calling the equal
92      * named method without any argument.
93      *
94      * @param index - index of sought file name (0, 1, 2, ...)
95      * @returns file name or empty string if index out of bounds
96      */
InstrumentFileName(int index)97     String EngineChannel::InstrumentFileName(int index) {
98         return (index == 0) ? InstrumentFileName() : "";
99     }
100 
SetMute(int state)101     void EngineChannel::SetMute(int state) throw (Exception) {
102         if (p->iMute == state) return;
103         if (state < -1 || state > 1)
104             throw Exception("Invalid Mute state: " + ToString(state));
105 
106         p->iMute = state;
107 
108         StatusChanged(true);
109     }
110 
GetMute()111     int EngineChannel::GetMute() {
112         return p->iMute;
113     }
114 
SetSolo(bool solo)115     void EngineChannel::SetSolo(bool solo) {
116         if (p->bSolo == solo) return;
117         p->bSolo = solo;
118         StatusChanged(true);
119     }
120 
GetSolo()121     bool EngineChannel::GetSolo() {
122         return p->bSolo;
123     }
124 
125     /*
126        We use a workaround for MIDI devices (i.e. old keyboards) which either
127        only send bank select MSB or only bank select LSB messages. Bank
128        selects will be modified according to the following table:
129 
130        MIDI Sequence received:            -> GetMidiBankMsb()= | GetMidiBankLsb()=
131        ---------------------------------------------------------------------------
132        program change                     ->        0          |        0
133        bank LSB, program change           ->        0          |     LSB value
134        bank MSB, program change           ->        0          |     MSB value
135        bank LSB, bank MSB, program change ->     MSB value     |     LSB value
136        bank MSB, bank LSB, program change ->     MSB value     |     LSB value
137        ---------------------------------------------------------------------------
138 
139        That way we ensure those limited devices always to switch between the
140        following set of MIDI instrument banks:  { 0, 1, 2, ..., 127 }
141     */
142 
GetMidiProgram()143     uint8_t EngineChannel::GetMidiProgram() {
144         return p->uiMidiProgram; // AFAIK atomic on all systems
145     }
146 
SetMidiProgram(uint8_t Program)147     void EngineChannel::SetMidiProgram(uint8_t Program) {
148         p->bProgramChangeReceived = true;
149         p->uiMidiProgram = Program; // AFAIK atomic on all systems
150     }
151 
GetMidiBankMsb()152     uint8_t EngineChannel::GetMidiBankMsb() {
153         return (p->bMidiBankMsbReceived && p->bMidiBankLsbReceived)
154             ? p->uiMidiBankMsb : 0;
155     }
156 
SetMidiBankMsb(uint8_t BankMSB)157     void EngineChannel::SetMidiBankMsb(uint8_t BankMSB) {
158         if (p->bProgramChangeReceived) {
159             p->bProgramChangeReceived =
160             p->bMidiBankLsbReceived = false;
161         }
162         p->bMidiBankMsbReceived = true;
163         p->uiMidiBankMsb = BankMSB; // AFAIK atomic on all systems
164     }
165 
GetMidiBankLsb()166     uint8_t EngineChannel::GetMidiBankLsb() {
167         return (!p->bMidiBankMsbReceived && !p->bMidiBankLsbReceived)
168                    ? 0
169                    : (p->bMidiBankMsbReceived && !p->bMidiBankLsbReceived)
170                          ? p->uiMidiBankMsb
171                          : p->uiMidiBankLsb;
172     }
173 
SetMidiBankLsb(uint8_t BankLSB)174     void EngineChannel::SetMidiBankLsb(uint8_t BankLSB) {
175         if (p->bProgramChangeReceived) {
176             p->bProgramChangeReceived =
177             p->bMidiBankMsbReceived = false;
178         }
179         p->bMidiBankLsbReceived = true;
180         p->uiMidiBankLsb = BankLSB; // AFAIK atomic on all systems
181     }
182 
UsesNoMidiInstrumentMap()183     bool EngineChannel::UsesNoMidiInstrumentMap() {
184         return (p->iMidiInstrumentMap == NO_MIDI_INSTRUMENT_MAP);
185     }
186 
UsesDefaultMidiInstrumentMap()187     bool EngineChannel::UsesDefaultMidiInstrumentMap() {
188         return (p->iMidiInstrumentMap == DEFAULT_MIDI_INSTRUMENT_MAP);
189     }
190 
GetMidiInstrumentMap()191     int EngineChannel::GetMidiInstrumentMap() throw (Exception) {
192         if (UsesNoMidiInstrumentMap())
193             throw Exception("EngineChannel is using no MIDI instrument map");
194         if (UsesDefaultMidiInstrumentMap())
195             throw Exception("EngineChannel is using default MIDI instrument map");
196         // check if the stored map still exists in the MIDI instrument mapper
197         std::vector<int> maps = MidiInstrumentMapper::Maps();
198         if (find(maps.begin(), maps.end(), p->iMidiInstrumentMap) == maps.end()) {
199             // it doesn't exist anymore, so fall back to NONE and throw an exception
200             p->iMidiInstrumentMap = NO_MIDI_INSTRUMENT_MAP;
201             throw Exception("Assigned MIDI instrument map doesn't exist anymore, falling back to NONE");
202         }
203         return p->iMidiInstrumentMap;
204     }
205 
SetMidiInstrumentMapToNone()206     void EngineChannel::SetMidiInstrumentMapToNone() {
207         if (p->iMidiInstrumentMap == NO_MIDI_INSTRUMENT_MAP) return;
208         p->iMidiInstrumentMap = NO_MIDI_INSTRUMENT_MAP;
209         StatusChanged(true);
210     }
211 
SetMidiInstrumentMapToDefault()212     void EngineChannel::SetMidiInstrumentMapToDefault() {
213         if (p->iMidiInstrumentMap == DEFAULT_MIDI_INSTRUMENT_MAP) return;
214         p->iMidiInstrumentMap = DEFAULT_MIDI_INSTRUMENT_MAP;
215         StatusChanged(true);
216     }
217 
SetMidiInstrumentMap(int MidiMap)218     void EngineChannel::SetMidiInstrumentMap(int MidiMap) throw (Exception) {
219         if (p->iMidiInstrumentMap == MidiMap) return;
220 
221         // check if given map actually exists in the MIDI instrument mapper
222         std::vector<int> maps = MidiInstrumentMapper::Maps();
223         if (find(maps.begin(), maps.end(), MidiMap) == maps.end())
224             throw Exception("MIDI instrument map doesn't exist");
225         p->iMidiInstrumentMap = MidiMap; // assign the new map ID
226         StatusChanged(true);
227     }
228 
229     // RPNs ...
230 
SetMidiRpnParameterMsb(uint8_t ParamMSB)231     void EngineChannel::SetMidiRpnParameterMsb(uint8_t ParamMSB) {
232         p->uiMidiRpnMsb = ParamMSB & 127;
233         p->bMidiRpnReceived = true;
234     }
235 
SetMidiRpnControllerMsb(uint8_t CtrlMSB)236     void EngineChannel::SetMidiRpnControllerMsb(uint8_t CtrlMSB) { // deprecated API
237         SetMidiRpnParameterMsb(CtrlMSB);
238     }
239 
SetMidiRpnParameterLsb(uint8_t ParamLSB)240     void EngineChannel::SetMidiRpnParameterLsb(uint8_t ParamLSB) {
241         p->uiMidiRpnLsb = ParamLSB & 127;
242         p->bMidiRpnReceived = true;
243     }
244 
SetMidiRpnControllerLsb(uint8_t CtrlLSB)245     void EngineChannel::SetMidiRpnControllerLsb(uint8_t CtrlLSB) { // deprecated API
246         SetMidiRpnParameterLsb(CtrlLSB);
247     }
248 
SetMidiRpnDataMsb(uint8_t DataMSB)249     void EngineChannel::SetMidiRpnDataMsb(uint8_t DataMSB) {
250         p->uiMidiRpnDataMsb = DataMSB & 127;
251     }
252 
SetMidiRpnDataLsb(uint8_t DataLSB)253     void EngineChannel::SetMidiRpnDataLsb(uint8_t DataLSB) {
254         p->uiMidiRpnDataLsb = DataLSB & 127;
255     }
256 
SetMidiRpnData(int Data)257     void EngineChannel::SetMidiRpnData(int Data) {
258         if (Data < 0) Data = 0;
259         if (Data > 16383) Data = 16383;
260         p->uiMidiRpnDataMsb = (Data >> 7) & 127;
261         p->uiMidiRpnDataLsb = Data & 127;
262     }
263 
ResetMidiRpnParameter()264     void EngineChannel::ResetMidiRpnParameter() {
265         p->uiMidiRpnMsb = p->uiMidiRpnLsb = 0;
266         p->uiMidiRpnDataMsb = p->uiMidiRpnDataLsb = 0;
267         p->bMidiRpnReceived = false;
268     }
269 
ResetMidiRpnController()270     void EngineChannel::ResetMidiRpnController() { // deprecated API
271         ResetMidiRpnParameter();
272     }
273 
GetMidiRpnParameter()274     int EngineChannel::GetMidiRpnParameter() {
275         return (p->bMidiRpnReceived) ?
276                (p->uiMidiRpnMsb << 7) | p->uiMidiRpnLsb : -1;
277     }
278 
GetMidiRpnController()279     int EngineChannel::GetMidiRpnController() { // deprecated API
280         return (p->bMidiRpnReceived) ?
281                (p->uiMidiRpnMsb << 8) | p->uiMidiRpnLsb : -1;
282     }
283 
GetMidiRpnData()284     int EngineChannel::GetMidiRpnData() {
285         return (p->bMidiRpnReceived) ?
286                (p->uiMidiRpnDataMsb << 7) | p->uiMidiRpnDataLsb : 0;
287     }
288 
289     // NRPNs ...
290 
SetMidiNrpnParameterMsb(uint8_t ParamMSB)291     void EngineChannel::SetMidiNrpnParameterMsb(uint8_t ParamMSB) {
292         p->uiMidiNrpnMsb = ParamMSB & 127;
293         p->bMidiNrpnReceived = true;
294     }
295 
SetMidiNrpnControllerMsb(uint8_t CtrlMSB)296     void EngineChannel::SetMidiNrpnControllerMsb(uint8_t CtrlMSB) { // deprecated API
297         SetMidiNrpnParameterMsb(CtrlMSB);
298     }
299 
SetMidiNrpnParameterLsb(uint8_t ParamLSB)300     void EngineChannel::SetMidiNrpnParameterLsb(uint8_t ParamLSB) {
301         p->uiMidiNrpnLsb = ParamLSB & 127;
302         p->bMidiNrpnReceived = true;
303     }
304 
SetMidiNrpnControllerLsb(uint8_t CtrlLSB)305     void EngineChannel::SetMidiNrpnControllerLsb(uint8_t CtrlLSB) { // deprecated API
306         SetMidiNrpnParameterLsb(CtrlLSB);
307     }
308 
SetMidiNrpnDataMsb(uint8_t DataMSB)309     void EngineChannel::SetMidiNrpnDataMsb(uint8_t DataMSB) {
310         p->uiMidiNrpnDataMsb = DataMSB & 127;
311     }
312 
SetMidiNrpnDataLsb(uint8_t DataLSB)313     void EngineChannel::SetMidiNrpnDataLsb(uint8_t DataLSB) {
314         p->uiMidiNrpnDataLsb = DataLSB & 127;
315     }
316 
SetMidiNrpnData(int Data)317     void EngineChannel::SetMidiNrpnData(int Data) {
318         if (Data < 0) Data = 0;
319         if (Data > 16383) Data = 16383;
320         p->uiMidiNrpnDataMsb = (Data >> 7) & 127;
321         p->uiMidiNrpnDataLsb = Data & 127;
322     }
323 
ResetMidiNrpnParameter()324     void EngineChannel::ResetMidiNrpnParameter() {
325         p->uiMidiNrpnMsb = p->uiMidiNrpnLsb = 0;
326         p->uiMidiNrpnDataMsb = p->uiMidiNrpnDataLsb = 0;
327         p->bMidiNrpnReceived = false;
328     }
329 
ResetMidiNrpnController()330     void EngineChannel::ResetMidiNrpnController() { // deprecated API
331         ResetMidiNrpnParameter();
332     }
333 
GetMidiNrpnParameter()334     int EngineChannel::GetMidiNrpnParameter() {
335         return (p->bMidiNrpnReceived) ?
336                (p->uiMidiNrpnMsb << 7)  | p->uiMidiNrpnLsb : -1;
337     }
338 
GetMidiNrpnController()339     int EngineChannel::GetMidiNrpnController() { // deprecated API
340         return (p->bMidiNrpnReceived) ?
341                (p->uiMidiNrpnMsb << 8) | p->uiMidiNrpnLsb : -1;
342     }
343 
GetMidiNrpnData()344     int EngineChannel::GetMidiNrpnData() {
345         return (p->bMidiNrpnReceived) ?
346                (p->uiMidiNrpnDataMsb << 7) | p->uiMidiNrpnDataLsb : 0;
347     }
348 
GetVoiceCount()349     uint EngineChannel::GetVoiceCount() {
350         return atomic_read(&p->voiceCount);
351     }
352 
SetVoiceCount(uint Voices)353     void EngineChannel::SetVoiceCount(uint Voices) {
354         atomic_set(&p->voiceCount, Voices);
355     }
356 
GetDiskStreamCount()357     uint EngineChannel::GetDiskStreamCount() {
358         return atomic_read(&p->diskStreamCount);
359     }
360 
SetDiskStreamCount(uint Streams)361     void EngineChannel::SetDiskStreamCount(uint Streams) {
362         atomic_set(&p->diskStreamCount, Streams);
363     }
364 
GetSamplerChannel()365     SamplerChannel* EngineChannel::GetSamplerChannel() {
366         if (p->pSamplerChannel == NULL) {
367             std::cerr << "EngineChannel::GetSamplerChannel(): pSamplerChannel is NULL, this is a bug!\n" << std::flush;
368         }
369         return p->pSamplerChannel;
370     }
371 
SetSamplerChannel(SamplerChannel * pChannel)372     void EngineChannel::SetSamplerChannel(SamplerChannel* pChannel) {
373         p->pSamplerChannel = pChannel;
374     }
375 
GetSampler()376     Sampler* EngineChannel::GetSampler() {
377         if (GetSamplerChannel() == NULL) return NULL;
378         return GetSamplerChannel()->GetSampler();
379     }
380 
AddFxSendCountListener(FxSendCountListener * l)381     void EngineChannel::AddFxSendCountListener(FxSendCountListener* l) {
382         p->llFxSendCountListeners.AddListener(l);
383     }
384 
RemoveFxSendCountListener(FxSendCountListener * l)385     void EngineChannel::RemoveFxSendCountListener(FxSendCountListener* l) {
386         p->llFxSendCountListeners.RemoveListener(l);
387     }
388 
RemoveAllFxSendCountListeners()389     void EngineChannel::RemoveAllFxSendCountListeners() {
390         p->llFxSendCountListeners.RemoveAllListeners();
391     }
392 
fireFxSendCountChanged(int ChannelId,int NewCount)393     void EngineChannel::fireFxSendCountChanged(int ChannelId, int NewCount) {
394         for (int i = 0; i < p->llFxSendCountListeners.GetListenerCount(); i++) {
395             p->llFxSendCountListeners.GetListener(i)->FxSendCountChanged(ChannelId, NewCount);
396         }
397     }
398 
ExecuteProgramChange(uint32_t Program)399     void EngineChannel::ExecuteProgramChange(uint32_t Program) {
400         uint8_t hb = (Program >> 16) & 0xff;
401         uint8_t lb = (Program >> 8) & 0xff;
402         uint8_t pc = Program & 0x7f;
403 
404         dmsg(1,("Received MIDI program change (msb=%d) (lsb=%d) (prog=%d)\n", hb ,lb, pc));
405         std::vector<int> maps = MidiInstrumentMapper::Maps();
406         if (maps.empty()) return;
407 
408         if (UsesNoMidiInstrumentMap()) return;
409         if (MidiInstrumentMapper::GetMapCount() == 0) return;
410         // retrieve the MIDI instrument map this engine channel is assigned to
411         int iMapID = (UsesDefaultMidiInstrumentMap())
412             ? MidiInstrumentMapper::GetDefaultMap() /*default*/ : GetMidiInstrumentMap();
413         // is there an entry for this MIDI bank&prog pair in that map?
414         midi_prog_index_t midiIndex;
415         midiIndex.midi_bank_msb = hb;
416         midiIndex.midi_bank_lsb = lb;
417         midiIndex.midi_prog     = pc;
418         optional<MidiInstrumentMapper::entry_t> mapping =
419             MidiInstrumentMapper::GetEntry(iMapID, midiIndex);
420         if (mapping) { // if mapping exists ...
421             InstrumentManager::instrument_id_t id;
422             id.FileName = mapping->InstrumentFile;
423             id.Index    = mapping->InstrumentIndex;
424             //TODO: we should switch the engine type here
425             InstrumentManager::LoadInstrumentInBackground(id, this);
426             Volume(mapping->Volume);
427         }
428     }
429 
430 } // namespace LinuxSampler
431