/[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 1424 - (show annotations) (download)
Sun Oct 14 22:00:17 2007 UTC (16 years, 6 months ago) by schoenebeck
File size: 22776 byte(s)
* code cleanup:
- global.h now only covers global definitions that are needed for the C++
  API header files, all implementation internal global definitions are now
  in global_private.h
- atomic.h is not exposed to the C++ API anymore (replaced the references
  in SynchronizedConfig.h for this with local definitions)
- no need to include config.h anymore for using LS's API header files
- DB instruments classes are not exposed to the C++ API
- POSIX callback functions of Thread.h are hidden
- the (optional) gig Engine benchmark compiles again
- updated Doxyfile.in
- fixed warnings in API doc generation
* preparations for release 0.5.0

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

  ViewVC Help
Powered by ViewVC