/[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 3687 - (hide annotations) (download)
Thu Jan 2 22:37:07 2020 UTC (4 years, 3 months ago) by schoenebeck
File size: 14723 byte(s)
EngineChannel: Overhaul of RPN / NRPN related methods:

* Added new *Rpn*Parameter*() methods as replacement for previous
  *Rpn*Controller*() methods and marked the old ones as deprecated.

* Added new *Nrpn*Parameter*() methods as replacement for previous
  *Nrpn*Controller*() methods and marked the old ones as deprecated.

* The new GetMidiRpnParameter() and GetMidiNrpnParameter() methods
  return their result as common (in MIDI world) 14 bit representation
  of sender's MSB and LSB values, instead of the uncommon 16 bit
  representation of the old GetMidiRpnController() and
  GetMidiNrpnController() methods.

* Bumped version (2.1.1.svn28).

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

  ViewVC Help
Powered by ViewVC