/[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 3988 - (hide annotations) (download)
Wed Aug 4 18:23:05 2021 UTC (2 years, 8 months ago) by schoenebeck
File size: 54688 byte(s)
* AbstractEngineChannel: fix CCs not being forwarded to all
  VirtualMIDIDevices.

* Bumped version (2.2.0.svn6).

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

  ViewVC Help
Powered by ViewVC