/[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 2618 - (hide annotations) (download)
Wed Jun 11 11:39:44 2014 UTC (9 years, 9 months ago) by schoenebeck
File size: 44519 byte(s)
* Fixed execution of "init" instrument script handler.
* Fixed further crashes.
* Bumped version (1.0.0.svn50).

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

  ViewVC Help
Powered by ViewVC