/[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 1424 - (hide annotations) (download)
Sun Oct 14 22:00:17 2007 UTC (16 years, 6 months ago) by schoenebeck
File size: 31885 byte(s)
* code cleanup:
- global.h now only covers global definitions that are needed for the C++
  API header files, all implementation internal global definitions are now
  in global_private.h
- atomic.h is not exposed to the C++ API anymore (replaced the references
  in SynchronizedConfig.h for this with local definitions)
- no need to include config.h anymore for using LS's API header files
- DB instruments classes are not exposed to the C++ API
- POSIX callback functions of Thread.h are hidden
- the (optional) gig Engine benchmark compiles again
- updated Doxyfile.in
- fixed warnings in API doc generation
* preparations for release 0.5.0

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

  ViewVC Help
Powered by ViewVC