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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3699 - (show 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 /***************************************************************************
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
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
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 */
97 String EngineChannel::InstrumentFileName(int index) {
98 return (index == 0) ? InstrumentFileName() : "";
99 }
100
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
111 int EngineChannel::GetMute() {
112 return p->iMute;
113 }
114
115 void EngineChannel::SetSolo(bool solo) {
116 if (p->bSolo == solo) return;
117 p->bSolo = solo;
118 StatusChanged(true);
119 }
120
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
143 uint8_t EngineChannel::GetMidiProgram() {
144 return p->uiMidiProgram; // AFAIK atomic on all systems
145 }
146
147 void EngineChannel::SetMidiProgram(uint8_t Program) {
148 p->bProgramChangeReceived = true;
149 p->uiMidiProgram = Program; // AFAIK atomic on all systems
150 }
151
152 uint8_t EngineChannel::GetMidiBankMsb() {
153 return (p->bMidiBankMsbReceived && p->bMidiBankLsbReceived)
154 ? p->uiMidiBankMsb : 0;
155 }
156
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
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
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
183 bool EngineChannel::UsesNoMidiInstrumentMap() {
184 return (p->iMidiInstrumentMap == NO_MIDI_INSTRUMENT_MAP);
185 }
186
187 bool EngineChannel::UsesDefaultMidiInstrumentMap() {
188 return (p->iMidiInstrumentMap == DEFAULT_MIDI_INSTRUMENT_MAP);
189 }
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 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
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
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
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
231 void EngineChannel::SetMidiRpnParameterMsb(uint8_t ParamMSB) {
232 p->uiMidiRpnMsb = ParamMSB & 127;
233 p->bMidiRpnReceived = true;
234 }
235
236 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 p->bMidiRpnReceived = true;
243 }
244
245 void EngineChannel::SetMidiRpnControllerLsb(uint8_t CtrlLSB) { // deprecated API
246 SetMidiRpnParameterLsb(CtrlLSB);
247 }
248
249 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 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 void EngineChannel::ResetMidiRpnParameter() {
265 p->uiMidiRpnMsb = p->uiMidiRpnLsb = 0;
266 p->uiMidiRpnDataMsb = p->uiMidiRpnDataLsb = 0;
267 p->bMidiRpnReceived = false;
268 }
269
270 void EngineChannel::ResetMidiRpnController() { // deprecated API
271 ResetMidiRpnParameter();
272 }
273
274 int EngineChannel::GetMidiRpnParameter() {
275 return (p->bMidiRpnReceived) ?
276 (p->uiMidiRpnMsb << 7) | p->uiMidiRpnLsb : -1;
277 }
278
279 int EngineChannel::GetMidiRpnController() { // deprecated API
280 return (p->bMidiRpnReceived) ?
281 (p->uiMidiRpnMsb << 8) | p->uiMidiRpnLsb : -1;
282 }
283
284 int EngineChannel::GetMidiRpnData() {
285 return (p->bMidiRpnReceived) ?
286 (p->uiMidiRpnDataMsb << 7) | p->uiMidiRpnDataLsb : 0;
287 }
288
289 // NRPNs ...
290
291 void EngineChannel::SetMidiNrpnParameterMsb(uint8_t ParamMSB) {
292 p->uiMidiNrpnMsb = ParamMSB & 127;
293 p->bMidiNrpnReceived = true;
294 }
295
296 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 p->bMidiNrpnReceived = true;
303 }
304
305 void EngineChannel::SetMidiNrpnControllerLsb(uint8_t CtrlLSB) { // deprecated API
306 SetMidiNrpnParameterLsb(CtrlLSB);
307 }
308
309 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 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 void EngineChannel::ResetMidiNrpnParameter() {
325 p->uiMidiNrpnMsb = p->uiMidiNrpnLsb = 0;
326 p->uiMidiNrpnDataMsb = p->uiMidiNrpnDataLsb = 0;
327 p->bMidiNrpnReceived = false;
328 }
329
330 void EngineChannel::ResetMidiNrpnController() { // deprecated API
331 ResetMidiNrpnParameter();
332 }
333
334 int EngineChannel::GetMidiNrpnParameter() {
335 return (p->bMidiNrpnReceived) ?
336 (p->uiMidiNrpnMsb << 7) | p->uiMidiNrpnLsb : -1;
337 }
338
339 int EngineChannel::GetMidiNrpnController() { // deprecated API
340 return (p->bMidiNrpnReceived) ?
341 (p->uiMidiNrpnMsb << 8) | p->uiMidiNrpnLsb : -1;
342 }
343
344 int EngineChannel::GetMidiNrpnData() {
345 return (p->bMidiNrpnReceived) ?
346 (p->uiMidiNrpnDataMsb << 7) | p->uiMidiNrpnDataLsb : 0;
347 }
348
349 uint EngineChannel::GetVoiceCount() {
350 return atomic_read(&p->voiceCount);
351 }
352
353 void EngineChannel::SetVoiceCount(uint Voices) {
354 atomic_set(&p->voiceCount, Voices);
355 }
356
357 uint EngineChannel::GetDiskStreamCount() {
358 return atomic_read(&p->diskStreamCount);
359 }
360
361 void EngineChannel::SetDiskStreamCount(uint Streams) {
362 atomic_set(&p->diskStreamCount, Streams);
363 }
364
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
372 void EngineChannel::SetSamplerChannel(SamplerChannel* pChannel) {
373 p->pSamplerChannel = pChannel;
374 }
375
376 Sampler* EngineChannel::GetSampler() {
377 if (GetSamplerChannel() == NULL) return NULL;
378 return GetSamplerChannel()->GetSampler();
379 }
380
381 void EngineChannel::AddFxSendCountListener(FxSendCountListener* l) {
382 p->llFxSendCountListeners.AddListener(l);
383 }
384
385 void EngineChannel::RemoveFxSendCountListener(FxSendCountListener* l) {
386 p->llFxSendCountListeners.RemoveListener(l);
387 }
388
389 void EngineChannel::RemoveAllFxSendCountListeners() {
390 p->llFxSendCountListeners.RemoveAllListeners();
391 }
392
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
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

  ViewVC Help
Powered by ViewVC