/[svn]/linuxsampler/trunk/src/engines/gig/EngineChannel.cpp
ViewVC logotype

Annotation of /linuxsampler/trunk/src/engines/gig/EngineChannel.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1108 - (hide annotations) (download)
Thu Mar 22 20:39:04 2007 UTC (17 years, 1 month ago) by iliev
File size: 31876 byte(s)
* Added new notification events for tracking
effect send changes and global volume changes

1 schoenebeck 411 /***************************************************************************
2     * *
3     * LinuxSampler - modular, streaming capable sampler *
4     * *
5     * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6 schoenebeck 1040 * Copyright (C) 2005 - 2007 Christian Schoenebeck *
7 schoenebeck 411 * *
8     * This program is free software; you can redistribute it and/or modify *
9     * it under the terms of the GNU General Public License as published by *
10     * the Free Software Foundation; either version 2 of the License, or *
11     * (at your option) any later version. *
12     * *
13     * This program is distributed in the hope that it will be useful, *
14     * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16     * GNU General Public License for more details. *
17     * *
18     * You should have received a copy of the GNU General Public License *
19     * along with this program; if not, write to the Free Software *
20     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
21     * MA 02111-1307 USA *
22     ***************************************************************************/
23    
24     #include "EngineChannel.h"
25 iliev 1108 #include "../../network/lscpserver.h"
26 schoenebeck 411
27 persson 438 namespace LinuxSampler { namespace gig {
28 schoenebeck 411
29     EngineChannel::EngineChannel() {
30     pMIDIKeyInfo = new midi_key_info_t[128];
31     pEngine = NULL;
32     pInstrument = NULL;
33 schoenebeck 460 pEvents = NULL; // we allocate when we retrieve the right Engine object
34 schoenebeck 970 pEventQueue = new RingBuffer<Event,false>(CONFIG_MAX_EVENTS_PER_FRAGMENT, 0);
35 schoenebeck 411 pActiveKeys = new Pool<uint>(128);
36     for (uint i = 0; i < 128; i++) {
37     pMIDIKeyInfo[i].pActiveVoices = NULL; // we allocate when we retrieve the right Engine object
38     pMIDIKeyInfo[i].KeyPressed = false;
39     pMIDIKeyInfo[i].Active = false;
40     pMIDIKeyInfo[i].ReleaseTrigger = false;
41     pMIDIKeyInfo[i].pEvents = NULL; // we allocate when we retrieve the right Engine object
42 schoenebeck 473 pMIDIKeyInfo[i].VoiceTheftsQueued = 0;
43 persson 438 pMIDIKeyInfo[i].RoundRobinIndex = 0;
44 schoenebeck 411 }
45     InstrumentIdx = -1;
46     InstrumentStat = -1;
47 schoenebeck 1001 pChannelLeft = NULL;
48     pChannelRight = NULL;
49 schoenebeck 411 AudioDeviceChannelLeft = -1;
50     AudioDeviceChannelRight = -1;
51 schoenebeck 675 pMidiInputPort = NULL;
52     midiChannel = midi_chan_all;
53 schoenebeck 670 ResetControllers();
54 schoenebeck 829 SoloMode = false;
55     PortamentoMode = false;
56     PortamentoTime = CONFIG_PORTAMENTO_TIME_DEFAULT;
57 schoenebeck 411 }
58    
59     EngineChannel::~EngineChannel() {
60 schoenebeck 460 DisconnectAudioOutputDevice();
61 schoenebeck 411 if (pInstrument) Engine::instruments.HandBack(pInstrument, this);
62     if (pEventQueue) delete pEventQueue;
63     if (pActiveKeys) delete pActiveKeys;
64     if (pMIDIKeyInfo) delete[] pMIDIKeyInfo;
65 schoenebeck 1001 RemoveAllFxSends();
66 schoenebeck 411 }
67    
68     /**
69 schoenebeck 660 * Implementation of virtual method from abstract EngineChannel interface.
70     * This method will periodically be polled (e.g. by the LSCP server) to
71     * check if some engine channel parameter has changed since the last
72     * StatusChanged() call.
73     *
74 schoenebeck 670 * This method can also be used to mark the engine channel as changed
75     * from outside, e.g. by a MIDI input device. The optional argument
76     * \a nNewStatus can be used for this.
77     *
78 schoenebeck 660 * TODO: This "poll method" is just a lazy solution and might be
79     * replaced in future.
80 schoenebeck 670 * @param bNewStatus - (optional, default: false) sets the new status flag
81 schoenebeck 660 * @returns true if engine channel status has changed since last
82     * StatusChanged() call
83     */
84 schoenebeck 670 bool EngineChannel::StatusChanged(bool bNewStatus) {
85 schoenebeck 660 bool b = bStatusChanged;
86 schoenebeck 670 bStatusChanged = bNewStatus;
87 schoenebeck 660 return b;
88     }
89    
90 schoenebeck 670 void EngineChannel::Reset() {
91     if (pEngine) pEngine->DisableAndLock();
92     ResetInternal();
93     ResetControllers();
94     if (pEngine) {
95     pEngine->Enable();
96     pEngine->Reset();
97     }
98     }
99    
100 schoenebeck 660 /**
101 schoenebeck 411 * This method is not thread safe!
102     */
103     void EngineChannel::ResetInternal() {
104     CurrentKeyDimension = 0;
105    
106     // reset key info
107     for (uint i = 0; i < 128; i++) {
108     if (pMIDIKeyInfo[i].pActiveVoices)
109     pMIDIKeyInfo[i].pActiveVoices->clear();
110     if (pMIDIKeyInfo[i].pEvents)
111     pMIDIKeyInfo[i].pEvents->clear();
112     pMIDIKeyInfo[i].KeyPressed = false;
113     pMIDIKeyInfo[i].Active = false;
114     pMIDIKeyInfo[i].ReleaseTrigger = false;
115     pMIDIKeyInfo[i].itSelf = Pool<uint>::Iterator();
116 schoenebeck 473 pMIDIKeyInfo[i].VoiceTheftsQueued = 0;
117 schoenebeck 411 }
118 schoenebeck 829 SoloKey = -1; // no solo key active yet
119     PortamentoPos = -1.0f; // no portamento active yet
120 schoenebeck 411
121     // reset all key groups
122     std::map<uint,uint*>::iterator iter = ActiveKeyGroups.begin();
123     for (; iter != ActiveKeyGroups.end(); iter++) iter->second = NULL;
124    
125     // free all active keys
126     pActiveKeys->clear();
127    
128     // delete all input events
129     pEventQueue->init();
130    
131     if (pEngine) pEngine->ResetInternal();
132 schoenebeck 660
133     // status of engine channel has changed, so set notify flag
134     bStatusChanged = true;
135 schoenebeck 411 }
136    
137     LinuxSampler::Engine* EngineChannel::GetEngine() {
138     return pEngine;
139     }
140    
141     /**
142     * More or less a workaround to set the instrument name, index and load
143     * status variable to zero percent immediately, that is without blocking
144     * the calling thread. It might be used in future for other preparations
145     * as well though.
146     *
147     * @param FileName - file name of the Gigasampler instrument file
148     * @param Instrument - index of the instrument in the .gig file
149     * @see LoadInstrument()
150     */
151     void EngineChannel::PrepareLoadInstrument(const char* FileName, uint Instrument) {
152     InstrumentFile = FileName;
153     InstrumentIdx = Instrument;
154     InstrumentStat = 0;
155     }
156    
157     /**
158     * Load an instrument from a .gig file. PrepareLoadInstrument() has to
159     * be called first to provide the information which instrument to load.
160     * This method will then actually start to load the instrument and block
161     * the calling thread until loading was completed.
162     *
163     * @returns detailed description of the method call result
164     * @see PrepareLoadInstrument()
165     */
166     void EngineChannel::LoadInstrument() {
167 persson 1038 ::gig::Instrument* oldInstrument = pInstrument;
168 schoenebeck 411
169 persson 1038 // free old instrument
170     if (oldInstrument) {
171     if (pEngine) {
172     // make sure we don't trigger any new notes with the
173     // old instrument
174     ::gig::DimensionRegion** dimRegionsInUse = pEngine->ChangeInstrument(this, 0);
175 persson 438
176 persson 1038 // give old instrument back to instrument manager, but
177     // keep the dimension regions and samples that are in
178     // use
179     Engine::instruments.HandBackInstrument(oldInstrument, this, dimRegionsInUse);
180     } else {
181     Engine::instruments.HandBack(oldInstrument, this);
182     }
183 schoenebeck 411 }
184    
185     // delete all key groups
186     ActiveKeyGroups.clear();
187    
188     // request gig instrument from instrument manager
189 persson 1038 ::gig::Instrument* newInstrument;
190 schoenebeck 411 try {
191 schoenebeck 947 InstrumentManager::instrument_id_t instrid;
192     instrid.FileName = InstrumentFile;
193     instrid.Index = InstrumentIdx;
194 persson 1038 newInstrument = Engine::instruments.Borrow(instrid, this);
195     if (!newInstrument) {
196 schoenebeck 1040 throw InstrumentResourceManagerException("resource was not created");
197 schoenebeck 411 }
198     }
199     catch (RIFF::Exception e) {
200     InstrumentStat = -2;
201     String msg = "gig::Engine error: Failed to load instrument, cause: " + e.Message;
202 schoenebeck 880 throw Exception(msg);
203 schoenebeck 411 }
204     catch (InstrumentResourceManagerException e) {
205     InstrumentStat = -3;
206     String msg = "gig::Engine error: Failed to load instrument, cause: " + e.Message();
207 schoenebeck 880 throw Exception(msg);
208 schoenebeck 411 }
209     catch (...) {
210     InstrumentStat = -4;
211 schoenebeck 880 throw Exception("gig::Engine error: Failed to load instrument, cause: Unknown exception while trying to parse gig file.");
212 schoenebeck 411 }
213    
214     // rebuild ActiveKeyGroups map with key groups of current instrument
215 persson 1038 for (::gig::Region* pRegion = newInstrument->GetFirstRegion(); pRegion; pRegion = newInstrument->GetNextRegion())
216 schoenebeck 411 if (pRegion->KeyGroup) ActiveKeyGroups[pRegion->KeyGroup] = NULL;
217    
218 persson 1038 InstrumentIdxName = newInstrument->pInfo->Name;
219 schoenebeck 411 InstrumentStat = 100;
220    
221 persson 1038 if (pEngine) pEngine->ChangeInstrument(this, newInstrument);
222     else pInstrument = newInstrument;
223 schoenebeck 411 }
224    
225     /**
226     * Will be called by the InstrumentResourceManager when the instrument
227 schoenebeck 517 * we are currently using on this EngineChannel is going to be updated,
228     * so we can stop playback before that happens.
229 schoenebeck 411 */
230     void EngineChannel::ResourceToBeUpdated(::gig::Instrument* pResource, void*& pUpdateArg) {
231     dmsg(3,("gig::Engine: Received instrument update message.\n"));
232     if (pEngine) pEngine->DisableAndLock();
233     ResetInternal();
234     this->pInstrument = NULL;
235     }
236    
237     /**
238     * Will be called by the InstrumentResourceManager when the instrument
239     * update process was completed, so we can continue with playback.
240     */
241     void EngineChannel::ResourceUpdated(::gig::Instrument* pOldResource, ::gig::Instrument* pNewResource, void* pUpdateArg) {
242     this->pInstrument = pNewResource; //TODO: there are couple of engine parameters we should update here as well if the instrument was updated (see LoadInstrument())
243     if (pEngine) pEngine->Enable();
244 schoenebeck 660 bStatusChanged = true; // status of engine has changed, so set notify flag
245 schoenebeck 411 }
246    
247 schoenebeck 517 /**
248     * Will be called by the InstrumentResourceManager on progress changes
249     * while loading or realoading an instrument for this EngineChannel.
250     *
251     * @param fProgress - current progress as value between 0.0 and 1.0
252     */
253     void EngineChannel::OnResourceProgress(float fProgress) {
254     this->InstrumentStat = int(fProgress * 100.0f);
255     dmsg(7,("gig::EngineChannel: progress %d%", InstrumentStat));
256 schoenebeck 660 bStatusChanged = true; // status of engine has changed, so set notify flag
257 schoenebeck 517 }
258    
259 schoenebeck 412 void EngineChannel::Connect(AudioOutputDevice* pAudioOut) {
260 schoenebeck 460 if (pEngine) {
261     if (pEngine->pAudioOutputDevice == pAudioOut) return;
262 schoenebeck 412 DisconnectAudioOutputDevice();
263     }
264 schoenebeck 411 pEngine = Engine::AcquireEngine(this, pAudioOut);
265 persson 438 ResetInternal();
266 schoenebeck 738 pEvents = new RTList<Event>(pEngine->pEventPool);
267 schoenebeck 411 for (uint i = 0; i < 128; i++) {
268     pMIDIKeyInfo[i].pActiveVoices = new RTList<Voice>(pEngine->pVoicePool);
269     pMIDIKeyInfo[i].pEvents = new RTList<Event>(pEngine->pEventPool);
270     }
271     AudioDeviceChannelLeft = 0;
272     AudioDeviceChannelRight = 1;
273 schoenebeck 1001 if (fxSends.empty()) { // render directly into the AudioDevice's output buffers
274     pChannelLeft = pAudioOut->Channel(AudioDeviceChannelLeft);
275     pChannelRight = pAudioOut->Channel(AudioDeviceChannelRight);
276     } else { // use local buffers for rendering and copy later
277     // ensure the local buffers have the correct size
278     if (pChannelLeft) delete pChannelLeft;
279     if (pChannelRight) delete pChannelRight;
280     pChannelLeft = new AudioChannel(0, pAudioOut->MaxSamplesPerCycle());
281     pChannelRight = new AudioChannel(1, pAudioOut->MaxSamplesPerCycle());
282     }
283 persson 1039 if (pEngine->EngineDisabled.GetUnsafe()) pEngine->Enable();
284 persson 846 MidiInputPort::AddSysexListener(pEngine);
285 schoenebeck 411 }
286    
287     void EngineChannel::DisconnectAudioOutputDevice() {
288     if (pEngine) { // if clause to prevent disconnect loops
289     ResetInternal();
290 schoenebeck 460 if (pEvents) {
291     delete pEvents;
292     pEvents = NULL;
293     }
294 schoenebeck 411 for (uint i = 0; i < 128; i++) {
295 schoenebeck 420 if (pMIDIKeyInfo[i].pActiveVoices) {
296     delete pMIDIKeyInfo[i].pActiveVoices;
297     pMIDIKeyInfo[i].pActiveVoices = NULL;
298     }
299     if (pMIDIKeyInfo[i].pEvents) {
300     delete pMIDIKeyInfo[i].pEvents;
301     pMIDIKeyInfo[i].pEvents = NULL;
302     }
303 schoenebeck 411 }
304     Engine* oldEngine = pEngine;
305     AudioOutputDevice* oldAudioDevice = pEngine->pAudioOutputDevice;
306     pEngine = NULL;
307     Engine::FreeEngine(this, oldAudioDevice);
308     AudioDeviceChannelLeft = -1;
309 persson 438 AudioDeviceChannelRight = -1;
310 schoenebeck 1001 if (!fxSends.empty()) { // free the local rendering buffers
311     if (pChannelLeft) delete pChannelLeft;
312     if (pChannelRight) delete pChannelRight;
313     }
314     pChannelLeft = NULL;
315     pChannelRight = NULL;
316 schoenebeck 411 }
317     }
318    
319 schoenebeck 1001 AudioOutputDevice* EngineChannel::GetAudioOutputDevice() {
320     return (pEngine) ? pEngine->pAudioOutputDevice : NULL;
321     }
322    
323 schoenebeck 411 void EngineChannel::SetOutputChannel(uint EngineAudioChannel, uint AudioDeviceChannel) {
324     if (!pEngine || !pEngine->pAudioOutputDevice) throw AudioOutputException("No audio output device connected yet.");
325 persson 438
326 schoenebeck 411 AudioChannel* pChannel = pEngine->pAudioOutputDevice->Channel(AudioDeviceChannel);
327     if (!pChannel) throw AudioOutputException("Invalid audio output device channel " + ToString(AudioDeviceChannel));
328     switch (EngineAudioChannel) {
329     case 0: // left output channel
330 schoenebeck 1001 if (fxSends.empty()) pChannelLeft = pChannel;
331 schoenebeck 411 AudioDeviceChannelLeft = AudioDeviceChannel;
332     break;
333     case 1: // right output channel
334 schoenebeck 1001 if (fxSends.empty()) pChannelRight = pChannel;
335 schoenebeck 411 AudioDeviceChannelRight = AudioDeviceChannel;
336     break;
337     default:
338     throw AudioOutputException("Invalid engine audio channel " + ToString(EngineAudioChannel));
339     }
340     }
341    
342     int EngineChannel::OutputChannel(uint EngineAudioChannel) {
343     switch (EngineAudioChannel) {
344     case 0: // left channel
345     return AudioDeviceChannelLeft;
346     case 1: // right channel
347     return AudioDeviceChannelRight;
348     default:
349     throw AudioOutputException("Invalid engine audio channel " + ToString(EngineAudioChannel));
350     }
351     }
352    
353 schoenebeck 675 void EngineChannel::Connect(MidiInputPort* pMidiPort, midi_chan_t MidiChannel) {
354     if (!pMidiPort || pMidiPort == this->pMidiInputPort) return;
355     DisconnectMidiInputPort();
356     this->pMidiInputPort = pMidiPort;
357     this->midiChannel = MidiChannel;
358     pMidiPort->Connect(this, MidiChannel);
359     }
360    
361     void EngineChannel::DisconnectMidiInputPort() {
362     MidiInputPort* pOldPort = this->pMidiInputPort;
363     this->pMidiInputPort = NULL;
364     if (pOldPort) pOldPort->Disconnect(this);
365     }
366    
367     MidiInputPort* EngineChannel::GetMidiInputPort() {
368     return pMidiInputPort;
369     }
370    
371     midi_chan_t EngineChannel::MidiChannel() {
372     return midiChannel;
373     }
374    
375 schoenebeck 1001 FxSend* EngineChannel::AddFxSend(uint8_t MidiCtrl, String Name) throw (Exception) {
376     if (pEngine) pEngine->DisableAndLock();
377     FxSend* pFxSend = new FxSend(this, MidiCtrl, Name);
378     if (fxSends.empty()) {
379     if (pEngine && pEngine->pAudioOutputDevice) {
380     AudioOutputDevice* pDevice = pEngine->pAudioOutputDevice;
381     // create local render buffers
382     pChannelLeft = new AudioChannel(0, pDevice->MaxSamplesPerCycle());
383     pChannelRight = new AudioChannel(1, pDevice->MaxSamplesPerCycle());
384     } else {
385     // postpone local render buffer creation until audio device is assigned
386     pChannelLeft = NULL;
387     pChannelRight = NULL;
388     }
389     }
390     fxSends.push_back(pFxSend);
391     if (pEngine) pEngine->Enable();
392 iliev 1108 LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_fx_send_count, iSamplerChannelIndex, GetFxSendCount()));
393 schoenebeck 1001 return pFxSend;
394     }
395    
396     FxSend* EngineChannel::GetFxSend(uint FxSendIndex) {
397     return (FxSendIndex < fxSends.size()) ? fxSends[FxSendIndex] : NULL;
398     }
399    
400     uint EngineChannel::GetFxSendCount() {
401     return fxSends.size();
402     }
403    
404     void EngineChannel::RemoveFxSend(FxSend* pFxSend) {
405     if (pEngine) pEngine->DisableAndLock();
406     for (
407     std::vector<FxSend*>::iterator iter = fxSends.begin();
408     iter != fxSends.end(); iter++
409     ) {
410     if (*iter == pFxSend) {
411     delete pFxSend;
412     fxSends.erase(iter);
413     if (fxSends.empty()) {
414     // destroy local render buffers
415     if (pChannelLeft) delete pChannelLeft;
416     if (pChannelRight) delete pChannelRight;
417     // fallback to render directly into AudioOutputDevice's buffers
418     if (pEngine && pEngine->pAudioOutputDevice) {
419     pChannelLeft = pEngine->pAudioOutputDevice->Channel(AudioDeviceChannelLeft);
420     pChannelRight = pEngine->pAudioOutputDevice->Channel(AudioDeviceChannelRight);
421     } else { // we update the pointers later
422     pChannelLeft = NULL;
423     pChannelRight = NULL;
424     }
425     }
426     break;
427     }
428     }
429     if (pEngine) pEngine->Enable();
430 iliev 1108 LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_fx_send_count, iSamplerChannelIndex, GetFxSendCount()));
431 schoenebeck 1001 }
432    
433 schoenebeck 411 /**
434     * Will be called by the MIDIIn Thread to let the audio thread trigger a new
435 schoenebeck 906 * voice for the given key. This method is meant for real time rendering,
436     * that is an event will immediately be created with the current system
437     * time as time stamp.
438 schoenebeck 411 *
439     * @param Key - MIDI key number of the triggered key
440     * @param Velocity - MIDI velocity value of the triggered key
441     */
442     void EngineChannel::SendNoteOn(uint8_t Key, uint8_t Velocity) {
443     if (pEngine) {
444     Event event = pEngine->pEventGenerator->CreateEvent();
445     event.Type = Event::type_note_on;
446     event.Param.Note.Key = Key;
447     event.Param.Note.Velocity = Velocity;
448 persson 438 event.pEngineChannel = this;
449 schoenebeck 411 if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
450 schoenebeck 412 else dmsg(1,("EngineChannel: Input event queue full!"));
451 schoenebeck 411 }
452     }
453    
454     /**
455 schoenebeck 906 * Will be called by the MIDIIn Thread to let the audio thread trigger a new
456     * voice for the given key. This method is meant for offline rendering
457     * and / or for cases where the exact position of the event in the current
458     * audio fragment is already known.
459     *
460     * @param Key - MIDI key number of the triggered key
461     * @param Velocity - MIDI velocity value of the triggered key
462     * @param FragmentPos - sample point position in the current audio
463     * fragment to which this event belongs to
464     */
465     void EngineChannel::SendNoteOn(uint8_t Key, uint8_t Velocity, int32_t FragmentPos) {
466     if (FragmentPos < 0) {
467     dmsg(1,("EngineChannel::SendNoteOn(): negative FragmentPos! Seems MIDI driver is buggy!"));
468     }
469     else if (pEngine) {
470     Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);
471     event.Type = Event::type_note_on;
472     event.Param.Note.Key = Key;
473     event.Param.Note.Velocity = Velocity;
474     event.pEngineChannel = this;
475     if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
476     else dmsg(1,("EngineChannel: Input event queue full!"));
477     }
478     }
479    
480     /**
481 schoenebeck 411 * Will be called by the MIDIIn Thread to signal the audio thread to release
482 schoenebeck 906 * voice(s) on the given key. This method is meant for real time rendering,
483     * that is an event will immediately be created with the current system
484     * time as time stamp.
485 schoenebeck 411 *
486     * @param Key - MIDI key number of the released key
487     * @param Velocity - MIDI release velocity value of the released key
488     */
489     void EngineChannel::SendNoteOff(uint8_t Key, uint8_t Velocity) {
490     if (pEngine) {
491     Event event = pEngine->pEventGenerator->CreateEvent();
492     event.Type = Event::type_note_off;
493     event.Param.Note.Key = Key;
494     event.Param.Note.Velocity = Velocity;
495 schoenebeck 412 event.pEngineChannel = this;
496 schoenebeck 411 if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
497 schoenebeck 412 else dmsg(1,("EngineChannel: Input event queue full!"));
498 schoenebeck 411 }
499     }
500    
501     /**
502 schoenebeck 906 * Will be called by the MIDIIn Thread to signal the audio thread to release
503     * voice(s) on the given key. This method is meant for offline rendering
504     * and / or for cases where the exact position of the event in the current
505     * audio fragment is already known.
506     *
507     * @param Key - MIDI key number of the released key
508     * @param Velocity - MIDI release velocity value of the released key
509     * @param FragmentPos - sample point position in the current audio
510     * fragment to which this event belongs to
511     */
512     void EngineChannel::SendNoteOff(uint8_t Key, uint8_t Velocity, int32_t FragmentPos) {
513     if (FragmentPos < 0) {
514     dmsg(1,("EngineChannel::SendNoteOff(): negative FragmentPos! Seems MIDI driver is buggy!"));
515     }
516     else if (pEngine) {
517     Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);
518     event.Type = Event::type_note_off;
519     event.Param.Note.Key = Key;
520     event.Param.Note.Velocity = Velocity;
521     event.pEngineChannel = this;
522     if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
523     else dmsg(1,("EngineChannel: Input event queue full!"));
524     }
525     }
526    
527     /**
528 schoenebeck 411 * Will be called by the MIDIIn Thread to signal the audio thread to change
529 schoenebeck 906 * the pitch value for all voices. This method is meant for real time
530     * rendering, that is an event will immediately be created with the
531     * current system time as time stamp.
532 schoenebeck 411 *
533     * @param Pitch - MIDI pitch value (-8192 ... +8191)
534     */
535     void EngineChannel::SendPitchbend(int Pitch) {
536 persson 438 if (pEngine) {
537 schoenebeck 411 Event event = pEngine->pEventGenerator->CreateEvent();
538     event.Type = Event::type_pitchbend;
539     event.Param.Pitch.Pitch = Pitch;
540 schoenebeck 412 event.pEngineChannel = this;
541 schoenebeck 411 if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
542 schoenebeck 412 else dmsg(1,("EngineChannel: Input event queue full!"));
543 schoenebeck 411 }
544     }
545    
546     /**
547 schoenebeck 906 * Will be called by the MIDIIn Thread to signal the audio thread to change
548     * the pitch value for all voices. This method is meant for offline
549     * rendering and / or for cases where the exact position of the event in
550     * the current audio fragment is already known.
551     *
552     * @param Pitch - MIDI pitch value (-8192 ... +8191)
553     * @param FragmentPos - sample point position in the current audio
554     * fragment to which this event belongs to
555     */
556     void EngineChannel::SendPitchbend(int Pitch, int32_t FragmentPos) {
557     if (FragmentPos < 0) {
558     dmsg(1,("EngineChannel::SendPitchBend(): negative FragmentPos! Seems MIDI driver is buggy!"));
559     }
560     else if (pEngine) {
561     Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);
562     event.Type = Event::type_pitchbend;
563     event.Param.Pitch.Pitch = Pitch;
564     event.pEngineChannel = this;
565     if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
566     else dmsg(1,("EngineChannel: Input event queue full!"));
567     }
568     }
569    
570     /**
571 schoenebeck 411 * Will be called by the MIDIIn Thread to signal the audio thread that a
572 schoenebeck 906 * continuous controller value has changed. This method is meant for real
573     * time rendering, that is an event will immediately be created with the
574     * current system time as time stamp.
575 schoenebeck 411 *
576     * @param Controller - MIDI controller number of the occured control change
577     * @param Value - value of the control change
578     */
579     void EngineChannel::SendControlChange(uint8_t Controller, uint8_t Value) {
580     if (pEngine) {
581     Event event = pEngine->pEventGenerator->CreateEvent();
582     event.Type = Event::type_control_change;
583     event.Param.CC.Controller = Controller;
584     event.Param.CC.Value = Value;
585 schoenebeck 412 event.pEngineChannel = this;
586 schoenebeck 411 if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
587 schoenebeck 412 else dmsg(1,("EngineChannel: Input event queue full!"));
588 schoenebeck 411 }
589     }
590    
591 schoenebeck 906 /**
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     void EngineChannel::SendControlChange(uint8_t Controller, uint8_t Value, int32_t FragmentPos) {
603     if (FragmentPos < 0) {
604     dmsg(1,("EngineChannel::SendControlChange(): negative FragmentPos! Seems MIDI driver is buggy!"));
605     }
606     else if (pEngine) {
607     Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);
608     event.Type = Event::type_control_change;
609     event.Param.CC.Controller = Controller;
610     event.Param.CC.Value = Value;
611     event.pEngineChannel = this;
612     if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
613     else dmsg(1,("EngineChannel: Input event queue full!"));
614     }
615     }
616    
617 schoenebeck 460 void EngineChannel::ClearEventLists() {
618     pEvents->clear();
619     // empty MIDI key specific event lists
620     {
621     RTList<uint>::Iterator iuiKey = pActiveKeys->first();
622     RTList<uint>::Iterator end = pActiveKeys->end();
623     for(; iuiKey != end; ++iuiKey) {
624     pMIDIKeyInfo[*iuiKey].pEvents->clear(); // free all events on the key
625     }
626     }
627     }
628    
629 schoenebeck 473 void EngineChannel::ResetControllers() {
630 schoenebeck 670 Pitch = 0;
631     SustainPedal = false;
632 iliev 776 SostenutoPedal = false;
633 schoenebeck 1005 GlobalVolume = 1.0f;
634 schoenebeck 947 MidiVolume = 1.0;
635 schoenebeck 670 GlobalPanLeft = 1.0f;
636     GlobalPanRight = 1.0f;
637 schoenebeck 1041 GlobalTranspose = 0;
638 schoenebeck 473 // set all MIDI controller values to zero
639 persson 903 memset(ControllerTable, 0x00, 129);
640 schoenebeck 1040 // reset all FX Send levels
641     for (
642     std::vector<FxSend*>::iterator iter = fxSends.begin();
643     iter != fxSends.end(); iter++
644     ) {
645     (*iter)->Reset();
646     }
647 schoenebeck 473 }
648    
649 schoenebeck 460 /**
650     * Copy all events from the engine channel's input event queue buffer to
651     * the internal event list. This will be done at the beginning of each
652     * audio cycle (that is each RenderAudio() call) to distinguish all
653     * events which have to be processed in the current audio cycle. Each
654     * EngineChannel has it's own input event queue for the common channel
655     * specific events (like NoteOn, NoteOff and ControlChange events).
656     * Beside that, the engine also has a input event queue for global
657     * events (usually SysEx messages).
658     *
659     * @param Samples - number of sample points to be processed in the
660     * current audio cycle
661     */
662     void EngineChannel::ImportEvents(uint Samples) {
663 schoenebeck 970 RingBuffer<Event,false>::NonVolatileReader eventQueueReader = pEventQueue->get_non_volatile_reader();
664 schoenebeck 460 Event* pEvent;
665     while (true) {
666     // get next event from input event queue
667     if (!(pEvent = eventQueueReader.pop())) break;
668     // if younger event reached, ignore that and all subsequent ones for now
669     if (pEvent->FragmentPos() >= Samples) {
670     eventQueueReader--;
671     dmsg(2,("Younger Event, pos=%d ,Samples=%d!\n",pEvent->FragmentPos(),Samples));
672     pEvent->ResetFragmentPos();
673     break;
674     }
675     // copy event to internal event list
676     if (pEvents->poolIsEmpty()) {
677     dmsg(1,("Event pool emtpy!\n"));
678     break;
679     }
680     *pEvents->allocAppend() = *pEvent;
681     }
682     eventQueueReader.free(); // free all copied events from input queue
683     }
684    
685 schoenebeck 1001 void EngineChannel::RemoveAllFxSends() {
686     if (pEngine) pEngine->DisableAndLock();
687     if (!fxSends.empty()) { // free local render buffers
688     if (pChannelLeft) {
689     delete pChannelLeft;
690     if (pEngine && pEngine->pAudioOutputDevice) {
691     // fallback to render directly to the AudioOutputDevice's buffer
692     pChannelLeft = pEngine->pAudioOutputDevice->Channel(AudioDeviceChannelLeft);
693     } else pChannelLeft = NULL;
694     }
695     if (pChannelRight) {
696     delete pChannelRight;
697     if (pEngine && pEngine->pAudioOutputDevice) {
698     // fallback to render directly to the AudioOutputDevice's buffer
699     pChannelRight = pEngine->pAudioOutputDevice->Channel(AudioDeviceChannelRight);
700     } else pChannelRight = NULL;
701     }
702     }
703     for (int i = 0; i < fxSends.size(); i++) delete fxSends[i];
704     fxSends.clear();
705     if (pEngine) pEngine->Enable();
706     }
707    
708 schoenebeck 411 float EngineChannel::Volume() {
709     return GlobalVolume;
710     }
711    
712     void EngineChannel::Volume(float f) {
713     GlobalVolume = f;
714 schoenebeck 660 bStatusChanged = true; // status of engine channel has changed, so set notify flag
715 schoenebeck 411 }
716    
717     uint EngineChannel::Channels() {
718     return 2;
719     }
720    
721     String EngineChannel::InstrumentFileName() {
722     return InstrumentFile;
723     }
724    
725     String EngineChannel::InstrumentName() {
726     return InstrumentIdxName;
727     }
728    
729     int EngineChannel::InstrumentIndex() {
730     return InstrumentIdx;
731     }
732    
733     int EngineChannel::InstrumentStatus() {
734     return InstrumentStat;
735 persson 438 }
736 schoenebeck 411
737 schoenebeck 475 String EngineChannel::EngineName() {
738     return LS_GIG_ENGINE_NAME;
739     }
740 schoenebeck 660
741 schoenebeck 411 }} // namespace LinuxSampler::gig

  ViewVC Help
Powered by ViewVC