/[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 2559 - (hide annotations) (download)
Sun May 18 17:38:25 2014 UTC (9 years, 11 months ago) by schoenebeck
File size: 41967 byte(s)
* Aftertouch: extended API to explicitly handle channel pressure and
  polyphonic key pressure events (so far polyphonic pressure was not
  supported at all, and channel pressure was rerouted as CC128 but not
  used so far).
* Gig Engine: Fixed support for 'aftertouch' attenuation controller.
* Bumped version (1.0.0.svn39).

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

  ViewVC Help
Powered by ViewVC