/[svn]/linuxsampler/trunk/src/engines/AbstractEngineChannel.cpp
ViewVC logotype

Contents of /linuxsampler/trunk/src/engines/AbstractEngineChannel.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2521 - (show annotations) (download)
Wed Feb 19 19:02:43 2014 UTC (10 years, 1 month ago) by schoenebeck
File size: 38463 byte(s)
* VirtualMidiDevice: implemented support for program change, bank select
  and pitch bend.
* Bumped version (1.0.0.svn32).

1 /***************************************************************************
2 * *
3 * LinuxSampler - modular, streaming capable sampler *
4 * *
5 * Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck *
6 * Copyright (C) 2005-2008 Christian Schoenebeck *
7 * Copyright (C) 2009-2012 Christian Schoenebeck and Grigor Iliev *
8 * Copyright (C) 2013-2014 Christian Schoenebeck and Andreas Persson *
9 * *
10 * This program is free software; you can redistribute it and/or modify *
11 * it under the terms of the GNU General Public License as published by *
12 * the Free Software Foundation; either version 2 of the License, or *
13 * (at your option) any later version. *
14 * *
15 * This program is distributed in the hope that it will be useful, *
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
18 * GNU General Public License for more details. *
19 * *
20 * You should have received a copy of the GNU General Public License *
21 * along with this program; if not, write to the Free Software *
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
23 * MA 02111-1307 USA *
24 ***************************************************************************/
25
26 #include "AbstractEngineChannel.h"
27 #include "../common/global_private.h"
28 #include "../Sampler.h"
29
30 namespace LinuxSampler {
31
32 AbstractEngineChannel::AbstractEngineChannel() :
33 virtualMidiDevicesReader_AudioThread(virtualMidiDevices),
34 virtualMidiDevicesReader_MidiThread(virtualMidiDevices)
35 {
36 pEngine = NULL;
37 pEvents = NULL; // we allocate when we retrieve the right Engine object
38 pEventQueue = new RingBuffer<Event,false>(CONFIG_MAX_EVENTS_PER_FRAGMENT, 0);
39 InstrumentIdx = -1;
40 InstrumentStat = -1;
41 pChannelLeft = NULL;
42 pChannelRight = NULL;
43 AudioDeviceChannelLeft = -1;
44 AudioDeviceChannelRight = -1;
45 midiChannel = midi_chan_all;
46 ResetControllers();
47 PortamentoMode = false;
48 PortamentoTime = CONFIG_PORTAMENTO_TIME_DEFAULT;
49 }
50
51 AbstractEngineChannel::~AbstractEngineChannel() {
52 delete pEventQueue;
53 DeleteGroupEventLists();
54 RemoveAllFxSends();
55 }
56
57 Engine* AbstractEngineChannel::GetEngine() {
58 return pEngine;
59 }
60
61 uint AbstractEngineChannel::Channels() {
62 return 2;
63 }
64
65 /**
66 * More or less a workaround to set the instrument name, index and load
67 * status variable to zero percent immediately, that is without blocking
68 * the calling thread. It might be used in future for other preparations
69 * as well though.
70 *
71 * @param FileName - file name of the instrument file
72 * @param Instrument - index of the instrument in the file
73 * @see LoadInstrument()
74 */
75 void AbstractEngineChannel::PrepareLoadInstrument(const char* FileName, uint Instrument) {
76 InstrumentFile = FileName;
77 InstrumentIdx = Instrument;
78 InstrumentStat = 0;
79 }
80
81 String AbstractEngineChannel::InstrumentFileName() {
82 return InstrumentFile;
83 }
84
85 String AbstractEngineChannel::InstrumentName() {
86 return InstrumentIdxName;
87 }
88
89 int AbstractEngineChannel::InstrumentIndex() {
90 return InstrumentIdx;
91 }
92
93 int AbstractEngineChannel::InstrumentStatus() {
94 return InstrumentStat;
95 }
96
97 String AbstractEngineChannel::EngineName() {
98 return AbstractEngine::GetFormatString(GetEngineFormat());
99 }
100
101 void AbstractEngineChannel::Reset() {
102 if (pEngine) pEngine->DisableAndLock();
103 ResetInternal();
104 ResetControllers();
105 if (pEngine) {
106 pEngine->Enable();
107 pEngine->Reset();
108 }
109 }
110
111 void AbstractEngineChannel::ResetControllers() {
112 Pitch = 0;
113 GlobalVolume = 1.0f;
114 MidiVolume = 1.0;
115 iLastPanRequest = 64;
116 GlobalTranspose = 0;
117 // set all MIDI controller values to zero
118 memset(ControllerTable, 0x00, 129);
119 // reset all FX Send levels
120 for (
121 std::vector<FxSend*>::iterator iter = fxSends.begin();
122 iter != fxSends.end(); iter++
123 ) {
124 (*iter)->Reset();
125 }
126 }
127
128 /**
129 * This method is not thread safe!
130 */
131 void AbstractEngineChannel::ResetInternal() {
132 CurrentKeyDimension = 0;
133 PortamentoPos = -1.0f; // no portamento active yet
134
135 // delete all input events
136 pEventQueue->init();
137
138 if (pEngine) pEngine->ResetInternal();
139
140 // status of engine channel has changed, so set notify flag
141 bStatusChanged = true;
142 }
143
144 /**
145 * Implementation of virtual method from abstract EngineChannel interface.
146 * This method will periodically be polled (e.g. by the LSCP server) to
147 * check if some engine channel parameter has changed since the last
148 * StatusChanged() call.
149 *
150 * This method can also be used to mark the engine channel as changed
151 * from outside, e.g. by a MIDI input device. The optional argument
152 * \a nNewStatus can be used for this.
153 *
154 * TODO: This "poll method" is just a lazy solution and might be
155 * replaced in future.
156 * @param bNewStatus - (optional, default: false) sets the new status flag
157 * @returns true if engine channel status has changed since last
158 * StatusChanged() call
159 */
160 bool AbstractEngineChannel::StatusChanged(bool bNewStatus) {
161 bool b = bStatusChanged;
162 bStatusChanged = bNewStatus;
163 return b;
164 }
165
166 float AbstractEngineChannel::Volume() {
167 return GlobalVolume;
168 }
169
170 void AbstractEngineChannel::Volume(float f) {
171 GlobalVolume = f;
172 bStatusChanged = true; // status of engine channel has changed, so set notify flag
173 }
174
175 float AbstractEngineChannel::Pan() {
176 return float(iLastPanRequest - 64) / 64.0f;
177 }
178
179 void AbstractEngineChannel::Pan(float f) {
180 int iMidiPan = int(f * 64.0f) + 64;
181 if (iMidiPan > 127) iMidiPan = 127;
182 else if (iMidiPan < 0) iMidiPan = 0;
183 iLastPanRequest = iMidiPan;
184 }
185
186 AudioOutputDevice* AbstractEngineChannel::GetAudioOutputDevice() {
187 return (pEngine) ? pEngine->pAudioOutputDevice : NULL;
188 }
189
190 /**
191 * Gets thread safe access to the currently connected audio output
192 * device from other threads than the lscp thread.
193 */
194 AudioOutputDevice* AbstractEngineChannel::GetAudioOutputDeviceSafe() {
195 LockGuard lock(EngineMutex);
196 return GetAudioOutputDevice();
197 }
198
199 void AbstractEngineChannel::SetOutputChannel(uint EngineAudioChannel, uint AudioDeviceChannel) {
200 if (!pEngine || !pEngine->pAudioOutputDevice) throw AudioOutputException("No audio output device connected yet.");
201
202 AudioChannel* pChannel = pEngine->pAudioOutputDevice->Channel(AudioDeviceChannel);
203 if (!pChannel) throw AudioOutputException("Invalid audio output device channel " + ToString(AudioDeviceChannel));
204 switch (EngineAudioChannel) {
205 case 0: // left output channel
206 if (fxSends.empty()) pChannelLeft = pChannel;
207 AudioDeviceChannelLeft = AudioDeviceChannel;
208 break;
209 case 1: // right output channel
210 if (fxSends.empty()) pChannelRight = pChannel;
211 AudioDeviceChannelRight = AudioDeviceChannel;
212 break;
213 default:
214 throw AudioOutputException("Invalid engine audio channel " + ToString(EngineAudioChannel));
215 }
216
217 bStatusChanged = true;
218 }
219
220 int AbstractEngineChannel::OutputChannel(uint EngineAudioChannel) {
221 switch (EngineAudioChannel) {
222 case 0: // left channel
223 return AudioDeviceChannelLeft;
224 case 1: // right channel
225 return AudioDeviceChannelRight;
226 default:
227 throw AudioOutputException("Invalid engine audio channel " + ToString(EngineAudioChannel));
228 }
229 }
230
231 void AbstractEngineChannel::Connect(MidiInputPort* pMidiPort) {
232 if (!pMidiPort) return;
233
234 Sync< ArrayList<MidiInputPort*> > connections = midiInputs.back();
235
236 // check if connection already exists
237 for (int i = 0; i < connections->size(); ++i)
238 if ((*connections)[i] == pMidiPort)
239 return; // to avoid endless recursion
240
241 connections->add(pMidiPort);
242
243 // inform MIDI port about this new connection
244 pMidiPort->Connect(this, MidiChannel());
245 }
246
247 void AbstractEngineChannel::Disconnect(MidiInputPort* pMidiPort) {
248 if (!pMidiPort) return;
249
250 Sync< ArrayList<MidiInputPort*> > connections = midiInputs.back();
251
252 for (int i = 0; i < connections->size(); ++i) {
253 if ((*connections)[i] == pMidiPort) {
254 connections->remove(i);
255 // inform MIDI port about this disconnection
256 pMidiPort->Disconnect(this);
257 return;
258 }
259 }
260 }
261
262 void AbstractEngineChannel::DisconnectAllMidiInputPorts() {
263 Sync< ArrayList<MidiInputPort*> > connections = midiInputs.back();
264 ArrayList<MidiInputPort*> clonedList = *connections;
265 connections->clear();
266 for (int i = 0; i < clonedList.size(); ++i) clonedList[i]->Disconnect(this);
267 }
268
269 uint AbstractEngineChannel::GetMidiInputPortCount() {
270 Sync< ArrayList<MidiInputPort*> > connections = midiInputs.back();
271 return connections->size();
272 }
273
274 MidiInputPort* AbstractEngineChannel::GetMidiInputPort(uint index) {
275 Sync< ArrayList<MidiInputPort*> > connections = midiInputs.back();
276 return (index < connections->size()) ? (*connections)[index] : NULL;
277 }
278
279 // deprecated (just for API backward compatibility) - may be removed in future
280 void AbstractEngineChannel::Connect(MidiInputPort* pMidiPort, midi_chan_t MidiChannel) {
281 if (!pMidiPort) return;
282
283 Sync< ArrayList<MidiInputPort*> > connections = midiInputs.back();
284
285 // check against endless recursion
286 if (connections->size() == 1 && (*connections)[0] == pMidiPort && this->midiChannel == MidiChannel)
287 return;
288
289 if (!isValidMidiChan(MidiChannel))
290 throw MidiInputException("Invalid MIDI channel (" + ToString(int(MidiChannel)) + ")");
291
292 this->midiChannel = MidiChannel;
293
294 // disconnect all currently connected MIDI ports
295 ArrayList<MidiInputPort*> clonedList = *connections;
296 connections->clear();
297 for (int i = 0; i < clonedList.size(); ++i)
298 clonedList[i]->Disconnect(this);
299
300 // connect the new port
301 connections->add(pMidiPort);
302 pMidiPort->Connect(this, MidiChannel);
303 }
304
305 // deprecated (just for API backward compatibility) - may be removed in future
306 void AbstractEngineChannel::DisconnectMidiInputPort() {
307 DisconnectAllMidiInputPorts();
308 }
309
310 // deprecated (just for API backward compatibility) - may be removed in future
311 MidiInputPort* AbstractEngineChannel::GetMidiInputPort() {
312 return GetMidiInputPort(0);
313 }
314
315 midi_chan_t AbstractEngineChannel::MidiChannel() {
316 return midiChannel;
317 }
318
319 void AbstractEngineChannel::SetMidiChannel(midi_chan_t MidiChannel) {
320 if (this->midiChannel == MidiChannel) return;
321 if (!isValidMidiChan(MidiChannel))
322 throw MidiInputException("Invalid MIDI channel (" + ToString(int(MidiChannel)) + ")");
323
324 this->midiChannel = MidiChannel;
325
326 Sync< ArrayList<MidiInputPort*> > connections = midiInputs.back();
327 ArrayList<MidiInputPort*> clonedList = *connections;
328
329 DisconnectAllMidiInputPorts();
330
331 for (int i = 0; i < clonedList.size(); ++i) Connect(clonedList[i]);
332 }
333
334 void AbstractEngineChannel::Connect(VirtualMidiDevice* pDevice) {
335 // double buffer ... double work ...
336 {
337 ArrayList<VirtualMidiDevice*>& devices = virtualMidiDevices.GetConfigForUpdate();
338 devices.add(pDevice);
339 }
340 {
341 ArrayList<VirtualMidiDevice*>& devices = virtualMidiDevices.SwitchConfig();
342 devices.add(pDevice);
343 }
344 }
345
346 void AbstractEngineChannel::Disconnect(VirtualMidiDevice* pDevice) {
347 // double buffer ... double work ...
348 {
349 ArrayList<VirtualMidiDevice*>& devices = virtualMidiDevices.GetConfigForUpdate();
350 devices.remove(pDevice);
351 }
352 {
353 ArrayList<VirtualMidiDevice*>& devices = virtualMidiDevices.SwitchConfig();
354 devices.remove(pDevice);
355 }
356 }
357
358 /**
359 * Will be called by the MIDIIn Thread to let the audio thread trigger a new
360 * voice for the given key. This method is meant for real time rendering,
361 * that is an event will immediately be created with the current system
362 * time as time stamp.
363 *
364 * @param Key - MIDI key number of the triggered key
365 * @param Velocity - MIDI velocity value of the triggered key
366 */
367 void AbstractEngineChannel::SendNoteOn(uint8_t Key, uint8_t Velocity, uint8_t MidiChannel) {
368 if (pEngine) {
369 // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
370 LockGuard g;
371 if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
372
373 Event event = pEngine->pEventGenerator->CreateEvent();
374 event.Type = Event::type_note_on;
375 event.Param.Note.Key = Key;
376 event.Param.Note.Velocity = Velocity;
377 event.Param.Note.Channel = MidiChannel;
378 event.pEngineChannel = this;
379 if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
380 else dmsg(1,("EngineChannel: Input event queue full!"));
381 // inform connected virtual MIDI devices if any ...
382 // (e.g. virtual MIDI keyboard in instrument editor(s))
383 ArrayList<VirtualMidiDevice*>& devices =
384 const_cast<ArrayList<VirtualMidiDevice*>&>(
385 virtualMidiDevicesReader_MidiThread.Lock()
386 );
387 for (int i = 0; i < devices.size(); i++) {
388 devices[i]->SendNoteOnToDevice(Key, Velocity);
389 }
390 virtualMidiDevicesReader_MidiThread.Unlock();
391 }
392 }
393
394 /**
395 * Will be called by the MIDIIn Thread to let the audio thread trigger a new
396 * voice for the given key. This method is meant for offline rendering
397 * and / or for cases where the exact position of the event in the current
398 * audio fragment is already known.
399 *
400 * @param Key - MIDI key number of the triggered key
401 * @param Velocity - MIDI velocity value of the triggered key
402 * @param FragmentPos - sample point position in the current audio
403 * fragment to which this event belongs to
404 */
405 void AbstractEngineChannel::SendNoteOn(uint8_t Key, uint8_t Velocity, uint8_t MidiChannel, int32_t FragmentPos) {
406 if (FragmentPos < 0) {
407 dmsg(1,("EngineChannel::SendNoteOn(): negative FragmentPos! Seems MIDI driver is buggy!"));
408 }
409 else if (pEngine) {
410 // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
411 LockGuard g;
412 if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
413
414 Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);
415 event.Type = Event::type_note_on;
416 event.Param.Note.Key = Key;
417 event.Param.Note.Velocity = Velocity;
418 event.Param.Note.Channel = MidiChannel;
419 event.pEngineChannel = this;
420 if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
421 else dmsg(1,("EngineChannel: Input event queue full!"));
422 // inform connected virtual MIDI devices if any ...
423 // (e.g. virtual MIDI keyboard in instrument editor(s))
424 ArrayList<VirtualMidiDevice*>& devices =
425 const_cast<ArrayList<VirtualMidiDevice*>&>(
426 virtualMidiDevicesReader_MidiThread.Lock()
427 );
428 for (int i = 0; i < devices.size(); i++) {
429 devices[i]->SendNoteOnToDevice(Key, Velocity);
430 }
431 virtualMidiDevicesReader_MidiThread.Unlock();
432 }
433 }
434
435 /**
436 * Will be called by the MIDIIn Thread to signal the audio thread to release
437 * voice(s) on the given key. This method is meant for real time rendering,
438 * that is an event will immediately be created with the current system
439 * time as time stamp.
440 *
441 * @param Key - MIDI key number of the released key
442 * @param Velocity - MIDI release velocity value of the released key
443 */
444 void AbstractEngineChannel::SendNoteOff(uint8_t Key, uint8_t Velocity, uint8_t MidiChannel) {
445 if (pEngine) {
446 // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
447 LockGuard g;
448 if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
449
450 Event event = pEngine->pEventGenerator->CreateEvent();
451 event.Type = Event::type_note_off;
452 event.Param.Note.Key = Key;
453 event.Param.Note.Velocity = Velocity;
454 event.Param.Note.Channel = MidiChannel;
455 event.pEngineChannel = this;
456 if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
457 else dmsg(1,("EngineChannel: Input event queue full!"));
458 // inform connected virtual MIDI devices if any ...
459 // (e.g. virtual MIDI keyboard in instrument editor(s))
460 ArrayList<VirtualMidiDevice*>& devices =
461 const_cast<ArrayList<VirtualMidiDevice*>&>(
462 virtualMidiDevicesReader_MidiThread.Lock()
463 );
464 for (int i = 0; i < devices.size(); i++) {
465 devices[i]->SendNoteOffToDevice(Key, Velocity);
466 }
467 virtualMidiDevicesReader_MidiThread.Unlock();
468 }
469 }
470
471 /**
472 * Will be called by the MIDIIn Thread to signal the audio thread to release
473 * voice(s) on the given key. This method is meant for offline rendering
474 * and / or for cases where the exact position of the event in the current
475 * audio fragment is already known.
476 *
477 * @param Key - MIDI key number of the released key
478 * @param Velocity - MIDI release velocity value of the released key
479 * @param FragmentPos - sample point position in the current audio
480 * fragment to which this event belongs to
481 */
482 void AbstractEngineChannel::SendNoteOff(uint8_t Key, uint8_t Velocity, uint8_t MidiChannel, int32_t FragmentPos) {
483 if (FragmentPos < 0) {
484 dmsg(1,("EngineChannel::SendNoteOff(): negative FragmentPos! Seems MIDI driver is buggy!"));
485 }
486 else if (pEngine) {
487 // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
488 LockGuard g;
489 if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
490
491 Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);
492 event.Type = Event::type_note_off;
493 event.Param.Note.Key = Key;
494 event.Param.Note.Velocity = Velocity;
495 event.Param.Note.Channel = MidiChannel;
496 event.pEngineChannel = this;
497 if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
498 else dmsg(1,("EngineChannel: Input event queue full!"));
499 // inform connected virtual MIDI devices if any ...
500 // (e.g. virtual MIDI keyboard in instrument editor(s))
501 ArrayList<VirtualMidiDevice*>& devices =
502 const_cast<ArrayList<VirtualMidiDevice*>&>(
503 virtualMidiDevicesReader_MidiThread.Lock()
504 );
505 for (int i = 0; i < devices.size(); i++) {
506 devices[i]->SendNoteOffToDevice(Key, Velocity);
507 }
508 virtualMidiDevicesReader_MidiThread.Unlock();
509 }
510 }
511
512 /**
513 * Will be called by the MIDIIn Thread to signal the audio thread to change
514 * the pitch value for all voices. This method is meant for real time
515 * rendering, that is an event will immediately be created with the
516 * current system time as time stamp.
517 *
518 * @param Pitch - MIDI pitch value (-8192 ... +8191)
519 */
520 void AbstractEngineChannel::SendPitchbend(int Pitch, uint8_t MidiChannel) {
521 if (pEngine) {
522 // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
523 LockGuard g;
524 if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
525
526 Event event = pEngine->pEventGenerator->CreateEvent();
527 event.Type = Event::type_pitchbend;
528 event.Param.Pitch.Pitch = Pitch;
529 event.Param.Pitch.Channel = MidiChannel;
530 event.pEngineChannel = this;
531 if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
532 else dmsg(1,("EngineChannel: Input event queue full!"));
533 }
534 }
535
536 /**
537 * Will be called by the MIDIIn Thread to signal the audio thread to change
538 * the pitch value for all voices. This method is meant for offline
539 * rendering and / or for cases where the exact position of the event in
540 * the current audio fragment is already known.
541 *
542 * @param Pitch - MIDI pitch value (-8192 ... +8191)
543 * @param FragmentPos - sample point position in the current audio
544 * fragment to which this event belongs to
545 */
546 void AbstractEngineChannel::SendPitchbend(int Pitch, uint8_t MidiChannel, int32_t FragmentPos) {
547 if (FragmentPos < 0) {
548 dmsg(1,("AbstractEngineChannel::SendPitchBend(): negative FragmentPos! Seems MIDI driver is buggy!"));
549 }
550 else if (pEngine) {
551 // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
552 LockGuard g;
553 if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
554
555 Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);
556 event.Type = Event::type_pitchbend;
557 event.Param.Pitch.Pitch = Pitch;
558 event.Param.Pitch.Channel = MidiChannel;
559 event.pEngineChannel = this;
560 if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
561 else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
562 }
563 }
564
565 /**
566 * Will be called by the MIDIIn Thread to signal the audio thread that a
567 * continuous controller value has changed. This method is meant for real
568 * time rendering, that is an event will immediately be created with the
569 * current system time as time stamp.
570 *
571 * @param Controller - MIDI controller number of the occured control change
572 * @param Value - value of the control change
573 */
574 void AbstractEngineChannel::SendControlChange(uint8_t Controller, uint8_t Value, uint8_t MidiChannel) {
575 if (pEngine) {
576 // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
577 LockGuard g;
578 if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
579
580 Event event = pEngine->pEventGenerator->CreateEvent();
581 event.Type = Event::type_control_change;
582 event.Param.CC.Controller = Controller;
583 event.Param.CC.Value = Value;
584 event.Param.CC.Channel = MidiChannel;
585 event.pEngineChannel = this;
586 if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
587 else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
588 }
589 }
590
591 /**
592 * Will be called by the MIDIIn Thread to signal the audio thread that a
593 * continuous controller value has changed. This method is meant for
594 * offline rendering and / or for cases where the exact position of the
595 * event in the current audio fragment is already known.
596 *
597 * @param Controller - MIDI controller number of the occured control change
598 * @param Value - value of the control change
599 * @param FragmentPos - sample point position in the current audio
600 * fragment to which this event belongs to
601 */
602 void AbstractEngineChannel::SendControlChange(uint8_t Controller, uint8_t Value, uint8_t MidiChannel, int32_t FragmentPos) {
603 if (FragmentPos < 0) {
604 dmsg(1,("AbstractEngineChannel::SendControlChange(): negative FragmentPos! Seems MIDI driver is buggy!"));
605 }
606 else if (pEngine) {
607 // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
608 LockGuard g;
609 if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
610
611 Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);
612 event.Type = Event::type_control_change;
613 event.Param.CC.Controller = Controller;
614 event.Param.CC.Value = Value;
615 event.Param.CC.Channel = MidiChannel;
616 event.pEngineChannel = this;
617 if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
618 else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
619 }
620 }
621
622 /**
623 * Copy all events from the engine channel's input event queue buffer to
624 * the internal event list. This will be done at the beginning of each
625 * audio cycle (that is each RenderAudio() call) to distinguish all
626 * events which have to be processed in the current audio cycle. Each
627 * EngineChannel has it's own input event queue for the common channel
628 * specific events (like NoteOn, NoteOff and ControlChange events).
629 * Beside that, the engine also has a input event queue for global
630 * events (usually SysEx messages).
631 *
632 * @param Samples - number of sample points to be processed in the
633 * current audio cycle
634 */
635 void AbstractEngineChannel::ImportEvents(uint Samples) {
636 // import events from pure software MIDI "devices"
637 // (e.g. virtual keyboard in instrument editor)
638 {
639 const uint8_t channel = MidiChannel() == midi_chan_all ? 0 : MidiChannel();
640 const int FragmentPos = 0; // randomly chosen, we don't care about jitter for virtual MIDI devices
641 Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);
642 VirtualMidiDevice::event_t devEvent; // the event format we get from the virtual MIDI device
643 // as we're going to (carefully) write some status to the
644 // synchronized struct, we cast away the const
645 ArrayList<VirtualMidiDevice*>& devices =
646 const_cast<ArrayList<VirtualMidiDevice*>&>(virtualMidiDevicesReader_AudioThread.Lock());
647 // iterate through all virtual MIDI devices
648 for (int i = 0; i < devices.size(); i++) {
649 VirtualMidiDevice* pDev = devices[i];
650 // I think we can simply flush the whole FIFO(s), the user shouldn't be so fast ;-)
651 while (pDev->GetMidiEventFromDevice(devEvent)) {
652 switch (devEvent.Type) {
653 case VirtualMidiDevice::EVENT_TYPE_NOTEON:
654 event.Type = Event::type_note_on;
655 event.Param.Note.Key = devEvent.Arg1;
656 event.Param.Note.Velocity = devEvent.Arg2;
657 event.Param.Note.Channel = channel;
658 break;
659 case VirtualMidiDevice::EVENT_TYPE_NOTEOFF:
660 event.Type = Event::type_note_off;
661 event.Param.Note.Key = devEvent.Arg1;
662 event.Param.Note.Velocity = devEvent.Arg2;
663 event.Param.Note.Channel = channel;
664 break;
665 case VirtualMidiDevice::EVENT_TYPE_CC:
666 switch (devEvent.Arg1) {
667 case 0: // bank select MSB ...
668 SetMidiBankMsb(devEvent.Arg2);
669 continue; // don't push this event into FIFO
670 case 32: // bank select LSB ...
671 SetMidiBankLsb(devEvent.Arg2);
672 continue; // don't push this event into FIFO
673 default: // regular MIDI CC ...
674 event.Type = Event::type_control_change;
675 event.Param.CC.Controller = devEvent.Arg1;
676 event.Param.CC.Value = devEvent.Arg2;
677 event.Param.CC.Channel = channel;
678 }
679 break;
680 case VirtualMidiDevice::EVENT_TYPE_PITCHBEND:
681 event.Type = Event::type_pitchbend;
682 event.Param.Pitch.Pitch = int(devEvent.Arg2 << 7 | devEvent.Arg1) - 8192;
683 event.Param.Pitch.Channel = channel;
684 break;
685 case VirtualMidiDevice::EVENT_TYPE_PROGRAM:
686 SendProgramChange(devEvent.Arg1);
687 continue; // don't push this event into FIFO
688 default:
689 std::cerr << "AbstractEngineChannel::ImportEvents() ERROR: unknown event type ("
690 << devEvent.Type << "). This is a bug!";
691 continue;
692 }
693 event.pEngineChannel = this;
694 // copy event to internal event list
695 if (pEvents->poolIsEmpty()) {
696 dmsg(1,("Event pool emtpy!\n"));
697 goto exitVirtualDevicesLoop;
698 }
699 *pEvents->allocAppend() = event;
700 }
701 }
702 }
703 exitVirtualDevicesLoop:
704 virtualMidiDevicesReader_AudioThread.Unlock();
705
706 // import events from the regular MIDI devices
707 RingBuffer<Event,false>::NonVolatileReader eventQueueReader = pEventQueue->get_non_volatile_reader();
708 Event* pEvent;
709 while (true) {
710 // get next event from input event queue
711 if (!(pEvent = eventQueueReader.pop())) break;
712 // if younger event reached, ignore that and all subsequent ones for now
713 if (pEvent->FragmentPos() >= Samples) {
714 eventQueueReader--;
715 dmsg(2,("Younger Event, pos=%d ,Samples=%d!\n",pEvent->FragmentPos(),Samples));
716 pEvent->ResetFragmentPos();
717 break;
718 }
719 // copy event to internal event list
720 if (pEvents->poolIsEmpty()) {
721 dmsg(1,("Event pool emtpy!\n"));
722 break;
723 }
724 *pEvents->allocAppend() = *pEvent;
725 }
726 eventQueueReader.free(); // free all copied events from input queue
727 }
728
729 FxSend* AbstractEngineChannel::AddFxSend(uint8_t MidiCtrl, String Name) throw (Exception) {
730 if (pEngine) pEngine->DisableAndLock();
731 FxSend* pFxSend = new FxSend(this, MidiCtrl, Name);
732 if (fxSends.empty()) {
733 if (pEngine && pEngine->pAudioOutputDevice) {
734 AudioOutputDevice* pDevice = pEngine->pAudioOutputDevice;
735 // create local render buffers
736 pChannelLeft = new AudioChannel(0, pDevice->MaxSamplesPerCycle());
737 pChannelRight = new AudioChannel(1, pDevice->MaxSamplesPerCycle());
738 } else {
739 // postpone local render buffer creation until audio device is assigned
740 pChannelLeft = NULL;
741 pChannelRight = NULL;
742 }
743 }
744 fxSends.push_back(pFxSend);
745 if (pEngine) pEngine->Enable();
746 fireFxSendCountChanged(GetSamplerChannel()->Index(), GetFxSendCount());
747
748 return pFxSend;
749 }
750
751 FxSend* AbstractEngineChannel::GetFxSend(uint FxSendIndex) {
752 return (FxSendIndex < fxSends.size()) ? fxSends[FxSendIndex] : NULL;
753 }
754
755 uint AbstractEngineChannel::GetFxSendCount() {
756 return fxSends.size();
757 }
758
759 void AbstractEngineChannel::RemoveFxSend(FxSend* pFxSend) {
760 if (pEngine) pEngine->DisableAndLock();
761 for (
762 std::vector<FxSend*>::iterator iter = fxSends.begin();
763 iter != fxSends.end(); iter++
764 ) {
765 if (*iter == pFxSend) {
766 delete pFxSend;
767 fxSends.erase(iter);
768 if (fxSends.empty()) {
769 // destroy local render buffers
770 if (pChannelLeft) delete pChannelLeft;
771 if (pChannelRight) delete pChannelRight;
772 // fallback to render directly into AudioOutputDevice's buffers
773 if (pEngine && pEngine->pAudioOutputDevice) {
774 pChannelLeft = pEngine->pAudioOutputDevice->Channel(AudioDeviceChannelLeft);
775 pChannelRight = pEngine->pAudioOutputDevice->Channel(AudioDeviceChannelRight);
776 } else { // we update the pointers later
777 pChannelLeft = NULL;
778 pChannelRight = NULL;
779 }
780 }
781 break;
782 }
783 }
784 if (pEngine) pEngine->Enable();
785 fireFxSendCountChanged(GetSamplerChannel()->Index(), GetFxSendCount());
786 }
787
788 void AbstractEngineChannel::RemoveAllFxSends() {
789 if (pEngine) pEngine->DisableAndLock();
790 if (!fxSends.empty()) { // free local render buffers
791 if (pChannelLeft) {
792 delete pChannelLeft;
793 if (pEngine && pEngine->pAudioOutputDevice) {
794 // fallback to render directly to the AudioOutputDevice's buffer
795 pChannelLeft = pEngine->pAudioOutputDevice->Channel(AudioDeviceChannelLeft);
796 } else pChannelLeft = NULL;
797 }
798 if (pChannelRight) {
799 delete pChannelRight;
800 if (pEngine && pEngine->pAudioOutputDevice) {
801 // fallback to render directly to the AudioOutputDevice's buffer
802 pChannelRight = pEngine->pAudioOutputDevice->Channel(AudioDeviceChannelRight);
803 } else pChannelRight = NULL;
804 }
805 }
806 for (int i = 0; i < fxSends.size(); i++) delete fxSends[i];
807 fxSends.clear();
808 if (pEngine) pEngine->Enable();
809 }
810
811 /**
812 * Add a group number to the set of key groups. Should be called
813 * when an instrument is loaded to make sure there are event lists
814 * for all key groups.
815 */
816 void AbstractEngineChannel::AddGroup(uint group) {
817 if (group) {
818 std::pair<ActiveKeyGroupMap::iterator, bool> p =
819 ActiveKeyGroups.insert(ActiveKeyGroupMap::value_type(group, 0));
820 if (p.second) {
821 // If the engine channel is pending deletion (see bug
822 // #113), pEngine will be null, so we can't use
823 // pEngine->pEventPool here. Instead we're using a
824 // specialized RTList that allows specifying the pool
825 // later.
826 (*p.first).second = new LazyList<Event>;
827 }
828 }
829 }
830
831 /**
832 * Handle key group (a.k.a. exclusive group) conflicts.
833 */
834 void AbstractEngineChannel::HandleKeyGroupConflicts(uint KeyGroup, Pool<Event>::Iterator& itNoteOnEvent) {
835 dmsg(4,("HandelKeyGroupConflicts KeyGroup=%d\n", KeyGroup));
836 if (KeyGroup) {
837 // send a release event to all active voices in the group
838 RTList<Event>::Iterator itEvent = ActiveKeyGroups[KeyGroup]->allocAppend(pEngine->pEventPool);
839 *itEvent = *itNoteOnEvent;
840 }
841 }
842
843 /**
844 * Empty the lists of group events. Should be called from the
845 * audio thread, after all voices have been rendered.
846 */
847 void AbstractEngineChannel::ClearGroupEventLists() {
848 for (ActiveKeyGroupMap::iterator iter = ActiveKeyGroups.begin();
849 iter != ActiveKeyGroups.end(); iter++) {
850 if (iter->second) {
851 iter->second->clear();
852 } else {
853 dmsg(1,("EngineChannel: group event list was NULL"));
854 }
855 }
856 }
857
858 /**
859 * Remove all lists with group events.
860 */
861 void AbstractEngineChannel::DeleteGroupEventLists() {
862 for (ActiveKeyGroupMap::iterator iter = ActiveKeyGroups.begin();
863 iter != ActiveKeyGroups.end(); iter++) {
864 delete iter->second;
865 }
866 ActiveKeyGroups.clear();
867 }
868
869 } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC