/[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 2317 - (hide annotations) (download)
Sun Feb 19 12:13:19 2012 UTC (12 years, 1 month ago) by persson
File size: 32371 byte(s)
* sfz engine bugfix: looping was disabled if loop_start was set to 0
* sfz engine: allow regions with end=-1 to turn off other regions
  using the group and off_by opcodes (#168)
* sfz engine: made end=0 play the whole sample
* sfz engine: fixed support for lochan and hichan opcodes (#155)
* bumped version to 1.0.0.svn17

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

  ViewVC Help
Powered by ViewVC