/[svn]/linuxsampler/trunk/src/engines/EngineBase.h
ViewVC logotype

Annotation of /linuxsampler/trunk/src/engines/EngineBase.h

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2410 - (hide annotations) (download) (as text)
Sat Feb 2 18:52:15 2013 UTC (11 years, 1 month ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 79537 byte(s)
* Several fixes in JACK audio driver:
- React on sample rate changes.
- React on buffer size changes.
- jack_port_get_buffer() was cached and called
  outside RT context.

1 iliev 2012 /***************************************************************************
2     * *
3     * LinuxSampler - modular, streaming capable sampler *
4     * *
5     * Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck *
6 persson 2055 * Copyright (C) 2005-2008 Christian Schoenebeck *
7 persson 2327 * Copyright (C) 2009-2012 Christian Schoenebeck and Grigor Iliev *
8 iliev 2012 * *
9     * This program is free software; you can redistribute it and/or modify *
10     * it under the terms of the GNU General Public License as published by *
11     * the Free Software Foundation; either version 2 of the License, or *
12     * (at your option) any later version. *
13     * *
14     * This program is distributed in the hope that it will be useful, *
15     * but WITHOUT ANY WARRANTY; without even the implied warranty of *
16     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
17     * GNU General Public License for more details. *
18     * *
19     * You should have received a copy of the GNU General Public License *
20     * along with this program; if not, write to the Free Software *
21     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
22     * MA 02111-1307 USA *
23     ***************************************************************************/
24    
25     #ifndef __LS_ENGINEBASE_H__
26     #define __LS_ENGINEBASE_H__
27    
28     #include "AbstractEngine.h"
29     #include "EngineChannelBase.h"
30     #include "common/DiskThreadBase.h"
31     #include "common/MidiKeyboardManager.h"
32     #include "InstrumentManager.h"
33     #include "../common/global_private.h"
34    
35    
36     namespace LinuxSampler {
37    
38     class AbstractEngineChannel;
39    
40     template <
41     class V /* Voice */,
42     class RR /* Root Region */,
43     class R /* Region */,
44     class D /* Disk Thread */,
45     class IM /* Instrument Manager */,
46     class I /* Instrument */
47     >
48     class EngineBase: public AbstractEngine, public RegionPools<R>, public VoicePool<V> {
49    
50     public:
51     typedef typename RTList<V>::Iterator VoiceIterator;
52     typedef typename Pool<V>::Iterator PoolVoiceIterator;
53     typedef typename RTList<RR*>::Iterator RootRegionIterator;
54     typedef typename MidiKeyboardManager<V>::MidiKey MidiKey;
55    
56     EngineBase() : SuspendedRegions(128) {
57     pDiskThread = NULL;
58     pVoicePool = new Pool<V>(GLOBAL_MAX_VOICES);
59     pRegionPool[0] = new Pool<R*>(GLOBAL_MAX_VOICES);
60     pRegionPool[1] = new Pool<R*>(GLOBAL_MAX_VOICES);
61     pVoiceStealingQueue = new RTList<Event>(pEventPool);
62     iMaxDiskStreams = GLOBAL_MAX_STREAMS;
63    
64     for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
65     iterVoice->SetEngine(this);
66     }
67     pVoicePool->clear();
68    
69     ResetInternal();
70     ResetScaleTuning();
71     ResetSuspendedRegions();
72     }
73    
74     virtual ~EngineBase() {
75     if (pDiskThread) {
76     dmsg(1,("Stopping disk thread..."));
77     pDiskThread->StopThread();
78     delete pDiskThread;
79     dmsg(1,("OK\n"));
80     }
81    
82     if (pVoicePool) {
83     pVoicePool->clear();
84     delete pVoicePool;
85     }
86    
87     if (pVoiceStealingQueue) delete pVoiceStealingQueue;
88    
89     if (pRegionPool[0]) delete pRegionPool[0];
90     if (pRegionPool[1]) delete pRegionPool[1];
91     ResetSuspendedRegions();
92     }
93    
94     // implementation of abstract methods derived from class 'LinuxSampler::Engine'
95    
96     /**
97     * Let this engine proceed to render the given amount of sample points.
98     * The engine will iterate through all engine channels and render audio
99     * for each engine channel independently. The calculated audio data of
100     * all voices of each engine channel will be placed into the audio sum
101     * buffers of the respective audio output device, connected to the
102     * respective engine channel.
103     *
104     * @param Samples - number of sample points to be rendered
105     * @returns 0 on success
106     */
107     virtual int RenderAudio(uint Samples) {
108     dmsg(8,("RenderAudio(Samples=%d)\n", Samples));
109    
110     // return if engine disabled
111     if (EngineDisabled.Pop()) {
112     dmsg(5,("EngineBase: engine disabled (val=%d)\n",EngineDisabled.GetUnsafe()));
113     EngineDisabled.RttDone();
114     return 0;
115     }
116    
117     // process requests for suspending / resuming regions (i.e. to avoid
118     // crashes while these regions are modified by an instrument editor)
119     ProcessSuspensionsChanges();
120    
121     // update time of start and end of this audio fragment (as events' time stamps relate to this)
122     pEventGenerator->UpdateFragmentTime(Samples);
123    
124     // We only allow the given maximum number of voices to be spawned
125     // in each audio fragment. All subsequent request for spawning new
126     // voices in the same audio fragment will be ignored.
127     VoiceSpawnsLeft = MaxVoices();
128    
129     // get all events from the engine's global input event queue which belong to the current fragment
130     // (these are usually just SysEx messages)
131     ImportEvents(Samples);
132    
133     // process engine global events (these are currently only MIDI System Exclusive messages)
134     {
135     RTList<Event>::Iterator itEvent = pGlobalEvents->first();
136     RTList<Event>::Iterator end = pGlobalEvents->end();
137     for (; itEvent != end; ++itEvent) {
138     switch (itEvent->Type) {
139     case Event::type_sysex:
140     dmsg(5,("Engine: Sysex received\n"));
141     ProcessSysex(itEvent);
142     break;
143     }
144     }
145     }
146    
147     // reset internal voice counter (just for statistic of active voices)
148     ActiveVoiceCountTemp = 0;
149    
150     HandleInstrumentChanges();
151    
152     // handle events on all engine channels
153     for (int i = 0; i < engineChannels.size(); i++) {
154     ProcessEvents(engineChannels[i], Samples);
155     }
156    
157     // render all 'normal', active voices on all engine channels
158     for (int i = 0; i < engineChannels.size(); i++) {
159     RenderActiveVoices(engineChannels[i], Samples);
160     }
161    
162     // now that all ordinary voices on ALL engine channels are rendered, render new stolen voices
163     RenderStolenVoices(Samples);
164    
165     // handle audio routing for engine channels with FX sends
166     for (int i = 0; i < engineChannels.size(); i++) {
167     AbstractEngineChannel* pChannel = static_cast<AbstractEngineChannel*>(engineChannels[i]);
168     if (pChannel->fxSends.empty()) continue; // ignore if no FX sends
169     RouteAudio(engineChannels[i], Samples);
170     }
171    
172     // handle cleanup on all engine channels for the next audio fragment
173     for (int i = 0; i < engineChannels.size(); i++) {
174     PostProcess(engineChannels[i]);
175     }
176    
177    
178     // empty the engine's event list for the next audio fragment
179     ClearEventLists();
180    
181     // reset voice stealing for the next audio fragment
182     pVoiceStealingQueue->clear();
183    
184     // just some statistics about this engine instance
185     SetVoiceCount(ActiveVoiceCountTemp);
186     if (VoiceCount() > ActiveVoiceCountMax) ActiveVoiceCountMax = VoiceCount();
187    
188     // in case regions were previously suspended and we killed voices
189     // with disk streams due to that, check if those streams have finally
190     // been deleted by the disk thread
191     if (iPendingStreamDeletions) ProcessPendingStreamDeletions();
192    
193 persson 2162 // Release the instrument change command. (This has to
194     // be done after all voices have been rendered and not
195     // in HandleInstrumentChanges, as the RegionsInUse
196     // list has been built up by the voice renderers.)
197     for (int i = 0; i < engineChannels.size(); i++) {
198     EngineChannelBase<V, R, I>* channel =
199     static_cast<EngineChannelBase<V, R, I>*>(engineChannels[i]);
200     channel->InstrumentChangeCommandReader.Unlock();
201     }
202 iliev 2012 FrameTime += Samples;
203    
204     EngineDisabled.RttDone();
205     return 0;
206     }
207    
208     virtual int MaxVoices() { return pVoicePool->poolSize(); }
209    
210     virtual void SetMaxVoices(int iVoices) throw (Exception) {
211     if (iVoices < 1)
212     throw Exception("Maximum voices for an engine cannot be set lower than 1");
213    
214     SuspendAll();
215    
216     // NOTE: we need to clear pRegionsInUse before deleting pDimRegionPool,
217     // otherwise memory corruption will occur if there are active voices (see bug #118)
218     for (int iChannel = 0; iChannel < engineChannels.size(); iChannel++) {
219     EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannel]);
220     pChannel->ClearRegionsInUse();
221     }
222    
223     if (pRegionPool[0]) delete pRegionPool[0];
224     if (pRegionPool[1]) delete pRegionPool[1];
225    
226     pRegionPool[0] = new Pool<R*>(iVoices);
227     pRegionPool[1] = new Pool<R*>(iVoices);
228    
229     for (int iChannel = 0; iChannel < engineChannels.size(); iChannel++) {
230     EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannel]);
231     pChannel->ResetRegionsInUse(pRegionPool);
232     }
233    
234     try {
235     pVoicePool->resizePool(iVoices);
236     } catch (...) {
237     throw Exception("FATAL: Could not resize voice pool!");
238     }
239    
240     for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
241     iterVoice->SetEngine(this);
242     iterVoice->pDiskThread = this->pDiskThread;
243     }
244     pVoicePool->clear();
245    
246 iliev 2244 PostSetMaxVoices(iVoices);
247 iliev 2012 ResumeAll();
248     }
249 iliev 2244
250     /** Called after the new max number of voices is set and before resuming the engine. */
251     virtual void PostSetMaxVoices(int iVoices) { }
252 iliev 2012
253     virtual uint DiskStreamCount() { return (pDiskThread) ? pDiskThread->GetActiveStreamCount() : 0; }
254     virtual uint DiskStreamCountMax() { return (pDiskThread) ? pDiskThread->ActiveStreamCountMax : 0; }
255     virtual int MaxDiskStreams() { return iMaxDiskStreams; }
256    
257     virtual void SetMaxDiskStreams(int iStreams) throw (Exception) {
258     if (iStreams < 0)
259     throw Exception("Maximum disk streams for an engine cannot be set lower than 0");
260    
261     SuspendAll();
262    
263     iMaxDiskStreams = iStreams;
264    
265     // reconnect to audio output device, because that will automatically
266     // recreate the disk thread with the required amount of streams
267     if (pAudioOutputDevice) Connect(pAudioOutputDevice);
268    
269     ResumeAll();
270     }
271    
272     virtual String DiskStreamBufferFillBytes() { return (pDiskThread) ? pDiskThread->GetBufferFillBytes() : ""; }
273     virtual String DiskStreamBufferFillPercentage() { return (pDiskThread) ? pDiskThread->GetBufferFillPercentage() : ""; }
274     virtual InstrumentManager* GetInstrumentManager() { return &instruments; }
275    
276     /**
277     * Connect this engine instance with the given audio output device.
278     * This method will be called when an Engine instance is created.
279     * All of the engine's data structures which are dependant to the used
280     * audio output device / driver will be (re)allocated and / or
281     * adjusted appropriately.
282     *
283     * @param pAudioOut - audio output device to connect to
284     */
285     virtual void Connect(AudioOutputDevice* pAudioOut) {
286     // caution: don't ignore if connecting to the same device here,
287     // because otherwise SetMaxDiskStreams() implementation won't work anymore!
288    
289     pAudioOutputDevice = pAudioOut;
290    
291     ResetInternal();
292    
293     // inform audio driver for the need of two channels
294     try {
295     pAudioOutputDevice->AcquireChannels(2); // default stereo
296     }
297     catch (AudioOutputException e) {
298     String msg = "Audio output device unable to provide 2 audio channels, cause: " + e.Message();
299     throw Exception(msg);
300     }
301    
302     this->MaxSamplesPerCycle = pAudioOutputDevice->MaxSamplesPerCycle();
303     this->SampleRate = pAudioOutputDevice->SampleRate();
304    
305     MinFadeOutSamples = int(double(SampleRate) * CONFIG_EG_MIN_RELEASE_TIME) - 1;
306     if (MaxSamplesPerCycle < MinFadeOutSamples) {
307     std::cerr << "EngineBase: WARNING, CONFIG_EG_MIN_RELEASE_TIME "
308     << "too big for current audio fragment size & sampling rate! "
309     << "May lead to click sounds if voice stealing chimes in!\n" << std::flush;
310     // force volume ramp downs at the beginning of each fragment
311     MinFadeOutSamples = MaxSamplesPerCycle;
312     // lower minimum release time
313     const float minReleaseTime = (float) MaxSamplesPerCycle / (float) SampleRate;
314     for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
315 persson 2327 iterVoice->CalculateFadeOutCoeff(minReleaseTime, SampleRate);
316 iliev 2012 }
317     pVoicePool->clear();
318     }
319    
320     // (re)create disk thread
321     if (this->pDiskThread) {
322     dmsg(1,("Stopping disk thread..."));
323     this->pDiskThread->StopThread();
324     delete this->pDiskThread;
325     dmsg(1,("OK\n"));
326     }
327     this->pDiskThread = CreateDiskThread();
328    
329     if (!pDiskThread) {
330     dmsg(0,("EngineBase new diskthread = NULL\n"));
331     exit(EXIT_FAILURE);
332     }
333    
334     for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
335     iterVoice->pDiskThread = this->pDiskThread;
336     dmsg(3,("d"));
337     }
338     pVoicePool->clear();
339    
340     // (re)create event generator
341     if (pEventGenerator) delete pEventGenerator;
342     pEventGenerator = new EventGenerator(pAudioOut->SampleRate());
343    
344     dmsg(1,("Starting disk thread..."));
345     pDiskThread->StartThread();
346     dmsg(1,("OK\n"));
347    
348 iliev 2298 bool printEqInfo = true;
349 iliev 2012 for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
350     if (!iterVoice->pDiskThread) {
351     dmsg(0,("Engine -> voice::trigger: !pDiskThread\n"));
352     exit(EXIT_FAILURE);
353     }
354 iliev 2298
355     iterVoice->CreateEq();
356    
357     if(printEqInfo) {
358     iterVoice->PrintEqInfo();
359     printEqInfo = false;
360     }
361 iliev 2012 }
362     pVoicePool->clear();
363 schoenebeck 2121
364     // (re)create dedicated voice audio buffers
365     //TODO: we could optimize resource usage a bit by just allocating these dedicated voice buffers when there is at least one engine channel with FX sends, because only in this case those special buffers are used actually, but since it would usually only save couple bytes in total, its probably not worth it
366     if (pDedicatedVoiceChannelLeft) delete pDedicatedVoiceChannelLeft;
367     if (pDedicatedVoiceChannelRight) delete pDedicatedVoiceChannelRight;
368     pDedicatedVoiceChannelLeft = new AudioChannel(0, MaxSamplesPerCycle);
369     pDedicatedVoiceChannelRight = new AudioChannel(1, MaxSamplesPerCycle);
370 iliev 2012 }
371 schoenebeck 2410
372     // Implementattion for abstract method derived from Engine.
373     virtual void ReconnectAudioOutputDevice() {
374     SuspendAll();
375     if (pAudioOutputDevice) Connect(pAudioOutputDevice);
376     ResumeAll();
377     }
378 iliev 2012
379     /**
380     * Similar to @c Disable() but this method additionally kills all voices
381     * and disk streams and blocks until all voices and disk streams are actually
382     * killed / deleted.
383     *
384     * @e Note: only the original calling thread is able to re-enable the
385     * engine afterwards by calling @c ResumeAll() later on!
386     */
387     virtual void SuspendAll() {
388     dmsg(2,("Engine: Suspending all ...\n"));
389     // stop the engine, so we can safely modify the engine's
390     // data structures from this foreign thread
391     DisableAndLock();
392     // we could also use the respective class member variable here,
393     // but this is probably safer and cleaner
394     int iPendingStreamDeletions = 0;
395     // kill all voices on all engine channels the *die hard* way
396     for (int iChannel = 0; iChannel < engineChannels.size(); iChannel++) {
397     EngineChannelBase<V, R, I>* pEngineChannel =
398     static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannel]);
399    
400     iPendingStreamDeletions += pEngineChannel->KillAllVoicesImmediately();
401     }
402     // wait until all streams were actually deleted by the disk thread
403     while (iPendingStreamDeletions) {
404     while (
405     iPendingStreamDeletions &&
406     pDiskThread->AskForDeletedStream() != Stream::INVALID_HANDLE
407     ) iPendingStreamDeletions--;
408     if (!iPendingStreamDeletions) break;
409     usleep(10000); // sleep for 10ms
410     }
411     dmsg(2,("EngineBase: Everything suspended.\n"));
412     }
413    
414     /**
415     * At the moment same as calling @c Enable() directly, but this might
416     * change in future, so better call this method as counterpart to
417     * @c SuspendAll() instead of @c Enable() !
418     */
419     virtual void ResumeAll() { Enable(); }
420    
421     /**
422     * Order the engine to stop rendering audio for the given region.
423     * Additionally this method will block until all voices and their disk
424     * streams associated with that region are actually killed / deleted, so
425     * one can i.e. safely modify the region with an instrument editor after
426     * returning from this method.
427     *
428     * @param pRegion - region the engine shall stop using
429     */
430     virtual void Suspend(RR* pRegion) {
431     dmsg(2,("EngineBase: Suspending Region %x ...\n",pRegion));
432     SuspendedRegionsMutex.Lock();
433     SuspensionChangeOngoing.Set(true);
434     pPendingRegionSuspension = pRegion;
435     SuspensionChangeOngoing.WaitAndUnlockIf(true);
436     SuspendedRegionsMutex.Unlock();
437     dmsg(2,("EngineBase: Region %x suspended.",pRegion));
438     }
439    
440     /**
441     * Orders the engine to resume playing back the given region, previously
442     * suspended with @c Suspend() .
443     *
444     * @param pRegion - region the engine shall be allowed to use again
445     */
446     virtual void Resume(RR* pRegion) {
447     dmsg(2,("EngineBase: Resuming Region %x ...\n",pRegion));
448     SuspendedRegionsMutex.Lock();
449     SuspensionChangeOngoing.Set(true);
450     pPendingRegionResumption = pRegion;
451     SuspensionChangeOngoing.WaitAndUnlockIf(true);
452     SuspendedRegionsMutex.Unlock();
453     dmsg(2,("EngineBase: Region %x resumed.\n",pRegion));
454     }
455    
456     virtual void ResetSuspendedRegions() {
457     SuspendedRegions.clear();
458     iPendingStreamDeletions = 0;
459     pPendingRegionSuspension = pPendingRegionResumption = NULL;
460     SuspensionChangeOngoing.Set(false);
461     }
462    
463     /**
464     * Called by the engine's (audio) thread once per cycle to process requests
465     * from the outer world to suspend or resume a given @c gig::Region .
466     */
467     virtual void ProcessSuspensionsChanges() {
468     // process request for suspending one region
469     if (pPendingRegionSuspension) {
470     // kill all voices on all engine channels that use this region
471     for (int iChannel = 0; iChannel < engineChannels.size(); iChannel++) {
472     EngineChannelBase<V, R, I>* pEngineChannel =
473     static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannel]);
474     SuspensionVoiceHandler handler(pPendingRegionSuspension);
475     pEngineChannel->ProcessActiveVoices(&handler);
476     iPendingStreamDeletions += handler.PendingStreamDeletions;
477     }
478     // make sure the region is not yet on the list
479     bool bAlreadySuspended = false;
480     RootRegionIterator iter = SuspendedRegions.first();
481     RootRegionIterator end = SuspendedRegions.end();
482     for (; iter != end; ++iter) { // iterate through all suspended regions
483     if (*iter == pPendingRegionSuspension) { // found
484     bAlreadySuspended = true;
485     dmsg(1,("EngineBase: attempt to suspend an already suspended region !!!\n"));
486     break;
487     }
488     }
489     if (!bAlreadySuspended) {
490     // put the region on the list of suspended regions
491     RootRegionIterator iter = SuspendedRegions.allocAppend();
492     if (iter) {
493     *iter = pPendingRegionSuspension;
494     } else std::cerr << "EngineBase: Could not suspend Region, list is full. This is a bug!!!\n" << std::flush;
495     }
496     // free request slot for next caller (and to make sure that
497     // we're not going to process the same request in the next cycle)
498     pPendingRegionSuspension = NULL;
499     // if no disk stream deletions are pending, awaken other side, as
500     // we're done in this case
501     if (!iPendingStreamDeletions) SuspensionChangeOngoing.Set(false);
502     }
503    
504     // process request for resuming one region
505     if (pPendingRegionResumption) {
506     // remove region from the list of suspended regions
507     RootRegionIterator iter = SuspendedRegions.first();
508     RootRegionIterator end = SuspendedRegions.end();
509     for (; iter != end; ++iter) { // iterate through all suspended regions
510     if (*iter == pPendingRegionResumption) { // found
511     SuspendedRegions.free(iter);
512     break; // done
513     }
514     }
515     // free request slot for next caller
516     pPendingRegionResumption = NULL;
517     // awake other side as we're done
518     SuspensionChangeOngoing.Set(false);
519     }
520     }
521    
522     /**
523     * Called by the engine's (audio) thread once per cycle to check if
524     * streams of voices that were killed due to suspension request have
525     * finally really been deleted by the disk thread.
526     */
527     virtual void ProcessPendingStreamDeletions() {
528     if (!iPendingStreamDeletions) return;
529     //TODO: or shall we better store a list with stream handles instead of a scalar amount of streams to be deleted? might be safer
530     while (
531     iPendingStreamDeletions &&
532     pDiskThread->AskForDeletedStream() != Stream::INVALID_HANDLE
533     ) iPendingStreamDeletions--;
534     // just for safety ...
535     while (pDiskThread->AskForDeletedStream() != Stream::INVALID_HANDLE);
536     // now that all disk streams are deleted, awake other side as
537     // we're finally done with suspending the requested region
538     if (!iPendingStreamDeletions) SuspensionChangeOngoing.Set(false);
539     }
540    
541     /**
542     * Returns @c true if the given region is currently set to be suspended
543     * from being used, @c false otherwise.
544     */
545     virtual bool RegionSuspended(RR* pRegion) {
546     if (SuspendedRegions.isEmpty()) return false;
547     //TODO: or shall we use a sorted container instead of the RTList? might be faster ... or trivial ;-)
548     RootRegionIterator iter = SuspendedRegions.first();
549     RootRegionIterator end = SuspendedRegions.end();
550     for (; iter != end; ++iter) // iterate through all suspended regions
551     if (*iter == pRegion) return true;
552     return false;
553     }
554    
555     // implementation of abstract method derived from class 'LinuxSampler::RegionPools'
556     virtual Pool<R*>* GetRegionPool(int index) {
557     if (index < 0 || index > 1) throw Exception("Index out of bounds");
558     return pRegionPool[index];
559     }
560    
561     // implementation of abstract method derived from class 'LinuxSampler::VoicePool'
562     virtual Pool<V>* GetVoicePool() { return pVoicePool; }
563    
564     D* GetDiskThread() { return pDiskThread; }
565    
566     //friend class EngineChannelBase<V, R, I>;
567    
568 persson 2127 static IM instruments;
569    
570 iliev 2012 protected:
571     class SuspensionVoiceHandler : public MidiKeyboardManager<V>::VoiceHandler {
572     public:
573     int PendingStreamDeletions;
574     RR* pPendingRegionSuspension;
575     SuspensionVoiceHandler(RR* pPendingRegionSuspension) {
576     PendingStreamDeletions = 0;
577     this->pPendingRegionSuspension = pPendingRegionSuspension;
578     }
579    
580     virtual bool Process(MidiKey* pMidiKey) {
581     VoiceIterator itVoice = pMidiKey->pActiveVoices->first();
582     // if current key is not associated with this region, skip this key
583     if (itVoice->GetRegion()->GetParent() != pPendingRegionSuspension) return false;
584    
585     return true;
586     }
587    
588     virtual void Process(VoiceIterator& itVoice) {
589     // request a notification from disk thread side for stream deletion
590     const Stream::Handle hStream = itVoice->KillImmediately(true);
591     if (hStream != Stream::INVALID_HANDLE) { // voice actually used a stream
592     PendingStreamDeletions++;
593     }
594     //NOTE: maybe we should call FreeVoice() here, shouldn't cause a harm though I think, since the voices should be freed by RenderActiveVoices() in the render loop, they are probably just freed a bit later than they could/should be
595     }
596     };
597    
598     Pool<R*>* pRegionPool[2]; ///< Double buffered pool, used by the engine channels to keep track of regions in use.
599     int MinFadeOutSamples; ///< The number of samples needed to make an instant fade out (e.g. for voice stealing) without leading to clicks.
600     D* pDiskThread;
601    
602     int ActiveVoiceCountTemp; ///< number of currently active voices (for internal usage, will be used for incrementation)
603     VoiceIterator itLastStolenVoice; ///< Only for voice stealing: points to the last voice which was theft in current audio fragment, NULL otherwise.
604     RTList<uint>::Iterator iuiLastStolenKey; ///< Only for voice stealing: key number of last key on which the last voice was theft in current audio fragment, NULL otherwise.
605     EngineChannelBase<V, R, I>* pLastStolenChannel; ///< Only for voice stealing: points to the engine channel on which the previous voice was stolen in this audio fragment.
606     VoiceIterator itLastStolenVoiceGlobally; ///< Same as itLastStolenVoice, but engine globally
607     RTList<uint>::Iterator iuiLastStolenKeyGlobally; ///< Same as iuiLastStolenKey, but engine globally
608     RTList<Event>* pVoiceStealingQueue; ///< All voice-launching events which had to be postponed due to free voice shortage.
609     Mutex ResetInternalMutex; ///< Mutex to protect the ResetInternal function for concurrent usage (e.g. by the lscp and instrument loader threads).
610     int iMaxDiskStreams;
611    
612     /**
613     * Dispatch and handle all events in this audio fragment for the given
614     * engine channel.
615     *
616     * @param pEngineChannel - engine channel on which events should be
617     * processed
618     * @param Samples - amount of sample points to be processed in
619     * this audio fragment cycle
620     */
621     void ProcessEvents(EngineChannel* pEngineChannel, uint Samples) {
622     // get all events from the engine channels's input event queue which belong to the current fragment
623     // (these are the common events like NoteOn, NoteOff, ControlChange, etc.)
624     AbstractEngineChannel* pChannel = static_cast<AbstractEngineChannel*>(pEngineChannel);
625     pChannel->ImportEvents(Samples);
626    
627     // process events
628     {
629     RTList<Event>::Iterator itEvent = pChannel->pEvents->first();
630     RTList<Event>::Iterator end = pChannel->pEvents->end();
631     for (; itEvent != end; ++itEvent) {
632     switch (itEvent->Type) {
633     case Event::type_note_on:
634     dmsg(5,("Engine: Note on received\n"));
635     ProcessNoteOn((EngineChannel*)itEvent->pEngineChannel, itEvent);
636     break;
637     case Event::type_note_off:
638     dmsg(5,("Engine: Note off received\n"));
639     ProcessNoteOff((EngineChannel*)itEvent->pEngineChannel, itEvent);
640     break;
641     case Event::type_control_change:
642     dmsg(5,("Engine: MIDI CC received\n"));
643     ProcessControlChange((EngineChannel*)itEvent->pEngineChannel, itEvent);
644     break;
645     case Event::type_pitchbend:
646     dmsg(5,("Engine: Pitchbend received\n"));
647     ProcessPitchbend(static_cast<AbstractEngineChannel*>(itEvent->pEngineChannel), itEvent);
648     break;
649     }
650     }
651     }
652    
653     // reset voice stealing for the next engine channel (or next audio fragment)
654     itLastStolenVoice = VoiceIterator();
655     itLastStolenVoiceGlobally = VoiceIterator();
656     iuiLastStolenKey = RTList<uint>::Iterator();
657     iuiLastStolenKeyGlobally = RTList<uint>::Iterator();
658     pLastStolenChannel = NULL;
659     }
660    
661     /**
662     * Will be called by LaunchVoice() method in case there are no free
663     * voices left. This method will select and kill one old voice for
664     * voice stealing and postpone the note-on event until the selected
665     * voice actually died.
666     *
667     * @param pEngineChannel - engine channel on which this event occured on
668     * @param itNoteOnEvent - key, velocity and time stamp of the event
669     * @returns 0 on success, a value < 0 if no active voice could be picked for voice stealing
670     */
671     int StealVoice(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {
672     if (VoiceSpawnsLeft <= 0) {
673     dmsg(1,("Max. voice thefts per audio fragment reached (you may raise CONFIG_MAX_VOICES).\n"));
674     return -1;
675     }
676    
677     EngineChannelBase<V, R, I>* pEngineChn = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
678    
679     if (!pEventPool->poolIsEmpty()) {
680    
681     if(!pEngineChn->StealVoice(itNoteOnEvent, &itLastStolenVoice, &iuiLastStolenKey)) {
682     --VoiceSpawnsLeft;
683     return 0;
684     }
685    
686     // if we couldn't steal a voice from the same engine channel then
687     // steal oldest voice on the oldest key from any other engine channel
688     // (the smaller engine channel number, the higher priority)
689     EngineChannelBase<V, R, I>* pSelectedChannel;
690     int iChannelIndex;
691     VoiceIterator itSelectedVoice;
692    
693     // select engine channel
694     if (pLastStolenChannel) {
695     pSelectedChannel = pLastStolenChannel;
696     iChannelIndex = pSelectedChannel->iEngineIndexSelf;
697     } else { // pick the engine channel followed by this engine channel
698     iChannelIndex = (pEngineChn->iEngineIndexSelf + 1) % engineChannels.size();
699     pSelectedChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannelIndex]);
700     }
701    
702     // if we already stole in this fragment, try to proceed on same key
703     if (this->itLastStolenVoiceGlobally) {
704     itSelectedVoice = this->itLastStolenVoiceGlobally;
705     do {
706     ++itSelectedVoice;
707     } while (itSelectedVoice && !itSelectedVoice->IsStealable()); // proceed iterating if voice was created in this fragment cycle
708     }
709    
710     #if CONFIG_DEVMODE
711     EngineChannel* pBegin = pSelectedChannel; // to detect endless loop
712     #endif // CONFIG_DEVMODE
713    
714     // did we find a 'stealable' voice?
715     if (itSelectedVoice && itSelectedVoice->IsStealable()) {
716     // remember which voice we stole, so we can simply proceed on next voice stealing
717     this->itLastStolenVoiceGlobally = itSelectedVoice;
718     } else while (true) { // iterate through engine channels
719     // get (next) oldest key
720     RTList<uint>::Iterator iuiSelectedKey = (this->iuiLastStolenKeyGlobally) ? ++this->iuiLastStolenKeyGlobally : pSelectedChannel->pActiveKeys->first();
721     this->iuiLastStolenKeyGlobally = RTList<uint>::Iterator(); // to prevent endless loop (see line above)
722     while (iuiSelectedKey) {
723     MidiKey* pSelectedKey = &pSelectedChannel->pMIDIKeyInfo[*iuiSelectedKey];
724     itSelectedVoice = pSelectedKey->pActiveVoices->first();
725     // proceed iterating if voice was created in this fragment cycle
726     while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice;
727     // found a "stealable" voice ?
728     if (itSelectedVoice && itSelectedVoice->IsStealable()) {
729     // remember which voice on which key on which engine channel we stole, so we can simply proceed on next voice stealing
730     this->iuiLastStolenKeyGlobally = iuiSelectedKey;
731     this->itLastStolenVoiceGlobally = itSelectedVoice;
732     this->pLastStolenChannel = pSelectedChannel;
733     goto stealable_voice_found; // selection succeeded
734     }
735     ++iuiSelectedKey; // get next key on current engine channel
736     }
737     // get next engine channel
738     iChannelIndex = (iChannelIndex + 1) % engineChannels.size();
739     pSelectedChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannelIndex]);
740    
741     #if CONFIG_DEVMODE
742     if (pSelectedChannel == pBegin) {
743     dmsg(1,("FATAL ERROR: voice stealing endless loop!\n"));
744     dmsg(1,("VoiceSpawnsLeft=%d.\n", VoiceSpawnsLeft));
745     dmsg(1,("Exiting.\n"));
746     exit(-1);
747     }
748     #endif // CONFIG_DEVMODE
749     }
750    
751     // jump point if a 'stealable' voice was found
752     stealable_voice_found:
753    
754     #if CONFIG_DEVMODE
755     if (!itSelectedVoice->IsActive()) {
756     dmsg(1,("EngineBase: ERROR, tried to steal a voice which was not active !!!\n"));
757     return -1;
758     }
759     #endif // CONFIG_DEVMODE
760    
761     // now kill the selected voice
762     itSelectedVoice->Kill(itNoteOnEvent);
763    
764     --VoiceSpawnsLeft;
765    
766     return 0; // success
767     }
768     else {
769     dmsg(1,("Event pool emtpy!\n"));
770     return -1;
771     }
772     }
773    
774     void HandleInstrumentChanges() {
775     bool instrumentChanged = false;
776     for (int i = 0; i < engineChannels.size(); i++) {
777     EngineChannelBase<V, R, I>* pEngineChannel =
778     static_cast<EngineChannelBase<V, R, I>*>(engineChannels[i]);
779    
780     // as we're going to (carefully) write some status to the
781     // synchronized struct, we cast away the const
782     InstrumentChangeCmd<R, I>& cmd =
783     const_cast<InstrumentChangeCmd<R, I>&>(pEngineChannel->InstrumentChangeCommandReader.Lock());
784    
785     pEngineChannel->pRegionsInUse = cmd.pRegionsInUse;
786     pEngineChannel->pRegionsInUse->clear();
787    
788     if (cmd.bChangeInstrument) {
789     // change instrument
790     dmsg(5,("Engine: instrument change command received\n"));
791     cmd.bChangeInstrument = false;
792     pEngineChannel->pInstrument = cmd.pInstrument;
793     instrumentChanged = true;
794    
795     pEngineChannel->MarkAllActiveVoicesAsOrphans();
796     }
797     }
798    
799     if (instrumentChanged) {
800     //TODO: this is a lazy solution ATM and not safe in case somebody is currently editing the instrument we're currently switching to (we should store all suspended regions on instrument manager side and when switching to another instrument copy that list to the engine's local list of suspensions
801     ResetSuspendedRegions();
802     }
803     }
804    
805     /**
806     * Render all 'normal' voices (that is voices which were not stolen in
807     * this fragment) on the given engine channel.
808     *
809     * @param pEngineChannel - engine channel on which audio should be
810     * rendered
811     * @param Samples - amount of sample points to be rendered in
812     * this audio fragment cycle
813     */
814     void RenderActiveVoices(EngineChannel* pEngineChannel, uint Samples) {
815     #if !CONFIG_PROCESS_MUTED_CHANNELS
816     if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
817     #endif
818    
819     EngineChannelBase<V, R, I>* pChannel =
820     static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
821     pChannel->RenderActiveVoices(Samples);
822    
823     ActiveVoiceCountTemp += pEngineChannel->GetVoiceCount();
824     }
825    
826     /**
827     * Render all stolen voices (only voices which were stolen in this
828     * fragment) on the given engine channel. Stolen voices are rendered
829     * after all normal voices have been rendered; this is needed to render
830     * audio of those voices which were selected for voice stealing until
831     * the point were the stealing (that is the take over of the voice)
832     * actually happened.
833     *
834     * @param pEngineChannel - engine channel on which audio should be
835     * rendered
836     * @param Samples - amount of sample points to be rendered in
837     * this audio fragment cycle
838     */
839     void RenderStolenVoices(uint Samples) {
840     RTList<Event>::Iterator itVoiceStealEvent = pVoiceStealingQueue->first();
841     RTList<Event>::Iterator end = pVoiceStealingQueue->end();
842     for (; itVoiceStealEvent != end; ++itVoiceStealEvent) {
843     EngineChannelBase<V, R, I>* pEngineChannel =
844     static_cast<EngineChannelBase<V, R, I>*>(itVoiceStealEvent->pEngineChannel);;
845     if (!pEngineChannel->pInstrument) continue; // ignore if no instrument loaded
846     PoolVoiceIterator itNewVoice =
847     LaunchVoice(pEngineChannel, itVoiceStealEvent, itVoiceStealEvent->Param.Note.Layer, itVoiceStealEvent->Param.Note.ReleaseTrigger, false, false);
848     if (itNewVoice) {
849     itNewVoice->Render(Samples);
850     if (itNewVoice->IsActive()) { // still active
851     *(pEngineChannel->pRegionsInUse->allocAppend()) = itNewVoice->GetRegion();
852     ActiveVoiceCountTemp++;
853     pEngineChannel->SetVoiceCount(pEngineChannel->GetVoiceCount() + 1);
854    
855     if (itNewVoice->PlaybackState == Voice::playback_state_disk) {
856     if (itNewVoice->DiskStreamRef.State != Stream::state_unused) {
857     pEngineChannel->SetDiskStreamCount(pEngineChannel->GetDiskStreamCount() + 1);
858     }
859     }
860     } else { // voice reached end, is now inactive
861     pEngineChannel->FreeVoice(itNewVoice); // remove voice from the list of active voices
862     }
863     }
864     else dmsg(1,("EngineBase: ERROR, voice stealing didn't work out!\n"));
865    
866     // we need to clear the key's event list explicitly here in case key was never active
867     MidiKey* pKey = &pEngineChannel->pMIDIKeyInfo[itVoiceStealEvent->Param.Note.Key];
868     pKey->VoiceTheftsQueued--;
869     if (!pKey->Active && !pKey->VoiceTheftsQueued) pKey->pEvents->clear();
870     }
871     }
872    
873     /**
874     * Free all keys which have turned inactive in this audio fragment, from
875     * the list of active keys and clear all event lists on that engine
876     * channel.
877     *
878     * @param pEngineChannel - engine channel to cleanup
879     */
880     void PostProcess(EngineChannel* pEngineChannel) {
881     EngineChannelBase<V, R, I>* pChannel =
882     static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
883     pChannel->FreeAllInactiveKyes();
884    
885     // empty the engine channel's own event lists
886     pChannel->ClearEventLists();
887     }
888    
889 schoenebeck 2121 /**
890     * Process MIDI control change events with hard coded behavior,
891     * that is controllers whose behavior is defined independently
892     * of the actual sampler engine type and instrument.
893     *
894     * @param pEngineChannel - engine channel on which the MIDI CC event was received
895     * @param itControlChangeEvent - the actual MIDI CC event
896     */
897 iliev 2012 void ProcessHardcodedControllers (
898     EngineChannel* pEngineChannel,
899     Pool<Event>::Iterator& itControlChangeEvent
900     ) {
901     EngineChannelBase<V, R, I>* pChannel =
902     static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
903    
904     switch (itControlChangeEvent->Param.CC.Controller) {
905     case 5: { // portamento time
906     pChannel->PortamentoTime = (float) itControlChangeEvent->Param.CC.Value / 127.0f * (float) CONFIG_PORTAMENTO_TIME_MAX + (float) CONFIG_PORTAMENTO_TIME_MIN;
907     break;
908     }
909 schoenebeck 2121 case 6: { // data entry (currently only used for RPN and NRPN controllers)
910     //dmsg(1,("DATA ENTRY %d\n", itControlChangeEvent->Param.CC.Value));
911     if (pChannel->GetMidiRpnController() >= 0) { // RPN controller number was sent previously ...
912     dmsg(4,("Guess it's an RPN ...\n"));
913     if (pChannel->GetMidiRpnController() == 2) { // coarse tuning in half tones
914     int transpose = (int) itControlChangeEvent->Param.CC.Value - 64;
915     // limit to +- two octaves for now
916     transpose = RTMath::Min(transpose, 24);
917     transpose = RTMath::Max(transpose, -24);
918     pChannel->GlobalTranspose = transpose;
919     // workaround, so we won't have hanging notes
920     pChannel->ReleaseAllVoices(itControlChangeEvent);
921     }
922     // to prevent other MIDI CC #6 messages to be misenterpreted as RPN controller data
923     pChannel->ResetMidiRpnController();
924     } else if (pChannel->GetMidiNrpnController() >= 0) { // NRPN controller number was sent previously ...
925     dmsg(4,("Guess it's an NRPN ...\n"));
926     const int NrpnCtrlMSB = pChannel->GetMidiNrpnController() >> 8;
927     const int NrpnCtrlLSB = pChannel->GetMidiNrpnController() & 0xff;
928     dmsg(4,("NRPN MSB=%d LSB=%d Data=%d\n", NrpnCtrlMSB, NrpnCtrlLSB, itControlChangeEvent->Param.CC.Value));
929     switch (NrpnCtrlMSB) {
930     case 0x1a: { // volume level of note (Roland GS NRPN)
931     const uint note = NrpnCtrlLSB;
932     const uint vol = itControlChangeEvent->Param.CC.Value;
933     dmsg(4,("Note Volume NRPN received (note=%d,vol=%d).\n", note, vol));
934     if (note < 128 && vol < 128)
935     pChannel->pMIDIKeyInfo[note].Volume = VolumeCurve[vol];
936     break;
937     }
938     case 0x1c: { // panpot of note (Roland GS NRPN)
939     const uint note = NrpnCtrlLSB;
940     const uint pan = itControlChangeEvent->Param.CC.Value;
941     dmsg(4,("Note Pan NRPN received (note=%d,pan=%d).\n", note, pan));
942     if (note < 128 && pan < 128) {
943     pChannel->pMIDIKeyInfo[note].PanLeft = PanCurve[128 - pan];
944     pChannel->pMIDIKeyInfo[note].PanRight = PanCurve[pan];
945     }
946     break;
947     }
948     case 0x1d: { // reverb send of note (Roland GS NRPN)
949     const uint note = NrpnCtrlLSB;
950     const float reverb = float(itControlChangeEvent->Param.CC.Value) / 127.0f;
951     dmsg(4,("Note Reverb Send NRPN received (note=%d,send=%d).\n", note, reverb));
952     if (note < 128)
953     pChannel->pMIDIKeyInfo[note].ReverbSend = reverb;
954     break;
955     }
956     case 0x1e: { // chorus send of note (Roland GS NRPN)
957     const uint note = NrpnCtrlLSB;
958     const float chorus = float(itControlChangeEvent->Param.CC.Value) / 127.0f;
959     dmsg(4,("Note Chorus Send NRPN received (note=%d,send=%d).\n", note, chorus));
960     if (note < 128)
961     pChannel->pMIDIKeyInfo[note].ChorusSend = chorus;
962     break;
963     }
964     }
965     // to prevent other MIDI CC #6 messages to be misenterpreted as NRPN controller data
966     pChannel->ResetMidiNrpnController();
967 iliev 2012 }
968     break;
969     }
970     case 7: { // volume
971     //TODO: not sample accurate yet
972     pChannel->MidiVolume = VolumeCurve[itControlChangeEvent->Param.CC.Value];
973     pChannel->bStatusChanged = true; // engine channel status has changed, so set notify flag
974     break;
975     }
976     case 10: { // panpot
977     //TODO: not sample accurate yet
978     pChannel->iLastPanRequest = itControlChangeEvent->Param.CC.Value;
979     break;
980     }
981     case 64: { // sustain
982     if (itControlChangeEvent->Param.CC.Value >= 64 && !pChannel->SustainPedal) {
983     dmsg(4,("DAMPER (RIGHT) PEDAL DOWN\n"));
984     pChannel->SustainPedal = true;
985     pChannel->listeners.PreProcessSustainPedalDown();
986    
987     #if !CONFIG_PROCESS_MUTED_CHANNELS
988     if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
989     pChannel->listeners.PostProcessSustainPedalDown();
990     return;
991     }
992     #endif
993    
994     pChannel->ProcessSustainPedalDown(itControlChangeEvent);
995     pChannel->listeners.PostProcessSustainPedalDown();
996     }
997     if (itControlChangeEvent->Param.CC.Value < 64 && pChannel->SustainPedal) {
998     dmsg(4,("DAMPER (RIGHT) PEDAL UP\n"));
999     pChannel->SustainPedal = false;
1000     pChannel->listeners.PreProcessSustainPedalUp();
1001    
1002     #if !CONFIG_PROCESS_MUTED_CHANNELS
1003     if (pChannel->GetMute()) { // skip if sampler channel is muted
1004     pChannel->listeners.PostProcessSustainPedalUp();
1005     return;
1006     }
1007     #endif
1008    
1009     pChannel->ProcessSustainPedalUp(itControlChangeEvent);
1010     pChannel->listeners.PostProcessSustainPedalUp();
1011     }
1012     break;
1013     }
1014     case 65: { // portamento on / off
1015     const bool bPortamento = itControlChangeEvent->Param.CC.Value >= 64;
1016     if (bPortamento != pChannel->PortamentoMode)
1017     KillAllVoices(pChannel, itControlChangeEvent);
1018     pChannel->PortamentoMode = bPortamento;
1019     break;
1020     }
1021     case 66: { // sostenuto
1022     if (itControlChangeEvent->Param.CC.Value >= 64 && !pChannel->SostenutoPedal) {
1023     dmsg(4,("SOSTENUTO (CENTER) PEDAL DOWN\n"));
1024     pChannel->SostenutoPedal = true;
1025     pChannel->listeners.PreProcessSostenutoPedalDown();
1026    
1027     #if !CONFIG_PROCESS_MUTED_CHANNELS
1028     if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
1029     pChannel->listeners.PostProcessSostenutoPedalDown();
1030     return;
1031     }
1032     #endif
1033    
1034     pChannel->ProcessSostenutoPedalDown();
1035     pChannel->listeners.PostProcessSostenutoPedalDown();
1036     }
1037     if (itControlChangeEvent->Param.CC.Value < 64 && pChannel->SostenutoPedal) {
1038     dmsg(4,("SOSTENUTO (CENTER) PEDAL UP\n"));
1039     pChannel->SostenutoPedal = false;
1040     pChannel->listeners.PreProcessSostenutoPedalUp();
1041    
1042     #if !CONFIG_PROCESS_MUTED_CHANNELS
1043     if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
1044     pChannel->listeners.PostProcessSostenutoPedalUp();
1045     return;
1046     }
1047     #endif
1048    
1049     pChannel->ProcessSostenutoPedalUp(itControlChangeEvent);
1050     pChannel->listeners.PostProcessSostenutoPedalUp();
1051     }
1052     break;
1053     }
1054 schoenebeck 2121 case 98: { // NRPN controller LSB
1055     dmsg(4,("NRPN LSB %d\n", itControlChangeEvent->Param.CC.Value));
1056     pEngineChannel->SetMidiNrpnControllerLsb(itControlChangeEvent->Param.CC.Value);
1057     break;
1058     }
1059     case 99: { // NRPN controller MSB
1060     dmsg(4,("NRPN MSB %d\n", itControlChangeEvent->Param.CC.Value));
1061     pEngineChannel->SetMidiNrpnControllerMsb(itControlChangeEvent->Param.CC.Value);
1062     break;
1063     }
1064 iliev 2012 case 100: { // RPN controller LSB
1065 schoenebeck 2121 dmsg(4,("RPN LSB %d\n", itControlChangeEvent->Param.CC.Value));
1066 iliev 2012 pEngineChannel->SetMidiRpnControllerLsb(itControlChangeEvent->Param.CC.Value);
1067     break;
1068     }
1069     case 101: { // RPN controller MSB
1070 schoenebeck 2121 dmsg(4,("RPN MSB %d\n", itControlChangeEvent->Param.CC.Value));
1071 iliev 2012 pEngineChannel->SetMidiRpnControllerMsb(itControlChangeEvent->Param.CC.Value);
1072     break;
1073     }
1074    
1075    
1076     // Channel Mode Messages
1077    
1078     case 120: { // all sound off
1079     KillAllVoices(pEngineChannel, itControlChangeEvent);
1080     break;
1081     }
1082     case 121: { // reset all controllers
1083     pChannel->ResetControllers();
1084     break;
1085     }
1086     case 123: { // all notes off
1087     #if CONFIG_PROCESS_ALL_NOTES_OFF
1088     pChannel->ReleaseAllVoices(itControlChangeEvent);
1089     #endif // CONFIG_PROCESS_ALL_NOTES_OFF
1090     break;
1091     }
1092     case 126: { // mono mode on
1093     if (!pChannel->SoloMode)
1094     KillAllVoices(pEngineChannel, itControlChangeEvent);
1095     pChannel->SoloMode = true;
1096     break;
1097     }
1098     case 127: { // poly mode on
1099     if (pChannel->SoloMode)
1100     KillAllVoices(pEngineChannel, itControlChangeEvent);
1101     pChannel->SoloMode = false;
1102     break;
1103     }
1104     }
1105     }
1106    
1107     virtual D* CreateDiskThread() = 0;
1108    
1109     /**
1110     * Assigns and triggers a new voice for the respective MIDI key.
1111     *
1112     * @param pEngineChannel - engine channel on which this event occured on
1113     * @param itNoteOnEvent - key, velocity and time stamp of the event
1114     */
1115     virtual void ProcessNoteOn(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {
1116     EngineChannelBase<V, R, I>* pChannel =
1117     static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1118    
1119     //HACK: we should better add the transpose value only to the most mandatory places (like for retrieving the region and calculating the tuning), because otherwise voices will unintendedly survive when changing transpose while playing
1120     int k = itNoteOnEvent->Param.Note.Key + pChannel->GlobalTranspose;
1121     if (k < 0 || k > 127) return; //ignore keys outside the key range
1122    
1123     itNoteOnEvent->Param.Note.Key += pChannel->GlobalTranspose;
1124     int vel = itNoteOnEvent->Param.Note.Velocity;
1125    
1126     const int key = itNoteOnEvent->Param.Note.Key;
1127     MidiKey* pKey = &pChannel->pMIDIKeyInfo[key];
1128    
1129     pChannel->listeners.PreProcessNoteOn(key, vel);
1130     #if !CONFIG_PROCESS_MUTED_CHANNELS
1131     if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
1132     pChannel->listeners.PostProcessNoteOn(key, vel);
1133     return;
1134     }
1135     #endif
1136    
1137     if (!pChannel->pInstrument) {
1138     pChannel->listeners.PostProcessNoteOn(key, vel);
1139     return; // ignore if no instrument loaded
1140     }
1141    
1142     // move note on event to the key's own event list
1143     RTList<Event>::Iterator itNoteOnEventOnKeyList = itNoteOnEvent.moveToEndOf(pKey->pEvents);
1144    
1145     // if Solo Mode then kill all already active voices
1146     if (pChannel->SoloMode) {
1147     Pool<uint>::Iterator itYoungestKey = pChannel->pActiveKeys->last();
1148     if (itYoungestKey) {
1149     const int iYoungestKey = *itYoungestKey;
1150     const MidiKey* pOtherKey = &pChannel->pMIDIKeyInfo[iYoungestKey];
1151     if (pOtherKey->Active) {
1152     // get final portamento position of currently active voice
1153     if (pChannel->PortamentoMode) {
1154     VoiceIterator itVoice = pOtherKey->pActiveVoices->last();
1155     if (itVoice) itVoice->UpdatePortamentoPos(itNoteOnEventOnKeyList);
1156     }
1157     // kill all voices on the (other) key
1158     VoiceIterator itVoiceToBeKilled = pOtherKey->pActiveVoices->first();
1159     VoiceIterator end = pOtherKey->pActiveVoices->end();
1160     for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1161 persson 2115 if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))
1162 iliev 2012 itVoiceToBeKilled->Kill(itNoteOnEventOnKeyList);
1163     }
1164     }
1165     }
1166     // set this key as 'currently active solo key'
1167     pChannel->SoloKey = key;
1168     }
1169    
1170     pChannel->ProcessKeySwitchChange(key);
1171    
1172     pKey->KeyPressed = true; // the MIDI key was now pressed down
1173     pKey->Velocity = itNoteOnEventOnKeyList->Param.Note.Velocity;
1174     pKey->NoteOnTime = FrameTime + itNoteOnEventOnKeyList->FragmentPos(); // will be used to calculate note length
1175    
1176     // cancel release process of voices on this key if needed
1177     if (pKey->Active && !pChannel->SustainPedal) {
1178     RTList<Event>::Iterator itCancelReleaseEvent = pKey->pEvents->allocAppend();
1179     if (itCancelReleaseEvent) {
1180     *itCancelReleaseEvent = *itNoteOnEventOnKeyList; // copy event
1181     itCancelReleaseEvent->Type = Event::type_cancel_release; // transform event type
1182     }
1183     else dmsg(1,("Event pool emtpy!\n"));
1184     }
1185    
1186     TriggerNewVoices(pEngineChannel, itNoteOnEventOnKeyList);
1187    
1188     // if neither a voice was spawned or postponed then remove note on event from key again
1189     if (!pKey->Active && !pKey->VoiceTheftsQueued)
1190     pKey->pEvents->free(itNoteOnEventOnKeyList);
1191    
1192     if (!pChannel->SoloMode || pChannel->PortamentoPos < 0.0f) pChannel->PortamentoPos = (float) key;
1193 persson 2043 if (pKey->pRoundRobinIndex) {
1194     (*pKey->pRoundRobinIndex)++; // counter specific for the key or region
1195     pChannel->RoundRobinIndex++; // common counter for the channel
1196     }
1197 iliev 2012 pChannel->listeners.PostProcessNoteOn(key, vel);
1198     }
1199    
1200     /**
1201     * Allocate and trigger new voice(s) for the key.
1202     */
1203     virtual void TriggerNewVoices (
1204     EngineChannel* pEngineChannel,
1205     RTList<Event>::Iterator& itNoteOnEvent,
1206     bool HandleKeyGroupConflicts = true
1207     ) = 0;
1208    
1209     /**
1210     * Allocate and trigger release voice(s) for the key.
1211     */
1212     virtual void TriggerReleaseVoices (
1213     EngineChannel* pEngineChannel,
1214     RTList<Event>::Iterator& itNoteOffEvent
1215     ) = 0;
1216    
1217     /**
1218     * Releases the voices on the given key if sustain pedal is not pressed.
1219     * If sustain is pressed, the release of the note will be postponed until
1220     * sustain pedal will be released or voice turned inactive by itself (e.g.
1221     * due to completion of sample playback).
1222     *
1223     * @param pEngineChannel - engine channel on which this event occured on
1224     * @param itNoteOffEvent - key, velocity and time stamp of the event
1225     */
1226     virtual void ProcessNoteOff(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOffEvent) {
1227     EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1228    
1229     int k = itNoteOffEvent->Param.Note.Key + pChannel->GlobalTranspose;
1230     if (k < 0 || k > 127) return; //ignore keys outside the key range
1231    
1232     //HACK: we should better add the transpose value only to the most mandatory places (like for retrieving the region and calculating the tuning), because otherwise voices will unintendedly survive when changing transpose while playing
1233     itNoteOffEvent->Param.Note.Key += pChannel->GlobalTranspose;
1234     int vel = itNoteOffEvent->Param.Note.Velocity;
1235    
1236     const int iKey = itNoteOffEvent->Param.Note.Key;
1237     MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];
1238    
1239     pChannel->listeners.PreProcessNoteOff(iKey, vel);
1240    
1241     #if !CONFIG_PROCESS_MUTED_CHANNELS
1242     if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
1243     pChannel->listeners.PostProcessNoteOff(iKey, vel);
1244     return;
1245     }
1246     #endif
1247    
1248     pKey->KeyPressed = false; // the MIDI key was now released
1249    
1250     // move event to the key's own event list
1251     RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);
1252    
1253     bool bShouldRelease = pKey->Active && pChannel->ShouldReleaseVoice(itNoteOffEventOnKeyList->Param.Note.Key);
1254    
1255     // in case Solo Mode is enabled, kill all voices on this key and respawn a voice on the highest pressed key (if any)
1256     if (pChannel->SoloMode && pChannel->pInstrument) { //TODO: this feels like too much code just for handling solo mode :P
1257     bool bOtherKeysPressed = false;
1258     if (iKey == pChannel->SoloKey) {
1259     pChannel->SoloKey = -1;
1260     // if there's still a key pressed down, respawn a voice (group) on the highest key
1261     for (int i = 127; i > 0; i--) {
1262     MidiKey* pOtherKey = &pChannel->pMIDIKeyInfo[i];
1263     if (pOtherKey->KeyPressed) {
1264     bOtherKeysPressed = true;
1265     // make the other key the new 'currently active solo key'
1266     pChannel->SoloKey = i;
1267     // get final portamento position of currently active voice
1268     if (pChannel->PortamentoMode) {
1269     VoiceIterator itVoice = pKey->pActiveVoices->first();
1270     if (itVoice) itVoice->UpdatePortamentoPos(itNoteOffEventOnKeyList);
1271     }
1272     // create a pseudo note on event
1273     RTList<Event>::Iterator itPseudoNoteOnEvent = pOtherKey->pEvents->allocAppend();
1274     if (itPseudoNoteOnEvent) {
1275     // copy event
1276     *itPseudoNoteOnEvent = *itNoteOffEventOnKeyList;
1277     // transform event to a note on event
1278     itPseudoNoteOnEvent->Type = Event::type_note_on;
1279     itPseudoNoteOnEvent->Param.Note.Key = i;
1280     itPseudoNoteOnEvent->Param.Note.Velocity = pOtherKey->Velocity;
1281     // allocate and trigger new voice(s) for the other key
1282     TriggerNewVoices(pChannel, itPseudoNoteOnEvent, false);
1283     // if neither a voice was spawned or postponed then remove note on event from key again
1284     if (!pOtherKey->Active && !pOtherKey->VoiceTheftsQueued)
1285     pOtherKey->pEvents->free(itPseudoNoteOnEvent);
1286    
1287     } else dmsg(1,("Could not respawn voice, no free event left\n"));
1288     break; // done
1289     }
1290     }
1291     }
1292     if (bOtherKeysPressed) {
1293     if (pKey->Active) { // kill all voices on this key
1294     bShouldRelease = false; // no need to release, as we kill it here
1295     VoiceIterator itVoiceToBeKilled = pKey->pActiveVoices->first();
1296     VoiceIterator end = pKey->pActiveVoices->end();
1297     for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1298 persson 2115 if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))
1299 iliev 2012 itVoiceToBeKilled->Kill(itNoteOffEventOnKeyList);
1300     }
1301     }
1302     } else pChannel->PortamentoPos = -1.0f;
1303     }
1304    
1305     // if no solo mode (the usual case) or if solo mode and no other key pressed, then release voices on this key if needed
1306     if (bShouldRelease) {
1307     itNoteOffEventOnKeyList->Type = Event::type_release; // transform event type
1308    
1309     // spawn release triggered voice(s) if needed
1310     if (pKey->ReleaseTrigger && pChannel->pInstrument) {
1311     TriggerReleaseVoices(pChannel, itNoteOffEventOnKeyList);
1312     pKey->ReleaseTrigger = false;
1313     }
1314     }
1315    
1316     // if neither a voice was spawned or postponed on this key then remove note off event from key again
1317     if (!pKey->Active && !pKey->VoiceTheftsQueued)
1318     pKey->pEvents->free(itNoteOffEventOnKeyList);
1319    
1320     pChannel->listeners.PostProcessNoteOff(iKey, vel);
1321     }
1322    
1323     /**
1324     * Reset all voices and disk thread and clear input event queue and all
1325     * control and status variables. This method is protected by a mutex.
1326     */
1327     virtual void ResetInternal() {
1328     ResetInternalMutex.Lock();
1329    
1330     // make sure that the engine does not get any sysex messages
1331     // while it's reseting
1332     bool sysexDisabled = MidiInputPort::RemoveSysexListener(this);
1333     SetVoiceCount(0);
1334     ActiveVoiceCountMax = 0;
1335    
1336     // reset voice stealing parameters
1337     pVoiceStealingQueue->clear();
1338     itLastStolenVoice = VoiceIterator();
1339     itLastStolenVoiceGlobally = VoiceIterator();
1340     iuiLastStolenKey = RTList<uint>::Iterator();
1341     iuiLastStolenKeyGlobally = RTList<uint>::Iterator();
1342     pLastStolenChannel = NULL;
1343    
1344     // reset all voices
1345     for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
1346     iterVoice->Reset();
1347     }
1348     pVoicePool->clear();
1349    
1350     // reset disk thread
1351     if (pDiskThread) pDiskThread->Reset();
1352    
1353     // delete all input events
1354     pEventQueue->init();
1355     pSysexBuffer->init();
1356     if (sysexDisabled) MidiInputPort::AddSysexListener(this);
1357     ResetInternalMutex.Unlock();
1358     }
1359    
1360     /**
1361     * Kills all voices on an engine channel as soon as possible. Voices
1362     * won't get into release state, their volume level will be ramped down
1363     * as fast as possible.
1364     *
1365     * @param pEngineChannel - engine channel on which all voices should be killed
1366     * @param itKillEvent - event which caused this killing of all voices
1367     */
1368     virtual void KillAllVoices(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itKillEvent) {
1369     EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1370     int count = pChannel->KillAllVoices(itKillEvent);
1371     VoiceSpawnsLeft -= count; //FIXME: just a temporary workaround, we should check the cause in StealVoice() instead
1372     }
1373    
1374     /**
1375     * Allocates and triggers a new voice. This method will usually be
1376     * called by the ProcessNoteOn() method and by the voices itself
1377     * (e.g. to spawn further voices on the same key for layered sounds).
1378     *
1379     * @param pEngineChannel - engine channel on which this event occured on
1380     * @param itNoteOnEvent - key, velocity and time stamp of the event
1381     * @param iLayer - layer index for the new voice (optional - only
1382     * in case of layered sounds of course)
1383     * @param ReleaseTriggerVoice - if new voice is a release triggered voice
1384     * (optional, default = false)
1385     * @param VoiceStealing - if voice stealing should be performed
1386     * when there is no free voice
1387     * (optional, default = true)
1388     * @param HandleKeyGroupConflicts - if voices should be killed due to a
1389     * key group conflict
1390     * @returns pointer to new voice or NULL if there was no free voice or
1391     * if the voice wasn't triggered (for example when no region is
1392     * defined for the given key).
1393     */
1394     virtual PoolVoiceIterator LaunchVoice (
1395     EngineChannel* pEngineChannel,
1396     Pool<Event>::Iterator& itNoteOnEvent,
1397     int iLayer,
1398     bool ReleaseTriggerVoice,
1399     bool VoiceStealing,
1400     bool HandleKeyGroupConflicts
1401     ) = 0;
1402    
1403 iliev 2015 virtual int GetMinFadeOutSamples() { return MinFadeOutSamples; }
1404    
1405 iliev 2027 int InitNewVoice (
1406     EngineChannelBase<V, R, I>* pChannel,
1407     R* pRegion,
1408     Pool<Event>::Iterator& itNoteOnEvent,
1409     Voice::type_t VoiceType,
1410     int iLayer,
1411     int iKeyGroup,
1412     bool ReleaseTriggerVoice,
1413     bool VoiceStealing,
1414     typename Pool<V>::Iterator& itNewVoice
1415     ) {
1416     int key = itNoteOnEvent->Param.Note.Key;
1417     typename MidiKeyboardManager<V>::MidiKey* pKey = &pChannel->pMIDIKeyInfo[key];
1418     if (itNewVoice) {
1419     // launch the new voice
1420     if (itNewVoice->Trigger(pChannel, itNoteOnEvent, pChannel->Pitch, pRegion, VoiceType, iKeyGroup) < 0) {
1421     dmsg(4,("Voice not triggered\n"));
1422     pKey->pActiveVoices->free(itNewVoice);
1423     }
1424     else { // on success
1425     --VoiceSpawnsLeft;
1426     if (!pKey->Active) { // mark as active key
1427     pKey->Active = true;
1428     pKey->itSelf = pChannel->pActiveKeys->allocAppend();
1429     *pKey->itSelf = itNoteOnEvent->Param.Note.Key;
1430     }
1431 persson 2115 if (itNewVoice->Type & Voice::type_release_trigger_required) pKey->ReleaseTrigger = true; // mark key for the need of release triggered voice(s)
1432 iliev 2027 return 0; // success
1433     }
1434     }
1435     else if (VoiceStealing) {
1436     // try to steal one voice
1437     int result = StealVoice(pChannel, itNoteOnEvent);
1438     if (!result) { // voice stolen successfully
1439     // put note-on event into voice-stealing queue, so it will be reprocessed after killed voice died
1440     RTList<Event>::Iterator itStealEvent = pVoiceStealingQueue->allocAppend();
1441     if (itStealEvent) {
1442     *itStealEvent = *itNoteOnEvent; // copy event
1443     itStealEvent->Param.Note.Layer = iLayer;
1444     itStealEvent->Param.Note.ReleaseTrigger = ReleaseTriggerVoice;
1445     pKey->VoiceTheftsQueued++;
1446     }
1447     else dmsg(1,("Voice stealing queue full!\n"));
1448     }
1449     }
1450    
1451     return -1;
1452     }
1453    
1454 iliev 2012 private:
1455     Pool<V>* pVoicePool; ///< Contains all voices that can be activated.
1456     Pool<RR*> SuspendedRegions;
1457     Mutex SuspendedRegionsMutex;
1458     Condition SuspensionChangeOngoing;
1459     RR* pPendingRegionSuspension;
1460     RR* pPendingRegionResumption;
1461     int iPendingStreamDeletions;
1462     };
1463    
1464     template <class V, class RR, class R, class D, class IM, class I>
1465     IM EngineBase<V, RR, R, D, IM, I>::instruments;
1466    
1467     } // namespace LinuxSampler
1468    
1469     #endif /* __LS_ENGINEBASE_H__ */
1470    

  ViewVC Help
Powered by ViewVC