/[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 2330 - (show annotations) (download)
Mon Mar 12 15:14:31 2012 UTC (12 years, 1 month ago) by schoenebeck
File size: 13592 byte(s)
* Introduced new C++ API method EngineChannel::InstrumentFileName(int index)
  allowing to retrieve the whole list of files used for the loaded
  instrument on an engine channel (a.k.a. part). Some GigaStudio instruments
  for example are splitted over several files like "Foo.gig", "Foo.gx01",
  "Foo.gx02", ...
* Bumped version to 1.0.0.svn18

1 /***************************************************************************
2 * *
3 * LinuxSampler - modular, streaming capable sampler *
4 * *
5 * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6 * Copyright (C) 2005 - 2012 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 /**
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
97 void EngineChannel::SetMute(int state) throw (Exception) {
98 if (p->iMute == state) return;
99 if (state < -1 || state > 1)
100 throw Exception("Invalid Mute state: " + ToString(state));
101
102 p->iMute = state;
103
104 StatusChanged(true);
105 }
106
107 int EngineChannel::GetMute() {
108 return p->iMute;
109 }
110
111 void EngineChannel::SetSolo(bool solo) {
112 if (p->bSolo == solo) return;
113 p->bSolo = solo;
114 StatusChanged(true);
115 }
116
117 bool EngineChannel::GetSolo() {
118 return p->bSolo;
119 }
120
121 /*
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 uint8_t EngineChannel::GetMidiProgram() {
140 return p->uiMidiProgram; // AFAIK atomic on all systems
141 }
142
143 void EngineChannel::SetMidiProgram(uint8_t Program) {
144 p->bProgramChangeReceived = true;
145 p->uiMidiProgram = Program; // AFAIK atomic on all systems
146 }
147
148 uint8_t EngineChannel::GetMidiBankMsb() {
149 return (p->bMidiBankMsbReceived && p->bMidiBankLsbReceived)
150 ? p->uiMidiBankMsb : 0;
151 }
152
153 void EngineChannel::SetMidiBankMsb(uint8_t BankMSB) {
154 if (p->bProgramChangeReceived) {
155 p->bProgramChangeReceived =
156 p->bMidiBankLsbReceived = false;
157 }
158 p->bMidiBankMsbReceived = true;
159 p->uiMidiBankMsb = BankMSB; // AFAIK atomic on all systems
160 }
161
162 uint8_t EngineChannel::GetMidiBankLsb() {
163 return (!p->bMidiBankMsbReceived && !p->bMidiBankLsbReceived)
164 ? 0
165 : (p->bMidiBankMsbReceived && !p->bMidiBankLsbReceived)
166 ? p->uiMidiBankMsb
167 : p->uiMidiBankLsb;
168 }
169
170 void EngineChannel::SetMidiBankLsb(uint8_t BankLSB) {
171 if (p->bProgramChangeReceived) {
172 p->bProgramChangeReceived =
173 p->bMidiBankMsbReceived = false;
174 }
175 p->bMidiBankLsbReceived = true;
176 p->uiMidiBankLsb = BankLSB; // AFAIK atomic on all systems
177 }
178
179 bool EngineChannel::UsesNoMidiInstrumentMap() {
180 return (p->iMidiInstrumentMap == NO_MIDI_INSTRUMENT_MAP);
181 }
182
183 bool EngineChannel::UsesDefaultMidiInstrumentMap() {
184 return (p->iMidiInstrumentMap == DEFAULT_MIDI_INSTRUMENT_MAP);
185 }
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 if (find(maps.begin(), maps.end(), p->iMidiInstrumentMap) == maps.end()) {
195 // it doesn't exist anymore, so fall back to NONE and throw an exception
196 p->iMidiInstrumentMap = NO_MIDI_INSTRUMENT_MAP;
197 throw Exception("Assigned MIDI instrument map doesn't exist anymore, falling back to NONE");
198 }
199 return p->iMidiInstrumentMap;
200 }
201
202 void EngineChannel::SetMidiInstrumentMapToNone() {
203 if (p->iMidiInstrumentMap == NO_MIDI_INSTRUMENT_MAP) return;
204 p->iMidiInstrumentMap = NO_MIDI_INSTRUMENT_MAP;
205 StatusChanged(true);
206 }
207
208 void EngineChannel::SetMidiInstrumentMapToDefault() {
209 if (p->iMidiInstrumentMap == DEFAULT_MIDI_INSTRUMENT_MAP) return;
210 p->iMidiInstrumentMap = DEFAULT_MIDI_INSTRUMENT_MAP;
211 StatusChanged(true);
212 }
213
214 void EngineChannel::SetMidiInstrumentMap(int MidiMap) throw (Exception) {
215 if (p->iMidiInstrumentMap == MidiMap) return;
216
217 // 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 p->iMidiInstrumentMap = MidiMap; // assign the new map ID
222 StatusChanged(true);
223 }
224
225 // RPNs ...
226
227 void EngineChannel::SetMidiRpnControllerMsb(uint8_t CtrlMSB) {
228 p->uiMidiRpnMsb = CtrlMSB;
229 p->bMidiRpnReceived = true;
230 }
231
232 void EngineChannel::SetMidiRpnControllerLsb(uint8_t CtrlLSB) {
233 p->uiMidiRpnLsb = CtrlLSB;
234 p->bMidiRpnReceived = true;
235 }
236
237 void EngineChannel::ResetMidiRpnController() {
238 p->uiMidiRpnMsb = p->uiMidiRpnLsb = 0;
239 p->bMidiRpnReceived = false;
240 }
241
242 int EngineChannel::GetMidiRpnController() {
243 return (p->bMidiRpnReceived) ?
244 (p->uiMidiRpnMsb << 8) | p->uiMidiRpnLsb : -1;
245 }
246
247 // NRPNs ...
248
249 void EngineChannel::SetMidiNrpnControllerMsb(uint8_t CtrlMSB) {
250 p->uiMidiNrpnMsb = CtrlMSB;
251 p->bMidiNrpnReceived = true;
252 }
253
254 void EngineChannel::SetMidiNrpnControllerLsb(uint8_t CtrlLSB) {
255 p->uiMidiNrpnLsb = CtrlLSB;
256 p->bMidiNrpnReceived = true;
257 }
258
259 void EngineChannel::ResetMidiNrpnController() {
260 p->uiMidiNrpnMsb = p->uiMidiNrpnLsb = 0;
261 p->bMidiNrpnReceived = false;
262 }
263
264 int EngineChannel::GetMidiNrpnController() {
265 return (p->bMidiNrpnReceived) ?
266 (p->uiMidiNrpnMsb << 8) | p->uiMidiNrpnLsb : -1;
267 }
268
269 uint EngineChannel::GetVoiceCount() {
270 return atomic_read(&p->voiceCount);
271 }
272
273 void EngineChannel::SetVoiceCount(uint Voices) {
274 atomic_set(&p->voiceCount, Voices);
275 }
276
277 uint EngineChannel::GetDiskStreamCount() {
278 return atomic_read(&p->diskStreamCount);
279 }
280
281 void EngineChannel::SetDiskStreamCount(uint Streams) {
282 atomic_set(&p->diskStreamCount, Streams);
283 }
284
285 SamplerChannel* EngineChannel::GetSamplerChannel() {
286 if (p->pSamplerChannel == NULL) {
287 std::cerr << "EngineChannel::GetSamplerChannel(): pSamplerChannel is NULL, this is a bug!\n" << std::flush;
288 }
289 return p->pSamplerChannel;
290 }
291
292 void EngineChannel::SetSamplerChannel(SamplerChannel* pChannel) {
293 p->pSamplerChannel = pChannel;
294 }
295
296 Sampler* EngineChannel::GetSampler() {
297 if (GetSamplerChannel() == NULL) return NULL;
298 return GetSamplerChannel()->GetSampler();
299 }
300
301 void EngineChannel::AddFxSendCountListener(FxSendCountListener* l) {
302 p->llFxSendCountListeners.AddListener(l);
303 }
304
305 void EngineChannel::RemoveFxSendCountListener(FxSendCountListener* l) {
306 p->llFxSendCountListeners.RemoveListener(l);
307 }
308
309 void EngineChannel::RemoveAllFxSendCountListeners() {
310 p->llFxSendCountListeners.RemoveAllListeners();
311 }
312
313 void EngineChannel::fireFxSendCountChanged(int ChannelId, int NewCount) {
314 for (int i = 0; i < p->llFxSendCountListeners.GetListenerCount(); i++) {
315 p->llFxSendCountListeners.GetListener(i)->FxSendCountChanged(ChannelId, NewCount);
316 }
317 }
318
319 void EngineChannel::ExecuteProgramChange(uint32_t Program) {
320 uint8_t hb = (Program >> 16) & 0xff;
321 uint8_t lb = (Program >> 8) & 0xff;
322 uint8_t pc = Program & 0x7f;
323
324 dmsg(1,("Received MIDI program change (msb=%d) (lsb=%d) (prog=%d)\n", hb ,lb, pc));
325 std::vector<int> maps = MidiInstrumentMapper::Maps();
326 if (maps.empty()) return;
327
328 if (UsesNoMidiInstrumentMap()) return;
329 if (MidiInstrumentMapper::GetMapCount() == 0) return;
330 // retrieve the MIDI instrument map this engine channel is assigned to
331 int iMapID = (UsesDefaultMidiInstrumentMap())
332 ? MidiInstrumentMapper::GetDefaultMap() /*default*/ : GetMidiInstrumentMap();
333 // is there an entry for this MIDI bank&prog pair in that map?
334 midi_prog_index_t midiIndex;
335 midiIndex.midi_bank_msb = hb;
336 midiIndex.midi_bank_lsb = lb;
337 midiIndex.midi_prog = pc;
338 optional<MidiInstrumentMapper::entry_t> mapping =
339 MidiInstrumentMapper::GetEntry(iMapID, midiIndex);
340 if (mapping) { // if mapping exists ...
341 InstrumentManager::instrument_id_t id;
342 id.FileName = mapping->InstrumentFile;
343 id.Index = mapping->InstrumentIndex;
344 //TODO: we should switch the engine type here
345 InstrumentManager::LoadInstrumentInBackground(id, this);
346 Volume(mapping->Volume);
347 }
348 }
349
350 } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC