/[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 2121 - (show annotations) (download)
Tue Sep 14 17:09:08 2010 UTC (13 years, 7 months ago) by schoenebeck
File size: 12770 byte(s)
* implemented Roland GS NRPN 1ArrH which allows to set volume per note
* implemented Roland GS NRPN 1CrrH which allows to set pan per note
* implemented Roland GS NRPN 1DrrH which allows to set reverb send per
  note (in this implementation of the sampler its simply hard routed to
  the 1st effect send of the sampler channel, no matter what the actual
  effect type is)
* implemented Roland GS NRPN 1ErrH which allows to set chorus send per
  note (in this implementation of the sampler its simply hard routed to
  the 2nd effect send of the sampler channel, no matter what the actual
  effect type is)
* bumped version to 1.0.0cvs4

1 /***************************************************************************
2 * *
3 * LinuxSampler - modular, streaming capable sampler *
4 * *
5 * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6 * Copyright (C) 2005 - 20010 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 8 bits / coarse)
45 uint8_t uiMidiRpnLsb; ///< MIDI Registered Parameter Number (lower 8 bits / fine)
46 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 bool bMidiBankMsbReceived;
49 bool bMidiBankLsbReceived;
50 bool bProgramChangeReceived;
51 bool bMidiRpnReceived;
52 bool bMidiNrpnReceived;
53 int iMidiInstrumentMap;
54 atomic_t voiceCount;
55 atomic_t diskStreamCount;
56 SamplerChannel* pSamplerChannel;
57 ListenerList<FxSendCountListener*> llFxSendCountListeners;
58 };
59
60 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 SetVoiceCount(0);
71 SetDiskStreamCount(0);
72 p->pSamplerChannel = NULL;
73 ResetMidiRpnController();
74 ResetMidiNrpnController();
75 }
76
77 EngineChannel::~EngineChannel() {
78 delete p;
79 }
80
81 void EngineChannel::SetMute(int state) throw (Exception) {
82 if (p->iMute == state) return;
83 if (state < -1 || state > 1)
84 throw Exception("Invalid Mute state: " + ToString(state));
85
86 p->iMute = state;
87
88 StatusChanged(true);
89 }
90
91 int EngineChannel::GetMute() {
92 return p->iMute;
93 }
94
95 void EngineChannel::SetSolo(bool solo) {
96 if (p->bSolo == solo) return;
97 p->bSolo = solo;
98 StatusChanged(true);
99 }
100
101 bool EngineChannel::GetSolo() {
102 return p->bSolo;
103 }
104
105 /*
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 uint8_t EngineChannel::GetMidiProgram() {
124 return p->uiMidiProgram; // AFAIK atomic on all systems
125 }
126
127 void EngineChannel::SetMidiProgram(uint8_t Program) {
128 p->bProgramChangeReceived = true;
129 p->uiMidiProgram = Program; // AFAIK atomic on all systems
130 }
131
132 uint8_t EngineChannel::GetMidiBankMsb() {
133 return (p->bMidiBankMsbReceived && p->bMidiBankLsbReceived)
134 ? p->uiMidiBankMsb : 0;
135 }
136
137 void EngineChannel::SetMidiBankMsb(uint8_t BankMSB) {
138 if (p->bProgramChangeReceived) {
139 p->bProgramChangeReceived =
140 p->bMidiBankLsbReceived = false;
141 }
142 p->bMidiBankMsbReceived = true;
143 p->uiMidiBankMsb = BankMSB; // AFAIK atomic on all systems
144 }
145
146 uint8_t EngineChannel::GetMidiBankLsb() {
147 return (!p->bMidiBankMsbReceived && !p->bMidiBankLsbReceived)
148 ? 0
149 : (p->bMidiBankMsbReceived && !p->bMidiBankLsbReceived)
150 ? p->uiMidiBankMsb
151 : p->uiMidiBankLsb;
152 }
153
154 void EngineChannel::SetMidiBankLsb(uint8_t BankLSB) {
155 if (p->bProgramChangeReceived) {
156 p->bProgramChangeReceived =
157 p->bMidiBankMsbReceived = false;
158 }
159 p->bMidiBankLsbReceived = true;
160 p->uiMidiBankLsb = BankLSB; // AFAIK atomic on all systems
161 }
162
163 bool EngineChannel::UsesNoMidiInstrumentMap() {
164 return (p->iMidiInstrumentMap == NO_MIDI_INSTRUMENT_MAP);
165 }
166
167 bool EngineChannel::UsesDefaultMidiInstrumentMap() {
168 return (p->iMidiInstrumentMap == DEFAULT_MIDI_INSTRUMENT_MAP);
169 }
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 if (find(maps.begin(), maps.end(), p->iMidiInstrumentMap) == maps.end()) {
179 // it doesn't exist anymore, so fall back to NONE and throw an exception
180 p->iMidiInstrumentMap = NO_MIDI_INSTRUMENT_MAP;
181 throw Exception("Assigned MIDI instrument map doesn't exist anymore, falling back to NONE");
182 }
183 return p->iMidiInstrumentMap;
184 }
185
186 void EngineChannel::SetMidiInstrumentMapToNone() {
187 if (p->iMidiInstrumentMap == NO_MIDI_INSTRUMENT_MAP) return;
188 p->iMidiInstrumentMap = NO_MIDI_INSTRUMENT_MAP;
189 StatusChanged(true);
190 }
191
192 void EngineChannel::SetMidiInstrumentMapToDefault() {
193 if (p->iMidiInstrumentMap == DEFAULT_MIDI_INSTRUMENT_MAP) return;
194 p->iMidiInstrumentMap = DEFAULT_MIDI_INSTRUMENT_MAP;
195 StatusChanged(true);
196 }
197
198 void EngineChannel::SetMidiInstrumentMap(int MidiMap) throw (Exception) {
199 if (p->iMidiInstrumentMap == MidiMap) return;
200
201 // 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 p->iMidiInstrumentMap = MidiMap; // assign the new map ID
206 StatusChanged(true);
207 }
208
209 // RPNs ...
210
211 void EngineChannel::SetMidiRpnControllerMsb(uint8_t CtrlMSB) {
212 p->uiMidiRpnMsb = CtrlMSB;
213 p->bMidiRpnReceived = true;
214 }
215
216 void EngineChannel::SetMidiRpnControllerLsb(uint8_t CtrlLSB) {
217 p->uiMidiRpnLsb = CtrlLSB;
218 p->bMidiRpnReceived = true;
219 }
220
221 void EngineChannel::ResetMidiRpnController() {
222 p->uiMidiRpnMsb = p->uiMidiRpnLsb = 0;
223 p->bMidiRpnReceived = false;
224 }
225
226 int EngineChannel::GetMidiRpnController() {
227 return (p->bMidiRpnReceived) ?
228 (p->uiMidiRpnMsb << 8) | p->uiMidiRpnLsb : -1;
229 }
230
231 // 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 uint EngineChannel::GetVoiceCount() {
254 return atomic_read(&p->voiceCount);
255 }
256
257 void EngineChannel::SetVoiceCount(uint Voices) {
258 atomic_set(&p->voiceCount, Voices);
259 }
260
261 uint EngineChannel::GetDiskStreamCount() {
262 return atomic_read(&p->diskStreamCount);
263 }
264
265 void EngineChannel::SetDiskStreamCount(uint Streams) {
266 atomic_set(&p->diskStreamCount, Streams);
267 }
268
269 SamplerChannel* EngineChannel::GetSamplerChannel() {
270 if (p->pSamplerChannel == NULL) {
271 std::cerr << "EngineChannel::GetSamplerChannel(): pSamplerChannel is NULL, this is a bug!\n" << std::flush;
272 }
273 return p->pSamplerChannel;
274 }
275
276 void EngineChannel::SetSamplerChannel(SamplerChannel* pChannel) {
277 p->pSamplerChannel = pChannel;
278 }
279
280 Sampler* EngineChannel::GetSampler() {
281 if (GetSamplerChannel() == NULL) return NULL;
282 return GetSamplerChannel()->GetSampler();
283 }
284
285 void EngineChannel::AddFxSendCountListener(FxSendCountListener* l) {
286 p->llFxSendCountListeners.AddListener(l);
287 }
288
289 void EngineChannel::RemoveFxSendCountListener(FxSendCountListener* l) {
290 p->llFxSendCountListeners.RemoveListener(l);
291 }
292
293 void EngineChannel::RemoveAllFxSendCountListeners() {
294 p->llFxSendCountListeners.RemoveAllListeners();
295 }
296
297 void EngineChannel::fireFxSendCountChanged(int ChannelId, int NewCount) {
298 for (int i = 0; i < p->llFxSendCountListeners.GetListenerCount(); i++) {
299 p->llFxSendCountListeners.GetListener(i)->FxSendCountChanged(ChannelId, NewCount);
300 }
301 }
302
303 void EngineChannel::ExecuteProgramChange(uint8_t Program) {
304 dmsg(1,("Received MIDI program change (prog=%d)\n",Program));
305 std::vector<int> maps = MidiInstrumentMapper::Maps();
306 if (maps.empty()) return;
307
308 SetMidiProgram(Program);
309 if (UsesNoMidiInstrumentMap()) return;
310 if (MidiInstrumentMapper::GetMapCount() == 0) return;
311 // retrieve the MIDI instrument map this engine channel is assigned to
312 int iMapID = (UsesDefaultMidiInstrumentMap())
313 ? MidiInstrumentMapper::GetDefaultMap() /*default*/ : GetMidiInstrumentMap();
314 // is there an entry for this MIDI bank&prog pair in that map?
315 midi_prog_index_t midiIndex;
316 midiIndex.midi_bank_msb = GetMidiBankMsb();
317 midiIndex.midi_bank_lsb = GetMidiBankLsb();
318 midiIndex.midi_prog = GetMidiProgram();
319 optional<MidiInstrumentMapper::entry_t> mapping =
320 MidiInstrumentMapper::GetEntry(iMapID, midiIndex);
321 if (mapping) { // if mapping exists ...
322 InstrumentManager::instrument_id_t id;
323 id.FileName = mapping->InstrumentFile;
324 id.Index = mapping->InstrumentIndex;
325 //TODO: we should switch the engine type here
326 InstrumentManager::LoadInstrumentInBackground(id, this);
327 Volume(mapping->Volume);
328 }
329 }
330
331 } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC