/[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 2612 - (hide annotations) (download)
Tue Jun 10 13:32:16 2014 UTC (9 years, 9 months ago) by schoenebeck
File size: 44603 byte(s)
* Fixed crashes when exiting the sampler.
* Bumped version (1.0.0.svn47).

1 iliev 2012 /***************************************************************************
2     * *
3     * LinuxSampler - modular, streaming capable sampler *
4     * *
5     * Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck *
6 persson 2114 * Copyright (C) 2005-2008 Christian Schoenebeck *
7 schoenebeck 2500 * Copyright (C) 2009-2012 Christian Schoenebeck and Grigor Iliev *
8     * Copyright (C) 2013-2014 Christian Schoenebeck and Andreas Persson *
9 iliev 2012 * *
10     * This program is free software; you can redistribute it and/or modify *
11     * it under the terms of the GNU General Public License as published by *
12     * the Free Software Foundation; either version 2 of the License, or *
13     * (at your option) any later version. *
14     * *
15     * This program is distributed in the hope that it will be useful, *
16     * but WITHOUT ANY WARRANTY; without even the implied warranty of *
17     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
18     * GNU General Public License for more details. *
19     * *
20     * You should have received a copy of the GNU General Public License *
21     * along with this program; if not, write to the Free Software *
22     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
23     * MA 02111-1307 USA *
24     ***************************************************************************/
25    
26     #include "AbstractEngineChannel.h"
27     #include "../common/global_private.h"
28     #include "../Sampler.h"
29    
30     namespace LinuxSampler {
31    
32     AbstractEngineChannel::AbstractEngineChannel() :
33     virtualMidiDevicesReader_AudioThread(virtualMidiDevices),
34     virtualMidiDevicesReader_MidiThread(virtualMidiDevices)
35     {
36     pEngine = NULL;
37     pEvents = NULL; // we allocate when we retrieve the right Engine object
38     pEventQueue = new RingBuffer<Event,false>(CONFIG_MAX_EVENTS_PER_FRAGMENT, 0);
39     InstrumentIdx = -1;
40     InstrumentStat = -1;
41     pChannelLeft = NULL;
42     pChannelRight = NULL;
43     AudioDeviceChannelLeft = -1;
44     AudioDeviceChannelRight = -1;
45     midiChannel = midi_chan_all;
46     ResetControllers();
47     PortamentoMode = false;
48     PortamentoTime = CONFIG_PORTAMENTO_TIME_DEFAULT;
49 schoenebeck 2611 pScript = NULL;
50 iliev 2012 }
51    
52     AbstractEngineChannel::~AbstractEngineChannel() {
53 schoenebeck 2612 if (pScript) pScript->resetAll(); // unloads script (in case one is loaded)
54 persson 2114 delete pEventQueue;
55     DeleteGroupEventLists();
56 iliev 2012 RemoveAllFxSends();
57     }
58    
59     Engine* AbstractEngineChannel::GetEngine() {
60     return pEngine;
61     }
62    
63     uint AbstractEngineChannel::Channels() {
64     return 2;
65     }
66    
67     /**
68     * More or less a workaround to set the instrument name, index and load
69     * status variable to zero percent immediately, that is without blocking
70     * the calling thread. It might be used in future for other preparations
71     * as well though.
72     *
73     * @param FileName - file name of the instrument file
74     * @param Instrument - index of the instrument in the file
75     * @see LoadInstrument()
76     */
77     void AbstractEngineChannel::PrepareLoadInstrument(const char* FileName, uint Instrument) {
78     InstrumentFile = FileName;
79     InstrumentIdx = Instrument;
80     InstrumentStat = 0;
81     }
82    
83     String AbstractEngineChannel::InstrumentFileName() {
84     return InstrumentFile;
85     }
86    
87     String AbstractEngineChannel::InstrumentName() {
88     return InstrumentIdxName;
89     }
90    
91     int AbstractEngineChannel::InstrumentIndex() {
92     return InstrumentIdx;
93     }
94    
95     int AbstractEngineChannel::InstrumentStatus() {
96     return InstrumentStat;
97     }
98    
99     String AbstractEngineChannel::EngineName() {
100     return AbstractEngine::GetFormatString(GetEngineFormat());
101     }
102    
103     void AbstractEngineChannel::Reset() {
104     if (pEngine) pEngine->DisableAndLock();
105     ResetInternal();
106     ResetControllers();
107     if (pEngine) {
108     pEngine->Enable();
109     pEngine->Reset();
110     }
111     }
112    
113     void AbstractEngineChannel::ResetControllers() {
114     Pitch = 0;
115     GlobalVolume = 1.0f;
116     MidiVolume = 1.0;
117     iLastPanRequest = 64;
118     GlobalTranspose = 0;
119     // set all MIDI controller values to zero
120     memset(ControllerTable, 0x00, 129);
121     // reset all FX Send levels
122     for (
123     std::vector<FxSend*>::iterator iter = fxSends.begin();
124     iter != fxSends.end(); iter++
125     ) {
126     (*iter)->Reset();
127     }
128     }
129    
130     /**
131     * This method is not thread safe!
132     */
133     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     iLastPanRequest = iMidiPan;
186     }
187    
188     AudioOutputDevice* AbstractEngineChannel::GetAudioOutputDevice() {
189     return (pEngine) ? pEngine->pAudioOutputDevice : NULL;
190     }
191    
192 persson 2326 /**
193     * Gets thread safe access to the currently connected audio output
194     * device from other threads than the lscp thread.
195     */
196     AudioOutputDevice* AbstractEngineChannel::GetAudioOutputDeviceSafe() {
197 persson 2427 LockGuard lock(EngineMutex);
198     return GetAudioOutputDevice();
199 persson 2326 }
200    
201 iliev 2012 void AbstractEngineChannel::SetOutputChannel(uint EngineAudioChannel, uint AudioDeviceChannel) {
202     if (!pEngine || !pEngine->pAudioOutputDevice) throw AudioOutputException("No audio output device connected yet.");
203    
204     AudioChannel* pChannel = pEngine->pAudioOutputDevice->Channel(AudioDeviceChannel);
205     if (!pChannel) throw AudioOutputException("Invalid audio output device channel " + ToString(AudioDeviceChannel));
206     switch (EngineAudioChannel) {
207     case 0: // left output channel
208     if (fxSends.empty()) pChannelLeft = pChannel;
209     AudioDeviceChannelLeft = AudioDeviceChannel;
210     break;
211     case 1: // right output channel
212     if (fxSends.empty()) pChannelRight = pChannel;
213     AudioDeviceChannelRight = AudioDeviceChannel;
214     break;
215     default:
216     throw AudioOutputException("Invalid engine audio channel " + ToString(EngineAudioChannel));
217     }
218    
219     bStatusChanged = true;
220     }
221    
222     int AbstractEngineChannel::OutputChannel(uint EngineAudioChannel) {
223     switch (EngineAudioChannel) {
224     case 0: // left channel
225     return AudioDeviceChannelLeft;
226     case 1: // right channel
227     return AudioDeviceChannelRight;
228     default:
229     throw AudioOutputException("Invalid engine audio channel " + ToString(EngineAudioChannel));
230     }
231     }
232    
233 schoenebeck 2500 void AbstractEngineChannel::Connect(MidiInputPort* pMidiPort) {
234     if (!pMidiPort) return;
235    
236     Sync< ArrayList<MidiInputPort*> > connections = midiInputs.back();
237    
238     // check if connection already exists
239     for (int i = 0; i < connections->size(); ++i)
240     if ((*connections)[i] == pMidiPort)
241     return; // to avoid endless recursion
242    
243     connections->add(pMidiPort);
244    
245     // inform MIDI port about this new connection
246     pMidiPort->Connect(this, MidiChannel());
247     }
248    
249     void AbstractEngineChannel::Disconnect(MidiInputPort* pMidiPort) {
250     if (!pMidiPort) return;
251    
252     Sync< ArrayList<MidiInputPort*> > connections = midiInputs.back();
253    
254     for (int i = 0; i < connections->size(); ++i) {
255     if ((*connections)[i] == pMidiPort) {
256     connections->remove(i);
257     // inform MIDI port about this disconnection
258     pMidiPort->Disconnect(this);
259     return;
260     }
261     }
262     }
263    
264     void AbstractEngineChannel::DisconnectAllMidiInputPorts() {
265     Sync< ArrayList<MidiInputPort*> > connections = midiInputs.back();
266     ArrayList<MidiInputPort*> clonedList = *connections;
267     connections->clear();
268     for (int i = 0; i < clonedList.size(); ++i) clonedList[i]->Disconnect(this);
269     }
270    
271     uint AbstractEngineChannel::GetMidiInputPortCount() {
272     Sync< ArrayList<MidiInputPort*> > connections = midiInputs.back();
273     return connections->size();
274     }
275    
276     MidiInputPort* AbstractEngineChannel::GetMidiInputPort(uint index) {
277     Sync< ArrayList<MidiInputPort*> > connections = midiInputs.back();
278     return (index < connections->size()) ? (*connections)[index] : NULL;
279     }
280    
281     // deprecated (just for API backward compatibility) - may be removed in future
282 iliev 2012 void AbstractEngineChannel::Connect(MidiInputPort* pMidiPort, midi_chan_t MidiChannel) {
283 schoenebeck 2500 if (!pMidiPort) return;
284    
285     Sync< ArrayList<MidiInputPort*> > connections = midiInputs.back();
286    
287     // check against endless recursion
288     if (connections->size() == 1 && (*connections)[0] == pMidiPort && this->midiChannel == MidiChannel)
289     return;
290    
291     if (!isValidMidiChan(MidiChannel))
292     throw MidiInputException("Invalid MIDI channel (" + ToString(int(MidiChannel)) + ")");
293    
294     this->midiChannel = MidiChannel;
295    
296     // disconnect all currently connected MIDI ports
297     ArrayList<MidiInputPort*> clonedList = *connections;
298     connections->clear();
299     for (int i = 0; i < clonedList.size(); ++i)
300     clonedList[i]->Disconnect(this);
301    
302     // connect the new port
303     connections->add(pMidiPort);
304 iliev 2012 pMidiPort->Connect(this, MidiChannel);
305     }
306    
307 schoenebeck 2500 // deprecated (just for API backward compatibility) - may be removed in future
308 iliev 2012 void AbstractEngineChannel::DisconnectMidiInputPort() {
309 schoenebeck 2500 DisconnectAllMidiInputPorts();
310 iliev 2012 }
311    
312 schoenebeck 2500 // deprecated (just for API backward compatibility) - may be removed in future
313 iliev 2012 MidiInputPort* AbstractEngineChannel::GetMidiInputPort() {
314 schoenebeck 2500 return GetMidiInputPort(0);
315 iliev 2012 }
316    
317     midi_chan_t AbstractEngineChannel::MidiChannel() {
318     return midiChannel;
319     }
320    
321 schoenebeck 2500 void AbstractEngineChannel::SetMidiChannel(midi_chan_t MidiChannel) {
322     if (this->midiChannel == MidiChannel) return;
323     if (!isValidMidiChan(MidiChannel))
324     throw MidiInputException("Invalid MIDI channel (" + ToString(int(MidiChannel)) + ")");
325    
326     this->midiChannel = MidiChannel;
327    
328     Sync< ArrayList<MidiInputPort*> > connections = midiInputs.back();
329     ArrayList<MidiInputPort*> clonedList = *connections;
330    
331     DisconnectAllMidiInputPorts();
332    
333     for (int i = 0; i < clonedList.size(); ++i) Connect(clonedList[i]);
334     }
335    
336 iliev 2012 void AbstractEngineChannel::Connect(VirtualMidiDevice* pDevice) {
337     // double buffer ... double work ...
338     {
339     ArrayList<VirtualMidiDevice*>& devices = virtualMidiDevices.GetConfigForUpdate();
340     devices.add(pDevice);
341     }
342     {
343     ArrayList<VirtualMidiDevice*>& devices = virtualMidiDevices.SwitchConfig();
344     devices.add(pDevice);
345     }
346     }
347    
348     void AbstractEngineChannel::Disconnect(VirtualMidiDevice* pDevice) {
349     // double buffer ... double work ...
350     {
351     ArrayList<VirtualMidiDevice*>& devices = virtualMidiDevices.GetConfigForUpdate();
352     devices.remove(pDevice);
353     }
354     {
355     ArrayList<VirtualMidiDevice*>& devices = virtualMidiDevices.SwitchConfig();
356     devices.remove(pDevice);
357     }
358     }
359    
360     /**
361     * Will be called by the MIDIIn Thread to let the audio thread trigger a new
362     * voice for the given key. This method is meant for real time rendering,
363     * that is an event will immediately be created with the current system
364     * time as time stamp.
365     *
366     * @param Key - MIDI key number of the triggered key
367     * @param Velocity - MIDI velocity value of the triggered key
368     */
369 persson 2317 void AbstractEngineChannel::SendNoteOn(uint8_t Key, uint8_t Velocity, uint8_t MidiChannel) {
370 iliev 2012 if (pEngine) {
371 schoenebeck 2500 // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
372     LockGuard g;
373     if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
374    
375 iliev 2012 Event event = pEngine->pEventGenerator->CreateEvent();
376     event.Type = Event::type_note_on;
377     event.Param.Note.Key = Key;
378     event.Param.Note.Velocity = Velocity;
379 persson 2317 event.Param.Note.Channel = MidiChannel;
380 persson 2606 memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes
381 iliev 2012 event.pEngineChannel = this;
382     if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
383     else dmsg(1,("EngineChannel: Input event queue full!"));
384     // inform connected virtual MIDI devices if any ...
385     // (e.g. virtual MIDI keyboard in instrument editor(s))
386     ArrayList<VirtualMidiDevice*>& devices =
387     const_cast<ArrayList<VirtualMidiDevice*>&>(
388     virtualMidiDevicesReader_MidiThread.Lock()
389     );
390     for (int i = 0; i < devices.size(); i++) {
391     devices[i]->SendNoteOnToDevice(Key, Velocity);
392     }
393     virtualMidiDevicesReader_MidiThread.Unlock();
394     }
395     }
396    
397     /**
398     * Will be called by the MIDIIn Thread to let the audio thread trigger a new
399     * voice for the given key. This method is meant for offline rendering
400     * and / or for cases where the exact position of the event in the current
401     * audio fragment is already known.
402     *
403     * @param Key - MIDI key number of the triggered key
404     * @param Velocity - MIDI velocity value of the triggered key
405     * @param FragmentPos - sample point position in the current audio
406     * fragment to which this event belongs to
407     */
408 persson 2317 void AbstractEngineChannel::SendNoteOn(uint8_t Key, uint8_t Velocity, uint8_t MidiChannel, int32_t FragmentPos) {
409 iliev 2012 if (FragmentPos < 0) {
410     dmsg(1,("EngineChannel::SendNoteOn(): negative FragmentPos! Seems MIDI driver is buggy!"));
411     }
412     else if (pEngine) {
413 schoenebeck 2500 // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
414     LockGuard g;
415     if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
416    
417 iliev 2012 Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);
418     event.Type = Event::type_note_on;
419     event.Param.Note.Key = Key;
420     event.Param.Note.Velocity = Velocity;
421 persson 2317 event.Param.Note.Channel = MidiChannel;
422 persson 2606 memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes
423 iliev 2012 event.pEngineChannel = this;
424     if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
425     else dmsg(1,("EngineChannel: Input event queue full!"));
426     // inform connected virtual MIDI devices if any ...
427     // (e.g. virtual MIDI keyboard in instrument editor(s))
428     ArrayList<VirtualMidiDevice*>& devices =
429     const_cast<ArrayList<VirtualMidiDevice*>&>(
430     virtualMidiDevicesReader_MidiThread.Lock()
431     );
432     for (int i = 0; i < devices.size(); i++) {
433     devices[i]->SendNoteOnToDevice(Key, Velocity);
434     }
435     virtualMidiDevicesReader_MidiThread.Unlock();
436     }
437     }
438    
439     /**
440     * Will be called by the MIDIIn Thread to signal the audio thread to release
441     * voice(s) on the given key. This method is meant for real time rendering,
442     * that is an event will immediately be created with the current system
443     * time as time stamp.
444     *
445     * @param Key - MIDI key number of the released key
446     * @param Velocity - MIDI release velocity value of the released key
447     */
448 persson 2317 void AbstractEngineChannel::SendNoteOff(uint8_t Key, uint8_t Velocity, uint8_t MidiChannel) {
449 iliev 2012 if (pEngine) {
450 schoenebeck 2500 // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
451     LockGuard g;
452     if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
453    
454 iliev 2012 Event event = pEngine->pEventGenerator->CreateEvent();
455     event.Type = Event::type_note_off;
456     event.Param.Note.Key = Key;
457     event.Param.Note.Velocity = Velocity;
458 persson 2317 event.Param.Note.Channel = MidiChannel;
459 persson 2606 memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes
460 iliev 2012 event.pEngineChannel = this;
461     if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
462     else dmsg(1,("EngineChannel: Input event queue full!"));
463     // inform connected virtual MIDI devices if any ...
464     // (e.g. virtual MIDI keyboard in instrument editor(s))
465     ArrayList<VirtualMidiDevice*>& devices =
466     const_cast<ArrayList<VirtualMidiDevice*>&>(
467     virtualMidiDevicesReader_MidiThread.Lock()
468     );
469     for (int i = 0; i < devices.size(); i++) {
470     devices[i]->SendNoteOffToDevice(Key, Velocity);
471     }
472     virtualMidiDevicesReader_MidiThread.Unlock();
473     }
474     }
475    
476     /**
477     * Will be called by the MIDIIn Thread to signal the audio thread to release
478     * voice(s) on the given key. This method is meant for offline rendering
479     * and / or for cases where the exact position of the event in the current
480     * audio fragment is already known.
481     *
482     * @param Key - MIDI key number of the released key
483     * @param Velocity - MIDI release velocity value of the released key
484     * @param FragmentPos - sample point position in the current audio
485     * fragment to which this event belongs to
486     */
487 persson 2317 void AbstractEngineChannel::SendNoteOff(uint8_t Key, uint8_t Velocity, uint8_t MidiChannel, int32_t FragmentPos) {
488 iliev 2012 if (FragmentPos < 0) {
489     dmsg(1,("EngineChannel::SendNoteOff(): negative FragmentPos! Seems MIDI driver is buggy!"));
490     }
491     else if (pEngine) {
492 schoenebeck 2500 // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
493     LockGuard g;
494     if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
495    
496 iliev 2012 Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);
497     event.Type = Event::type_note_off;
498     event.Param.Note.Key = Key;
499     event.Param.Note.Velocity = Velocity;
500 persson 2317 event.Param.Note.Channel = MidiChannel;
501 persson 2606 memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes
502 iliev 2012 event.pEngineChannel = this;
503     if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
504     else dmsg(1,("EngineChannel: Input event queue full!"));
505     // inform connected virtual MIDI devices if any ...
506     // (e.g. virtual MIDI keyboard in instrument editor(s))
507     ArrayList<VirtualMidiDevice*>& devices =
508     const_cast<ArrayList<VirtualMidiDevice*>&>(
509     virtualMidiDevicesReader_MidiThread.Lock()
510     );
511     for (int i = 0; i < devices.size(); i++) {
512     devices[i]->SendNoteOffToDevice(Key, Velocity);
513     }
514     virtualMidiDevicesReader_MidiThread.Unlock();
515     }
516     }
517    
518     /**
519     * Will be called by the MIDIIn Thread to signal the audio thread to change
520     * the pitch value for all voices. This method is meant for real time
521     * rendering, that is an event will immediately be created with the
522     * current system time as time stamp.
523     *
524     * @param Pitch - MIDI pitch value (-8192 ... +8191)
525     */
526 persson 2317 void AbstractEngineChannel::SendPitchbend(int Pitch, uint8_t MidiChannel) {
527 iliev 2012 if (pEngine) {
528 schoenebeck 2500 // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
529     LockGuard g;
530     if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
531    
532 iliev 2012 Event event = pEngine->pEventGenerator->CreateEvent();
533     event.Type = Event::type_pitchbend;
534     event.Param.Pitch.Pitch = Pitch;
535 persson 2317 event.Param.Pitch.Channel = MidiChannel;
536 persson 2606 memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes
537 iliev 2012 event.pEngineChannel = this;
538     if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
539     else dmsg(1,("EngineChannel: Input event queue full!"));
540     }
541     }
542    
543     /**
544     * Will be called by the MIDIIn Thread to signal the audio thread to change
545     * the pitch value for all voices. This method is meant for offline
546     * rendering and / or for cases where the exact position of the event in
547     * the current audio fragment is already known.
548     *
549     * @param Pitch - MIDI pitch value (-8192 ... +8191)
550     * @param FragmentPos - sample point position in the current audio
551     * fragment to which this event belongs to
552     */
553 persson 2317 void AbstractEngineChannel::SendPitchbend(int Pitch, uint8_t MidiChannel, int32_t FragmentPos) {
554 iliev 2012 if (FragmentPos < 0) {
555     dmsg(1,("AbstractEngineChannel::SendPitchBend(): negative FragmentPos! Seems MIDI driver is buggy!"));
556     }
557     else if (pEngine) {
558 schoenebeck 2500 // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
559     LockGuard g;
560     if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
561    
562 iliev 2012 Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);
563     event.Type = Event::type_pitchbend;
564     event.Param.Pitch.Pitch = Pitch;
565 persson 2317 event.Param.Pitch.Channel = MidiChannel;
566 persson 2606 memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes
567 iliev 2012 event.pEngineChannel = this;
568     if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
569     else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
570     }
571     }
572    
573     /**
574     * Will be called by the MIDIIn Thread to signal the audio thread that a
575     * continuous controller value has changed. This method is meant for real
576     * time rendering, that is an event will immediately be created with the
577     * current system time as time stamp.
578     *
579     * @param Controller - MIDI controller number of the occured control change
580     * @param Value - value of the control change
581     */
582 persson 2317 void AbstractEngineChannel::SendControlChange(uint8_t Controller, uint8_t Value, uint8_t MidiChannel) {
583 iliev 2012 if (pEngine) {
584 schoenebeck 2500 // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
585     LockGuard g;
586     if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
587    
588 iliev 2012 Event event = pEngine->pEventGenerator->CreateEvent();
589     event.Type = Event::type_control_change;
590     event.Param.CC.Controller = Controller;
591     event.Param.CC.Value = Value;
592 persson 2317 event.Param.CC.Channel = MidiChannel;
593 persson 2606 memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes
594 iliev 2012 event.pEngineChannel = this;
595     if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
596     else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
597     }
598     }
599    
600     /**
601     * Will be called by the MIDIIn Thread to signal the audio thread that a
602     * continuous controller value has changed. This method is meant for
603     * offline rendering and / or for cases where the exact position of the
604     * event in the current audio fragment is already known.
605     *
606     * @param Controller - MIDI controller number of the occured control change
607     * @param Value - value of the control change
608     * @param FragmentPos - sample point position in the current audio
609     * fragment to which this event belongs to
610     */
611 persson 2317 void AbstractEngineChannel::SendControlChange(uint8_t Controller, uint8_t Value, uint8_t MidiChannel, int32_t FragmentPos) {
612 iliev 2012 if (FragmentPos < 0) {
613     dmsg(1,("AbstractEngineChannel::SendControlChange(): negative FragmentPos! Seems MIDI driver is buggy!"));
614     }
615     else if (pEngine) {
616 schoenebeck 2500 // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
617     LockGuard g;
618     if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
619    
620 iliev 2012 Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);
621     event.Type = Event::type_control_change;
622     event.Param.CC.Controller = Controller;
623     event.Param.CC.Value = Value;
624 persson 2317 event.Param.CC.Channel = MidiChannel;
625 persson 2606 memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes
626 iliev 2012 event.pEngineChannel = this;
627     if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
628     else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
629     }
630     }
631    
632 schoenebeck 2559 void AbstractEngineChannel::SendChannelPressure(uint8_t Value, uint8_t MidiChannel) {
633     if (pEngine) {
634     // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
635     LockGuard g;
636     if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
637    
638     Event event = pEngine->pEventGenerator->CreateEvent();
639     event.Type = Event::type_channel_pressure;
640 schoenebeck 2611 event.Param.ChannelPressure.Controller = CTRL_TABLE_IDX_AFTERTOUCH; // required for instrument scripts
641 schoenebeck 2559 event.Param.ChannelPressure.Value = Value;
642     event.Param.ChannelPressure.Channel = MidiChannel;
643 persson 2606 memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes
644 schoenebeck 2559 event.pEngineChannel = this;
645     if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
646     else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
647     }
648     }
649    
650     void AbstractEngineChannel::SendChannelPressure(uint8_t Value, uint8_t MidiChannel, int32_t FragmentPos) {
651     if (pEngine) {
652     // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
653     LockGuard g;
654     if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
655    
656     Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);
657     event.Type = Event::type_channel_pressure;
658 schoenebeck 2611 event.Param.ChannelPressure.Controller = CTRL_TABLE_IDX_AFTERTOUCH; // required for instrument scripts
659 schoenebeck 2559 event.Param.ChannelPressure.Value = Value;
660     event.Param.ChannelPressure.Channel = MidiChannel;
661 persson 2606 memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes
662 schoenebeck 2559 event.pEngineChannel = this;
663     if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
664     else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
665     }
666     }
667    
668     void AbstractEngineChannel::SendPolyphonicKeyPressure(uint8_t Key, uint8_t Value, uint8_t MidiChannel) {
669     if (pEngine) {
670     // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
671     LockGuard g;
672     if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
673    
674     Event event = pEngine->pEventGenerator->CreateEvent();
675     event.Type = Event::type_note_pressure;
676     event.Param.NotePressure.Key = Key;
677     event.Param.NotePressure.Value = Value;
678     event.Param.NotePressure.Channel = MidiChannel;
679 persson 2606 memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes
680 schoenebeck 2559 event.pEngineChannel = this;
681     if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
682     else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
683     }
684     }
685    
686     void AbstractEngineChannel::SendPolyphonicKeyPressure(uint8_t Key, uint8_t Value, uint8_t MidiChannel, int32_t FragmentPos) {
687     if (pEngine) {
688     // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
689     LockGuard g;
690     if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
691    
692     Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);
693     event.Type = Event::type_note_pressure;
694     event.Param.NotePressure.Key = Key;
695     event.Param.NotePressure.Value = Value;
696     event.Param.NotePressure.Channel = MidiChannel;
697 persson 2606 memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes
698 schoenebeck 2559 event.pEngineChannel = this;
699     if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
700     else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
701     }
702     }
703    
704 iliev 2012 /**
705     * Copy all events from the engine channel's input event queue buffer to
706     * the internal event list. This will be done at the beginning of each
707     * audio cycle (that is each RenderAudio() call) to distinguish all
708     * events which have to be processed in the current audio cycle. Each
709     * EngineChannel has it's own input event queue for the common channel
710     * specific events (like NoteOn, NoteOff and ControlChange events).
711     * Beside that, the engine also has a input event queue for global
712     * events (usually SysEx messages).
713     *
714     * @param Samples - number of sample points to be processed in the
715     * current audio cycle
716     */
717     void AbstractEngineChannel::ImportEvents(uint Samples) {
718     // import events from pure software MIDI "devices"
719     // (e.g. virtual keyboard in instrument editor)
720     {
721 persson 2317 const uint8_t channel = MidiChannel() == midi_chan_all ? 0 : MidiChannel();
722 iliev 2012 const int FragmentPos = 0; // randomly chosen, we don't care about jitter for virtual MIDI devices
723     Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);
724     VirtualMidiDevice::event_t devEvent; // the event format we get from the virtual MIDI device
725     // as we're going to (carefully) write some status to the
726     // synchronized struct, we cast away the const
727     ArrayList<VirtualMidiDevice*>& devices =
728     const_cast<ArrayList<VirtualMidiDevice*>&>(virtualMidiDevicesReader_AudioThread.Lock());
729     // iterate through all virtual MIDI devices
730     for (int i = 0; i < devices.size(); i++) {
731     VirtualMidiDevice* pDev = devices[i];
732     // I think we can simply flush the whole FIFO(s), the user shouldn't be so fast ;-)
733     while (pDev->GetMidiEventFromDevice(devEvent)) {
734 schoenebeck 2025 switch (devEvent.Type) {
735     case VirtualMidiDevice::EVENT_TYPE_NOTEON:
736     event.Type = Event::type_note_on;
737     event.Param.Note.Key = devEvent.Arg1;
738     event.Param.Note.Velocity = devEvent.Arg2;
739 persson 2317 event.Param.Note.Channel = channel;
740 schoenebeck 2025 break;
741     case VirtualMidiDevice::EVENT_TYPE_NOTEOFF:
742     event.Type = Event::type_note_off;
743     event.Param.Note.Key = devEvent.Arg1;
744     event.Param.Note.Velocity = devEvent.Arg2;
745 persson 2317 event.Param.Note.Channel = channel;
746 schoenebeck 2025 break;
747     case VirtualMidiDevice::EVENT_TYPE_CC:
748 schoenebeck 2521 switch (devEvent.Arg1) {
749     case 0: // bank select MSB ...
750     SetMidiBankMsb(devEvent.Arg2);
751     continue; // don't push this event into FIFO
752     case 32: // bank select LSB ...
753     SetMidiBankLsb(devEvent.Arg2);
754     continue; // don't push this event into FIFO
755     default: // regular MIDI CC ...
756     event.Type = Event::type_control_change;
757     event.Param.CC.Controller = devEvent.Arg1;
758     event.Param.CC.Value = devEvent.Arg2;
759     event.Param.CC.Channel = channel;
760     }
761 schoenebeck 2025 break;
762 schoenebeck 2521 case VirtualMidiDevice::EVENT_TYPE_PITCHBEND:
763     event.Type = Event::type_pitchbend;
764     event.Param.Pitch.Pitch = int(devEvent.Arg2 << 7 | devEvent.Arg1) - 8192;
765     event.Param.Pitch.Channel = channel;
766     break;
767     case VirtualMidiDevice::EVENT_TYPE_PROGRAM:
768     SendProgramChange(devEvent.Arg1);
769     continue; // don't push this event into FIFO
770 schoenebeck 2025 default:
771     std::cerr << "AbstractEngineChannel::ImportEvents() ERROR: unknown event type ("
772     << devEvent.Type << "). This is a bug!";
773     continue;
774     }
775     event.pEngineChannel = this;
776 iliev 2012 // copy event to internal event list
777     if (pEvents->poolIsEmpty()) {
778     dmsg(1,("Event pool emtpy!\n"));
779     goto exitVirtualDevicesLoop;
780     }
781     *pEvents->allocAppend() = event;
782     }
783     }
784     }
785     exitVirtualDevicesLoop:
786     virtualMidiDevicesReader_AudioThread.Unlock();
787    
788     // import events from the regular MIDI devices
789     RingBuffer<Event,false>::NonVolatileReader eventQueueReader = pEventQueue->get_non_volatile_reader();
790     Event* pEvent;
791     while (true) {
792     // get next event from input event queue
793     if (!(pEvent = eventQueueReader.pop())) break;
794     // if younger event reached, ignore that and all subsequent ones for now
795     if (pEvent->FragmentPos() >= Samples) {
796     eventQueueReader--;
797     dmsg(2,("Younger Event, pos=%d ,Samples=%d!\n",pEvent->FragmentPos(),Samples));
798     pEvent->ResetFragmentPos();
799     break;
800     }
801     // copy event to internal event list
802     if (pEvents->poolIsEmpty()) {
803     dmsg(1,("Event pool emtpy!\n"));
804     break;
805     }
806     *pEvents->allocAppend() = *pEvent;
807     }
808     eventQueueReader.free(); // free all copied events from input queue
809     }
810 schoenebeck 2598
811 schoenebeck 2596 /**
812     * Called by real-time instrument script functions to schedule a new event
813     * somewhere in future.
814 schoenebeck 2598 *
815     * @returns unique event ID of scheduled new event
816 schoenebeck 2596 */
817 schoenebeck 2598 int AbstractEngineChannel::ScheduleEvent(const Event* pEvent, int delay) { //TODO: delay not implemented yet
818 schoenebeck 2596 // since delay is not implemented yet, we simply add the new event
819     // to the event list of the current audio fragmet cycle for now
820     RTList<Event>::Iterator itEvent = pEvents->allocAppend();
821     if (itEvent) *itEvent = *pEvent; // copy event
822 schoenebeck 2598 return pEvents->getID(itEvent);
823 schoenebeck 2596 }
824 iliev 2012
825 schoenebeck 2598 /**
826     * Called by real-time instrument script functions to ignore the event
827     * reflected by given event ID. The event will be freed immediately to its
828     * pool and cannot be dereferenced by its old ID anymore. Even if its
829     * allocated back from the Pool later on, it will have a different ID.
830     */
831     void AbstractEngineChannel::IgnoreEvent(int id) {
832     RTList<Event>::Iterator it = pEvents->fromID(id);
833     if (it) pEvents->free(it);
834     }
835    
836 iliev 2012 FxSend* AbstractEngineChannel::AddFxSend(uint8_t MidiCtrl, String Name) throw (Exception) {
837     if (pEngine) pEngine->DisableAndLock();
838     FxSend* pFxSend = new FxSend(this, MidiCtrl, Name);
839     if (fxSends.empty()) {
840     if (pEngine && pEngine->pAudioOutputDevice) {
841     AudioOutputDevice* pDevice = pEngine->pAudioOutputDevice;
842     // create local render buffers
843     pChannelLeft = new AudioChannel(0, pDevice->MaxSamplesPerCycle());
844     pChannelRight = new AudioChannel(1, pDevice->MaxSamplesPerCycle());
845     } else {
846     // postpone local render buffer creation until audio device is assigned
847     pChannelLeft = NULL;
848     pChannelRight = NULL;
849     }
850     }
851     fxSends.push_back(pFxSend);
852     if (pEngine) pEngine->Enable();
853     fireFxSendCountChanged(GetSamplerChannel()->Index(), GetFxSendCount());
854    
855     return pFxSend;
856     }
857    
858     FxSend* AbstractEngineChannel::GetFxSend(uint FxSendIndex) {
859     return (FxSendIndex < fxSends.size()) ? fxSends[FxSendIndex] : NULL;
860     }
861    
862     uint AbstractEngineChannel::GetFxSendCount() {
863     return fxSends.size();
864     }
865    
866     void AbstractEngineChannel::RemoveFxSend(FxSend* pFxSend) {
867     if (pEngine) pEngine->DisableAndLock();
868     for (
869     std::vector<FxSend*>::iterator iter = fxSends.begin();
870     iter != fxSends.end(); iter++
871     ) {
872     if (*iter == pFxSend) {
873     delete pFxSend;
874     fxSends.erase(iter);
875     if (fxSends.empty()) {
876     // destroy local render buffers
877     if (pChannelLeft) delete pChannelLeft;
878     if (pChannelRight) delete pChannelRight;
879     // fallback to render directly into AudioOutputDevice's buffers
880     if (pEngine && pEngine->pAudioOutputDevice) {
881     pChannelLeft = pEngine->pAudioOutputDevice->Channel(AudioDeviceChannelLeft);
882     pChannelRight = pEngine->pAudioOutputDevice->Channel(AudioDeviceChannelRight);
883     } else { // we update the pointers later
884     pChannelLeft = NULL;
885     pChannelRight = NULL;
886     }
887     }
888     break;
889     }
890     }
891     if (pEngine) pEngine->Enable();
892     fireFxSendCountChanged(GetSamplerChannel()->Index(), GetFxSendCount());
893     }
894    
895     void AbstractEngineChannel::RemoveAllFxSends() {
896     if (pEngine) pEngine->DisableAndLock();
897     if (!fxSends.empty()) { // free local render buffers
898     if (pChannelLeft) {
899     delete pChannelLeft;
900     if (pEngine && pEngine->pAudioOutputDevice) {
901     // fallback to render directly to the AudioOutputDevice's buffer
902     pChannelLeft = pEngine->pAudioOutputDevice->Channel(AudioDeviceChannelLeft);
903     } else pChannelLeft = NULL;
904     }
905     if (pChannelRight) {
906     delete pChannelRight;
907     if (pEngine && pEngine->pAudioOutputDevice) {
908     // fallback to render directly to the AudioOutputDevice's buffer
909     pChannelRight = pEngine->pAudioOutputDevice->Channel(AudioDeviceChannelRight);
910     } else pChannelRight = NULL;
911     }
912     }
913     for (int i = 0; i < fxSends.size(); i++) delete fxSends[i];
914     fxSends.clear();
915     if (pEngine) pEngine->Enable();
916     }
917    
918 persson 2114 /**
919     * Add a group number to the set of key groups. Should be called
920     * when an instrument is loaded to make sure there are event lists
921     * for all key groups.
922     */
923     void AbstractEngineChannel::AddGroup(uint group) {
924     if (group) {
925 persson 2127 std::pair<ActiveKeyGroupMap::iterator, bool> p =
926     ActiveKeyGroups.insert(ActiveKeyGroupMap::value_type(group, 0));
927 persson 2114 if (p.second) {
928 persson 2127 // If the engine channel is pending deletion (see bug
929     // #113), pEngine will be null, so we can't use
930     // pEngine->pEventPool here. Instead we're using a
931     // specialized RTList that allows specifying the pool
932     // later.
933     (*p.first).second = new LazyList<Event>;
934 persson 2114 }
935     }
936     }
937    
938     /**
939     * Handle key group (a.k.a. exclusive group) conflicts.
940     */
941     void AbstractEngineChannel::HandleKeyGroupConflicts(uint KeyGroup, Pool<Event>::Iterator& itNoteOnEvent) {
942     dmsg(4,("HandelKeyGroupConflicts KeyGroup=%d\n", KeyGroup));
943     if (KeyGroup) {
944     // send a release event to all active voices in the group
945 persson 2127 RTList<Event>::Iterator itEvent = ActiveKeyGroups[KeyGroup]->allocAppend(pEngine->pEventPool);
946 persson 2114 *itEvent = *itNoteOnEvent;
947     }
948     }
949    
950     /**
951     * Empty the lists of group events. Should be called from the
952     * audio thread, after all voices have been rendered.
953     */
954     void AbstractEngineChannel::ClearGroupEventLists() {
955 persson 2127 for (ActiveKeyGroupMap::iterator iter = ActiveKeyGroups.begin();
956 persson 2114 iter != ActiveKeyGroups.end(); iter++) {
957     if (iter->second) {
958     iter->second->clear();
959     } else {
960     dmsg(1,("EngineChannel: group event list was NULL"));
961     }
962     }
963     }
964    
965     /**
966     * Remove all lists with group events.
967     */
968     void AbstractEngineChannel::DeleteGroupEventLists() {
969 persson 2127 for (ActiveKeyGroupMap::iterator iter = ActiveKeyGroups.begin();
970 persson 2114 iter != ActiveKeyGroups.end(); iter++) {
971     delete iter->second;
972     }
973     ActiveKeyGroups.clear();
974     }
975    
976 iliev 2012 } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC