/[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 2330 - (hide annotations) (download)
Mon Mar 12 15:14:31 2012 UTC (12 years, 2 months 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 schoenebeck 888 /***************************************************************************
2     * *
3     * LinuxSampler - modular, streaming capable sampler *
4     * *
5     * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6 schoenebeck 2330 * Copyright (C) 2005 - 2012 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 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 1041 void EngineChannel::SetMidiRpnControllerMsb(uint8_t CtrlMSB) {
228 persson 1896 p->uiMidiRpnMsb = CtrlMSB;
229     p->bMidiRpnReceived = true;
230 schoenebeck 1041 }
231    
232     void EngineChannel::SetMidiRpnControllerLsb(uint8_t CtrlLSB) {
233 persson 1896 p->uiMidiRpnLsb = CtrlLSB;
234     p->bMidiRpnReceived = true;
235 schoenebeck 1041 }
236    
237 schoenebeck 1044 void EngineChannel::ResetMidiRpnController() {
238 persson 1896 p->uiMidiRpnMsb = p->uiMidiRpnLsb = 0;
239     p->bMidiRpnReceived = false;
240 schoenebeck 1044 }
241    
242 schoenebeck 1041 int EngineChannel::GetMidiRpnController() {
243 persson 1896 return (p->bMidiRpnReceived) ?
244     (p->uiMidiRpnMsb << 8) | p->uiMidiRpnLsb : -1;
245 schoenebeck 1041 }
246    
247 schoenebeck 2121 // 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 iliev 1297 uint EngineChannel::GetVoiceCount() {
270 persson 1896 return atomic_read(&p->voiceCount);
271 iliev 1297 }
272 schoenebeck 1879
273 iliev 1297 void EngineChannel::SetVoiceCount(uint Voices) {
274 persson 1896 atomic_set(&p->voiceCount, Voices);
275 iliev 1297 }
276    
277     uint EngineChannel::GetDiskStreamCount() {
278 persson 1896 return atomic_read(&p->diskStreamCount);
279 iliev 1297 }
280 schoenebeck 1879
281 iliev 1297 void EngineChannel::SetDiskStreamCount(uint Streams) {
282 persson 1896 atomic_set(&p->diskStreamCount, Streams);
283 iliev 1297 }
284 schoenebeck 1879
285 iliev 1761 SamplerChannel* EngineChannel::GetSamplerChannel() {
286 persson 1896 if (p->pSamplerChannel == NULL) {
287 iliev 1761 std::cerr << "EngineChannel::GetSamplerChannel(): pSamplerChannel is NULL, this is a bug!\n" << std::flush;
288     }
289 persson 1896 return p->pSamplerChannel;
290 iliev 1761 }
291 iliev 1297
292 iliev 1761 void EngineChannel::SetSamplerChannel(SamplerChannel* pChannel) {
293 persson 1896 p->pSamplerChannel = pChannel;
294 iliev 1761 }
295    
296     Sampler* EngineChannel::GetSampler() {
297     if (GetSamplerChannel() == NULL) return NULL;
298     return GetSamplerChannel()->GetSampler();
299     }
300    
301 iliev 1130 void EngineChannel::AddFxSendCountListener(FxSendCountListener* l) {
302 persson 1896 p->llFxSendCountListeners.AddListener(l);
303 iliev 1130 }
304    
305     void EngineChannel::RemoveFxSendCountListener(FxSendCountListener* l) {
306 persson 1896 p->llFxSendCountListeners.RemoveListener(l);
307 iliev 1130 }
308    
309     void EngineChannel::RemoveAllFxSendCountListeners() {
310 persson 1896 p->llFxSendCountListeners.RemoveAllListeners();
311 iliev 1130 }
312    
313     void EngineChannel::fireFxSendCountChanged(int ChannelId, int NewCount) {
314 persson 1896 for (int i = 0; i < p->llFxSendCountListeners.GetListenerCount(); i++) {
315     p->llFxSendCountListeners.GetListener(i)->FxSendCountChanged(ChannelId, NewCount);
316 iliev 1130 }
317     }
318    
319 persson 2277 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 persson 1924 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 persson 2277 midiIndex.midi_bank_msb = hb;
336     midiIndex.midi_bank_lsb = lb;
337     midiIndex.midi_prog = pc;
338 persson 1924 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 schoenebeck 888 } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC