/[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 2606 - (show annotations) (download)
Sun Jun 8 05:42:56 2014 UTC (9 years, 10 months ago) by persson
File size: 48452 byte(s)
* removed usage of c++11 initializer that caused compilation errors on
  older compilers

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

  ViewVC Help
Powered by ViewVC