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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2598 - (hide annotations) (download)
Fri Jun 6 12:38:54 2014 UTC (9 years, 9 months ago) by schoenebeck
File size: 47240 byte(s)
* ScriptVM (WIP): Built-in script function "play_note()" now returns the
  event ID of the triggered note.
* ScriptVM (WIP): Implemented built-in script int variable $EVENT_ID.
* ScriptVM (WIP): Implemented built-in script function "ignore_event()".
* ScriptVM (WIP): Implemented built-in script function
  "ignore_controller()" (accepts one and no argument).
* Bumped version (1.0.0.svn44).

1 iliev 2012 /***************************************************************************
2     * *
3     * LinuxSampler - modular, streaming capable sampler *
4     * *
5     * Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck *
6 persson 2114 * Copyright (C) 2005-2008 Christian Schoenebeck *
7 schoenebeck 2500 * Copyright (C) 2009-2012 Christian Schoenebeck and Grigor Iliev *
8     * Copyright (C) 2013-2014 Christian Schoenebeck and Andreas Persson *
9 iliev 2012 * *
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 schoenebeck 2594 pScriptEvents = NULL;
50 iliev 2012 }
51    
52     AbstractEngineChannel::~AbstractEngineChannel() {
53 schoenebeck 2594 unloadCurrentInstrumentScript();
54     if (pScriptEvents) delete pScriptEvents;
55 persson 2114 delete pEventQueue;
56     DeleteGroupEventLists();
57 iliev 2012 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 schoenebeck 2594 * 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 schoenebeck 2596 script.handlerRelease = script.parserContext->eventHandlerByName("release");
175 schoenebeck 2594 script.handlerController = script.parserContext->eventHandlerByName("controller");
176     script.bHasValidScript =
177 schoenebeck 2596 script.handlerInit || script.handlerNote || script.handlerRelease ||
178     script.handlerController;
179 schoenebeck 2594
180     // amount of script handlers each script event has to execute
181     int handlerExecCount = 0;
182 schoenebeck 2596 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 schoenebeck 2594
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 schoenebeck 2596 script.handlerRelease = NULL;
235 schoenebeck 2594 script.handlerController = NULL;
236     }
237     script.bHasValidScript = false;
238     }
239    
240     /**
241 iliev 2012 * 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 persson 2326 /**
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 persson 2427 LockGuard lock(EngineMutex);
292     return GetAudioOutputDevice();
293 persson 2326 }
294    
295 iliev 2012 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 schoenebeck 2500 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 iliev 2012 void AbstractEngineChannel::Connect(MidiInputPort* pMidiPort, midi_chan_t MidiChannel) {
377 schoenebeck 2500 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 iliev 2012 pMidiPort->Connect(this, MidiChannel);
399     }
400    
401 schoenebeck 2500 // deprecated (just for API backward compatibility) - may be removed in future
402 iliev 2012 void AbstractEngineChannel::DisconnectMidiInputPort() {
403 schoenebeck 2500 DisconnectAllMidiInputPorts();
404 iliev 2012 }
405    
406 schoenebeck 2500 // deprecated (just for API backward compatibility) - may be removed in future
407 iliev 2012 MidiInputPort* AbstractEngineChannel::GetMidiInputPort() {
408 schoenebeck 2500 return GetMidiInputPort(0);
409 iliev 2012 }
410    
411     midi_chan_t AbstractEngineChannel::MidiChannel() {
412     return midiChannel;
413     }
414    
415 schoenebeck 2500 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 iliev 2012 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 persson 2317 void AbstractEngineChannel::SendNoteOn(uint8_t Key, uint8_t Velocity, uint8_t MidiChannel) {
464 iliev 2012 if (pEngine) {
465 schoenebeck 2500 // 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 iliev 2012 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 persson 2317 event.Param.Note.Channel = MidiChannel;
474 iliev 2012 event.pEngineChannel = this;
475     if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
476     else dmsg(1,("EngineChannel: Input event queue full!"));
477     // inform connected virtual MIDI devices if any ...
478     // (e.g. virtual MIDI keyboard in instrument editor(s))
479     ArrayList<VirtualMidiDevice*>& devices =
480     const_cast<ArrayList<VirtualMidiDevice*>&>(
481     virtualMidiDevicesReader_MidiThread.Lock()
482     );
483     for (int i = 0; i < devices.size(); i++) {
484     devices[i]->SendNoteOnToDevice(Key, Velocity);
485     }
486     virtualMidiDevicesReader_MidiThread.Unlock();
487     }
488     }
489    
490     /**
491     * Will be called by the MIDIIn Thread to let the audio thread trigger a new
492     * voice for the given key. This method is meant for offline rendering
493     * and / or for cases where the exact position of the event in the current
494     * audio fragment is already known.
495     *
496     * @param Key - MIDI key number of the triggered key
497     * @param Velocity - MIDI velocity value of the triggered key
498     * @param FragmentPos - sample point position in the current audio
499     * fragment to which this event belongs to
500     */
501 persson 2317 void AbstractEngineChannel::SendNoteOn(uint8_t Key, uint8_t Velocity, uint8_t MidiChannel, int32_t FragmentPos) {
502 iliev 2012 if (FragmentPos < 0) {
503     dmsg(1,("EngineChannel::SendNoteOn(): negative FragmentPos! Seems MIDI driver is buggy!"));
504     }
505     else if (pEngine) {
506 schoenebeck 2500 // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
507     LockGuard g;
508     if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
509    
510 iliev 2012 Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);
511     event.Type = Event::type_note_on;
512     event.Param.Note.Key = Key;
513     event.Param.Note.Velocity = Velocity;
514 persson 2317 event.Param.Note.Channel = MidiChannel;
515 iliev 2012 event.pEngineChannel = this;
516     if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
517     else dmsg(1,("EngineChannel: Input event queue full!"));
518     // inform connected virtual MIDI devices if any ...
519     // (e.g. virtual MIDI keyboard in instrument editor(s))
520     ArrayList<VirtualMidiDevice*>& devices =
521     const_cast<ArrayList<VirtualMidiDevice*>&>(
522     virtualMidiDevicesReader_MidiThread.Lock()
523     );
524     for (int i = 0; i < devices.size(); i++) {
525     devices[i]->SendNoteOnToDevice(Key, Velocity);
526     }
527     virtualMidiDevicesReader_MidiThread.Unlock();
528     }
529     }
530    
531     /**
532     * Will be called by the MIDIIn Thread to signal the audio thread to release
533     * voice(s) on the given key. This method is meant for real time rendering,
534     * that is an event will immediately be created with the current system
535     * time as time stamp.
536     *
537     * @param Key - MIDI key number of the released key
538     * @param Velocity - MIDI release velocity value of the released key
539     */
540 persson 2317 void AbstractEngineChannel::SendNoteOff(uint8_t Key, uint8_t Velocity, uint8_t MidiChannel) {
541 iliev 2012 if (pEngine) {
542 schoenebeck 2500 // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
543     LockGuard g;
544     if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
545    
546 iliev 2012 Event event = pEngine->pEventGenerator->CreateEvent();
547     event.Type = Event::type_note_off;
548     event.Param.Note.Key = Key;
549     event.Param.Note.Velocity = Velocity;
550 persson 2317 event.Param.Note.Channel = MidiChannel;
551 iliev 2012 event.pEngineChannel = this;
552     if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
553     else dmsg(1,("EngineChannel: Input event queue full!"));
554     // inform connected virtual MIDI devices if any ...
555     // (e.g. virtual MIDI keyboard in instrument editor(s))
556     ArrayList<VirtualMidiDevice*>& devices =
557     const_cast<ArrayList<VirtualMidiDevice*>&>(
558     virtualMidiDevicesReader_MidiThread.Lock()
559     );
560     for (int i = 0; i < devices.size(); i++) {
561     devices[i]->SendNoteOffToDevice(Key, Velocity);
562     }
563     virtualMidiDevicesReader_MidiThread.Unlock();
564     }
565     }
566    
567     /**
568     * Will be called by the MIDIIn Thread to signal the audio thread to release
569     * voice(s) on the given key. This method is meant for offline rendering
570     * and / or for cases where the exact position of the event in the current
571     * audio fragment is already known.
572     *
573     * @param Key - MIDI key number of the released key
574     * @param Velocity - MIDI release velocity value of the released key
575     * @param FragmentPos - sample point position in the current audio
576     * fragment to which this event belongs to
577     */
578 persson 2317 void AbstractEngineChannel::SendNoteOff(uint8_t Key, uint8_t Velocity, uint8_t MidiChannel, int32_t FragmentPos) {
579 iliev 2012 if (FragmentPos < 0) {
580     dmsg(1,("EngineChannel::SendNoteOff(): negative FragmentPos! Seems MIDI driver is buggy!"));
581     }
582     else if (pEngine) {
583 schoenebeck 2500 // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
584     LockGuard g;
585     if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
586    
587 iliev 2012 Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);
588     event.Type = Event::type_note_off;
589     event.Param.Note.Key = Key;
590     event.Param.Note.Velocity = Velocity;
591 persson 2317 event.Param.Note.Channel = MidiChannel;
592 iliev 2012 event.pEngineChannel = this;
593     if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
594     else dmsg(1,("EngineChannel: Input event queue full!"));
595     // inform connected virtual MIDI devices if any ...
596     // (e.g. virtual MIDI keyboard in instrument editor(s))
597     ArrayList<VirtualMidiDevice*>& devices =
598     const_cast<ArrayList<VirtualMidiDevice*>&>(
599     virtualMidiDevicesReader_MidiThread.Lock()
600     );
601     for (int i = 0; i < devices.size(); i++) {
602     devices[i]->SendNoteOffToDevice(Key, Velocity);
603     }
604     virtualMidiDevicesReader_MidiThread.Unlock();
605     }
606     }
607    
608     /**
609     * Will be called by the MIDIIn Thread to signal the audio thread to change
610     * the pitch value for all voices. This method is meant for real time
611     * rendering, that is an event will immediately be created with the
612     * current system time as time stamp.
613     *
614     * @param Pitch - MIDI pitch value (-8192 ... +8191)
615     */
616 persson 2317 void AbstractEngineChannel::SendPitchbend(int Pitch, uint8_t MidiChannel) {
617 iliev 2012 if (pEngine) {
618 schoenebeck 2500 // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
619     LockGuard g;
620     if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
621    
622 iliev 2012 Event event = pEngine->pEventGenerator->CreateEvent();
623     event.Type = Event::type_pitchbend;
624     event.Param.Pitch.Pitch = Pitch;
625 persson 2317 event.Param.Pitch.Channel = MidiChannel;
626 iliev 2012 event.pEngineChannel = this;
627     if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
628     else dmsg(1,("EngineChannel: Input event queue full!"));
629     }
630     }
631    
632     /**
633     * Will be called by the MIDIIn Thread to signal the audio thread to change
634     * the pitch value for all voices. This method is meant for offline
635     * rendering and / or for cases where the exact position of the event in
636     * the current audio fragment is already known.
637     *
638     * @param Pitch - MIDI pitch value (-8192 ... +8191)
639     * @param FragmentPos - sample point position in the current audio
640     * fragment to which this event belongs to
641     */
642 persson 2317 void AbstractEngineChannel::SendPitchbend(int Pitch, uint8_t MidiChannel, int32_t FragmentPos) {
643 iliev 2012 if (FragmentPos < 0) {
644     dmsg(1,("AbstractEngineChannel::SendPitchBend(): negative FragmentPos! Seems MIDI driver is buggy!"));
645     }
646     else if (pEngine) {
647 schoenebeck 2500 // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
648     LockGuard g;
649     if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
650    
651 iliev 2012 Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);
652     event.Type = Event::type_pitchbend;
653     event.Param.Pitch.Pitch = Pitch;
654 persson 2317 event.Param.Pitch.Channel = MidiChannel;
655 iliev 2012 event.pEngineChannel = this;
656     if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
657     else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
658     }
659     }
660    
661     /**
662     * Will be called by the MIDIIn Thread to signal the audio thread that a
663     * continuous controller value has changed. This method is meant for real
664     * time rendering, that is an event will immediately be created with the
665     * current system time as time stamp.
666     *
667     * @param Controller - MIDI controller number of the occured control change
668     * @param Value - value of the control change
669     */
670 persson 2317 void AbstractEngineChannel::SendControlChange(uint8_t Controller, uint8_t Value, uint8_t MidiChannel) {
671 iliev 2012 if (pEngine) {
672 schoenebeck 2500 // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
673     LockGuard g;
674     if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
675    
676 iliev 2012 Event event = pEngine->pEventGenerator->CreateEvent();
677     event.Type = Event::type_control_change;
678     event.Param.CC.Controller = Controller;
679     event.Param.CC.Value = Value;
680 persson 2317 event.Param.CC.Channel = MidiChannel;
681 iliev 2012 event.pEngineChannel = this;
682     if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
683     else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
684     }
685     }
686    
687     /**
688     * Will be called by the MIDIIn Thread to signal the audio thread that a
689     * continuous controller value has changed. This method is meant for
690     * offline rendering and / or for cases where the exact position of the
691     * event in the current audio fragment is already known.
692     *
693     * @param Controller - MIDI controller number of the occured control change
694     * @param Value - value of the control change
695     * @param FragmentPos - sample point position in the current audio
696     * fragment to which this event belongs to
697     */
698 persson 2317 void AbstractEngineChannel::SendControlChange(uint8_t Controller, uint8_t Value, uint8_t MidiChannel, int32_t FragmentPos) {
699 iliev 2012 if (FragmentPos < 0) {
700     dmsg(1,("AbstractEngineChannel::SendControlChange(): negative FragmentPos! Seems MIDI driver is buggy!"));
701     }
702     else if (pEngine) {
703 schoenebeck 2500 // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
704     LockGuard g;
705     if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
706    
707 iliev 2012 Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);
708     event.Type = Event::type_control_change;
709     event.Param.CC.Controller = Controller;
710     event.Param.CC.Value = Value;
711 persson 2317 event.Param.CC.Channel = MidiChannel;
712 iliev 2012 event.pEngineChannel = this;
713     if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
714     else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
715     }
716     }
717    
718 schoenebeck 2559 void AbstractEngineChannel::SendChannelPressure(uint8_t Value, uint8_t MidiChannel) {
719     if (pEngine) {
720     // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
721     LockGuard g;
722     if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
723    
724     Event event = pEngine->pEventGenerator->CreateEvent();
725     event.Type = Event::type_channel_pressure;
726     event.Param.ChannelPressure.Value = Value;
727     event.Param.ChannelPressure.Channel = MidiChannel;
728     event.pEngineChannel = this;
729     if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
730     else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
731     }
732     }
733    
734     void AbstractEngineChannel::SendChannelPressure(uint8_t Value, uint8_t MidiChannel, int32_t FragmentPos) {
735     if (pEngine) {
736     // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
737     LockGuard g;
738     if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
739    
740     Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);
741     event.Type = Event::type_channel_pressure;
742     event.Param.ChannelPressure.Value = Value;
743     event.Param.ChannelPressure.Channel = MidiChannel;
744     event.pEngineChannel = this;
745     if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
746     else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
747     }
748     }
749    
750     void AbstractEngineChannel::SendPolyphonicKeyPressure(uint8_t Key, uint8_t Value, uint8_t MidiChannel) {
751     if (pEngine) {
752     // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
753     LockGuard g;
754     if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
755    
756     Event event = pEngine->pEventGenerator->CreateEvent();
757     event.Type = Event::type_note_pressure;
758     event.Param.NotePressure.Key = Key;
759     event.Param.NotePressure.Value = Value;
760     event.Param.NotePressure.Channel = MidiChannel;
761     event.pEngineChannel = this;
762     if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
763     else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
764     }
765     }
766    
767     void AbstractEngineChannel::SendPolyphonicKeyPressure(uint8_t Key, uint8_t Value, uint8_t MidiChannel, int32_t FragmentPos) {
768     if (pEngine) {
769     // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
770     LockGuard g;
771     if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
772    
773     Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);
774     event.Type = Event::type_note_pressure;
775     event.Param.NotePressure.Key = Key;
776     event.Param.NotePressure.Value = Value;
777     event.Param.NotePressure.Channel = MidiChannel;
778     event.pEngineChannel = this;
779     if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
780     else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
781     }
782     }
783    
784 iliev 2012 /**
785     * Copy all events from the engine channel's input event queue buffer to
786     * the internal event list. This will be done at the beginning of each
787     * audio cycle (that is each RenderAudio() call) to distinguish all
788     * events which have to be processed in the current audio cycle. Each
789     * EngineChannel has it's own input event queue for the common channel
790     * specific events (like NoteOn, NoteOff and ControlChange events).
791     * Beside that, the engine also has a input event queue for global
792     * events (usually SysEx messages).
793     *
794     * @param Samples - number of sample points to be processed in the
795     * current audio cycle
796     */
797     void AbstractEngineChannel::ImportEvents(uint Samples) {
798     // import events from pure software MIDI "devices"
799     // (e.g. virtual keyboard in instrument editor)
800     {
801 persson 2317 const uint8_t channel = MidiChannel() == midi_chan_all ? 0 : MidiChannel();
802 iliev 2012 const int FragmentPos = 0; // randomly chosen, we don't care about jitter for virtual MIDI devices
803     Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);
804     VirtualMidiDevice::event_t devEvent; // the event format we get from the virtual MIDI device
805     // as we're going to (carefully) write some status to the
806     // synchronized struct, we cast away the const
807     ArrayList<VirtualMidiDevice*>& devices =
808     const_cast<ArrayList<VirtualMidiDevice*>&>(virtualMidiDevicesReader_AudioThread.Lock());
809     // iterate through all virtual MIDI devices
810     for (int i = 0; i < devices.size(); i++) {
811     VirtualMidiDevice* pDev = devices[i];
812     // I think we can simply flush the whole FIFO(s), the user shouldn't be so fast ;-)
813     while (pDev->GetMidiEventFromDevice(devEvent)) {
814 schoenebeck 2025 switch (devEvent.Type) {
815     case VirtualMidiDevice::EVENT_TYPE_NOTEON:
816     event.Type = Event::type_note_on;
817     event.Param.Note.Key = devEvent.Arg1;
818     event.Param.Note.Velocity = devEvent.Arg2;
819 persson 2317 event.Param.Note.Channel = channel;
820 schoenebeck 2025 break;
821     case VirtualMidiDevice::EVENT_TYPE_NOTEOFF:
822     event.Type = Event::type_note_off;
823     event.Param.Note.Key = devEvent.Arg1;
824     event.Param.Note.Velocity = devEvent.Arg2;
825 persson 2317 event.Param.Note.Channel = channel;
826 schoenebeck 2025 break;
827     case VirtualMidiDevice::EVENT_TYPE_CC:
828 schoenebeck 2521 switch (devEvent.Arg1) {
829     case 0: // bank select MSB ...
830     SetMidiBankMsb(devEvent.Arg2);
831     continue; // don't push this event into FIFO
832     case 32: // bank select LSB ...
833     SetMidiBankLsb(devEvent.Arg2);
834     continue; // don't push this event into FIFO
835     default: // regular MIDI CC ...
836     event.Type = Event::type_control_change;
837     event.Param.CC.Controller = devEvent.Arg1;
838     event.Param.CC.Value = devEvent.Arg2;
839     event.Param.CC.Channel = channel;
840     }
841 schoenebeck 2025 break;
842 schoenebeck 2521 case VirtualMidiDevice::EVENT_TYPE_PITCHBEND:
843     event.Type = Event::type_pitchbend;
844     event.Param.Pitch.Pitch = int(devEvent.Arg2 << 7 | devEvent.Arg1) - 8192;
845     event.Param.Pitch.Channel = channel;
846     break;
847     case VirtualMidiDevice::EVENT_TYPE_PROGRAM:
848     SendProgramChange(devEvent.Arg1);
849     continue; // don't push this event into FIFO
850 schoenebeck 2025 default:
851     std::cerr << "AbstractEngineChannel::ImportEvents() ERROR: unknown event type ("
852     << devEvent.Type << "). This is a bug!";
853     continue;
854     }
855     event.pEngineChannel = this;
856 iliev 2012 // copy event to internal event list
857     if (pEvents->poolIsEmpty()) {
858     dmsg(1,("Event pool emtpy!\n"));
859     goto exitVirtualDevicesLoop;
860     }
861     *pEvents->allocAppend() = event;
862     }
863     }
864     }
865     exitVirtualDevicesLoop:
866     virtualMidiDevicesReader_AudioThread.Unlock();
867    
868     // import events from the regular MIDI devices
869     RingBuffer<Event,false>::NonVolatileReader eventQueueReader = pEventQueue->get_non_volatile_reader();
870     Event* pEvent;
871     while (true) {
872     // get next event from input event queue
873     if (!(pEvent = eventQueueReader.pop())) break;
874     // if younger event reached, ignore that and all subsequent ones for now
875     if (pEvent->FragmentPos() >= Samples) {
876     eventQueueReader--;
877     dmsg(2,("Younger Event, pos=%d ,Samples=%d!\n",pEvent->FragmentPos(),Samples));
878     pEvent->ResetFragmentPos();
879     break;
880     }
881     // copy event to internal event list
882     if (pEvents->poolIsEmpty()) {
883     dmsg(1,("Event pool emtpy!\n"));
884     break;
885     }
886     *pEvents->allocAppend() = *pEvent;
887     }
888     eventQueueReader.free(); // free all copied events from input queue
889     }
890 schoenebeck 2598
891 schoenebeck 2596 /**
892     * Called by real-time instrument script functions to schedule a new event
893     * somewhere in future.
894 schoenebeck 2598 *
895     * @returns unique event ID of scheduled new event
896 schoenebeck 2596 */
897 schoenebeck 2598 int AbstractEngineChannel::ScheduleEvent(const Event* pEvent, int delay) { //TODO: delay not implemented yet
898 schoenebeck 2596 // since delay is not implemented yet, we simply add the new event
899     // to the event list of the current audio fragmet cycle for now
900     RTList<Event>::Iterator itEvent = pEvents->allocAppend();
901     if (itEvent) *itEvent = *pEvent; // copy event
902 schoenebeck 2598 return pEvents->getID(itEvent);
903 schoenebeck 2596 }
904 iliev 2012
905 schoenebeck 2598 /**
906     * Called by real-time instrument script functions to ignore the event
907     * reflected by given event ID. The event will be freed immediately to its
908     * pool and cannot be dereferenced by its old ID anymore. Even if its
909     * allocated back from the Pool later on, it will have a different ID.
910     */
911     void AbstractEngineChannel::IgnoreEvent(int id) {
912     RTList<Event>::Iterator it = pEvents->fromID(id);
913     if (it) pEvents->free(it);
914     }
915    
916 iliev 2012 FxSend* AbstractEngineChannel::AddFxSend(uint8_t MidiCtrl, String Name) throw (Exception) {
917     if (pEngine) pEngine->DisableAndLock();
918     FxSend* pFxSend = new FxSend(this, MidiCtrl, Name);
919     if (fxSends.empty()) {
920     if (pEngine && pEngine->pAudioOutputDevice) {
921     AudioOutputDevice* pDevice = pEngine->pAudioOutputDevice;
922     // create local render buffers
923     pChannelLeft = new AudioChannel(0, pDevice->MaxSamplesPerCycle());
924     pChannelRight = new AudioChannel(1, pDevice->MaxSamplesPerCycle());
925     } else {
926     // postpone local render buffer creation until audio device is assigned
927     pChannelLeft = NULL;
928     pChannelRight = NULL;
929     }
930     }
931     fxSends.push_back(pFxSend);
932     if (pEngine) pEngine->Enable();
933     fireFxSendCountChanged(GetSamplerChannel()->Index(), GetFxSendCount());
934    
935     return pFxSend;
936     }
937    
938     FxSend* AbstractEngineChannel::GetFxSend(uint FxSendIndex) {
939     return (FxSendIndex < fxSends.size()) ? fxSends[FxSendIndex] : NULL;
940     }
941    
942     uint AbstractEngineChannel::GetFxSendCount() {
943     return fxSends.size();
944     }
945    
946     void AbstractEngineChannel::RemoveFxSend(FxSend* pFxSend) {
947     if (pEngine) pEngine->DisableAndLock();
948     for (
949     std::vector<FxSend*>::iterator iter = fxSends.begin();
950     iter != fxSends.end(); iter++
951     ) {
952     if (*iter == pFxSend) {
953     delete pFxSend;
954     fxSends.erase(iter);
955     if (fxSends.empty()) {
956     // destroy local render buffers
957     if (pChannelLeft) delete pChannelLeft;
958     if (pChannelRight) delete pChannelRight;
959     // fallback to render directly into AudioOutputDevice's buffers
960     if (pEngine && pEngine->pAudioOutputDevice) {
961     pChannelLeft = pEngine->pAudioOutputDevice->Channel(AudioDeviceChannelLeft);
962     pChannelRight = pEngine->pAudioOutputDevice->Channel(AudioDeviceChannelRight);
963     } else { // we update the pointers later
964     pChannelLeft = NULL;
965     pChannelRight = NULL;
966     }
967     }
968     break;
969     }
970     }
971     if (pEngine) pEngine->Enable();
972     fireFxSendCountChanged(GetSamplerChannel()->Index(), GetFxSendCount());
973     }
974    
975     void AbstractEngineChannel::RemoveAllFxSends() {
976     if (pEngine) pEngine->DisableAndLock();
977     if (!fxSends.empty()) { // free local render buffers
978     if (pChannelLeft) {
979     delete pChannelLeft;
980     if (pEngine && pEngine->pAudioOutputDevice) {
981     // fallback to render directly to the AudioOutputDevice's buffer
982     pChannelLeft = pEngine->pAudioOutputDevice->Channel(AudioDeviceChannelLeft);
983     } else pChannelLeft = NULL;
984     }
985     if (pChannelRight) {
986     delete pChannelRight;
987     if (pEngine && pEngine->pAudioOutputDevice) {
988     // fallback to render directly to the AudioOutputDevice's buffer
989     pChannelRight = pEngine->pAudioOutputDevice->Channel(AudioDeviceChannelRight);
990     } else pChannelRight = NULL;
991     }
992     }
993     for (int i = 0; i < fxSends.size(); i++) delete fxSends[i];
994     fxSends.clear();
995     if (pEngine) pEngine->Enable();
996     }
997    
998 persson 2114 /**
999     * Add a group number to the set of key groups. Should be called
1000     * when an instrument is loaded to make sure there are event lists
1001     * for all key groups.
1002     */
1003     void AbstractEngineChannel::AddGroup(uint group) {
1004     if (group) {
1005 persson 2127 std::pair<ActiveKeyGroupMap::iterator, bool> p =
1006     ActiveKeyGroups.insert(ActiveKeyGroupMap::value_type(group, 0));
1007 persson 2114 if (p.second) {
1008 persson 2127 // If the engine channel is pending deletion (see bug
1009     // #113), pEngine will be null, so we can't use
1010     // pEngine->pEventPool here. Instead we're using a
1011     // specialized RTList that allows specifying the pool
1012     // later.
1013     (*p.first).second = new LazyList<Event>;
1014 persson 2114 }
1015     }
1016     }
1017    
1018     /**
1019     * Handle key group (a.k.a. exclusive group) conflicts.
1020     */
1021     void AbstractEngineChannel::HandleKeyGroupConflicts(uint KeyGroup, Pool<Event>::Iterator& itNoteOnEvent) {
1022     dmsg(4,("HandelKeyGroupConflicts KeyGroup=%d\n", KeyGroup));
1023     if (KeyGroup) {
1024     // send a release event to all active voices in the group
1025 persson 2127 RTList<Event>::Iterator itEvent = ActiveKeyGroups[KeyGroup]->allocAppend(pEngine->pEventPool);
1026 persson 2114 *itEvent = *itNoteOnEvent;
1027     }
1028     }
1029    
1030     /**
1031     * Empty the lists of group events. Should be called from the
1032     * audio thread, after all voices have been rendered.
1033     */
1034     void AbstractEngineChannel::ClearGroupEventLists() {
1035 persson 2127 for (ActiveKeyGroupMap::iterator iter = ActiveKeyGroups.begin();
1036 persson 2114 iter != ActiveKeyGroups.end(); iter++) {
1037     if (iter->second) {
1038     iter->second->clear();
1039     } else {
1040     dmsg(1,("EngineChannel: group event list was NULL"));
1041     }
1042     }
1043     }
1044    
1045     /**
1046     * Remove all lists with group events.
1047     */
1048     void AbstractEngineChannel::DeleteGroupEventLists() {
1049 persson 2127 for (ActiveKeyGroupMap::iterator iter = ActiveKeyGroups.begin();
1050 persson 2114 iter != ActiveKeyGroups.end(); iter++) {
1051     delete iter->second;
1052     }
1053     ActiveKeyGroups.clear();
1054     }
1055    
1056 iliev 2012 } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC