/[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 2521 - (hide annotations) (download)
Wed Feb 19 19:02:43 2014 UTC (10 years, 2 months ago) by schoenebeck
File size: 38463 byte(s)
* VirtualMidiDevice: implemented support for program change, bank select
  and pitch bend.
* Bumped version (1.0.0.svn32).

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     /**
623     * Copy all events from the engine channel's input event queue buffer to
624     * the internal event list. This will be done at the beginning of each
625     * audio cycle (that is each RenderAudio() call) to distinguish all
626     * events which have to be processed in the current audio cycle. Each
627     * EngineChannel has it's own input event queue for the common channel
628     * specific events (like NoteOn, NoteOff and ControlChange events).
629     * Beside that, the engine also has a input event queue for global
630     * events (usually SysEx messages).
631     *
632     * @param Samples - number of sample points to be processed in the
633     * current audio cycle
634     */
635     void AbstractEngineChannel::ImportEvents(uint Samples) {
636     // import events from pure software MIDI "devices"
637     // (e.g. virtual keyboard in instrument editor)
638     {
639 persson 2317 const uint8_t channel = MidiChannel() == midi_chan_all ? 0 : MidiChannel();
640 iliev 2012 const int FragmentPos = 0; // randomly chosen, we don't care about jitter for virtual MIDI devices
641     Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);
642     VirtualMidiDevice::event_t devEvent; // the event format we get from the virtual MIDI device
643     // as we're going to (carefully) write some status to the
644     // synchronized struct, we cast away the const
645     ArrayList<VirtualMidiDevice*>& devices =
646     const_cast<ArrayList<VirtualMidiDevice*>&>(virtualMidiDevicesReader_AudioThread.Lock());
647     // iterate through all virtual MIDI devices
648     for (int i = 0; i < devices.size(); i++) {
649     VirtualMidiDevice* pDev = devices[i];
650     // I think we can simply flush the whole FIFO(s), the user shouldn't be so fast ;-)
651     while (pDev->GetMidiEventFromDevice(devEvent)) {
652 schoenebeck 2025 switch (devEvent.Type) {
653     case VirtualMidiDevice::EVENT_TYPE_NOTEON:
654     event.Type = Event::type_note_on;
655     event.Param.Note.Key = devEvent.Arg1;
656     event.Param.Note.Velocity = devEvent.Arg2;
657 persson 2317 event.Param.Note.Channel = channel;
658 schoenebeck 2025 break;
659     case VirtualMidiDevice::EVENT_TYPE_NOTEOFF:
660     event.Type = Event::type_note_off;
661     event.Param.Note.Key = devEvent.Arg1;
662     event.Param.Note.Velocity = devEvent.Arg2;
663 persson 2317 event.Param.Note.Channel = channel;
664 schoenebeck 2025 break;
665     case VirtualMidiDevice::EVENT_TYPE_CC:
666 schoenebeck 2521 switch (devEvent.Arg1) {
667     case 0: // bank select MSB ...
668     SetMidiBankMsb(devEvent.Arg2);
669     continue; // don't push this event into FIFO
670     case 32: // bank select LSB ...
671     SetMidiBankLsb(devEvent.Arg2);
672     continue; // don't push this event into FIFO
673     default: // regular MIDI CC ...
674     event.Type = Event::type_control_change;
675     event.Param.CC.Controller = devEvent.Arg1;
676     event.Param.CC.Value = devEvent.Arg2;
677     event.Param.CC.Channel = channel;
678     }
679 schoenebeck 2025 break;
680 schoenebeck 2521 case VirtualMidiDevice::EVENT_TYPE_PITCHBEND:
681     event.Type = Event::type_pitchbend;
682     event.Param.Pitch.Pitch = int(devEvent.Arg2 << 7 | devEvent.Arg1) - 8192;
683     event.Param.Pitch.Channel = channel;
684     break;
685     case VirtualMidiDevice::EVENT_TYPE_PROGRAM:
686     SendProgramChange(devEvent.Arg1);
687     continue; // don't push this event into FIFO
688 schoenebeck 2025 default:
689     std::cerr << "AbstractEngineChannel::ImportEvents() ERROR: unknown event type ("
690     << devEvent.Type << "). This is a bug!";
691     continue;
692     }
693     event.pEngineChannel = this;
694 iliev 2012 // copy event to internal event list
695     if (pEvents->poolIsEmpty()) {
696     dmsg(1,("Event pool emtpy!\n"));
697     goto exitVirtualDevicesLoop;
698     }
699     *pEvents->allocAppend() = event;
700     }
701     }
702     }
703     exitVirtualDevicesLoop:
704     virtualMidiDevicesReader_AudioThread.Unlock();
705    
706     // import events from the regular MIDI devices
707     RingBuffer<Event,false>::NonVolatileReader eventQueueReader = pEventQueue->get_non_volatile_reader();
708     Event* pEvent;
709     while (true) {
710     // get next event from input event queue
711     if (!(pEvent = eventQueueReader.pop())) break;
712     // if younger event reached, ignore that and all subsequent ones for now
713     if (pEvent->FragmentPos() >= Samples) {
714     eventQueueReader--;
715     dmsg(2,("Younger Event, pos=%d ,Samples=%d!\n",pEvent->FragmentPos(),Samples));
716     pEvent->ResetFragmentPos();
717     break;
718     }
719     // copy event to internal event list
720     if (pEvents->poolIsEmpty()) {
721     dmsg(1,("Event pool emtpy!\n"));
722     break;
723     }
724     *pEvents->allocAppend() = *pEvent;
725     }
726     eventQueueReader.free(); // free all copied events from input queue
727     }
728    
729     FxSend* AbstractEngineChannel::AddFxSend(uint8_t MidiCtrl, String Name) throw (Exception) {
730     if (pEngine) pEngine->DisableAndLock();
731     FxSend* pFxSend = new FxSend(this, MidiCtrl, Name);
732     if (fxSends.empty()) {
733     if (pEngine && pEngine->pAudioOutputDevice) {
734     AudioOutputDevice* pDevice = pEngine->pAudioOutputDevice;
735     // create local render buffers
736     pChannelLeft = new AudioChannel(0, pDevice->MaxSamplesPerCycle());
737     pChannelRight = new AudioChannel(1, pDevice->MaxSamplesPerCycle());
738     } else {
739     // postpone local render buffer creation until audio device is assigned
740     pChannelLeft = NULL;
741     pChannelRight = NULL;
742     }
743     }
744     fxSends.push_back(pFxSend);
745     if (pEngine) pEngine->Enable();
746     fireFxSendCountChanged(GetSamplerChannel()->Index(), GetFxSendCount());
747    
748     return pFxSend;
749     }
750    
751     FxSend* AbstractEngineChannel::GetFxSend(uint FxSendIndex) {
752     return (FxSendIndex < fxSends.size()) ? fxSends[FxSendIndex] : NULL;
753     }
754    
755     uint AbstractEngineChannel::GetFxSendCount() {
756     return fxSends.size();
757     }
758    
759     void AbstractEngineChannel::RemoveFxSend(FxSend* pFxSend) {
760     if (pEngine) pEngine->DisableAndLock();
761     for (
762     std::vector<FxSend*>::iterator iter = fxSends.begin();
763     iter != fxSends.end(); iter++
764     ) {
765     if (*iter == pFxSend) {
766     delete pFxSend;
767     fxSends.erase(iter);
768     if (fxSends.empty()) {
769     // destroy local render buffers
770     if (pChannelLeft) delete pChannelLeft;
771     if (pChannelRight) delete pChannelRight;
772     // fallback to render directly into AudioOutputDevice's buffers
773     if (pEngine && pEngine->pAudioOutputDevice) {
774     pChannelLeft = pEngine->pAudioOutputDevice->Channel(AudioDeviceChannelLeft);
775     pChannelRight = pEngine->pAudioOutputDevice->Channel(AudioDeviceChannelRight);
776     } else { // we update the pointers later
777     pChannelLeft = NULL;
778     pChannelRight = NULL;
779     }
780     }
781     break;
782     }
783     }
784     if (pEngine) pEngine->Enable();
785     fireFxSendCountChanged(GetSamplerChannel()->Index(), GetFxSendCount());
786     }
787    
788     void AbstractEngineChannel::RemoveAllFxSends() {
789     if (pEngine) pEngine->DisableAndLock();
790     if (!fxSends.empty()) { // free local render buffers
791     if (pChannelLeft) {
792     delete pChannelLeft;
793     if (pEngine && pEngine->pAudioOutputDevice) {
794     // fallback to render directly to the AudioOutputDevice's buffer
795     pChannelLeft = pEngine->pAudioOutputDevice->Channel(AudioDeviceChannelLeft);
796     } else pChannelLeft = NULL;
797     }
798     if (pChannelRight) {
799     delete pChannelRight;
800     if (pEngine && pEngine->pAudioOutputDevice) {
801     // fallback to render directly to the AudioOutputDevice's buffer
802     pChannelRight = pEngine->pAudioOutputDevice->Channel(AudioDeviceChannelRight);
803     } else pChannelRight = NULL;
804     }
805     }
806     for (int i = 0; i < fxSends.size(); i++) delete fxSends[i];
807     fxSends.clear();
808     if (pEngine) pEngine->Enable();
809     }
810    
811 persson 2114 /**
812     * Add a group number to the set of key groups. Should be called
813     * when an instrument is loaded to make sure there are event lists
814     * for all key groups.
815     */
816     void AbstractEngineChannel::AddGroup(uint group) {
817     if (group) {
818 persson 2127 std::pair<ActiveKeyGroupMap::iterator, bool> p =
819     ActiveKeyGroups.insert(ActiveKeyGroupMap::value_type(group, 0));
820 persson 2114 if (p.second) {
821 persson 2127 // If the engine channel is pending deletion (see bug
822     // #113), pEngine will be null, so we can't use
823     // pEngine->pEventPool here. Instead we're using a
824     // specialized RTList that allows specifying the pool
825     // later.
826     (*p.first).second = new LazyList<Event>;
827 persson 2114 }
828     }
829     }
830    
831     /**
832     * Handle key group (a.k.a. exclusive group) conflicts.
833     */
834     void AbstractEngineChannel::HandleKeyGroupConflicts(uint KeyGroup, Pool<Event>::Iterator& itNoteOnEvent) {
835     dmsg(4,("HandelKeyGroupConflicts KeyGroup=%d\n", KeyGroup));
836     if (KeyGroup) {
837     // send a release event to all active voices in the group
838 persson 2127 RTList<Event>::Iterator itEvent = ActiveKeyGroups[KeyGroup]->allocAppend(pEngine->pEventPool);
839 persson 2114 *itEvent = *itNoteOnEvent;
840     }
841     }
842    
843     /**
844     * Empty the lists of group events. Should be called from the
845     * audio thread, after all voices have been rendered.
846     */
847     void AbstractEngineChannel::ClearGroupEventLists() {
848 persson 2127 for (ActiveKeyGroupMap::iterator iter = ActiveKeyGroups.begin();
849 persson 2114 iter != ActiveKeyGroups.end(); iter++) {
850     if (iter->second) {
851     iter->second->clear();
852     } else {
853     dmsg(1,("EngineChannel: group event list was NULL"));
854     }
855     }
856     }
857    
858     /**
859     * Remove all lists with group events.
860     */
861     void AbstractEngineChannel::DeleteGroupEventLists() {
862 persson 2127 for (ActiveKeyGroupMap::iterator iter = ActiveKeyGroups.begin();
863 persson 2114 iter != ActiveKeyGroups.end(); iter++) {
864     delete iter->second;
865     }
866     ActiveKeyGroups.clear();
867     }
868    
869 iliev 2012 } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC