/[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 2326 - (hide annotations) (download)
Thu Mar 8 19:40:14 2012 UTC (12 years, 1 month ago) by persson
File size: 32730 byte(s)
* bugfix: instrument loading crashed for sfz and sf2 in Ardour (#176)
* more thread safety fixes for the instrument loading thread

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 persson 2317 * Copyright (C) 2009-2012 Christian Schoenebeck and Grigor Iliev *
8 iliev 2012 * *
9     * This program is free software; you can redistribute it and/or modify *
10     * it under the terms of the GNU General Public License as published by *
11     * the Free Software Foundation; either version 2 of the License, or *
12     * (at your option) any later version. *
13     * *
14     * This program is distributed in the hope that it will be useful, *
15     * but WITHOUT ANY WARRANTY; without even the implied warranty of *
16     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
17     * GNU General Public License for more details. *
18     * *
19     * You should have received a copy of the GNU General Public License *
20     * along with this program; if not, write to the Free Software *
21     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
22     * MA 02111-1307 USA *
23     ***************************************************************************/
24    
25     #include "AbstractEngineChannel.h"
26     #include "../common/global_private.h"
27     #include "../Sampler.h"
28    
29     namespace LinuxSampler {
30    
31     AbstractEngineChannel::AbstractEngineChannel() :
32     virtualMidiDevicesReader_AudioThread(virtualMidiDevices),
33     virtualMidiDevicesReader_MidiThread(virtualMidiDevices)
34     {
35     pEngine = NULL;
36     pEvents = NULL; // we allocate when we retrieve the right Engine object
37     pEventQueue = new RingBuffer<Event,false>(CONFIG_MAX_EVENTS_PER_FRAGMENT, 0);
38     InstrumentIdx = -1;
39     InstrumentStat = -1;
40     pChannelLeft = NULL;
41     pChannelRight = NULL;
42     AudioDeviceChannelLeft = -1;
43     AudioDeviceChannelRight = -1;
44     pMidiInputPort = NULL;
45     midiChannel = midi_chan_all;
46     ResetControllers();
47     PortamentoMode = false;
48     PortamentoTime = CONFIG_PORTAMENTO_TIME_DEFAULT;
49     }
50    
51     AbstractEngineChannel::~AbstractEngineChannel() {
52 persson 2114 delete pEventQueue;
53     DeleteGroupEventLists();
54 iliev 2012 RemoveAllFxSends();
55     }
56    
57     Engine* AbstractEngineChannel::GetEngine() {
58     return pEngine;
59     }
60    
61     uint AbstractEngineChannel::Channels() {
62     return 2;
63     }
64    
65     /**
66     * More or less a workaround to set the instrument name, index and load
67     * status variable to zero percent immediately, that is without blocking
68     * the calling thread. It might be used in future for other preparations
69     * as well though.
70     *
71     * @param FileName - file name of the instrument file
72     * @param Instrument - index of the instrument in the file
73     * @see LoadInstrument()
74     */
75     void AbstractEngineChannel::PrepareLoadInstrument(const char* FileName, uint Instrument) {
76     InstrumentFile = FileName;
77     InstrumentIdx = Instrument;
78     InstrumentStat = 0;
79     }
80    
81     String AbstractEngineChannel::InstrumentFileName() {
82     return InstrumentFile;
83     }
84    
85     String AbstractEngineChannel::InstrumentName() {
86     return InstrumentIdxName;
87     }
88    
89     int AbstractEngineChannel::InstrumentIndex() {
90     return InstrumentIdx;
91     }
92    
93     int AbstractEngineChannel::InstrumentStatus() {
94     return InstrumentStat;
95     }
96    
97     String AbstractEngineChannel::EngineName() {
98     return AbstractEngine::GetFormatString(GetEngineFormat());
99     }
100    
101     void AbstractEngineChannel::Reset() {
102     if (pEngine) pEngine->DisableAndLock();
103     ResetInternal();
104     ResetControllers();
105     if (pEngine) {
106     pEngine->Enable();
107     pEngine->Reset();
108     }
109     }
110    
111     void AbstractEngineChannel::ResetControllers() {
112     Pitch = 0;
113     GlobalVolume = 1.0f;
114     MidiVolume = 1.0;
115     GlobalPanLeft = 1.0f;
116     GlobalPanRight = 1.0f;
117     iLastPanRequest = 64;
118     GlobalTranspose = 0;
119     // set all MIDI controller values to zero
120     memset(ControllerTable, 0x00, 129);
121     // reset all FX Send levels
122     for (
123     std::vector<FxSend*>::iterator iter = fxSends.begin();
124     iter != fxSends.end(); iter++
125     ) {
126     (*iter)->Reset();
127     }
128     }
129    
130     /**
131     * This method is not thread safe!
132     */
133     void AbstractEngineChannel::ResetInternal() {
134     CurrentKeyDimension = 0;
135     PortamentoPos = -1.0f; // no portamento active yet
136    
137     // delete all input events
138     pEventQueue->init();
139    
140     if (pEngine) pEngine->ResetInternal();
141    
142     // status of engine channel has changed, so set notify flag
143     bStatusChanged = true;
144     }
145    
146     /**
147     * Implementation of virtual method from abstract EngineChannel interface.
148     * This method will periodically be polled (e.g. by the LSCP server) to
149     * check if some engine channel parameter has changed since the last
150     * StatusChanged() call.
151     *
152     * This method can also be used to mark the engine channel as changed
153     * from outside, e.g. by a MIDI input device. The optional argument
154     * \a nNewStatus can be used for this.
155     *
156     * TODO: This "poll method" is just a lazy solution and might be
157     * replaced in future.
158     * @param bNewStatus - (optional, default: false) sets the new status flag
159     * @returns true if engine channel status has changed since last
160     * StatusChanged() call
161     */
162     bool AbstractEngineChannel::StatusChanged(bool bNewStatus) {
163     bool b = bStatusChanged;
164     bStatusChanged = bNewStatus;
165     return b;
166     }
167    
168     float AbstractEngineChannel::Volume() {
169     return GlobalVolume;
170     }
171    
172     void AbstractEngineChannel::Volume(float f) {
173     GlobalVolume = f;
174     bStatusChanged = true; // status of engine channel has changed, so set notify flag
175     }
176    
177     float AbstractEngineChannel::Pan() {
178     return float(iLastPanRequest - 64) / 64.0f;
179     }
180    
181     void AbstractEngineChannel::Pan(float f) {
182     int iMidiPan = int(f * 64.0f) + 64;
183     if (iMidiPan > 127) iMidiPan = 127;
184     else if (iMidiPan < 0) iMidiPan = 0;
185     GlobalPanLeft = AbstractEngine::PanCurve[128 - iMidiPan];
186     GlobalPanRight = AbstractEngine::PanCurve[iMidiPan];
187     iLastPanRequest = iMidiPan;
188     }
189    
190     AudioOutputDevice* AbstractEngineChannel::GetAudioOutputDevice() {
191     return (pEngine) ? pEngine->pAudioOutputDevice : NULL;
192     }
193    
194 persson 2326 /**
195     * Gets thread safe access to the currently connected audio output
196     * device from other threads than the lscp thread.
197     */
198     AudioOutputDevice* AbstractEngineChannel::GetAudioOutputDeviceSafe() {
199     EngineMutex.Lock();
200     AudioOutputDevice* res = GetAudioOutputDevice();
201     EngineMutex.Unlock();
202     return res;
203     }
204    
205 iliev 2012 void AbstractEngineChannel::SetOutputChannel(uint EngineAudioChannel, uint AudioDeviceChannel) {
206     if (!pEngine || !pEngine->pAudioOutputDevice) throw AudioOutputException("No audio output device connected yet.");
207    
208     AudioChannel* pChannel = pEngine->pAudioOutputDevice->Channel(AudioDeviceChannel);
209     if (!pChannel) throw AudioOutputException("Invalid audio output device channel " + ToString(AudioDeviceChannel));
210     switch (EngineAudioChannel) {
211     case 0: // left output channel
212     if (fxSends.empty()) pChannelLeft = pChannel;
213     AudioDeviceChannelLeft = AudioDeviceChannel;
214     break;
215     case 1: // right output channel
216     if (fxSends.empty()) pChannelRight = pChannel;
217     AudioDeviceChannelRight = AudioDeviceChannel;
218     break;
219     default:
220     throw AudioOutputException("Invalid engine audio channel " + ToString(EngineAudioChannel));
221     }
222    
223     bStatusChanged = true;
224     }
225    
226     int AbstractEngineChannel::OutputChannel(uint EngineAudioChannel) {
227     switch (EngineAudioChannel) {
228     case 0: // left channel
229     return AudioDeviceChannelLeft;
230     case 1: // right channel
231     return AudioDeviceChannelRight;
232     default:
233     throw AudioOutputException("Invalid engine audio channel " + ToString(EngineAudioChannel));
234     }
235     }
236    
237     void AbstractEngineChannel::Connect(MidiInputPort* pMidiPort, midi_chan_t MidiChannel) {
238     if (!pMidiPort || pMidiPort == this->pMidiInputPort) return;
239     DisconnectMidiInputPort();
240     this->pMidiInputPort = pMidiPort;
241     this->midiChannel = MidiChannel;
242     pMidiPort->Connect(this, MidiChannel);
243     }
244    
245     void AbstractEngineChannel::DisconnectMidiInputPort() {
246     MidiInputPort* pOldPort = this->pMidiInputPort;
247     this->pMidiInputPort = NULL;
248     if (pOldPort) pOldPort->Disconnect(this);
249     }
250    
251     MidiInputPort* AbstractEngineChannel::GetMidiInputPort() {
252     return pMidiInputPort;
253     }
254    
255     midi_chan_t AbstractEngineChannel::MidiChannel() {
256     return midiChannel;
257     }
258    
259     void AbstractEngineChannel::Connect(VirtualMidiDevice* pDevice) {
260     // double buffer ... double work ...
261     {
262     ArrayList<VirtualMidiDevice*>& devices = virtualMidiDevices.GetConfigForUpdate();
263     devices.add(pDevice);
264     }
265     {
266     ArrayList<VirtualMidiDevice*>& devices = virtualMidiDevices.SwitchConfig();
267     devices.add(pDevice);
268     }
269     }
270    
271     void AbstractEngineChannel::Disconnect(VirtualMidiDevice* pDevice) {
272     // double buffer ... double work ...
273     {
274     ArrayList<VirtualMidiDevice*>& devices = virtualMidiDevices.GetConfigForUpdate();
275     devices.remove(pDevice);
276     }
277     {
278     ArrayList<VirtualMidiDevice*>& devices = virtualMidiDevices.SwitchConfig();
279     devices.remove(pDevice);
280     }
281     }
282    
283     /**
284     * Will be called by the MIDIIn Thread to let the audio thread trigger a new
285     * voice for the given key. This method is meant for real time rendering,
286     * that is an event will immediately be created with the current system
287     * time as time stamp.
288     *
289     * @param Key - MIDI key number of the triggered key
290     * @param Velocity - MIDI velocity value of the triggered key
291     */
292 persson 2317 void AbstractEngineChannel::SendNoteOn(uint8_t Key, uint8_t Velocity, uint8_t MidiChannel) {
293 iliev 2012 if (pEngine) {
294     Event event = pEngine->pEventGenerator->CreateEvent();
295     event.Type = Event::type_note_on;
296     event.Param.Note.Key = Key;
297     event.Param.Note.Velocity = Velocity;
298 persson 2317 event.Param.Note.Channel = MidiChannel;
299 iliev 2012 event.pEngineChannel = this;
300     if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
301     else dmsg(1,("EngineChannel: Input event queue full!"));
302     // inform connected virtual MIDI devices if any ...
303     // (e.g. virtual MIDI keyboard in instrument editor(s))
304     ArrayList<VirtualMidiDevice*>& devices =
305     const_cast<ArrayList<VirtualMidiDevice*>&>(
306     virtualMidiDevicesReader_MidiThread.Lock()
307     );
308     for (int i = 0; i < devices.size(); i++) {
309     devices[i]->SendNoteOnToDevice(Key, Velocity);
310     }
311     virtualMidiDevicesReader_MidiThread.Unlock();
312     }
313     }
314    
315     /**
316     * Will be called by the MIDIIn Thread to let the audio thread trigger a new
317     * voice for the given key. This method is meant for offline rendering
318     * and / or for cases where the exact position of the event in the current
319     * audio fragment is already known.
320     *
321     * @param Key - MIDI key number of the triggered key
322     * @param Velocity - MIDI velocity value of the triggered key
323     * @param FragmentPos - sample point position in the current audio
324     * fragment to which this event belongs to
325     */
326 persson 2317 void AbstractEngineChannel::SendNoteOn(uint8_t Key, uint8_t Velocity, uint8_t MidiChannel, int32_t FragmentPos) {
327 iliev 2012 if (FragmentPos < 0) {
328     dmsg(1,("EngineChannel::SendNoteOn(): negative FragmentPos! Seems MIDI driver is buggy!"));
329     }
330     else if (pEngine) {
331     Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);
332     event.Type = Event::type_note_on;
333     event.Param.Note.Key = Key;
334     event.Param.Note.Velocity = Velocity;
335 persson 2317 event.Param.Note.Channel = MidiChannel;
336 iliev 2012 event.pEngineChannel = this;
337     if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
338     else dmsg(1,("EngineChannel: Input event queue full!"));
339     // inform connected virtual MIDI devices if any ...
340     // (e.g. virtual MIDI keyboard in instrument editor(s))
341     ArrayList<VirtualMidiDevice*>& devices =
342     const_cast<ArrayList<VirtualMidiDevice*>&>(
343     virtualMidiDevicesReader_MidiThread.Lock()
344     );
345     for (int i = 0; i < devices.size(); i++) {
346     devices[i]->SendNoteOnToDevice(Key, Velocity);
347     }
348     virtualMidiDevicesReader_MidiThread.Unlock();
349     }
350     }
351    
352     /**
353     * Will be called by the MIDIIn Thread to signal the audio thread to release
354     * voice(s) on the given key. This method is meant for real time rendering,
355     * that is an event will immediately be created with the current system
356     * time as time stamp.
357     *
358     * @param Key - MIDI key number of the released key
359     * @param Velocity - MIDI release velocity value of the released key
360     */
361 persson 2317 void AbstractEngineChannel::SendNoteOff(uint8_t Key, uint8_t Velocity, uint8_t MidiChannel) {
362 iliev 2012 if (pEngine) {
363     Event event = pEngine->pEventGenerator->CreateEvent();
364     event.Type = Event::type_note_off;
365     event.Param.Note.Key = Key;
366     event.Param.Note.Velocity = Velocity;
367 persson 2317 event.Param.Note.Channel = MidiChannel;
368 iliev 2012 event.pEngineChannel = this;
369     if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
370     else dmsg(1,("EngineChannel: Input event queue full!"));
371     // inform connected virtual MIDI devices if any ...
372     // (e.g. virtual MIDI keyboard in instrument editor(s))
373     ArrayList<VirtualMidiDevice*>& devices =
374     const_cast<ArrayList<VirtualMidiDevice*>&>(
375     virtualMidiDevicesReader_MidiThread.Lock()
376     );
377     for (int i = 0; i < devices.size(); i++) {
378     devices[i]->SendNoteOffToDevice(Key, Velocity);
379     }
380     virtualMidiDevicesReader_MidiThread.Unlock();
381     }
382     }
383    
384     /**
385     * Will be called by the MIDIIn Thread to signal the audio thread to release
386     * voice(s) on the given key. This method is meant for offline rendering
387     * and / or for cases where the exact position of the event in the current
388     * audio fragment is already known.
389     *
390     * @param Key - MIDI key number of the released key
391     * @param Velocity - MIDI release velocity value of the released key
392     * @param FragmentPos - sample point position in the current audio
393     * fragment to which this event belongs to
394     */
395 persson 2317 void AbstractEngineChannel::SendNoteOff(uint8_t Key, uint8_t Velocity, uint8_t MidiChannel, int32_t FragmentPos) {
396 iliev 2012 if (FragmentPos < 0) {
397     dmsg(1,("EngineChannel::SendNoteOff(): negative FragmentPos! Seems MIDI driver is buggy!"));
398     }
399     else if (pEngine) {
400     Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);
401     event.Type = Event::type_note_off;
402     event.Param.Note.Key = Key;
403     event.Param.Note.Velocity = Velocity;
404 persson 2317 event.Param.Note.Channel = MidiChannel;
405 iliev 2012 event.pEngineChannel = this;
406     if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
407     else dmsg(1,("EngineChannel: Input event queue full!"));
408     // inform connected virtual MIDI devices if any ...
409     // (e.g. virtual MIDI keyboard in instrument editor(s))
410     ArrayList<VirtualMidiDevice*>& devices =
411     const_cast<ArrayList<VirtualMidiDevice*>&>(
412     virtualMidiDevicesReader_MidiThread.Lock()
413     );
414     for (int i = 0; i < devices.size(); i++) {
415     devices[i]->SendNoteOffToDevice(Key, Velocity);
416     }
417     virtualMidiDevicesReader_MidiThread.Unlock();
418     }
419     }
420    
421     /**
422     * Will be called by the MIDIIn Thread to signal the audio thread to change
423     * the pitch value for all voices. This method is meant for real time
424     * rendering, that is an event will immediately be created with the
425     * current system time as time stamp.
426     *
427     * @param Pitch - MIDI pitch value (-8192 ... +8191)
428     */
429 persson 2317 void AbstractEngineChannel::SendPitchbend(int Pitch, uint8_t MidiChannel) {
430 iliev 2012 if (pEngine) {
431     Event event = pEngine->pEventGenerator->CreateEvent();
432     event.Type = Event::type_pitchbend;
433     event.Param.Pitch.Pitch = Pitch;
434 persson 2317 event.Param.Pitch.Channel = MidiChannel;
435 iliev 2012 event.pEngineChannel = this;
436     if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
437     else dmsg(1,("EngineChannel: Input event queue full!"));
438     }
439     }
440    
441     /**
442     * Will be called by the MIDIIn Thread to signal the audio thread to change
443     * the pitch value for all voices. This method is meant for offline
444     * rendering and / or for cases where the exact position of the event in
445     * the current audio fragment is already known.
446     *
447     * @param Pitch - MIDI pitch value (-8192 ... +8191)
448     * @param FragmentPos - sample point position in the current audio
449     * fragment to which this event belongs to
450     */
451 persson 2317 void AbstractEngineChannel::SendPitchbend(int Pitch, uint8_t MidiChannel, int32_t FragmentPos) {
452 iliev 2012 if (FragmentPos < 0) {
453     dmsg(1,("AbstractEngineChannel::SendPitchBend(): negative FragmentPos! Seems MIDI driver is buggy!"));
454     }
455     else if (pEngine) {
456     Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);
457     event.Type = Event::type_pitchbend;
458     event.Param.Pitch.Pitch = Pitch;
459 persson 2317 event.Param.Pitch.Channel = MidiChannel;
460 iliev 2012 event.pEngineChannel = this;
461     if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
462     else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
463     }
464     }
465    
466     /**
467     * Will be called by the MIDIIn Thread to signal the audio thread that a
468     * continuous controller value has changed. This method is meant for real
469     * time rendering, that is an event will immediately be created with the
470     * current system time as time stamp.
471     *
472     * @param Controller - MIDI controller number of the occured control change
473     * @param Value - value of the control change
474     */
475 persson 2317 void AbstractEngineChannel::SendControlChange(uint8_t Controller, uint8_t Value, uint8_t MidiChannel) {
476 iliev 2012 if (pEngine) {
477     Event event = pEngine->pEventGenerator->CreateEvent();
478     event.Type = Event::type_control_change;
479     event.Param.CC.Controller = Controller;
480     event.Param.CC.Value = Value;
481 persson 2317 event.Param.CC.Channel = MidiChannel;
482 iliev 2012 event.pEngineChannel = this;
483     if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
484     else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
485     }
486     }
487    
488     /**
489     * Will be called by the MIDIIn Thread to signal the audio thread that a
490     * continuous controller value has changed. This method is meant for
491     * offline rendering and / or for cases where the exact position of the
492     * event in the current audio fragment is already known.
493     *
494     * @param Controller - MIDI controller number of the occured control change
495     * @param Value - value of the control change
496     * @param FragmentPos - sample point position in the current audio
497     * fragment to which this event belongs to
498     */
499 persson 2317 void AbstractEngineChannel::SendControlChange(uint8_t Controller, uint8_t Value, uint8_t MidiChannel, int32_t FragmentPos) {
500 iliev 2012 if (FragmentPos < 0) {
501     dmsg(1,("AbstractEngineChannel::SendControlChange(): negative FragmentPos! Seems MIDI driver is buggy!"));
502     }
503     else if (pEngine) {
504     Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);
505     event.Type = Event::type_control_change;
506     event.Param.CC.Controller = Controller;
507     event.Param.CC.Value = Value;
508 persson 2317 event.Param.CC.Channel = MidiChannel;
509 iliev 2012 event.pEngineChannel = this;
510     if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
511     else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
512     }
513     }
514    
515     /**
516     * Copy all events from the engine channel's input event queue buffer to
517     * the internal event list. This will be done at the beginning of each
518     * audio cycle (that is each RenderAudio() call) to distinguish all
519     * events which have to be processed in the current audio cycle. Each
520     * EngineChannel has it's own input event queue for the common channel
521     * specific events (like NoteOn, NoteOff and ControlChange events).
522     * Beside that, the engine also has a input event queue for global
523     * events (usually SysEx messages).
524     *
525     * @param Samples - number of sample points to be processed in the
526     * current audio cycle
527     */
528     void AbstractEngineChannel::ImportEvents(uint Samples) {
529     // import events from pure software MIDI "devices"
530     // (e.g. virtual keyboard in instrument editor)
531     {
532 persson 2317 const uint8_t channel = MidiChannel() == midi_chan_all ? 0 : MidiChannel();
533 iliev 2012 const int FragmentPos = 0; // randomly chosen, we don't care about jitter for virtual MIDI devices
534     Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);
535     VirtualMidiDevice::event_t devEvent; // the event format we get from the virtual MIDI device
536     // as we're going to (carefully) write some status to the
537     // synchronized struct, we cast away the const
538     ArrayList<VirtualMidiDevice*>& devices =
539     const_cast<ArrayList<VirtualMidiDevice*>&>(virtualMidiDevicesReader_AudioThread.Lock());
540     // iterate through all virtual MIDI devices
541     for (int i = 0; i < devices.size(); i++) {
542     VirtualMidiDevice* pDev = devices[i];
543     // I think we can simply flush the whole FIFO(s), the user shouldn't be so fast ;-)
544     while (pDev->GetMidiEventFromDevice(devEvent)) {
545 schoenebeck 2025 switch (devEvent.Type) {
546     case VirtualMidiDevice::EVENT_TYPE_NOTEON:
547     event.Type = Event::type_note_on;
548     event.Param.Note.Key = devEvent.Arg1;
549     event.Param.Note.Velocity = devEvent.Arg2;
550 persson 2317 event.Param.Note.Channel = channel;
551 schoenebeck 2025 break;
552     case VirtualMidiDevice::EVENT_TYPE_NOTEOFF:
553     event.Type = Event::type_note_off;
554     event.Param.Note.Key = devEvent.Arg1;
555     event.Param.Note.Velocity = devEvent.Arg2;
556 persson 2317 event.Param.Note.Channel = channel;
557 schoenebeck 2025 break;
558     case VirtualMidiDevice::EVENT_TYPE_CC:
559     event.Type = Event::type_control_change;
560     event.Param.CC.Controller = devEvent.Arg1;
561     event.Param.CC.Value = devEvent.Arg2;
562 persson 2317 event.Param.CC.Channel = channel;
563 schoenebeck 2025 break;
564     default:
565     std::cerr << "AbstractEngineChannel::ImportEvents() ERROR: unknown event type ("
566     << devEvent.Type << "). This is a bug!";
567     continue;
568     }
569     event.pEngineChannel = this;
570 iliev 2012 // copy event to internal event list
571     if (pEvents->poolIsEmpty()) {
572     dmsg(1,("Event pool emtpy!\n"));
573     goto exitVirtualDevicesLoop;
574     }
575     *pEvents->allocAppend() = event;
576     }
577     }
578     }
579     exitVirtualDevicesLoop:
580     virtualMidiDevicesReader_AudioThread.Unlock();
581    
582     // import events from the regular MIDI devices
583     RingBuffer<Event,false>::NonVolatileReader eventQueueReader = pEventQueue->get_non_volatile_reader();
584     Event* pEvent;
585     while (true) {
586     // get next event from input event queue
587     if (!(pEvent = eventQueueReader.pop())) break;
588     // if younger event reached, ignore that and all subsequent ones for now
589     if (pEvent->FragmentPos() >= Samples) {
590     eventQueueReader--;
591     dmsg(2,("Younger Event, pos=%d ,Samples=%d!\n",pEvent->FragmentPos(),Samples));
592     pEvent->ResetFragmentPos();
593     break;
594     }
595     // copy event to internal event list
596     if (pEvents->poolIsEmpty()) {
597     dmsg(1,("Event pool emtpy!\n"));
598     break;
599     }
600     *pEvents->allocAppend() = *pEvent;
601     }
602     eventQueueReader.free(); // free all copied events from input queue
603     }
604    
605     FxSend* AbstractEngineChannel::AddFxSend(uint8_t MidiCtrl, String Name) throw (Exception) {
606     if (pEngine) pEngine->DisableAndLock();
607     FxSend* pFxSend = new FxSend(this, MidiCtrl, Name);
608     if (fxSends.empty()) {
609     if (pEngine && pEngine->pAudioOutputDevice) {
610     AudioOutputDevice* pDevice = pEngine->pAudioOutputDevice;
611     // create local render buffers
612     pChannelLeft = new AudioChannel(0, pDevice->MaxSamplesPerCycle());
613     pChannelRight = new AudioChannel(1, pDevice->MaxSamplesPerCycle());
614     } else {
615     // postpone local render buffer creation until audio device is assigned
616     pChannelLeft = NULL;
617     pChannelRight = NULL;
618     }
619     }
620     fxSends.push_back(pFxSend);
621     if (pEngine) pEngine->Enable();
622     fireFxSendCountChanged(GetSamplerChannel()->Index(), GetFxSendCount());
623    
624     return pFxSend;
625     }
626    
627     FxSend* AbstractEngineChannel::GetFxSend(uint FxSendIndex) {
628     return (FxSendIndex < fxSends.size()) ? fxSends[FxSendIndex] : NULL;
629     }
630    
631     uint AbstractEngineChannel::GetFxSendCount() {
632     return fxSends.size();
633     }
634    
635     void AbstractEngineChannel::RemoveFxSend(FxSend* pFxSend) {
636     if (pEngine) pEngine->DisableAndLock();
637     for (
638     std::vector<FxSend*>::iterator iter = fxSends.begin();
639     iter != fxSends.end(); iter++
640     ) {
641     if (*iter == pFxSend) {
642     delete pFxSend;
643     fxSends.erase(iter);
644     if (fxSends.empty()) {
645     // destroy local render buffers
646     if (pChannelLeft) delete pChannelLeft;
647     if (pChannelRight) delete pChannelRight;
648     // fallback to render directly into AudioOutputDevice's buffers
649     if (pEngine && pEngine->pAudioOutputDevice) {
650     pChannelLeft = pEngine->pAudioOutputDevice->Channel(AudioDeviceChannelLeft);
651     pChannelRight = pEngine->pAudioOutputDevice->Channel(AudioDeviceChannelRight);
652     } else { // we update the pointers later
653     pChannelLeft = NULL;
654     pChannelRight = NULL;
655     }
656     }
657     break;
658     }
659     }
660     if (pEngine) pEngine->Enable();
661     fireFxSendCountChanged(GetSamplerChannel()->Index(), GetFxSendCount());
662     }
663    
664     void AbstractEngineChannel::RemoveAllFxSends() {
665     if (pEngine) pEngine->DisableAndLock();
666     if (!fxSends.empty()) { // free local render buffers
667     if (pChannelLeft) {
668     delete pChannelLeft;
669     if (pEngine && pEngine->pAudioOutputDevice) {
670     // fallback to render directly to the AudioOutputDevice's buffer
671     pChannelLeft = pEngine->pAudioOutputDevice->Channel(AudioDeviceChannelLeft);
672     } else pChannelLeft = NULL;
673     }
674     if (pChannelRight) {
675     delete pChannelRight;
676     if (pEngine && pEngine->pAudioOutputDevice) {
677     // fallback to render directly to the AudioOutputDevice's buffer
678     pChannelRight = pEngine->pAudioOutputDevice->Channel(AudioDeviceChannelRight);
679     } else pChannelRight = NULL;
680     }
681     }
682     for (int i = 0; i < fxSends.size(); i++) delete fxSends[i];
683     fxSends.clear();
684     if (pEngine) pEngine->Enable();
685     }
686    
687 persson 2114 /**
688     * Add a group number to the set of key groups. Should be called
689     * when an instrument is loaded to make sure there are event lists
690     * for all key groups.
691     */
692     void AbstractEngineChannel::AddGroup(uint group) {
693     if (group) {
694 persson 2127 std::pair<ActiveKeyGroupMap::iterator, bool> p =
695     ActiveKeyGroups.insert(ActiveKeyGroupMap::value_type(group, 0));
696 persson 2114 if (p.second) {
697 persson 2127 // If the engine channel is pending deletion (see bug
698     // #113), pEngine will be null, so we can't use
699     // pEngine->pEventPool here. Instead we're using a
700     // specialized RTList that allows specifying the pool
701     // later.
702     (*p.first).second = new LazyList<Event>;
703 persson 2114 }
704     }
705     }
706    
707     /**
708     * Handle key group (a.k.a. exclusive group) conflicts.
709     */
710     void AbstractEngineChannel::HandleKeyGroupConflicts(uint KeyGroup, Pool<Event>::Iterator& itNoteOnEvent) {
711     dmsg(4,("HandelKeyGroupConflicts KeyGroup=%d\n", KeyGroup));
712     if (KeyGroup) {
713     // send a release event to all active voices in the group
714 persson 2127 RTList<Event>::Iterator itEvent = ActiveKeyGroups[KeyGroup]->allocAppend(pEngine->pEventPool);
715 persson 2114 *itEvent = *itNoteOnEvent;
716     }
717     }
718    
719     /**
720     * Empty the lists of group events. Should be called from the
721     * audio thread, after all voices have been rendered.
722     */
723     void AbstractEngineChannel::ClearGroupEventLists() {
724 persson 2127 for (ActiveKeyGroupMap::iterator iter = ActiveKeyGroups.begin();
725 persson 2114 iter != ActiveKeyGroups.end(); iter++) {
726     if (iter->second) {
727     iter->second->clear();
728     } else {
729     dmsg(1,("EngineChannel: group event list was NULL"));
730     }
731     }
732     }
733    
734     /**
735     * Remove all lists with group events.
736     */
737     void AbstractEngineChannel::DeleteGroupEventLists() {
738 persson 2127 for (ActiveKeyGroupMap::iterator iter = ActiveKeyGroups.begin();
739 persson 2114 iter != ActiveKeyGroups.end(); iter++) {
740     delete iter->second;
741     }
742     ActiveKeyGroups.clear();
743     }
744    
745 iliev 2012 } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC