/[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 2277 - (hide annotations) (download)
Sat Oct 1 08:23:02 2011 UTC (12 years, 6 months ago) by persson
File size: 12845 byte(s)
* fixed handling of rapid bank select and program change messages sent
  to the same sampler channel (patch from the Open Octave project,
  slightly adjusted)

1 schoenebeck 888 /***************************************************************************
2     * *
3     * LinuxSampler - modular, streaming capable sampler *
4     * *
5     * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6 persson 2277 * Copyright (C) 2005 - 2011 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     uint8_t uiMidiRpnMsb; ///< MIDI Registered Parameter Number (upper 8 bits / coarse)
45     uint8_t uiMidiRpnLsb; ///< MIDI Registered Parameter Number (lower 8 bits / fine)
46 schoenebeck 2121 uint8_t uiMidiNrpnMsb; ///< MIDI Non-Registered Parameter Number (upper 8 bits / coarse)
47     uint8_t uiMidiNrpnLsb; ///< MIDI Non-Registered Parameter Number (lower 8 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 1044 ResetMidiRpnController();
74 schoenebeck 2121 ResetMidiNrpnController();
75 schoenebeck 888 }
76    
77 schoenebeck 1879 EngineChannel::~EngineChannel() {
78 persson 1896 delete p;
79 schoenebeck 1879 }
80    
81 schoenebeck 888 void EngineChannel::SetMute(int state) throw (Exception) {
82 persson 1896 if (p->iMute == state) return;
83 schoenebeck 1879 if (state < -1 || state > 1)
84 schoenebeck 888 throw Exception("Invalid Mute state: " + ToString(state));
85    
86 persson 1896 p->iMute = state;
87 schoenebeck 888
88     StatusChanged(true);
89     }
90    
91     int EngineChannel::GetMute() {
92 persson 1896 return p->iMute;
93 schoenebeck 888 }
94    
95     void EngineChannel::SetSolo(bool solo) {
96 persson 1896 if (p->bSolo == solo) return;
97     p->bSolo = solo;
98 schoenebeck 888 StatusChanged(true);
99     }
100    
101     bool EngineChannel::GetSolo() {
102 persson 1896 return p->bSolo;
103 schoenebeck 888 }
104    
105 schoenebeck 973 /*
106     We use a workaround for MIDI devices (i.e. old keyboards) which either
107     only send bank select MSB or only bank select LSB messages. Bank
108     selects will be modified according to the following table:
109    
110     MIDI Sequence received: -> GetMidiBankMsb()= | GetMidiBankLsb()=
111     ---------------------------------------------------------------------------
112     program change -> 0 | 0
113     bank LSB, program change -> 0 | LSB value
114     bank MSB, program change -> 0 | MSB value
115     bank LSB, bank MSB, program change -> MSB value | LSB value
116     bank MSB, bank LSB, program change -> MSB value | LSB value
117     ---------------------------------------------------------------------------
118    
119     That way we ensure those limited devices always to switch between the
120     following set of MIDI instrument banks: { 0, 1, 2, ..., 127 }
121     */
122    
123 schoenebeck 947 uint8_t EngineChannel::GetMidiProgram() {
124 persson 1896 return p->uiMidiProgram; // AFAIK atomic on all systems
125 schoenebeck 947 }
126    
127     void EngineChannel::SetMidiProgram(uint8_t Program) {
128 persson 1896 p->bProgramChangeReceived = true;
129     p->uiMidiProgram = Program; // AFAIK atomic on all systems
130 schoenebeck 947 }
131    
132     uint8_t EngineChannel::GetMidiBankMsb() {
133 persson 1896 return (p->bMidiBankMsbReceived && p->bMidiBankLsbReceived)
134     ? p->uiMidiBankMsb : 0;
135 schoenebeck 947 }
136    
137     void EngineChannel::SetMidiBankMsb(uint8_t BankMSB) {
138 persson 1896 if (p->bProgramChangeReceived) {
139     p->bProgramChangeReceived =
140     p->bMidiBankLsbReceived = false;
141 schoenebeck 1879 }
142 persson 1896 p->bMidiBankMsbReceived = true;
143     p->uiMidiBankMsb = BankMSB; // AFAIK atomic on all systems
144 schoenebeck 947 }
145    
146     uint8_t EngineChannel::GetMidiBankLsb() {
147 persson 1896 return (!p->bMidiBankMsbReceived && !p->bMidiBankLsbReceived)
148 schoenebeck 973 ? 0
149 persson 1896 : (p->bMidiBankMsbReceived && !p->bMidiBankLsbReceived)
150     ? p->uiMidiBankMsb
151     : p->uiMidiBankLsb;
152 schoenebeck 947 }
153    
154     void EngineChannel::SetMidiBankLsb(uint8_t BankLSB) {
155 persson 1896 if (p->bProgramChangeReceived) {
156     p->bProgramChangeReceived =
157     p->bMidiBankMsbReceived = false;
158 schoenebeck 1879 }
159 persson 1896 p->bMidiBankLsbReceived = true;
160     p->uiMidiBankLsb = BankLSB; // AFAIK atomic on all systems
161 schoenebeck 947 }
162    
163 schoenebeck 973 bool EngineChannel::UsesNoMidiInstrumentMap() {
164 persson 1896 return (p->iMidiInstrumentMap == NO_MIDI_INSTRUMENT_MAP);
165 schoenebeck 973 }
166    
167     bool EngineChannel::UsesDefaultMidiInstrumentMap() {
168 persson 1896 return (p->iMidiInstrumentMap == DEFAULT_MIDI_INSTRUMENT_MAP);
169 schoenebeck 973 }
170    
171     int EngineChannel::GetMidiInstrumentMap() throw (Exception) {
172     if (UsesNoMidiInstrumentMap())
173     throw Exception("EngineChannel is using no MIDI instrument map");
174     if (UsesDefaultMidiInstrumentMap())
175     throw Exception("EngineChannel is using default MIDI instrument map");
176     // check if the stored map still exists in the MIDI instrument mapper
177     std::vector<int> maps = MidiInstrumentMapper::Maps();
178 persson 1896 if (find(maps.begin(), maps.end(), p->iMidiInstrumentMap) == maps.end()) {
179 schoenebeck 973 // it doesn't exist anymore, so fall back to NONE and throw an exception
180 persson 1896 p->iMidiInstrumentMap = NO_MIDI_INSTRUMENT_MAP;
181 schoenebeck 973 throw Exception("Assigned MIDI instrument map doesn't exist anymore, falling back to NONE");
182     }
183 persson 1896 return p->iMidiInstrumentMap;
184 schoenebeck 973 }
185    
186     void EngineChannel::SetMidiInstrumentMapToNone() {
187 persson 1896 if (p->iMidiInstrumentMap == NO_MIDI_INSTRUMENT_MAP) return;
188     p->iMidiInstrumentMap = NO_MIDI_INSTRUMENT_MAP;
189 iliev 1254 StatusChanged(true);
190 schoenebeck 973 }
191    
192     void EngineChannel::SetMidiInstrumentMapToDefault() {
193 persson 1896 if (p->iMidiInstrumentMap == DEFAULT_MIDI_INSTRUMENT_MAP) return;
194     p->iMidiInstrumentMap = DEFAULT_MIDI_INSTRUMENT_MAP;
195 iliev 1254 StatusChanged(true);
196 schoenebeck 973 }
197    
198     void EngineChannel::SetMidiInstrumentMap(int MidiMap) throw (Exception) {
199 persson 1896 if (p->iMidiInstrumentMap == MidiMap) return;
200 iliev 1254
201 schoenebeck 973 // check if given map actually exists in the MIDI instrument mapper
202     std::vector<int> maps = MidiInstrumentMapper::Maps();
203     if (find(maps.begin(), maps.end(), MidiMap) == maps.end())
204     throw Exception("MIDI instrument map doesn't exist");
205 persson 1896 p->iMidiInstrumentMap = MidiMap; // assign the new map ID
206 iliev 1254 StatusChanged(true);
207 schoenebeck 973 }
208    
209 schoenebeck 2121 // RPNs ...
210    
211 schoenebeck 1041 void EngineChannel::SetMidiRpnControllerMsb(uint8_t CtrlMSB) {
212 persson 1896 p->uiMidiRpnMsb = CtrlMSB;
213     p->bMidiRpnReceived = true;
214 schoenebeck 1041 }
215    
216     void EngineChannel::SetMidiRpnControllerLsb(uint8_t CtrlLSB) {
217 persson 1896 p->uiMidiRpnLsb = CtrlLSB;
218     p->bMidiRpnReceived = true;
219 schoenebeck 1041 }
220    
221 schoenebeck 1044 void EngineChannel::ResetMidiRpnController() {
222 persson 1896 p->uiMidiRpnMsb = p->uiMidiRpnLsb = 0;
223     p->bMidiRpnReceived = false;
224 schoenebeck 1044 }
225    
226 schoenebeck 1041 int EngineChannel::GetMidiRpnController() {
227 persson 1896 return (p->bMidiRpnReceived) ?
228     (p->uiMidiRpnMsb << 8) | p->uiMidiRpnLsb : -1;
229 schoenebeck 1041 }
230    
231 schoenebeck 2121 // NRPNs ...
232    
233     void EngineChannel::SetMidiNrpnControllerMsb(uint8_t CtrlMSB) {
234     p->uiMidiNrpnMsb = CtrlMSB;
235     p->bMidiNrpnReceived = true;
236     }
237    
238     void EngineChannel::SetMidiNrpnControllerLsb(uint8_t CtrlLSB) {
239     p->uiMidiNrpnLsb = CtrlLSB;
240     p->bMidiNrpnReceived = true;
241     }
242    
243     void EngineChannel::ResetMidiNrpnController() {
244     p->uiMidiNrpnMsb = p->uiMidiNrpnLsb = 0;
245     p->bMidiNrpnReceived = false;
246     }
247    
248     int EngineChannel::GetMidiNrpnController() {
249     return (p->bMidiNrpnReceived) ?
250     (p->uiMidiNrpnMsb << 8) | p->uiMidiNrpnLsb : -1;
251     }
252    
253 iliev 1297 uint EngineChannel::GetVoiceCount() {
254 persson 1896 return atomic_read(&p->voiceCount);
255 iliev 1297 }
256 schoenebeck 1879
257 iliev 1297 void EngineChannel::SetVoiceCount(uint Voices) {
258 persson 1896 atomic_set(&p->voiceCount, Voices);
259 iliev 1297 }
260    
261     uint EngineChannel::GetDiskStreamCount() {
262 persson 1896 return atomic_read(&p->diskStreamCount);
263 iliev 1297 }
264 schoenebeck 1879
265 iliev 1297 void EngineChannel::SetDiskStreamCount(uint Streams) {
266 persson 1896 atomic_set(&p->diskStreamCount, Streams);
267 iliev 1297 }
268 schoenebeck 1879
269 iliev 1761 SamplerChannel* EngineChannel::GetSamplerChannel() {
270 persson 1896 if (p->pSamplerChannel == NULL) {
271 iliev 1761 std::cerr << "EngineChannel::GetSamplerChannel(): pSamplerChannel is NULL, this is a bug!\n" << std::flush;
272     }
273 persson 1896 return p->pSamplerChannel;
274 iliev 1761 }
275 iliev 1297
276 iliev 1761 void EngineChannel::SetSamplerChannel(SamplerChannel* pChannel) {
277 persson 1896 p->pSamplerChannel = pChannel;
278 iliev 1761 }
279    
280     Sampler* EngineChannel::GetSampler() {
281     if (GetSamplerChannel() == NULL) return NULL;
282     return GetSamplerChannel()->GetSampler();
283     }
284    
285 iliev 1130 void EngineChannel::AddFxSendCountListener(FxSendCountListener* l) {
286 persson 1896 p->llFxSendCountListeners.AddListener(l);
287 iliev 1130 }
288    
289     void EngineChannel::RemoveFxSendCountListener(FxSendCountListener* l) {
290 persson 1896 p->llFxSendCountListeners.RemoveListener(l);
291 iliev 1130 }
292    
293     void EngineChannel::RemoveAllFxSendCountListeners() {
294 persson 1896 p->llFxSendCountListeners.RemoveAllListeners();
295 iliev 1130 }
296    
297     void EngineChannel::fireFxSendCountChanged(int ChannelId, int NewCount) {
298 persson 1896 for (int i = 0; i < p->llFxSendCountListeners.GetListenerCount(); i++) {
299     p->llFxSendCountListeners.GetListener(i)->FxSendCountChanged(ChannelId, NewCount);
300 iliev 1130 }
301     }
302    
303 persson 2277 void EngineChannel::ExecuteProgramChange(uint32_t Program) {
304     uint8_t hb = (Program >> 16) & 0xff;
305     uint8_t lb = (Program >> 8) & 0xff;
306     uint8_t pc = Program & 0x7f;
307    
308     dmsg(1,("Received MIDI program change (msb=%d) (lsb=%d) (prog=%d)\n", hb ,lb, pc));
309 persson 1924 std::vector<int> maps = MidiInstrumentMapper::Maps();
310     if (maps.empty()) return;
311    
312     if (UsesNoMidiInstrumentMap()) return;
313     if (MidiInstrumentMapper::GetMapCount() == 0) return;
314     // retrieve the MIDI instrument map this engine channel is assigned to
315     int iMapID = (UsesDefaultMidiInstrumentMap())
316     ? MidiInstrumentMapper::GetDefaultMap() /*default*/ : GetMidiInstrumentMap();
317     // is there an entry for this MIDI bank&prog pair in that map?
318     midi_prog_index_t midiIndex;
319 persson 2277 midiIndex.midi_bank_msb = hb;
320     midiIndex.midi_bank_lsb = lb;
321     midiIndex.midi_prog = pc;
322 persson 1924 optional<MidiInstrumentMapper::entry_t> mapping =
323     MidiInstrumentMapper::GetEntry(iMapID, midiIndex);
324     if (mapping) { // if mapping exists ...
325     InstrumentManager::instrument_id_t id;
326     id.FileName = mapping->InstrumentFile;
327     id.Index = mapping->InstrumentIndex;
328     //TODO: we should switch the engine type here
329     InstrumentManager::LoadInstrumentInBackground(id, this);
330     Volume(mapping->Volume);
331     }
332     }
333    
334 schoenebeck 888 } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC