/[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 2559 - (show annotations) (download)
Sun May 18 17:38:25 2014 UTC (9 years, 10 months ago) by schoenebeck
File size: 41967 byte(s)
* Aftertouch: extended API to explicitly handle channel pressure and
  polyphonic key pressure events (so far polyphonic pressure was not
  supported at all, and channel pressure was rerouted as CC128 but not
  used so far).
* Gig Engine: Fixed support for 'aftertouch' attenuation controller.
* Bumped version (1.0.0.svn39).

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 void AbstractEngineChannel::SendChannelPressure(uint8_t Value, uint8_t MidiChannel) {
623 if (pEngine) {
624 // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
625 LockGuard g;
626 if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
627
628 Event event = pEngine->pEventGenerator->CreateEvent();
629 event.Type = Event::type_channel_pressure;
630 event.Param.ChannelPressure.Value = Value;
631 event.Param.ChannelPressure.Channel = MidiChannel;
632 event.pEngineChannel = this;
633 if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
634 else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
635 }
636 }
637
638 void AbstractEngineChannel::SendChannelPressure(uint8_t Value, uint8_t MidiChannel, int32_t FragmentPos) {
639 if (pEngine) {
640 // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
641 LockGuard g;
642 if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
643
644 Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);
645 event.Type = Event::type_channel_pressure;
646 event.Param.ChannelPressure.Value = Value;
647 event.Param.ChannelPressure.Channel = MidiChannel;
648 event.pEngineChannel = this;
649 if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
650 else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
651 }
652 }
653
654 void AbstractEngineChannel::SendPolyphonicKeyPressure(uint8_t Key, uint8_t Value, uint8_t MidiChannel) {
655 if (pEngine) {
656 // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
657 LockGuard g;
658 if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
659
660 Event event = pEngine->pEventGenerator->CreateEvent();
661 event.Type = Event::type_note_pressure;
662 event.Param.NotePressure.Key = Key;
663 event.Param.NotePressure.Value = Value;
664 event.Param.NotePressure.Channel = MidiChannel;
665 event.pEngineChannel = this;
666 if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
667 else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
668 }
669 }
670
671 void AbstractEngineChannel::SendPolyphonicKeyPressure(uint8_t Key, uint8_t Value, uint8_t MidiChannel, int32_t FragmentPos) {
672 if (pEngine) {
673 // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
674 LockGuard g;
675 if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
676
677 Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);
678 event.Type = Event::type_note_pressure;
679 event.Param.NotePressure.Key = Key;
680 event.Param.NotePressure.Value = Value;
681 event.Param.NotePressure.Channel = MidiChannel;
682 event.pEngineChannel = this;
683 if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
684 else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
685 }
686 }
687
688 /**
689 * Copy all events from the engine channel's input event queue buffer to
690 * the internal event list. This will be done at the beginning of each
691 * audio cycle (that is each RenderAudio() call) to distinguish all
692 * events which have to be processed in the current audio cycle. Each
693 * EngineChannel has it's own input event queue for the common channel
694 * specific events (like NoteOn, NoteOff and ControlChange events).
695 * Beside that, the engine also has a input event queue for global
696 * events (usually SysEx messages).
697 *
698 * @param Samples - number of sample points to be processed in the
699 * current audio cycle
700 */
701 void AbstractEngineChannel::ImportEvents(uint Samples) {
702 // import events from pure software MIDI "devices"
703 // (e.g. virtual keyboard in instrument editor)
704 {
705 const uint8_t channel = MidiChannel() == midi_chan_all ? 0 : MidiChannel();
706 const int FragmentPos = 0; // randomly chosen, we don't care about jitter for virtual MIDI devices
707 Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);
708 VirtualMidiDevice::event_t devEvent; // the event format we get from the virtual MIDI device
709 // as we're going to (carefully) write some status to the
710 // synchronized struct, we cast away the const
711 ArrayList<VirtualMidiDevice*>& devices =
712 const_cast<ArrayList<VirtualMidiDevice*>&>(virtualMidiDevicesReader_AudioThread.Lock());
713 // iterate through all virtual MIDI devices
714 for (int i = 0; i < devices.size(); i++) {
715 VirtualMidiDevice* pDev = devices[i];
716 // I think we can simply flush the whole FIFO(s), the user shouldn't be so fast ;-)
717 while (pDev->GetMidiEventFromDevice(devEvent)) {
718 switch (devEvent.Type) {
719 case VirtualMidiDevice::EVENT_TYPE_NOTEON:
720 event.Type = Event::type_note_on;
721 event.Param.Note.Key = devEvent.Arg1;
722 event.Param.Note.Velocity = devEvent.Arg2;
723 event.Param.Note.Channel = channel;
724 break;
725 case VirtualMidiDevice::EVENT_TYPE_NOTEOFF:
726 event.Type = Event::type_note_off;
727 event.Param.Note.Key = devEvent.Arg1;
728 event.Param.Note.Velocity = devEvent.Arg2;
729 event.Param.Note.Channel = channel;
730 break;
731 case VirtualMidiDevice::EVENT_TYPE_CC:
732 switch (devEvent.Arg1) {
733 case 0: // bank select MSB ...
734 SetMidiBankMsb(devEvent.Arg2);
735 continue; // don't push this event into FIFO
736 case 32: // bank select LSB ...
737 SetMidiBankLsb(devEvent.Arg2);
738 continue; // don't push this event into FIFO
739 default: // regular MIDI CC ...
740 event.Type = Event::type_control_change;
741 event.Param.CC.Controller = devEvent.Arg1;
742 event.Param.CC.Value = devEvent.Arg2;
743 event.Param.CC.Channel = channel;
744 }
745 break;
746 case VirtualMidiDevice::EVENT_TYPE_PITCHBEND:
747 event.Type = Event::type_pitchbend;
748 event.Param.Pitch.Pitch = int(devEvent.Arg2 << 7 | devEvent.Arg1) - 8192;
749 event.Param.Pitch.Channel = channel;
750 break;
751 case VirtualMidiDevice::EVENT_TYPE_PROGRAM:
752 SendProgramChange(devEvent.Arg1);
753 continue; // don't push this event into FIFO
754 default:
755 std::cerr << "AbstractEngineChannel::ImportEvents() ERROR: unknown event type ("
756 << devEvent.Type << "). This is a bug!";
757 continue;
758 }
759 event.pEngineChannel = this;
760 // copy event to internal event list
761 if (pEvents->poolIsEmpty()) {
762 dmsg(1,("Event pool emtpy!\n"));
763 goto exitVirtualDevicesLoop;
764 }
765 *pEvents->allocAppend() = event;
766 }
767 }
768 }
769 exitVirtualDevicesLoop:
770 virtualMidiDevicesReader_AudioThread.Unlock();
771
772 // import events from the regular MIDI devices
773 RingBuffer<Event,false>::NonVolatileReader eventQueueReader = pEventQueue->get_non_volatile_reader();
774 Event* pEvent;
775 while (true) {
776 // get next event from input event queue
777 if (!(pEvent = eventQueueReader.pop())) break;
778 // if younger event reached, ignore that and all subsequent ones for now
779 if (pEvent->FragmentPos() >= Samples) {
780 eventQueueReader--;
781 dmsg(2,("Younger Event, pos=%d ,Samples=%d!\n",pEvent->FragmentPos(),Samples));
782 pEvent->ResetFragmentPos();
783 break;
784 }
785 // copy event to internal event list
786 if (pEvents->poolIsEmpty()) {
787 dmsg(1,("Event pool emtpy!\n"));
788 break;
789 }
790 *pEvents->allocAppend() = *pEvent;
791 }
792 eventQueueReader.free(); // free all copied events from input queue
793 }
794
795 FxSend* AbstractEngineChannel::AddFxSend(uint8_t MidiCtrl, String Name) throw (Exception) {
796 if (pEngine) pEngine->DisableAndLock();
797 FxSend* pFxSend = new FxSend(this, MidiCtrl, Name);
798 if (fxSends.empty()) {
799 if (pEngine && pEngine->pAudioOutputDevice) {
800 AudioOutputDevice* pDevice = pEngine->pAudioOutputDevice;
801 // create local render buffers
802 pChannelLeft = new AudioChannel(0, pDevice->MaxSamplesPerCycle());
803 pChannelRight = new AudioChannel(1, pDevice->MaxSamplesPerCycle());
804 } else {
805 // postpone local render buffer creation until audio device is assigned
806 pChannelLeft = NULL;
807 pChannelRight = NULL;
808 }
809 }
810 fxSends.push_back(pFxSend);
811 if (pEngine) pEngine->Enable();
812 fireFxSendCountChanged(GetSamplerChannel()->Index(), GetFxSendCount());
813
814 return pFxSend;
815 }
816
817 FxSend* AbstractEngineChannel::GetFxSend(uint FxSendIndex) {
818 return (FxSendIndex < fxSends.size()) ? fxSends[FxSendIndex] : NULL;
819 }
820
821 uint AbstractEngineChannel::GetFxSendCount() {
822 return fxSends.size();
823 }
824
825 void AbstractEngineChannel::RemoveFxSend(FxSend* pFxSend) {
826 if (pEngine) pEngine->DisableAndLock();
827 for (
828 std::vector<FxSend*>::iterator iter = fxSends.begin();
829 iter != fxSends.end(); iter++
830 ) {
831 if (*iter == pFxSend) {
832 delete pFxSend;
833 fxSends.erase(iter);
834 if (fxSends.empty()) {
835 // destroy local render buffers
836 if (pChannelLeft) delete pChannelLeft;
837 if (pChannelRight) delete pChannelRight;
838 // fallback to render directly into AudioOutputDevice's buffers
839 if (pEngine && pEngine->pAudioOutputDevice) {
840 pChannelLeft = pEngine->pAudioOutputDevice->Channel(AudioDeviceChannelLeft);
841 pChannelRight = pEngine->pAudioOutputDevice->Channel(AudioDeviceChannelRight);
842 } else { // we update the pointers later
843 pChannelLeft = NULL;
844 pChannelRight = NULL;
845 }
846 }
847 break;
848 }
849 }
850 if (pEngine) pEngine->Enable();
851 fireFxSendCountChanged(GetSamplerChannel()->Index(), GetFxSendCount());
852 }
853
854 void AbstractEngineChannel::RemoveAllFxSends() {
855 if (pEngine) pEngine->DisableAndLock();
856 if (!fxSends.empty()) { // free local render buffers
857 if (pChannelLeft) {
858 delete pChannelLeft;
859 if (pEngine && pEngine->pAudioOutputDevice) {
860 // fallback to render directly to the AudioOutputDevice's buffer
861 pChannelLeft = pEngine->pAudioOutputDevice->Channel(AudioDeviceChannelLeft);
862 } else pChannelLeft = NULL;
863 }
864 if (pChannelRight) {
865 delete pChannelRight;
866 if (pEngine && pEngine->pAudioOutputDevice) {
867 // fallback to render directly to the AudioOutputDevice's buffer
868 pChannelRight = pEngine->pAudioOutputDevice->Channel(AudioDeviceChannelRight);
869 } else pChannelRight = NULL;
870 }
871 }
872 for (int i = 0; i < fxSends.size(); i++) delete fxSends[i];
873 fxSends.clear();
874 if (pEngine) pEngine->Enable();
875 }
876
877 /**
878 * Add a group number to the set of key groups. Should be called
879 * when an instrument is loaded to make sure there are event lists
880 * for all key groups.
881 */
882 void AbstractEngineChannel::AddGroup(uint group) {
883 if (group) {
884 std::pair<ActiveKeyGroupMap::iterator, bool> p =
885 ActiveKeyGroups.insert(ActiveKeyGroupMap::value_type(group, 0));
886 if (p.second) {
887 // If the engine channel is pending deletion (see bug
888 // #113), pEngine will be null, so we can't use
889 // pEngine->pEventPool here. Instead we're using a
890 // specialized RTList that allows specifying the pool
891 // later.
892 (*p.first).second = new LazyList<Event>;
893 }
894 }
895 }
896
897 /**
898 * Handle key group (a.k.a. exclusive group) conflicts.
899 */
900 void AbstractEngineChannel::HandleKeyGroupConflicts(uint KeyGroup, Pool<Event>::Iterator& itNoteOnEvent) {
901 dmsg(4,("HandelKeyGroupConflicts KeyGroup=%d\n", KeyGroup));
902 if (KeyGroup) {
903 // send a release event to all active voices in the group
904 RTList<Event>::Iterator itEvent = ActiveKeyGroups[KeyGroup]->allocAppend(pEngine->pEventPool);
905 *itEvent = *itNoteOnEvent;
906 }
907 }
908
909 /**
910 * Empty the lists of group events. Should be called from the
911 * audio thread, after all voices have been rendered.
912 */
913 void AbstractEngineChannel::ClearGroupEventLists() {
914 for (ActiveKeyGroupMap::iterator iter = ActiveKeyGroups.begin();
915 iter != ActiveKeyGroups.end(); iter++) {
916 if (iter->second) {
917 iter->second->clear();
918 } else {
919 dmsg(1,("EngineChannel: group event list was NULL"));
920 }
921 }
922 }
923
924 /**
925 * Remove all lists with group events.
926 */
927 void AbstractEngineChannel::DeleteGroupEventLists() {
928 for (ActiveKeyGroupMap::iterator iter = ActiveKeyGroups.begin();
929 iter != ActiveKeyGroups.end(); iter++) {
930 delete iter->second;
931 }
932 ActiveKeyGroups.clear();
933 }
934
935 } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC