/[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 2244 - (hide annotations) (download) (as text)
Thu Aug 18 11:32:33 2011 UTC (12 years, 8 months ago) by iliev
File MIME type: text/x-c++hdr
File size: 79187 byte(s)
* sfz engine: use common pool of CC objects to minimize RAM usage

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 2162 * Copyright (C) 2009-2011 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 2055 iterVoice->pEG1->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     for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
349     if (!iterVoice->pDiskThread) {
350     dmsg(0,("Engine -> voice::trigger: !pDiskThread\n"));
351     exit(EXIT_FAILURE);
352     }
353     }
354     pVoicePool->clear();
355 schoenebeck 2121
356     // (re)create dedicated voice audio buffers
357     //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
358     if (pDedicatedVoiceChannelLeft) delete pDedicatedVoiceChannelLeft;
359     if (pDedicatedVoiceChannelRight) delete pDedicatedVoiceChannelRight;
360     pDedicatedVoiceChannelLeft = new AudioChannel(0, MaxSamplesPerCycle);
361     pDedicatedVoiceChannelRight = new AudioChannel(1, MaxSamplesPerCycle);
362 iliev 2012 }
363    
364     /**
365     * Similar to @c Disable() but this method additionally kills all voices
366     * and disk streams and blocks until all voices and disk streams are actually
367     * killed / deleted.
368     *
369     * @e Note: only the original calling thread is able to re-enable the
370     * engine afterwards by calling @c ResumeAll() later on!
371     */
372     virtual void SuspendAll() {
373     dmsg(2,("Engine: Suspending all ...\n"));
374     // stop the engine, so we can safely modify the engine's
375     // data structures from this foreign thread
376     DisableAndLock();
377     // we could also use the respective class member variable here,
378     // but this is probably safer and cleaner
379     int iPendingStreamDeletions = 0;
380     // kill all voices on all engine channels the *die hard* way
381     for (int iChannel = 0; iChannel < engineChannels.size(); iChannel++) {
382     EngineChannelBase<V, R, I>* pEngineChannel =
383     static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannel]);
384    
385     iPendingStreamDeletions += pEngineChannel->KillAllVoicesImmediately();
386     }
387     // wait until all streams were actually deleted by the disk thread
388     while (iPendingStreamDeletions) {
389     while (
390     iPendingStreamDeletions &&
391     pDiskThread->AskForDeletedStream() != Stream::INVALID_HANDLE
392     ) iPendingStreamDeletions--;
393     if (!iPendingStreamDeletions) break;
394     usleep(10000); // sleep for 10ms
395     }
396     dmsg(2,("EngineBase: Everything suspended.\n"));
397     }
398    
399     /**
400     * At the moment same as calling @c Enable() directly, but this might
401     * change in future, so better call this method as counterpart to
402     * @c SuspendAll() instead of @c Enable() !
403     */
404     virtual void ResumeAll() { Enable(); }
405    
406     /**
407     * Order the engine to stop rendering audio for the given region.
408     * Additionally this method will block until all voices and their disk
409     * streams associated with that region are actually killed / deleted, so
410     * one can i.e. safely modify the region with an instrument editor after
411     * returning from this method.
412     *
413     * @param pRegion - region the engine shall stop using
414     */
415     virtual void Suspend(RR* pRegion) {
416     dmsg(2,("EngineBase: Suspending Region %x ...\n",pRegion));
417     SuspendedRegionsMutex.Lock();
418     SuspensionChangeOngoing.Set(true);
419     pPendingRegionSuspension = pRegion;
420     SuspensionChangeOngoing.WaitAndUnlockIf(true);
421     SuspendedRegionsMutex.Unlock();
422     dmsg(2,("EngineBase: Region %x suspended.",pRegion));
423     }
424    
425     /**
426     * Orders the engine to resume playing back the given region, previously
427     * suspended with @c Suspend() .
428     *
429     * @param pRegion - region the engine shall be allowed to use again
430     */
431     virtual void Resume(RR* pRegion) {
432     dmsg(2,("EngineBase: Resuming Region %x ...\n",pRegion));
433     SuspendedRegionsMutex.Lock();
434     SuspensionChangeOngoing.Set(true);
435     pPendingRegionResumption = pRegion;
436     SuspensionChangeOngoing.WaitAndUnlockIf(true);
437     SuspendedRegionsMutex.Unlock();
438     dmsg(2,("EngineBase: Region %x resumed.\n",pRegion));
439     }
440    
441     virtual void ResetSuspendedRegions() {
442     SuspendedRegions.clear();
443     iPendingStreamDeletions = 0;
444     pPendingRegionSuspension = pPendingRegionResumption = NULL;
445     SuspensionChangeOngoing.Set(false);
446     }
447    
448     /**
449     * Called by the engine's (audio) thread once per cycle to process requests
450     * from the outer world to suspend or resume a given @c gig::Region .
451     */
452     virtual void ProcessSuspensionsChanges() {
453     // process request for suspending one region
454     if (pPendingRegionSuspension) {
455     // kill all voices on all engine channels that use this region
456     for (int iChannel = 0; iChannel < engineChannels.size(); iChannel++) {
457     EngineChannelBase<V, R, I>* pEngineChannel =
458     static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannel]);
459     SuspensionVoiceHandler handler(pPendingRegionSuspension);
460     pEngineChannel->ProcessActiveVoices(&handler);
461     iPendingStreamDeletions += handler.PendingStreamDeletions;
462     }
463     // make sure the region is not yet on the list
464     bool bAlreadySuspended = false;
465     RootRegionIterator iter = SuspendedRegions.first();
466     RootRegionIterator end = SuspendedRegions.end();
467     for (; iter != end; ++iter) { // iterate through all suspended regions
468     if (*iter == pPendingRegionSuspension) { // found
469     bAlreadySuspended = true;
470     dmsg(1,("EngineBase: attempt to suspend an already suspended region !!!\n"));
471     break;
472     }
473     }
474     if (!bAlreadySuspended) {
475     // put the region on the list of suspended regions
476     RootRegionIterator iter = SuspendedRegions.allocAppend();
477     if (iter) {
478     *iter = pPendingRegionSuspension;
479     } else std::cerr << "EngineBase: Could not suspend Region, list is full. This is a bug!!!\n" << std::flush;
480     }
481     // free request slot for next caller (and to make sure that
482     // we're not going to process the same request in the next cycle)
483     pPendingRegionSuspension = NULL;
484     // if no disk stream deletions are pending, awaken other side, as
485     // we're done in this case
486     if (!iPendingStreamDeletions) SuspensionChangeOngoing.Set(false);
487     }
488    
489     // process request for resuming one region
490     if (pPendingRegionResumption) {
491     // remove region from the list of suspended regions
492     RootRegionIterator iter = SuspendedRegions.first();
493     RootRegionIterator end = SuspendedRegions.end();
494     for (; iter != end; ++iter) { // iterate through all suspended regions
495     if (*iter == pPendingRegionResumption) { // found
496     SuspendedRegions.free(iter);
497     break; // done
498     }
499     }
500     // free request slot for next caller
501     pPendingRegionResumption = NULL;
502     // awake other side as we're done
503     SuspensionChangeOngoing.Set(false);
504     }
505     }
506    
507     /**
508     * Called by the engine's (audio) thread once per cycle to check if
509     * streams of voices that were killed due to suspension request have
510     * finally really been deleted by the disk thread.
511     */
512     virtual void ProcessPendingStreamDeletions() {
513     if (!iPendingStreamDeletions) return;
514     //TODO: or shall we better store a list with stream handles instead of a scalar amount of streams to be deleted? might be safer
515     while (
516     iPendingStreamDeletions &&
517     pDiskThread->AskForDeletedStream() != Stream::INVALID_HANDLE
518     ) iPendingStreamDeletions--;
519     // just for safety ...
520     while (pDiskThread->AskForDeletedStream() != Stream::INVALID_HANDLE);
521     // now that all disk streams are deleted, awake other side as
522     // we're finally done with suspending the requested region
523     if (!iPendingStreamDeletions) SuspensionChangeOngoing.Set(false);
524     }
525    
526     /**
527     * Returns @c true if the given region is currently set to be suspended
528     * from being used, @c false otherwise.
529     */
530     virtual bool RegionSuspended(RR* pRegion) {
531     if (SuspendedRegions.isEmpty()) return false;
532     //TODO: or shall we use a sorted container instead of the RTList? might be faster ... or trivial ;-)
533     RootRegionIterator iter = SuspendedRegions.first();
534     RootRegionIterator end = SuspendedRegions.end();
535     for (; iter != end; ++iter) // iterate through all suspended regions
536     if (*iter == pRegion) return true;
537     return false;
538     }
539    
540     // implementation of abstract method derived from class 'LinuxSampler::RegionPools'
541     virtual Pool<R*>* GetRegionPool(int index) {
542     if (index < 0 || index > 1) throw Exception("Index out of bounds");
543     return pRegionPool[index];
544     }
545    
546     // implementation of abstract method derived from class 'LinuxSampler::VoicePool'
547     virtual Pool<V>* GetVoicePool() { return pVoicePool; }
548    
549     D* GetDiskThread() { return pDiskThread; }
550    
551     //friend class EngineChannelBase<V, R, I>;
552    
553 persson 2127 static IM instruments;
554    
555 iliev 2012 protected:
556     class SuspensionVoiceHandler : public MidiKeyboardManager<V>::VoiceHandler {
557     public:
558     int PendingStreamDeletions;
559     RR* pPendingRegionSuspension;
560     SuspensionVoiceHandler(RR* pPendingRegionSuspension) {
561     PendingStreamDeletions = 0;
562     this->pPendingRegionSuspension = pPendingRegionSuspension;
563     }
564    
565     virtual bool Process(MidiKey* pMidiKey) {
566     VoiceIterator itVoice = pMidiKey->pActiveVoices->first();
567     // if current key is not associated with this region, skip this key
568     if (itVoice->GetRegion()->GetParent() != pPendingRegionSuspension) return false;
569    
570     return true;
571     }
572    
573     virtual void Process(VoiceIterator& itVoice) {
574     // request a notification from disk thread side for stream deletion
575     const Stream::Handle hStream = itVoice->KillImmediately(true);
576     if (hStream != Stream::INVALID_HANDLE) { // voice actually used a stream
577     PendingStreamDeletions++;
578     }
579     //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
580     }
581     };
582    
583     Pool<R*>* pRegionPool[2]; ///< Double buffered pool, used by the engine channels to keep track of regions in use.
584     int MinFadeOutSamples; ///< The number of samples needed to make an instant fade out (e.g. for voice stealing) without leading to clicks.
585     D* pDiskThread;
586    
587     int ActiveVoiceCountTemp; ///< number of currently active voices (for internal usage, will be used for incrementation)
588     VoiceIterator itLastStolenVoice; ///< Only for voice stealing: points to the last voice which was theft in current audio fragment, NULL otherwise.
589     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.
590     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.
591     VoiceIterator itLastStolenVoiceGlobally; ///< Same as itLastStolenVoice, but engine globally
592     RTList<uint>::Iterator iuiLastStolenKeyGlobally; ///< Same as iuiLastStolenKey, but engine globally
593     RTList<Event>* pVoiceStealingQueue; ///< All voice-launching events which had to be postponed due to free voice shortage.
594     Mutex ResetInternalMutex; ///< Mutex to protect the ResetInternal function for concurrent usage (e.g. by the lscp and instrument loader threads).
595     int iMaxDiskStreams;
596    
597     /**
598     * Dispatch and handle all events in this audio fragment for the given
599     * engine channel.
600     *
601     * @param pEngineChannel - engine channel on which events should be
602     * processed
603     * @param Samples - amount of sample points to be processed in
604     * this audio fragment cycle
605     */
606     void ProcessEvents(EngineChannel* pEngineChannel, uint Samples) {
607     // get all events from the engine channels's input event queue which belong to the current fragment
608     // (these are the common events like NoteOn, NoteOff, ControlChange, etc.)
609     AbstractEngineChannel* pChannel = static_cast<AbstractEngineChannel*>(pEngineChannel);
610     pChannel->ImportEvents(Samples);
611    
612     // process events
613     {
614     RTList<Event>::Iterator itEvent = pChannel->pEvents->first();
615     RTList<Event>::Iterator end = pChannel->pEvents->end();
616     for (; itEvent != end; ++itEvent) {
617     switch (itEvent->Type) {
618     case Event::type_note_on:
619     dmsg(5,("Engine: Note on received\n"));
620     ProcessNoteOn((EngineChannel*)itEvent->pEngineChannel, itEvent);
621     break;
622     case Event::type_note_off:
623     dmsg(5,("Engine: Note off received\n"));
624     ProcessNoteOff((EngineChannel*)itEvent->pEngineChannel, itEvent);
625     break;
626     case Event::type_control_change:
627     dmsg(5,("Engine: MIDI CC received\n"));
628     ProcessControlChange((EngineChannel*)itEvent->pEngineChannel, itEvent);
629     break;
630     case Event::type_pitchbend:
631     dmsg(5,("Engine: Pitchbend received\n"));
632     ProcessPitchbend(static_cast<AbstractEngineChannel*>(itEvent->pEngineChannel), itEvent);
633     break;
634     }
635     }
636     }
637    
638     // reset voice stealing for the next engine channel (or next audio fragment)
639     itLastStolenVoice = VoiceIterator();
640     itLastStolenVoiceGlobally = VoiceIterator();
641     iuiLastStolenKey = RTList<uint>::Iterator();
642     iuiLastStolenKeyGlobally = RTList<uint>::Iterator();
643     pLastStolenChannel = NULL;
644     }
645    
646     /**
647     * Will be called by LaunchVoice() method in case there are no free
648     * voices left. This method will select and kill one old voice for
649     * voice stealing and postpone the note-on event until the selected
650     * voice actually died.
651     *
652     * @param pEngineChannel - engine channel on which this event occured on
653     * @param itNoteOnEvent - key, velocity and time stamp of the event
654     * @returns 0 on success, a value < 0 if no active voice could be picked for voice stealing
655     */
656     int StealVoice(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {
657     if (VoiceSpawnsLeft <= 0) {
658     dmsg(1,("Max. voice thefts per audio fragment reached (you may raise CONFIG_MAX_VOICES).\n"));
659     return -1;
660     }
661    
662     EngineChannelBase<V, R, I>* pEngineChn = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
663    
664     if (!pEventPool->poolIsEmpty()) {
665    
666     if(!pEngineChn->StealVoice(itNoteOnEvent, &itLastStolenVoice, &iuiLastStolenKey)) {
667     --VoiceSpawnsLeft;
668     return 0;
669     }
670    
671     // if we couldn't steal a voice from the same engine channel then
672     // steal oldest voice on the oldest key from any other engine channel
673     // (the smaller engine channel number, the higher priority)
674     EngineChannelBase<V, R, I>* pSelectedChannel;
675     int iChannelIndex;
676     VoiceIterator itSelectedVoice;
677    
678     // select engine channel
679     if (pLastStolenChannel) {
680     pSelectedChannel = pLastStolenChannel;
681     iChannelIndex = pSelectedChannel->iEngineIndexSelf;
682     } else { // pick the engine channel followed by this engine channel
683     iChannelIndex = (pEngineChn->iEngineIndexSelf + 1) % engineChannels.size();
684     pSelectedChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannelIndex]);
685     }
686    
687     // if we already stole in this fragment, try to proceed on same key
688     if (this->itLastStolenVoiceGlobally) {
689     itSelectedVoice = this->itLastStolenVoiceGlobally;
690     do {
691     ++itSelectedVoice;
692     } while (itSelectedVoice && !itSelectedVoice->IsStealable()); // proceed iterating if voice was created in this fragment cycle
693     }
694    
695     #if CONFIG_DEVMODE
696     EngineChannel* pBegin = pSelectedChannel; // to detect endless loop
697     #endif // CONFIG_DEVMODE
698    
699     // did we find a 'stealable' voice?
700     if (itSelectedVoice && itSelectedVoice->IsStealable()) {
701     // remember which voice we stole, so we can simply proceed on next voice stealing
702     this->itLastStolenVoiceGlobally = itSelectedVoice;
703     } else while (true) { // iterate through engine channels
704     // get (next) oldest key
705     RTList<uint>::Iterator iuiSelectedKey = (this->iuiLastStolenKeyGlobally) ? ++this->iuiLastStolenKeyGlobally : pSelectedChannel->pActiveKeys->first();
706     this->iuiLastStolenKeyGlobally = RTList<uint>::Iterator(); // to prevent endless loop (see line above)
707     while (iuiSelectedKey) {
708     MidiKey* pSelectedKey = &pSelectedChannel->pMIDIKeyInfo[*iuiSelectedKey];
709     itSelectedVoice = pSelectedKey->pActiveVoices->first();
710     // proceed iterating if voice was created in this fragment cycle
711     while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice;
712     // found a "stealable" voice ?
713     if (itSelectedVoice && itSelectedVoice->IsStealable()) {
714     // remember which voice on which key on which engine channel we stole, so we can simply proceed on next voice stealing
715     this->iuiLastStolenKeyGlobally = iuiSelectedKey;
716     this->itLastStolenVoiceGlobally = itSelectedVoice;
717     this->pLastStolenChannel = pSelectedChannel;
718     goto stealable_voice_found; // selection succeeded
719     }
720     ++iuiSelectedKey; // get next key on current engine channel
721     }
722     // get next engine channel
723     iChannelIndex = (iChannelIndex + 1) % engineChannels.size();
724     pSelectedChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannelIndex]);
725    
726     #if CONFIG_DEVMODE
727     if (pSelectedChannel == pBegin) {
728     dmsg(1,("FATAL ERROR: voice stealing endless loop!\n"));
729     dmsg(1,("VoiceSpawnsLeft=%d.\n", VoiceSpawnsLeft));
730     dmsg(1,("Exiting.\n"));
731     exit(-1);
732     }
733     #endif // CONFIG_DEVMODE
734     }
735    
736     // jump point if a 'stealable' voice was found
737     stealable_voice_found:
738    
739     #if CONFIG_DEVMODE
740     if (!itSelectedVoice->IsActive()) {
741     dmsg(1,("EngineBase: ERROR, tried to steal a voice which was not active !!!\n"));
742     return -1;
743     }
744     #endif // CONFIG_DEVMODE
745    
746     // now kill the selected voice
747     itSelectedVoice->Kill(itNoteOnEvent);
748    
749     --VoiceSpawnsLeft;
750    
751     return 0; // success
752     }
753     else {
754     dmsg(1,("Event pool emtpy!\n"));
755     return -1;
756     }
757     }
758    
759     void HandleInstrumentChanges() {
760     bool instrumentChanged = false;
761     for (int i = 0; i < engineChannels.size(); i++) {
762     EngineChannelBase<V, R, I>* pEngineChannel =
763     static_cast<EngineChannelBase<V, R, I>*>(engineChannels[i]);
764    
765     // as we're going to (carefully) write some status to the
766     // synchronized struct, we cast away the const
767     InstrumentChangeCmd<R, I>& cmd =
768     const_cast<InstrumentChangeCmd<R, I>&>(pEngineChannel->InstrumentChangeCommandReader.Lock());
769    
770     pEngineChannel->pRegionsInUse = cmd.pRegionsInUse;
771     pEngineChannel->pRegionsInUse->clear();
772    
773     if (cmd.bChangeInstrument) {
774     // change instrument
775     dmsg(5,("Engine: instrument change command received\n"));
776     cmd.bChangeInstrument = false;
777     pEngineChannel->pInstrument = cmd.pInstrument;
778     instrumentChanged = true;
779    
780     pEngineChannel->MarkAllActiveVoicesAsOrphans();
781     }
782     }
783    
784     if (instrumentChanged) {
785     //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
786     ResetSuspendedRegions();
787     }
788     }
789    
790     /**
791     * Render all 'normal' voices (that is voices which were not stolen in
792     * this fragment) on the given engine channel.
793     *
794     * @param pEngineChannel - engine channel on which audio should be
795     * rendered
796     * @param Samples - amount of sample points to be rendered in
797     * this audio fragment cycle
798     */
799     void RenderActiveVoices(EngineChannel* pEngineChannel, uint Samples) {
800     #if !CONFIG_PROCESS_MUTED_CHANNELS
801     if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
802     #endif
803    
804     EngineChannelBase<V, R, I>* pChannel =
805     static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
806     pChannel->RenderActiveVoices(Samples);
807    
808     ActiveVoiceCountTemp += pEngineChannel->GetVoiceCount();
809     }
810    
811     /**
812     * Render all stolen voices (only voices which were stolen in this
813     * fragment) on the given engine channel. Stolen voices are rendered
814     * after all normal voices have been rendered; this is needed to render
815     * audio of those voices which were selected for voice stealing until
816     * the point were the stealing (that is the take over of the voice)
817     * actually happened.
818     *
819     * @param pEngineChannel - engine channel on which audio should be
820     * rendered
821     * @param Samples - amount of sample points to be rendered in
822     * this audio fragment cycle
823     */
824     void RenderStolenVoices(uint Samples) {
825     RTList<Event>::Iterator itVoiceStealEvent = pVoiceStealingQueue->first();
826     RTList<Event>::Iterator end = pVoiceStealingQueue->end();
827     for (; itVoiceStealEvent != end; ++itVoiceStealEvent) {
828     EngineChannelBase<V, R, I>* pEngineChannel =
829     static_cast<EngineChannelBase<V, R, I>*>(itVoiceStealEvent->pEngineChannel);;
830     if (!pEngineChannel->pInstrument) continue; // ignore if no instrument loaded
831     PoolVoiceIterator itNewVoice =
832     LaunchVoice(pEngineChannel, itVoiceStealEvent, itVoiceStealEvent->Param.Note.Layer, itVoiceStealEvent->Param.Note.ReleaseTrigger, false, false);
833     if (itNewVoice) {
834     itNewVoice->Render(Samples);
835     if (itNewVoice->IsActive()) { // still active
836     *(pEngineChannel->pRegionsInUse->allocAppend()) = itNewVoice->GetRegion();
837     ActiveVoiceCountTemp++;
838     pEngineChannel->SetVoiceCount(pEngineChannel->GetVoiceCount() + 1);
839    
840     if (itNewVoice->PlaybackState == Voice::playback_state_disk) {
841     if (itNewVoice->DiskStreamRef.State != Stream::state_unused) {
842     pEngineChannel->SetDiskStreamCount(pEngineChannel->GetDiskStreamCount() + 1);
843     }
844     }
845     } else { // voice reached end, is now inactive
846     pEngineChannel->FreeVoice(itNewVoice); // remove voice from the list of active voices
847     }
848     }
849     else dmsg(1,("EngineBase: ERROR, voice stealing didn't work out!\n"));
850    
851     // we need to clear the key's event list explicitly here in case key was never active
852     MidiKey* pKey = &pEngineChannel->pMIDIKeyInfo[itVoiceStealEvent->Param.Note.Key];
853     pKey->VoiceTheftsQueued--;
854     if (!pKey->Active && !pKey->VoiceTheftsQueued) pKey->pEvents->clear();
855     }
856     }
857    
858     /**
859     * Free all keys which have turned inactive in this audio fragment, from
860     * the list of active keys and clear all event lists on that engine
861     * channel.
862     *
863     * @param pEngineChannel - engine channel to cleanup
864     */
865     void PostProcess(EngineChannel* pEngineChannel) {
866     EngineChannelBase<V, R, I>* pChannel =
867     static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
868     pChannel->FreeAllInactiveKyes();
869    
870     // empty the engine channel's own event lists
871     pChannel->ClearEventLists();
872     }
873    
874 schoenebeck 2121 /**
875     * Process MIDI control change events with hard coded behavior,
876     * that is controllers whose behavior is defined independently
877     * of the actual sampler engine type and instrument.
878     *
879     * @param pEngineChannel - engine channel on which the MIDI CC event was received
880     * @param itControlChangeEvent - the actual MIDI CC event
881     */
882 iliev 2012 void ProcessHardcodedControllers (
883     EngineChannel* pEngineChannel,
884     Pool<Event>::Iterator& itControlChangeEvent
885     ) {
886     EngineChannelBase<V, R, I>* pChannel =
887     static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
888    
889     switch (itControlChangeEvent->Param.CC.Controller) {
890     case 5: { // portamento time
891     pChannel->PortamentoTime = (float) itControlChangeEvent->Param.CC.Value / 127.0f * (float) CONFIG_PORTAMENTO_TIME_MAX + (float) CONFIG_PORTAMENTO_TIME_MIN;
892     break;
893     }
894 schoenebeck 2121 case 6: { // data entry (currently only used for RPN and NRPN controllers)
895     //dmsg(1,("DATA ENTRY %d\n", itControlChangeEvent->Param.CC.Value));
896     if (pChannel->GetMidiRpnController() >= 0) { // RPN controller number was sent previously ...
897     dmsg(4,("Guess it's an RPN ...\n"));
898     if (pChannel->GetMidiRpnController() == 2) { // coarse tuning in half tones
899     int transpose = (int) itControlChangeEvent->Param.CC.Value - 64;
900     // limit to +- two octaves for now
901     transpose = RTMath::Min(transpose, 24);
902     transpose = RTMath::Max(transpose, -24);
903     pChannel->GlobalTranspose = transpose;
904     // workaround, so we won't have hanging notes
905     pChannel->ReleaseAllVoices(itControlChangeEvent);
906     }
907     // to prevent other MIDI CC #6 messages to be misenterpreted as RPN controller data
908     pChannel->ResetMidiRpnController();
909     } else if (pChannel->GetMidiNrpnController() >= 0) { // NRPN controller number was sent previously ...
910     dmsg(4,("Guess it's an NRPN ...\n"));
911     const int NrpnCtrlMSB = pChannel->GetMidiNrpnController() >> 8;
912     const int NrpnCtrlLSB = pChannel->GetMidiNrpnController() & 0xff;
913     dmsg(4,("NRPN MSB=%d LSB=%d Data=%d\n", NrpnCtrlMSB, NrpnCtrlLSB, itControlChangeEvent->Param.CC.Value));
914     switch (NrpnCtrlMSB) {
915     case 0x1a: { // volume level of note (Roland GS NRPN)
916     const uint note = NrpnCtrlLSB;
917     const uint vol = itControlChangeEvent->Param.CC.Value;
918     dmsg(4,("Note Volume NRPN received (note=%d,vol=%d).\n", note, vol));
919     if (note < 128 && vol < 128)
920     pChannel->pMIDIKeyInfo[note].Volume = VolumeCurve[vol];
921     break;
922     }
923     case 0x1c: { // panpot of note (Roland GS NRPN)
924     const uint note = NrpnCtrlLSB;
925     const uint pan = itControlChangeEvent->Param.CC.Value;
926     dmsg(4,("Note Pan NRPN received (note=%d,pan=%d).\n", note, pan));
927     if (note < 128 && pan < 128) {
928     pChannel->pMIDIKeyInfo[note].PanLeft = PanCurve[128 - pan];
929     pChannel->pMIDIKeyInfo[note].PanRight = PanCurve[pan];
930     }
931     break;
932     }
933     case 0x1d: { // reverb send of note (Roland GS NRPN)
934     const uint note = NrpnCtrlLSB;
935     const float reverb = float(itControlChangeEvent->Param.CC.Value) / 127.0f;
936     dmsg(4,("Note Reverb Send NRPN received (note=%d,send=%d).\n", note, reverb));
937     if (note < 128)
938     pChannel->pMIDIKeyInfo[note].ReverbSend = reverb;
939     break;
940     }
941     case 0x1e: { // chorus send of note (Roland GS NRPN)
942     const uint note = NrpnCtrlLSB;
943     const float chorus = float(itControlChangeEvent->Param.CC.Value) / 127.0f;
944     dmsg(4,("Note Chorus Send NRPN received (note=%d,send=%d).\n", note, chorus));
945     if (note < 128)
946     pChannel->pMIDIKeyInfo[note].ChorusSend = chorus;
947     break;
948     }
949     }
950     // to prevent other MIDI CC #6 messages to be misenterpreted as NRPN controller data
951     pChannel->ResetMidiNrpnController();
952 iliev 2012 }
953     break;
954     }
955     case 7: { // volume
956     //TODO: not sample accurate yet
957     pChannel->MidiVolume = VolumeCurve[itControlChangeEvent->Param.CC.Value];
958     pChannel->bStatusChanged = true; // engine channel status has changed, so set notify flag
959     break;
960     }
961     case 10: { // panpot
962     //TODO: not sample accurate yet
963     pChannel->GlobalPanLeft = PanCurve[128 - itControlChangeEvent->Param.CC.Value];
964     pChannel->GlobalPanRight = PanCurve[itControlChangeEvent->Param.CC.Value];
965     pChannel->iLastPanRequest = itControlChangeEvent->Param.CC.Value;
966     break;
967     }
968     case 64: { // sustain
969     if (itControlChangeEvent->Param.CC.Value >= 64 && !pChannel->SustainPedal) {
970     dmsg(4,("DAMPER (RIGHT) PEDAL DOWN\n"));
971     pChannel->SustainPedal = true;
972     pChannel->listeners.PreProcessSustainPedalDown();
973    
974     #if !CONFIG_PROCESS_MUTED_CHANNELS
975     if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
976     pChannel->listeners.PostProcessSustainPedalDown();
977     return;
978     }
979     #endif
980    
981     pChannel->ProcessSustainPedalDown(itControlChangeEvent);
982     pChannel->listeners.PostProcessSustainPedalDown();
983     }
984     if (itControlChangeEvent->Param.CC.Value < 64 && pChannel->SustainPedal) {
985     dmsg(4,("DAMPER (RIGHT) PEDAL UP\n"));
986     pChannel->SustainPedal = false;
987     pChannel->listeners.PreProcessSustainPedalUp();
988    
989     #if !CONFIG_PROCESS_MUTED_CHANNELS
990     if (pChannel->GetMute()) { // skip if sampler channel is muted
991     pChannel->listeners.PostProcessSustainPedalUp();
992     return;
993     }
994     #endif
995    
996     pChannel->ProcessSustainPedalUp(itControlChangeEvent);
997     pChannel->listeners.PostProcessSustainPedalUp();
998     }
999     break;
1000     }
1001     case 65: { // portamento on / off
1002     const bool bPortamento = itControlChangeEvent->Param.CC.Value >= 64;
1003     if (bPortamento != pChannel->PortamentoMode)
1004     KillAllVoices(pChannel, itControlChangeEvent);
1005     pChannel->PortamentoMode = bPortamento;
1006     break;
1007     }
1008     case 66: { // sostenuto
1009     if (itControlChangeEvent->Param.CC.Value >= 64 && !pChannel->SostenutoPedal) {
1010     dmsg(4,("SOSTENUTO (CENTER) PEDAL DOWN\n"));
1011     pChannel->SostenutoPedal = true;
1012     pChannel->listeners.PreProcessSostenutoPedalDown();
1013    
1014     #if !CONFIG_PROCESS_MUTED_CHANNELS
1015     if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
1016     pChannel->listeners.PostProcessSostenutoPedalDown();
1017     return;
1018     }
1019     #endif
1020    
1021     pChannel->ProcessSostenutoPedalDown();
1022     pChannel->listeners.PostProcessSostenutoPedalDown();
1023     }
1024     if (itControlChangeEvent->Param.CC.Value < 64 && pChannel->SostenutoPedal) {
1025     dmsg(4,("SOSTENUTO (CENTER) PEDAL UP\n"));
1026     pChannel->SostenutoPedal = false;
1027     pChannel->listeners.PreProcessSostenutoPedalUp();
1028    
1029     #if !CONFIG_PROCESS_MUTED_CHANNELS
1030     if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
1031     pChannel->listeners.PostProcessSostenutoPedalUp();
1032     return;
1033     }
1034     #endif
1035    
1036     pChannel->ProcessSostenutoPedalUp(itControlChangeEvent);
1037     pChannel->listeners.PostProcessSostenutoPedalUp();
1038     }
1039     break;
1040     }
1041 schoenebeck 2121 case 98: { // NRPN controller LSB
1042     dmsg(4,("NRPN LSB %d\n", itControlChangeEvent->Param.CC.Value));
1043     pEngineChannel->SetMidiNrpnControllerLsb(itControlChangeEvent->Param.CC.Value);
1044     break;
1045     }
1046     case 99: { // NRPN controller MSB
1047     dmsg(4,("NRPN MSB %d\n", itControlChangeEvent->Param.CC.Value));
1048     pEngineChannel->SetMidiNrpnControllerMsb(itControlChangeEvent->Param.CC.Value);
1049     break;
1050     }
1051 iliev 2012 case 100: { // RPN controller LSB
1052 schoenebeck 2121 dmsg(4,("RPN LSB %d\n", itControlChangeEvent->Param.CC.Value));
1053 iliev 2012 pEngineChannel->SetMidiRpnControllerLsb(itControlChangeEvent->Param.CC.Value);
1054     break;
1055     }
1056     case 101: { // RPN controller MSB
1057 schoenebeck 2121 dmsg(4,("RPN MSB %d\n", itControlChangeEvent->Param.CC.Value));
1058 iliev 2012 pEngineChannel->SetMidiRpnControllerMsb(itControlChangeEvent->Param.CC.Value);
1059     break;
1060     }
1061    
1062    
1063     // Channel Mode Messages
1064    
1065     case 120: { // all sound off
1066     KillAllVoices(pEngineChannel, itControlChangeEvent);
1067     break;
1068     }
1069     case 121: { // reset all controllers
1070     pChannel->ResetControllers();
1071     break;
1072     }
1073     case 123: { // all notes off
1074     #if CONFIG_PROCESS_ALL_NOTES_OFF
1075     pChannel->ReleaseAllVoices(itControlChangeEvent);
1076     #endif // CONFIG_PROCESS_ALL_NOTES_OFF
1077     break;
1078     }
1079     case 126: { // mono mode on
1080     if (!pChannel->SoloMode)
1081     KillAllVoices(pEngineChannel, itControlChangeEvent);
1082     pChannel->SoloMode = true;
1083     break;
1084     }
1085     case 127: { // poly mode on
1086     if (pChannel->SoloMode)
1087     KillAllVoices(pEngineChannel, itControlChangeEvent);
1088     pChannel->SoloMode = false;
1089     break;
1090     }
1091     }
1092     }
1093    
1094     virtual D* CreateDiskThread() = 0;
1095    
1096     /**
1097     * Assigns and triggers a new voice for the respective MIDI key.
1098     *
1099     * @param pEngineChannel - engine channel on which this event occured on
1100     * @param itNoteOnEvent - key, velocity and time stamp of the event
1101     */
1102     virtual void ProcessNoteOn(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {
1103     EngineChannelBase<V, R, I>* pChannel =
1104     static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1105    
1106     //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
1107     int k = itNoteOnEvent->Param.Note.Key + pChannel->GlobalTranspose;
1108     if (k < 0 || k > 127) return; //ignore keys outside the key range
1109    
1110     itNoteOnEvent->Param.Note.Key += pChannel->GlobalTranspose;
1111     int vel = itNoteOnEvent->Param.Note.Velocity;
1112    
1113     const int key = itNoteOnEvent->Param.Note.Key;
1114     MidiKey* pKey = &pChannel->pMIDIKeyInfo[key];
1115    
1116     pChannel->listeners.PreProcessNoteOn(key, vel);
1117     #if !CONFIG_PROCESS_MUTED_CHANNELS
1118     if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
1119     pChannel->listeners.PostProcessNoteOn(key, vel);
1120     return;
1121     }
1122     #endif
1123    
1124     if (!pChannel->pInstrument) {
1125     pChannel->listeners.PostProcessNoteOn(key, vel);
1126     return; // ignore if no instrument loaded
1127     }
1128    
1129     // move note on event to the key's own event list
1130     RTList<Event>::Iterator itNoteOnEventOnKeyList = itNoteOnEvent.moveToEndOf(pKey->pEvents);
1131    
1132     // if Solo Mode then kill all already active voices
1133     if (pChannel->SoloMode) {
1134     Pool<uint>::Iterator itYoungestKey = pChannel->pActiveKeys->last();
1135     if (itYoungestKey) {
1136     const int iYoungestKey = *itYoungestKey;
1137     const MidiKey* pOtherKey = &pChannel->pMIDIKeyInfo[iYoungestKey];
1138     if (pOtherKey->Active) {
1139     // get final portamento position of currently active voice
1140     if (pChannel->PortamentoMode) {
1141     VoiceIterator itVoice = pOtherKey->pActiveVoices->last();
1142     if (itVoice) itVoice->UpdatePortamentoPos(itNoteOnEventOnKeyList);
1143     }
1144     // kill all voices on the (other) key
1145     VoiceIterator itVoiceToBeKilled = pOtherKey->pActiveVoices->first();
1146     VoiceIterator end = pOtherKey->pActiveVoices->end();
1147     for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1148 persson 2115 if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))
1149 iliev 2012 itVoiceToBeKilled->Kill(itNoteOnEventOnKeyList);
1150     }
1151     }
1152     }
1153     // set this key as 'currently active solo key'
1154     pChannel->SoloKey = key;
1155     }
1156    
1157     pChannel->ProcessKeySwitchChange(key);
1158    
1159     pKey->KeyPressed = true; // the MIDI key was now pressed down
1160     pKey->Velocity = itNoteOnEventOnKeyList->Param.Note.Velocity;
1161     pKey->NoteOnTime = FrameTime + itNoteOnEventOnKeyList->FragmentPos(); // will be used to calculate note length
1162    
1163     // cancel release process of voices on this key if needed
1164     if (pKey->Active && !pChannel->SustainPedal) {
1165     RTList<Event>::Iterator itCancelReleaseEvent = pKey->pEvents->allocAppend();
1166     if (itCancelReleaseEvent) {
1167     *itCancelReleaseEvent = *itNoteOnEventOnKeyList; // copy event
1168     itCancelReleaseEvent->Type = Event::type_cancel_release; // transform event type
1169     }
1170     else dmsg(1,("Event pool emtpy!\n"));
1171     }
1172    
1173     TriggerNewVoices(pEngineChannel, itNoteOnEventOnKeyList);
1174    
1175     // if neither a voice was spawned or postponed then remove note on event from key again
1176     if (!pKey->Active && !pKey->VoiceTheftsQueued)
1177     pKey->pEvents->free(itNoteOnEventOnKeyList);
1178    
1179     if (!pChannel->SoloMode || pChannel->PortamentoPos < 0.0f) pChannel->PortamentoPos = (float) key;
1180 persson 2043 if (pKey->pRoundRobinIndex) {
1181     (*pKey->pRoundRobinIndex)++; // counter specific for the key or region
1182     pChannel->RoundRobinIndex++; // common counter for the channel
1183     }
1184 iliev 2012 pChannel->listeners.PostProcessNoteOn(key, vel);
1185     }
1186    
1187     /**
1188     * Allocate and trigger new voice(s) for the key.
1189     */
1190     virtual void TriggerNewVoices (
1191     EngineChannel* pEngineChannel,
1192     RTList<Event>::Iterator& itNoteOnEvent,
1193     bool HandleKeyGroupConflicts = true
1194     ) = 0;
1195    
1196     /**
1197     * Allocate and trigger release voice(s) for the key.
1198     */
1199     virtual void TriggerReleaseVoices (
1200     EngineChannel* pEngineChannel,
1201     RTList<Event>::Iterator& itNoteOffEvent
1202     ) = 0;
1203    
1204     /**
1205     * Releases the voices on the given key if sustain pedal is not pressed.
1206     * If sustain is pressed, the release of the note will be postponed until
1207     * sustain pedal will be released or voice turned inactive by itself (e.g.
1208     * due to completion of sample playback).
1209     *
1210     * @param pEngineChannel - engine channel on which this event occured on
1211     * @param itNoteOffEvent - key, velocity and time stamp of the event
1212     */
1213     virtual void ProcessNoteOff(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOffEvent) {
1214     EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1215    
1216     int k = itNoteOffEvent->Param.Note.Key + pChannel->GlobalTranspose;
1217     if (k < 0 || k > 127) return; //ignore keys outside the key range
1218    
1219     //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
1220     itNoteOffEvent->Param.Note.Key += pChannel->GlobalTranspose;
1221     int vel = itNoteOffEvent->Param.Note.Velocity;
1222    
1223     const int iKey = itNoteOffEvent->Param.Note.Key;
1224     MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];
1225    
1226     pChannel->listeners.PreProcessNoteOff(iKey, vel);
1227    
1228     #if !CONFIG_PROCESS_MUTED_CHANNELS
1229     if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
1230     pChannel->listeners.PostProcessNoteOff(iKey, vel);
1231     return;
1232     }
1233     #endif
1234    
1235     pKey->KeyPressed = false; // the MIDI key was now released
1236    
1237     // move event to the key's own event list
1238     RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);
1239    
1240     bool bShouldRelease = pKey->Active && pChannel->ShouldReleaseVoice(itNoteOffEventOnKeyList->Param.Note.Key);
1241    
1242     // in case Solo Mode is enabled, kill all voices on this key and respawn a voice on the highest pressed key (if any)
1243     if (pChannel->SoloMode && pChannel->pInstrument) { //TODO: this feels like too much code just for handling solo mode :P
1244     bool bOtherKeysPressed = false;
1245     if (iKey == pChannel->SoloKey) {
1246     pChannel->SoloKey = -1;
1247     // if there's still a key pressed down, respawn a voice (group) on the highest key
1248     for (int i = 127; i > 0; i--) {
1249     MidiKey* pOtherKey = &pChannel->pMIDIKeyInfo[i];
1250     if (pOtherKey->KeyPressed) {
1251     bOtherKeysPressed = true;
1252     // make the other key the new 'currently active solo key'
1253     pChannel->SoloKey = i;
1254     // get final portamento position of currently active voice
1255     if (pChannel->PortamentoMode) {
1256     VoiceIterator itVoice = pKey->pActiveVoices->first();
1257     if (itVoice) itVoice->UpdatePortamentoPos(itNoteOffEventOnKeyList);
1258     }
1259     // create a pseudo note on event
1260     RTList<Event>::Iterator itPseudoNoteOnEvent = pOtherKey->pEvents->allocAppend();
1261     if (itPseudoNoteOnEvent) {
1262     // copy event
1263     *itPseudoNoteOnEvent = *itNoteOffEventOnKeyList;
1264     // transform event to a note on event
1265     itPseudoNoteOnEvent->Type = Event::type_note_on;
1266     itPseudoNoteOnEvent->Param.Note.Key = i;
1267     itPseudoNoteOnEvent->Param.Note.Velocity = pOtherKey->Velocity;
1268     // allocate and trigger new voice(s) for the other key
1269     TriggerNewVoices(pChannel, itPseudoNoteOnEvent, false);
1270     // if neither a voice was spawned or postponed then remove note on event from key again
1271     if (!pOtherKey->Active && !pOtherKey->VoiceTheftsQueued)
1272     pOtherKey->pEvents->free(itPseudoNoteOnEvent);
1273    
1274     } else dmsg(1,("Could not respawn voice, no free event left\n"));
1275     break; // done
1276     }
1277     }
1278     }
1279     if (bOtherKeysPressed) {
1280     if (pKey->Active) { // kill all voices on this key
1281     bShouldRelease = false; // no need to release, as we kill it here
1282     VoiceIterator itVoiceToBeKilled = pKey->pActiveVoices->first();
1283     VoiceIterator end = pKey->pActiveVoices->end();
1284     for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1285 persson 2115 if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))
1286 iliev 2012 itVoiceToBeKilled->Kill(itNoteOffEventOnKeyList);
1287     }
1288     }
1289     } else pChannel->PortamentoPos = -1.0f;
1290     }
1291    
1292     // if no solo mode (the usual case) or if solo mode and no other key pressed, then release voices on this key if needed
1293     if (bShouldRelease) {
1294     itNoteOffEventOnKeyList->Type = Event::type_release; // transform event type
1295    
1296     // spawn release triggered voice(s) if needed
1297     if (pKey->ReleaseTrigger && pChannel->pInstrument) {
1298     TriggerReleaseVoices(pChannel, itNoteOffEventOnKeyList);
1299     pKey->ReleaseTrigger = false;
1300     }
1301     }
1302    
1303     // if neither a voice was spawned or postponed on this key then remove note off event from key again
1304     if (!pKey->Active && !pKey->VoiceTheftsQueued)
1305     pKey->pEvents->free(itNoteOffEventOnKeyList);
1306    
1307     pChannel->listeners.PostProcessNoteOff(iKey, vel);
1308     }
1309    
1310     /**
1311     * Reset all voices and disk thread and clear input event queue and all
1312     * control and status variables. This method is protected by a mutex.
1313     */
1314     virtual void ResetInternal() {
1315     ResetInternalMutex.Lock();
1316    
1317     // make sure that the engine does not get any sysex messages
1318     // while it's reseting
1319     bool sysexDisabled = MidiInputPort::RemoveSysexListener(this);
1320     SetVoiceCount(0);
1321     ActiveVoiceCountMax = 0;
1322    
1323     // reset voice stealing parameters
1324     pVoiceStealingQueue->clear();
1325     itLastStolenVoice = VoiceIterator();
1326     itLastStolenVoiceGlobally = VoiceIterator();
1327     iuiLastStolenKey = RTList<uint>::Iterator();
1328     iuiLastStolenKeyGlobally = RTList<uint>::Iterator();
1329     pLastStolenChannel = NULL;
1330    
1331     // reset all voices
1332     for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
1333     iterVoice->Reset();
1334     }
1335     pVoicePool->clear();
1336    
1337     // reset disk thread
1338     if (pDiskThread) pDiskThread->Reset();
1339    
1340     // delete all input events
1341     pEventQueue->init();
1342     pSysexBuffer->init();
1343     if (sysexDisabled) MidiInputPort::AddSysexListener(this);
1344     ResetInternalMutex.Unlock();
1345     }
1346    
1347     /**
1348     * Kills all voices on an engine channel as soon as possible. Voices
1349     * won't get into release state, their volume level will be ramped down
1350     * as fast as possible.
1351     *
1352     * @param pEngineChannel - engine channel on which all voices should be killed
1353     * @param itKillEvent - event which caused this killing of all voices
1354     */
1355     virtual void KillAllVoices(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itKillEvent) {
1356     EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1357     int count = pChannel->KillAllVoices(itKillEvent);
1358     VoiceSpawnsLeft -= count; //FIXME: just a temporary workaround, we should check the cause in StealVoice() instead
1359     }
1360    
1361     /**
1362     * Allocates and triggers a new voice. This method will usually be
1363     * called by the ProcessNoteOn() method and by the voices itself
1364     * (e.g. to spawn further voices on the same key for layered sounds).
1365     *
1366     * @param pEngineChannel - engine channel on which this event occured on
1367     * @param itNoteOnEvent - key, velocity and time stamp of the event
1368     * @param iLayer - layer index for the new voice (optional - only
1369     * in case of layered sounds of course)
1370     * @param ReleaseTriggerVoice - if new voice is a release triggered voice
1371     * (optional, default = false)
1372     * @param VoiceStealing - if voice stealing should be performed
1373     * when there is no free voice
1374     * (optional, default = true)
1375     * @param HandleKeyGroupConflicts - if voices should be killed due to a
1376     * key group conflict
1377     * @returns pointer to new voice or NULL if there was no free voice or
1378     * if the voice wasn't triggered (for example when no region is
1379     * defined for the given key).
1380     */
1381     virtual PoolVoiceIterator LaunchVoice (
1382     EngineChannel* pEngineChannel,
1383     Pool<Event>::Iterator& itNoteOnEvent,
1384     int iLayer,
1385     bool ReleaseTriggerVoice,
1386     bool VoiceStealing,
1387     bool HandleKeyGroupConflicts
1388     ) = 0;
1389    
1390 iliev 2015 virtual int GetMinFadeOutSamples() { return MinFadeOutSamples; }
1391    
1392 iliev 2027 int InitNewVoice (
1393     EngineChannelBase<V, R, I>* pChannel,
1394     R* pRegion,
1395     Pool<Event>::Iterator& itNoteOnEvent,
1396     Voice::type_t VoiceType,
1397     int iLayer,
1398     int iKeyGroup,
1399     bool ReleaseTriggerVoice,
1400     bool VoiceStealing,
1401     typename Pool<V>::Iterator& itNewVoice
1402     ) {
1403     int key = itNoteOnEvent->Param.Note.Key;
1404     typename MidiKeyboardManager<V>::MidiKey* pKey = &pChannel->pMIDIKeyInfo[key];
1405     if (itNewVoice) {
1406     // launch the new voice
1407     if (itNewVoice->Trigger(pChannel, itNoteOnEvent, pChannel->Pitch, pRegion, VoiceType, iKeyGroup) < 0) {
1408     dmsg(4,("Voice not triggered\n"));
1409     pKey->pActiveVoices->free(itNewVoice);
1410     }
1411     else { // on success
1412     --VoiceSpawnsLeft;
1413     if (!pKey->Active) { // mark as active key
1414     pKey->Active = true;
1415     pKey->itSelf = pChannel->pActiveKeys->allocAppend();
1416     *pKey->itSelf = itNoteOnEvent->Param.Note.Key;
1417     }
1418 persson 2115 if (itNewVoice->Type & Voice::type_release_trigger_required) pKey->ReleaseTrigger = true; // mark key for the need of release triggered voice(s)
1419 iliev 2027 return 0; // success
1420     }
1421     }
1422     else if (VoiceStealing) {
1423     // try to steal one voice
1424     int result = StealVoice(pChannel, itNoteOnEvent);
1425     if (!result) { // voice stolen successfully
1426     // put note-on event into voice-stealing queue, so it will be reprocessed after killed voice died
1427     RTList<Event>::Iterator itStealEvent = pVoiceStealingQueue->allocAppend();
1428     if (itStealEvent) {
1429     *itStealEvent = *itNoteOnEvent; // copy event
1430     itStealEvent->Param.Note.Layer = iLayer;
1431     itStealEvent->Param.Note.ReleaseTrigger = ReleaseTriggerVoice;
1432     pKey->VoiceTheftsQueued++;
1433     }
1434     else dmsg(1,("Voice stealing queue full!\n"));
1435     }
1436     }
1437    
1438     return -1;
1439     }
1440    
1441 iliev 2012 private:
1442     Pool<V>* pVoicePool; ///< Contains all voices that can be activated.
1443     Pool<RR*> SuspendedRegions;
1444     Mutex SuspendedRegionsMutex;
1445     Condition SuspensionChangeOngoing;
1446     RR* pPendingRegionSuspension;
1447     RR* pPendingRegionResumption;
1448     int iPendingStreamDeletions;
1449     };
1450    
1451     template <class V, class RR, class R, class D, class IM, class I>
1452     IM EngineBase<V, RR, R, D, IM, I>::instruments;
1453    
1454     } // namespace LinuxSampler
1455    
1456     #endif /* __LS_ENGINEBASE_H__ */
1457    

  ViewVC Help
Powered by ViewVC