/[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 2427 - (hide annotations) (download)
Sat Mar 2 07:03:04 2013 UTC (11 years ago) by persson
File size: 32481 byte(s)
* code refactoring: added a lock guard class for exception safe mutex
  handling and used it everywhere appropriate

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

  ViewVC Help
Powered by ViewVC