/[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 2594 - (hide annotations) (download)
Thu Jun 5 00:16:25 2014 UTC (9 years, 10 months ago) by schoenebeck
File size: 45829 byte(s)
* ScriptVM (WIP): started to integrate real-time instrument script
  support into the sampler engine implementations. The code is
  shared among all sampler engines, however currently only the gig
  file format supports storing instrument scripts (as LinuxSampler
  extension to the original GigaStudio 4 file format).
* gig engine: Added support for loading instrument scripts from .gig
  files.
* ScriptVM (WIP): Implemented built-in script variables %CC, $CC_NUM,
  $EVENT_NOTE, $EVENT_VELOCITY, $VCC_MONO_AT, $VCC_PITCH_BEND.
* ScriptVM (WIP): Implemented execution of script event handler "init".
* ScriptVM (WIP): Implemented execution of script event handler
  "controller".
* Bumped version (1.0.0.svn42).

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

  ViewVC Help
Powered by ViewVC