/[svn]/linuxsampler/trunk/src/drivers/midi/MidiInputPort.cpp
ViewVC logotype

Contents of /linuxsampler/trunk/src/drivers/midi/MidiInputPort.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 973 - (show annotations) (download)
Fri Dec 15 21:40:27 2006 UTC (17 years, 4 months ago) by schoenebeck
File size: 22531 byte(s)
* revised and extended MIDI instrument mapping feature to allow managing
  arbitrary amount of maps and assigning each sampler channel individually
  to one map (this commit batch includes LSCP spec document update and
  respective implementation on LS side)

1 /***************************************************************************
2 * *
3 * LinuxSampler - modular, streaming capable sampler *
4 * *
5 * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6 * Copyright (C) 2005, 2006 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 "MidiInputPort.h"
25
26 #include "MidiInstrumentMapper.h"
27 #include "../../Sampler.h"
28 #include "../../engines/EngineFactory.h"
29
30 namespace LinuxSampler {
31
32 // *************** ParameterName ***************
33 // *
34
35 MidiInputPort::ParameterName::ParameterName(MidiInputPort* pPort) : DeviceRuntimeParameterString("Port " + ToString(pPort->GetPortNumber())) {
36 this->pPort = pPort;
37 }
38
39 MidiInputPort::ParameterName::ParameterName(MidiInputPort* pPort, String val) : DeviceRuntimeParameterString(val) {
40 this->pPort = pPort;
41 }
42
43 String MidiInputPort::ParameterName::Description() {
44 return "Name for this port";
45 }
46
47 bool MidiInputPort::ParameterName::Fix() {
48 return false;
49 }
50
51 std::vector<String> MidiInputPort::ParameterName::PossibilitiesAsString() {
52 return std::vector<String>();
53 }
54
55 void MidiInputPort::ParameterName::OnSetValue(String s) throw (Exception) {
56 return; /* FIXME: Nothing to do here */
57 }
58
59
60
61 // *************** MidiInputPort ***************
62 // *
63
64 MidiInputPort::~MidiInputPort() {
65 std::map<String,DeviceRuntimeParameter*>::iterator iter = Parameters.begin();
66 while (iter != Parameters.end()) {
67 delete iter->second;
68 iter++;
69 }
70 Parameters.clear();
71 }
72
73 MidiInputPort::MidiInputPort(MidiInputDevice* pDevice, int portNumber)
74 : MidiChannelMapReader(MidiChannelMap),
75 SysexListenersReader(SysexListeners) {
76 this->pDevice = pDevice;
77 this->portNumber = portNumber;
78 Parameters["NAME"] = new ParameterName(this);
79 }
80
81 MidiInputDevice* MidiInputPort::GetDevice() {
82 return pDevice;
83 }
84
85 uint MidiInputPort::GetPortNumber() {
86 return portNumber;
87 }
88
89 std::map<String,DeviceRuntimeParameter*> MidiInputPort::PortParameters() {
90 return Parameters;
91 }
92
93 void MidiInputPort::DispatchNoteOn(uint8_t Key, uint8_t Velocity, uint MidiChannel) {
94 if (Key > 127 || Velocity > 127 || MidiChannel > 16) return;
95 const MidiChannelMap_t& midiChannelMap = MidiChannelMapReader.Lock();
96 // dispatch event for engines listening to the same MIDI channel
97 {
98 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
99 std::set<EngineChannel*>::iterator end = midiChannelMap[MidiChannel].end();
100 for (; engineiter != end; engineiter++) (*engineiter)->SendNoteOn(Key, Velocity);
101 }
102 // dispatch event for engines listening to ALL MIDI channels
103 {
104 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();
105 std::set<EngineChannel*>::iterator end = midiChannelMap[midi_chan_all].end();
106 for (; engineiter != end; engineiter++) (*engineiter)->SendNoteOn(Key, Velocity);
107 }
108 MidiChannelMapReader.Unlock();
109 }
110
111 void MidiInputPort::DispatchNoteOn(uint8_t Key, uint8_t Velocity, uint MidiChannel, int32_t FragmentPos) {
112 if (Key > 127 || Velocity > 127 || MidiChannel > 16) return;
113 const MidiChannelMap_t& midiChannelMap = MidiChannelMapReader.Lock();
114 // dispatch event for engines listening to the same MIDI channel
115 {
116 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
117 std::set<EngineChannel*>::iterator end = midiChannelMap[MidiChannel].end();
118 for (; engineiter != end; engineiter++) (*engineiter)->SendNoteOn(Key, Velocity, FragmentPos);
119 }
120 // dispatch event for engines listening to ALL MIDI channels
121 {
122 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();
123 std::set<EngineChannel*>::iterator end = midiChannelMap[midi_chan_all].end();
124 for (; engineiter != end; engineiter++) (*engineiter)->SendNoteOn(Key, Velocity, FragmentPos);
125 }
126 MidiChannelMapReader.Unlock();
127 }
128
129 void MidiInputPort::DispatchNoteOff(uint8_t Key, uint8_t Velocity, uint MidiChannel) {
130 if (Key > 127 || Velocity > 127 || MidiChannel > 16) return;
131 const MidiChannelMap_t& midiChannelMap = MidiChannelMapReader.Lock();
132 // dispatch event for engines listening to the same MIDI channel
133 {
134 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
135 std::set<EngineChannel*>::iterator end = midiChannelMap[MidiChannel].end();
136 for (; engineiter != end; engineiter++) (*engineiter)->SendNoteOff(Key, Velocity);
137 }
138 // dispatch event for engines listening to ALL MIDI channels
139 {
140 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();
141 std::set<EngineChannel*>::iterator end = midiChannelMap[midi_chan_all].end();
142 for (; engineiter != end; engineiter++) (*engineiter)->SendNoteOff(Key, Velocity);
143 }
144 MidiChannelMapReader.Unlock();
145 }
146
147 void MidiInputPort::DispatchNoteOff(uint8_t Key, uint8_t Velocity, uint MidiChannel, int32_t FragmentPos) {
148 if (Key > 127 || Velocity > 127 || MidiChannel > 16) return;
149 const MidiChannelMap_t& midiChannelMap = MidiChannelMapReader.Lock();
150 // dispatch event for engines listening to the same MIDI channel
151 {
152 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
153 std::set<EngineChannel*>::iterator end = midiChannelMap[MidiChannel].end();
154 for (; engineiter != end; engineiter++) (*engineiter)->SendNoteOff(Key, Velocity, FragmentPos);
155 }
156 // dispatch event for engines listening to ALL MIDI channels
157 {
158 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();
159 std::set<EngineChannel*>::iterator end = midiChannelMap[midi_chan_all].end();
160 for (; engineiter != end; engineiter++) (*engineiter)->SendNoteOff(Key, Velocity, FragmentPos);
161 }
162 MidiChannelMapReader.Unlock();
163 }
164
165 void MidiInputPort::DispatchPitchbend(int Pitch, uint MidiChannel) {
166 if (Pitch < -8192 || Pitch > 8191 || MidiChannel > 16) return;
167 const MidiChannelMap_t& midiChannelMap = MidiChannelMapReader.Lock();
168 // dispatch event for engines listening to the same MIDI channel
169 {
170 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
171 std::set<EngineChannel*>::iterator end = midiChannelMap[MidiChannel].end();
172 for (; engineiter != end; engineiter++) (*engineiter)->SendPitchbend(Pitch);
173 }
174 // dispatch event for engines listening to ALL MIDI channels
175 {
176 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();
177 std::set<EngineChannel*>::iterator end = midiChannelMap[midi_chan_all].end();
178 for (; engineiter != end; engineiter++) (*engineiter)->SendPitchbend(Pitch);
179 }
180 MidiChannelMapReader.Unlock();
181 }
182
183 void MidiInputPort::DispatchPitchbend(int Pitch, uint MidiChannel, int32_t FragmentPos) {
184 if (Pitch < -8192 || Pitch > 8191 || MidiChannel > 16) return;
185 const MidiChannelMap_t& midiChannelMap = MidiChannelMapReader.Lock();
186 // dispatch event for engines listening to the same MIDI channel
187 {
188 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
189 std::set<EngineChannel*>::iterator end = midiChannelMap[MidiChannel].end();
190 for (; engineiter != end; engineiter++) (*engineiter)->SendPitchbend(Pitch, FragmentPos);
191 }
192 // dispatch event for engines listening to ALL MIDI channels
193 {
194 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();
195 std::set<EngineChannel*>::iterator end = midiChannelMap[midi_chan_all].end();
196 for (; engineiter != end; engineiter++) (*engineiter)->SendPitchbend(Pitch, FragmentPos);
197 }
198 MidiChannelMapReader.Unlock();
199 }
200
201 void MidiInputPort::DispatchControlChange(uint8_t Controller, uint8_t Value, uint MidiChannel) {
202 if (Controller > 128 || Value > 127 || MidiChannel > 16) return;
203 const MidiChannelMap_t& midiChannelMap = MidiChannelMapReader.Lock();
204 // dispatch event for engines listening to the same MIDI channel
205 {
206 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
207 std::set<EngineChannel*>::iterator end = midiChannelMap[MidiChannel].end();
208 for (; engineiter != end; engineiter++) (*engineiter)->SendControlChange(Controller, Value);
209 }
210 // dispatch event for engines listening to ALL MIDI channels
211 {
212 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();
213 std::set<EngineChannel*>::iterator end = midiChannelMap[midi_chan_all].end();
214 for (; engineiter != end; engineiter++) (*engineiter)->SendControlChange(Controller, Value);
215 }
216 MidiChannelMapReader.Unlock();
217 }
218
219 void MidiInputPort::DispatchControlChange(uint8_t Controller, uint8_t Value, uint MidiChannel, int32_t FragmentPos) {
220 if (Controller > 128 || Value > 127 || MidiChannel > 16) return;
221 const MidiChannelMap_t& midiChannelMap = MidiChannelMapReader.Lock();
222 // dispatch event for engines listening to the same MIDI channel
223 {
224 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
225 std::set<EngineChannel*>::iterator end = midiChannelMap[MidiChannel].end();
226 for (; engineiter != end; engineiter++) (*engineiter)->SendControlChange(Controller, Value, FragmentPos);
227 }
228 // dispatch event for engines listening to ALL MIDI channels
229 {
230 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();
231 std::set<EngineChannel*>::iterator end = midiChannelMap[midi_chan_all].end();
232 for (; engineiter != end; engineiter++) (*engineiter)->SendControlChange(Controller, Value, FragmentPos);
233 }
234 MidiChannelMapReader.Unlock();
235 }
236
237 void MidiInputPort::DispatchSysex(void* pData, uint Size) {
238 const std::set<Engine*> allEngines = SysexListenersReader.Lock();
239 // dispatch event to all engine instances
240 std::set<Engine*>::iterator engineiter = allEngines.begin();
241 std::set<Engine*>::iterator end = allEngines.end();
242 for (; engineiter != end; engineiter++) (*engineiter)->SendSysex(pData, Size);
243 SysexListenersReader.Unlock();
244 }
245
246 void MidiInputPort::DispatchProgramChange(uint8_t Program, uint MidiChannel) {
247 dmsg(1,("Received MIDI program change (prog=%d,ch=%d)\n",Program,MidiChannel));
248 if (Program > 127 || MidiChannel > 16) return;
249 if (!pDevice || !pDevice->pSampler) {
250 std::cerr << "MidiInputPort: ERROR, no sampler instance to handle program change."
251 << "This is a bug, please report it!\n" << std::flush;
252 return;
253 }
254 std::vector<int> maps = MidiInstrumentMapper::Maps();
255 if (maps.empty()) return;
256
257 const MidiChannelMap_t& midiChannelMap = MidiChannelMapReader.Lock();
258 // dispatch event for engines listening to the same MIDI channel
259 {
260 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
261 std::set<EngineChannel*>::iterator end = midiChannelMap[MidiChannel].end();
262 for (; engineiter != end; engineiter++) {
263 (*engineiter)->SetMidiProgram(Program);
264 if ((*engineiter)->UsesNoMidiInstrumentMap()) continue;
265 // retrieve the MIDI instrument map this engine channel is assigned to
266 int iMapID = ((*engineiter)->UsesDefaultMidiInstrumentMap())
267 ? maps[0] /*default*/ : (*engineiter)->GetMidiInstrumentMap();
268 // is there an entry for this MIDI bank&prog pair in that map?
269 midi_prog_index_t midiIndex;
270 midiIndex.midi_bank_msb = (*engineiter)->GetMidiBankMsb();
271 midiIndex.midi_bank_lsb = (*engineiter)->GetMidiBankLsb();
272 midiIndex.midi_prog = (*engineiter)->GetMidiProgram();
273 optional<MidiInstrumentMapper::entry_t> mapping =
274 MidiInstrumentMapper::GetEntry(iMapID, midiIndex);
275 if (mapping) { // if mapping exists ...
276 InstrumentManager::instrument_id_t id;
277 id.FileName = mapping->InstrumentFile;
278 id.Index = mapping->InstrumentIndex;
279 //TODO: we should switch the engine type here
280 InstrumentManager::LoadInstrumentInBackground(id, *engineiter);
281 (*engineiter)->Volume(mapping->Volume);
282 }
283 }
284 }
285 // dispatch event for engines listening to ALL MIDI channels
286 {
287 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();
288 std::set<EngineChannel*>::iterator end = midiChannelMap[midi_chan_all].end();
289 for (; engineiter != end; engineiter++) {
290 (*engineiter)->SetMidiProgram(Program);
291 if ((*engineiter)->UsesNoMidiInstrumentMap()) continue;
292 // retrieve the MIDI instrument map this engine channel is assigned to
293 int iMapID = ((*engineiter)->UsesDefaultMidiInstrumentMap())
294 ? maps[0] /*default*/ : (*engineiter)->GetMidiInstrumentMap();
295 // is there an entry for this MIDI bank&prog pair in that map?
296 midi_prog_index_t midiIndex;
297 midiIndex.midi_bank_msb = (*engineiter)->GetMidiBankMsb();
298 midiIndex.midi_bank_lsb = (*engineiter)->GetMidiBankLsb();
299 midiIndex.midi_prog = (*engineiter)->GetMidiProgram();
300 optional<MidiInstrumentMapper::entry_t> mapping =
301 MidiInstrumentMapper::GetEntry(iMapID, midiIndex);
302 if (mapping) { // if mapping exists ...
303 InstrumentManager::instrument_id_t id;
304 id.FileName = mapping->InstrumentFile;
305 id.Index = mapping->InstrumentIndex;
306 //TODO: we should switch the engine type here
307 InstrumentManager::LoadInstrumentInBackground(id, *engineiter);
308 (*engineiter)->Volume(mapping->Volume);
309 }
310 }
311 }
312 MidiChannelMapReader.Unlock();
313 }
314
315 void MidiInputPort::DispatchBankSelectMsb(uint8_t BankMSB, uint MidiChannel) {
316 if (BankMSB > 127 || MidiChannel > 16) return;
317 if (!pDevice || !pDevice->pSampler) {
318 std::cerr << "MidiInputPort: ERROR, no sampler instance to handle bank select MSB."
319 << "This is a bug, please report it!\n" << std::flush;
320 return;
321 }
322 const MidiChannelMap_t& midiChannelMap = MidiChannelMapReader.Lock();
323 // dispatch event for engines listening to the same MIDI channel
324 {
325 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
326 std::set<EngineChannel*>::iterator end = midiChannelMap[MidiChannel].end();
327 // according to the MIDI specs, a bank select should not alter the patch
328 for (; engineiter != end; engineiter++) (*engineiter)->SetMidiBankMsb(BankMSB);
329 }
330 // dispatch event for engines listening to ALL MIDI channels
331 {
332 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();
333 std::set<EngineChannel*>::iterator end = midiChannelMap[midi_chan_all].end();
334 // according to the MIDI specs, a bank select should not alter the patch
335 for (; engineiter != end; engineiter++) (*engineiter)->SetMidiBankMsb(BankMSB);
336 }
337 MidiChannelMapReader.Unlock();
338 }
339
340 void MidiInputPort::DispatchBankSelectLsb(uint8_t BankLSB, uint MidiChannel) {
341 if (BankLSB > 127 || MidiChannel > 16) return;
342 if (!pDevice || !pDevice->pSampler) {
343 std::cerr << "MidiInputPort: ERROR, no sampler instance to handle bank select LSB."
344 << "This is a bug, please report it!\n" << std::flush;
345 return;
346 }
347 const MidiChannelMap_t& midiChannelMap = MidiChannelMapReader.Lock();
348 // dispatch event for engines listening to the same MIDI channel
349 {
350 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
351 std::set<EngineChannel*>::iterator end = midiChannelMap[MidiChannel].end();
352 // according to the MIDI specs, a bank select should not alter the patch
353 for (; engineiter != end; engineiter++) (*engineiter)->SetMidiBankLsb(BankLSB);
354 }
355 // dispatch event for engines listening to ALL MIDI channels
356 {
357 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();
358 std::set<EngineChannel*>::iterator end = midiChannelMap[midi_chan_all].end();
359 // according to the MIDI specs, a bank select should not alter the patch
360 for (; engineiter != end; engineiter++) (*engineiter)->SetMidiBankLsb(BankLSB);
361 }
362 MidiChannelMapReader.Unlock();
363 }
364
365 void MidiInputPort::Connect(EngineChannel* pEngineChannel, midi_chan_t MidiChannel) {
366 if (MidiChannel < 0 || MidiChannel > 16)
367 throw MidiInputException("MIDI channel index out of bounds");
368
369 // first check if desired connection is already established
370 MidiChannelMapMutex.Lock();
371 MidiChannelMap_t& midiChannelMap = MidiChannelMap.GetConfigForUpdate();
372 bool bAlreadyDone = midiChannelMap[MidiChannel].count(pEngineChannel);
373 MidiChannelMapMutex.Unlock();
374 if (bAlreadyDone) return;
375
376 // remove all other connections of that engine channel (if any)
377 Disconnect(pEngineChannel);
378
379 // register engine channel on the desired MIDI channel
380 MidiChannelMapMutex.Lock();
381 MidiChannelMap.GetConfigForUpdate()[MidiChannel].insert(pEngineChannel);
382 MidiChannelMap.SwitchConfig()[MidiChannel].insert(pEngineChannel);
383 MidiChannelMapMutex.Unlock();
384
385 // inform engine channel about this connection
386 pEngineChannel->Connect(this, MidiChannel);
387
388 // mark engine channel as changed
389 pEngineChannel->StatusChanged(true);
390 }
391
392 void MidiInputPort::Disconnect(EngineChannel* pEngineChannel) {
393 if (!pEngineChannel) return;
394
395 bool bChannelFound = false;
396
397 // unregister engine channel from all MIDI channels
398 MidiChannelMapMutex.Lock();
399 try {
400 {
401 MidiChannelMap_t& midiChannelMap = MidiChannelMap.GetConfigForUpdate();
402 for (int i = 0; i <= 16; i++) {
403 bChannelFound |= midiChannelMap[i].count(pEngineChannel);
404 midiChannelMap[i].erase(pEngineChannel);
405 }
406 }
407 // do the same update again, after switching to the other config
408 {
409 MidiChannelMap_t& midiChannelMap = MidiChannelMap.SwitchConfig();
410 for (int i = 0; i <= 16; i++) {
411 bChannelFound |= midiChannelMap[i].count(pEngineChannel);
412 midiChannelMap[i].erase(pEngineChannel);
413 }
414 }
415 }
416 catch(...) { /* NOOP */ }
417 MidiChannelMapMutex.Unlock();
418
419 // inform engine channel about the disconnection (if there is one)
420 if (bChannelFound) pEngineChannel->DisconnectMidiInputPort();
421
422 // mark engine channel as changed
423 pEngineChannel->StatusChanged(true);
424 }
425
426 SynchronizedConfig<std::set<LinuxSampler::Engine*> > MidiInputPort::SysexListeners;
427
428 void MidiInputPort::AddSysexListener(Engine* engine) {
429 std::pair<std::set<Engine*>::iterator, bool> p = SysexListeners.GetConfigForUpdate().insert(engine);
430 if (p.second) SysexListeners.SwitchConfig().insert(engine);
431 }
432
433 bool MidiInputPort::RemoveSysexListener(Engine* engine) {
434 int count = SysexListeners.GetConfigForUpdate().erase(engine);
435 if (count) SysexListeners.SwitchConfig().erase(engine);
436 return count;
437 }
438
439 } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC