/[svn]/linuxsampler/trunk/src/engines/EngineChannel.cpp
ViewVC logotype

Annotation of /linuxsampler/trunk/src/engines/EngineChannel.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3699 - (hide annotations) (download)
Sat Jan 4 14:07:02 2020 UTC (4 years, 3 months ago) by schoenebeck
File size: 16422 byte(s)
* Added support for MIDI CC #96 (data increment).

* Added support for MIDI CC #97 (data decrement).

* Bumped version (2.1.1.svn34).

1 schoenebeck 888 /***************************************************************************
2     * *
3     * LinuxSampler - modular, streaming capable sampler *
4     * *
5     * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6 schoenebeck 3687 * Copyright (C) 2005 - 2020 Christian Schoenebeck *
7 schoenebeck 888 * *
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 schoenebeck 973 #include <algorithm>
27    
28 iliev 1761 #include "../Sampler.h"
29 schoenebeck 1424 #include "../common/global_private.h"
30 schoenebeck 973 #include "../drivers/midi/MidiInstrumentMapper.h"
31 schoenebeck 1879 #include "../common/atomic.h"
32 schoenebeck 973
33     #define NO_MIDI_INSTRUMENT_MAP -1
34     #define DEFAULT_MIDI_INSTRUMENT_MAP -2
35    
36 schoenebeck 888 namespace LinuxSampler {
37    
38 persson 1896 struct EngineChannel::private_data_t {
39 schoenebeck 1879 int iMute;
40     bool bSolo;
41     uint8_t uiMidiProgram;
42     uint8_t uiMidiBankMsb;
43     uint8_t uiMidiBankLsb;
44 schoenebeck 3687 uint8_t uiMidiRpnMsb; ///< MIDI Registered Parameter Number (upper 7 bits / coarse)
45     uint8_t uiMidiRpnLsb; ///< MIDI Registered Parameter Number (lower 7 bits / fine)
46 schoenebeck 3697 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 schoenebeck 3687 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 schoenebeck 3697 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 schoenebeck 1879 bool bMidiBankMsbReceived;
53     bool bMidiBankLsbReceived;
54     bool bProgramChangeReceived;
55     bool bMidiRpnReceived;
56 schoenebeck 2121 bool bMidiNrpnReceived;
57 schoenebeck 1879 int iMidiInstrumentMap;
58     atomic_t voiceCount;
59     atomic_t diskStreamCount;
60     SamplerChannel* pSamplerChannel;
61     ListenerList<FxSendCountListener*> llFxSendCountListeners;
62     };
63    
64 persson 1896 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 iliev 1789 SetVoiceCount(0);
75     SetDiskStreamCount(0);
76 persson 1896 p->pSamplerChannel = NULL;
77 schoenebeck 3687 ResetMidiRpnParameter();
78     ResetMidiNrpnParameter();
79 schoenebeck 888 }
80    
81 schoenebeck 1879 EngineChannel::~EngineChannel() {
82 persson 1896 delete p;
83 schoenebeck 1879 }
84 schoenebeck 2330
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     */
97     String EngineChannel::InstrumentFileName(int index) {
98     return (index == 0) ? InstrumentFileName() : "";
99     }
100 schoenebeck 1879
101 schoenebeck 888 void EngineChannel::SetMute(int state) throw (Exception) {
102 persson 1896 if (p->iMute == state) return;
103 schoenebeck 1879 if (state < -1 || state > 1)
104 schoenebeck 888 throw Exception("Invalid Mute state: " + ToString(state));
105    
106 persson 1896 p->iMute = state;
107 schoenebeck 888
108     StatusChanged(true);
109     }
110    
111     int EngineChannel::GetMute() {
112 persson 1896 return p->iMute;
113 schoenebeck 888 }
114    
115     void EngineChannel::SetSolo(bool solo) {
116 persson 1896 if (p->bSolo == solo) return;
117     p->bSolo = solo;
118 schoenebeck 888 StatusChanged(true);
119     }
120    
121     bool EngineChannel::GetSolo() {
122 persson 1896 return p->bSolo;
123 schoenebeck 888 }
124    
125 schoenebeck 973 /*
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    
143 schoenebeck 947 uint8_t EngineChannel::GetMidiProgram() {
144 persson 1896 return p->uiMidiProgram; // AFAIK atomic on all systems
145 schoenebeck 947 }
146    
147     void EngineChannel::SetMidiProgram(uint8_t Program) {
148 persson 1896 p->bProgramChangeReceived = true;
149     p->uiMidiProgram = Program; // AFAIK atomic on all systems
150 schoenebeck 947 }
151    
152     uint8_t EngineChannel::GetMidiBankMsb() {
153 persson 1896 return (p->bMidiBankMsbReceived && p->bMidiBankLsbReceived)
154     ? p->uiMidiBankMsb : 0;
155 schoenebeck 947 }
156    
157     void EngineChannel::SetMidiBankMsb(uint8_t BankMSB) {
158 persson 1896 if (p->bProgramChangeReceived) {
159     p->bProgramChangeReceived =
160     p->bMidiBankLsbReceived = false;
161 schoenebeck 1879 }
162 persson 1896 p->bMidiBankMsbReceived = true;
163     p->uiMidiBankMsb = BankMSB; // AFAIK atomic on all systems
164 schoenebeck 947 }
165    
166     uint8_t EngineChannel::GetMidiBankLsb() {
167 persson 1896 return (!p->bMidiBankMsbReceived && !p->bMidiBankLsbReceived)
168 schoenebeck 973 ? 0
169 persson 1896 : (p->bMidiBankMsbReceived && !p->bMidiBankLsbReceived)
170     ? p->uiMidiBankMsb
171     : p->uiMidiBankLsb;
172 schoenebeck 947 }
173    
174     void EngineChannel::SetMidiBankLsb(uint8_t BankLSB) {
175 persson 1896 if (p->bProgramChangeReceived) {
176     p->bProgramChangeReceived =
177     p->bMidiBankMsbReceived = false;
178 schoenebeck 1879 }
179 persson 1896 p->bMidiBankLsbReceived = true;
180     p->uiMidiBankLsb = BankLSB; // AFAIK atomic on all systems
181 schoenebeck 947 }
182    
183 schoenebeck 973 bool EngineChannel::UsesNoMidiInstrumentMap() {
184 persson 1896 return (p->iMidiInstrumentMap == NO_MIDI_INSTRUMENT_MAP);
185 schoenebeck 973 }
186    
187     bool EngineChannel::UsesDefaultMidiInstrumentMap() {
188 persson 1896 return (p->iMidiInstrumentMap == DEFAULT_MIDI_INSTRUMENT_MAP);
189 schoenebeck 973 }
190    
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 persson 1896 if (find(maps.begin(), maps.end(), p->iMidiInstrumentMap) == maps.end()) {
199 schoenebeck 973 // it doesn't exist anymore, so fall back to NONE and throw an exception
200 persson 1896 p->iMidiInstrumentMap = NO_MIDI_INSTRUMENT_MAP;
201 schoenebeck 973 throw Exception("Assigned MIDI instrument map doesn't exist anymore, falling back to NONE");
202     }
203 persson 1896 return p->iMidiInstrumentMap;
204 schoenebeck 973 }
205    
206     void EngineChannel::SetMidiInstrumentMapToNone() {
207 persson 1896 if (p->iMidiInstrumentMap == NO_MIDI_INSTRUMENT_MAP) return;
208     p->iMidiInstrumentMap = NO_MIDI_INSTRUMENT_MAP;
209 iliev 1254 StatusChanged(true);
210 schoenebeck 973 }
211    
212     void EngineChannel::SetMidiInstrumentMapToDefault() {
213 persson 1896 if (p->iMidiInstrumentMap == DEFAULT_MIDI_INSTRUMENT_MAP) return;
214     p->iMidiInstrumentMap = DEFAULT_MIDI_INSTRUMENT_MAP;
215 iliev 1254 StatusChanged(true);
216 schoenebeck 973 }
217    
218     void EngineChannel::SetMidiInstrumentMap(int MidiMap) throw (Exception) {
219 persson 1896 if (p->iMidiInstrumentMap == MidiMap) return;
220 iliev 1254
221 schoenebeck 973 // 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 persson 1896 p->iMidiInstrumentMap = MidiMap; // assign the new map ID
226 iliev 1254 StatusChanged(true);
227 schoenebeck 973 }
228    
229 schoenebeck 2121 // RPNs ...
230    
231 schoenebeck 3687 void EngineChannel::SetMidiRpnParameterMsb(uint8_t ParamMSB) {
232     p->uiMidiRpnMsb = ParamMSB & 127;
233 persson 1896 p->bMidiRpnReceived = true;
234 schoenebeck 1041 }
235    
236 schoenebeck 3687 void EngineChannel::SetMidiRpnControllerMsb(uint8_t CtrlMSB) { // deprecated API
237     SetMidiRpnParameterMsb(CtrlMSB);
238     }
239    
240     void EngineChannel::SetMidiRpnParameterLsb(uint8_t ParamLSB) {
241     p->uiMidiRpnLsb = ParamLSB & 127;
242 persson 1896 p->bMidiRpnReceived = true;
243 schoenebeck 1041 }
244    
245 schoenebeck 3687 void EngineChannel::SetMidiRpnControllerLsb(uint8_t CtrlLSB) { // deprecated API
246     SetMidiRpnParameterLsb(CtrlLSB);
247     }
248    
249 schoenebeck 3697 void EngineChannel::SetMidiRpnDataMsb(uint8_t DataMSB) {
250     p->uiMidiRpnDataMsb = DataMSB & 127;
251     }
252    
253     void EngineChannel::SetMidiRpnDataLsb(uint8_t DataLSB) {
254     p->uiMidiRpnDataLsb = DataLSB & 127;
255     }
256    
257 schoenebeck 3699 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    
264 schoenebeck 3687 void EngineChannel::ResetMidiRpnParameter() {
265 persson 1896 p->uiMidiRpnMsb = p->uiMidiRpnLsb = 0;
266 schoenebeck 3697 p->uiMidiRpnDataMsb = p->uiMidiRpnDataLsb = 0;
267 persson 1896 p->bMidiRpnReceived = false;
268 schoenebeck 1044 }
269    
270 schoenebeck 3687 void EngineChannel::ResetMidiRpnController() { // deprecated API
271     ResetMidiRpnParameter();
272     }
273    
274     int EngineChannel::GetMidiRpnParameter() {
275 persson 1896 return (p->bMidiRpnReceived) ?
276 schoenebeck 3687 (p->uiMidiRpnMsb << 7) | p->uiMidiRpnLsb : -1;
277     }
278    
279     int EngineChannel::GetMidiRpnController() { // deprecated API
280     return (p->bMidiRpnReceived) ?
281 persson 1896 (p->uiMidiRpnMsb << 8) | p->uiMidiRpnLsb : -1;
282 schoenebeck 1041 }
283    
284 schoenebeck 3697 int EngineChannel::GetMidiRpnData() {
285     return (p->bMidiRpnReceived) ?
286     (p->uiMidiRpnDataMsb << 7) | p->uiMidiRpnDataLsb : 0;
287     }
288    
289 schoenebeck 2121 // NRPNs ...
290    
291 schoenebeck 3687 void EngineChannel::SetMidiNrpnParameterMsb(uint8_t ParamMSB) {
292     p->uiMidiNrpnMsb = ParamMSB & 127;
293 schoenebeck 2121 p->bMidiNrpnReceived = true;
294     }
295    
296 schoenebeck 3687 void EngineChannel::SetMidiNrpnControllerMsb(uint8_t CtrlMSB) { // deprecated API
297     SetMidiNrpnParameterMsb(CtrlMSB);
298     }
299    
300     void EngineChannel::SetMidiNrpnParameterLsb(uint8_t ParamLSB) {
301     p->uiMidiNrpnLsb = ParamLSB & 127;
302 schoenebeck 2121 p->bMidiNrpnReceived = true;
303     }
304    
305 schoenebeck 3687 void EngineChannel::SetMidiNrpnControllerLsb(uint8_t CtrlLSB) { // deprecated API
306     SetMidiNrpnParameterLsb(CtrlLSB);
307     }
308    
309 schoenebeck 3697 void EngineChannel::SetMidiNrpnDataMsb(uint8_t DataMSB) {
310     p->uiMidiNrpnDataMsb = DataMSB & 127;
311     }
312    
313     void EngineChannel::SetMidiNrpnDataLsb(uint8_t DataLSB) {
314     p->uiMidiNrpnDataLsb = DataLSB & 127;
315     }
316    
317 schoenebeck 3699 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    
324 schoenebeck 3687 void EngineChannel::ResetMidiNrpnParameter() {
325 schoenebeck 2121 p->uiMidiNrpnMsb = p->uiMidiNrpnLsb = 0;
326 schoenebeck 3697 p->uiMidiNrpnDataMsb = p->uiMidiNrpnDataLsb = 0;
327 schoenebeck 2121 p->bMidiNrpnReceived = false;
328     }
329    
330 schoenebeck 3687 void EngineChannel::ResetMidiNrpnController() { // deprecated API
331     ResetMidiNrpnParameter();
332     }
333    
334     int EngineChannel::GetMidiNrpnParameter() {
335 schoenebeck 2121 return (p->bMidiNrpnReceived) ?
336 schoenebeck 3687 (p->uiMidiNrpnMsb << 7) | p->uiMidiNrpnLsb : -1;
337     }
338    
339     int EngineChannel::GetMidiNrpnController() { // deprecated API
340     return (p->bMidiNrpnReceived) ?
341 schoenebeck 2121 (p->uiMidiNrpnMsb << 8) | p->uiMidiNrpnLsb : -1;
342     }
343    
344 schoenebeck 3697 int EngineChannel::GetMidiNrpnData() {
345     return (p->bMidiNrpnReceived) ?
346     (p->uiMidiNrpnDataMsb << 7) | p->uiMidiNrpnDataLsb : 0;
347     }
348    
349 iliev 1297 uint EngineChannel::GetVoiceCount() {
350 persson 1896 return atomic_read(&p->voiceCount);
351 iliev 1297 }
352 schoenebeck 1879
353 iliev 1297 void EngineChannel::SetVoiceCount(uint Voices) {
354 persson 1896 atomic_set(&p->voiceCount, Voices);
355 iliev 1297 }
356    
357     uint EngineChannel::GetDiskStreamCount() {
358 persson 1896 return atomic_read(&p->diskStreamCount);
359 iliev 1297 }
360 schoenebeck 1879
361 iliev 1297 void EngineChannel::SetDiskStreamCount(uint Streams) {
362 persson 1896 atomic_set(&p->diskStreamCount, Streams);
363 iliev 1297 }
364 schoenebeck 1879
365 iliev 1761 SamplerChannel* EngineChannel::GetSamplerChannel() {
366 persson 1896 if (p->pSamplerChannel == NULL) {
367 iliev 1761 std::cerr << "EngineChannel::GetSamplerChannel(): pSamplerChannel is NULL, this is a bug!\n" << std::flush;
368     }
369 persson 1896 return p->pSamplerChannel;
370 iliev 1761 }
371 iliev 1297
372 iliev 1761 void EngineChannel::SetSamplerChannel(SamplerChannel* pChannel) {
373 persson 1896 p->pSamplerChannel = pChannel;
374 iliev 1761 }
375    
376     Sampler* EngineChannel::GetSampler() {
377     if (GetSamplerChannel() == NULL) return NULL;
378     return GetSamplerChannel()->GetSampler();
379     }
380    
381 iliev 1130 void EngineChannel::AddFxSendCountListener(FxSendCountListener* l) {
382 persson 1896 p->llFxSendCountListeners.AddListener(l);
383 iliev 1130 }
384    
385     void EngineChannel::RemoveFxSendCountListener(FxSendCountListener* l) {
386 persson 1896 p->llFxSendCountListeners.RemoveListener(l);
387 iliev 1130 }
388    
389     void EngineChannel::RemoveAllFxSendCountListeners() {
390 persson 1896 p->llFxSendCountListeners.RemoveAllListeners();
391 iliev 1130 }
392    
393     void EngineChannel::fireFxSendCountChanged(int ChannelId, int NewCount) {
394 persson 1896 for (int i = 0; i < p->llFxSendCountListeners.GetListenerCount(); i++) {
395     p->llFxSendCountListeners.GetListener(i)->FxSendCountChanged(ChannelId, NewCount);
396 iliev 1130 }
397     }
398    
399 persson 2277 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 persson 1924 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 persson 2277 midiIndex.midi_bank_msb = hb;
416     midiIndex.midi_bank_lsb = lb;
417     midiIndex.midi_prog = pc;
418 persson 1924 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 schoenebeck 888 } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC