/[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 2871 - (show annotations) (download)
Sun Apr 10 18:22:23 2016 UTC (8 years ago) by schoenebeck
File size: 46636 byte(s)
* All engines: Implemented scheduler for delayed MIDI events and for
  suspended real-time instrument scripts.
* Real-Time instrument scripts: Implemented support for built-in "wait()"
  function's "duration-us" argument, thus scripts using this function are
  now correctly resumed after the requested amount of microseconds.
* Real-Time instrument scripts: Implemented support for built-in
  "play_note()" function's "duration-us" argument, thus notes triggered
  with this argument are now correctly released after the requested amount
  of microseconds.
* Real-Time instrument scripts: Fixed crash which happened when trying to
  reference an undeclared script variable.
* Real-Time instrument scripts: Script events were not cleared when
  engine channel was reset, potentially causing undefined behavior.
* All engines: Attempt to partly fix resetting engine channels vs.
  resetting engine, an overall cleanup of the Reset*(),
  ConnectAudioDevice(), DisconnectAudioDevice() API methods would still be
  desirable though, because the current situation is still inconsistent
  and error prone.
* Bumped version (2.0.0.svn2).

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

  ViewVC Help
Powered by ViewVC