/[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 2015 - (hide annotations) (download) (as text)
Sun Oct 25 22:22:52 2009 UTC (14 years, 5 months ago) by iliev
File MIME type: text/x-c++hdr
File size: 70448 byte(s)
* Refactoring: moved the independent code from gig::Voice to base classes
* SoundFont format engine: implemented EG1 & EG2

1 iliev 2012 /***************************************************************************
2     * *
3     * LinuxSampler - modular, streaming capable sampler *
4     * *
5     * Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck *
6     * Copyright (C) 2005-2009 Christian Schoenebeck *
7     * Copyright (C) 2009 Grigor Iliev *
8     * *
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     FrameTime += Samples;
194    
195     EngineDisabled.RttDone();
196     return 0;
197     }
198    
199     virtual int MaxVoices() { return pVoicePool->poolSize(); }
200    
201     virtual void SetMaxVoices(int iVoices) throw (Exception) {
202     if (iVoices < 1)
203     throw Exception("Maximum voices for an engine cannot be set lower than 1");
204    
205     SuspendAll();
206    
207     // NOTE: we need to clear pRegionsInUse before deleting pDimRegionPool,
208     // otherwise memory corruption will occur if there are active voices (see bug #118)
209     for (int iChannel = 0; iChannel < engineChannels.size(); iChannel++) {
210     EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannel]);
211     pChannel->ClearRegionsInUse();
212     }
213    
214     if (pRegionPool[0]) delete pRegionPool[0];
215     if (pRegionPool[1]) delete pRegionPool[1];
216    
217     pRegionPool[0] = new Pool<R*>(iVoices);
218     pRegionPool[1] = new Pool<R*>(iVoices);
219    
220     for (int iChannel = 0; iChannel < engineChannels.size(); iChannel++) {
221     EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannel]);
222     pChannel->ResetRegionsInUse(pRegionPool);
223     }
224    
225     try {
226     pVoicePool->resizePool(iVoices);
227     } catch (...) {
228     throw Exception("FATAL: Could not resize voice pool!");
229     }
230    
231     for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
232     iterVoice->SetEngine(this);
233     iterVoice->pDiskThread = this->pDiskThread;
234     }
235     pVoicePool->clear();
236    
237     ResumeAll();
238     }
239    
240     virtual uint DiskStreamCount() { return (pDiskThread) ? pDiskThread->GetActiveStreamCount() : 0; }
241     virtual uint DiskStreamCountMax() { return (pDiskThread) ? pDiskThread->ActiveStreamCountMax : 0; }
242     virtual int MaxDiskStreams() { return iMaxDiskStreams; }
243    
244     virtual void SetMaxDiskStreams(int iStreams) throw (Exception) {
245     if (iStreams < 0)
246     throw Exception("Maximum disk streams for an engine cannot be set lower than 0");
247    
248     SuspendAll();
249    
250     iMaxDiskStreams = iStreams;
251    
252     // reconnect to audio output device, because that will automatically
253     // recreate the disk thread with the required amount of streams
254     if (pAudioOutputDevice) Connect(pAudioOutputDevice);
255    
256     ResumeAll();
257     }
258    
259     virtual String DiskStreamBufferFillBytes() { return (pDiskThread) ? pDiskThread->GetBufferFillBytes() : ""; }
260     virtual String DiskStreamBufferFillPercentage() { return (pDiskThread) ? pDiskThread->GetBufferFillPercentage() : ""; }
261     virtual InstrumentManager* GetInstrumentManager() { return &instruments; }
262    
263     /**
264     * Connect this engine instance with the given audio output device.
265     * This method will be called when an Engine instance is created.
266     * All of the engine's data structures which are dependant to the used
267     * audio output device / driver will be (re)allocated and / or
268     * adjusted appropriately.
269     *
270     * @param pAudioOut - audio output device to connect to
271     */
272     virtual void Connect(AudioOutputDevice* pAudioOut) {
273     // caution: don't ignore if connecting to the same device here,
274     // because otherwise SetMaxDiskStreams() implementation won't work anymore!
275    
276     pAudioOutputDevice = pAudioOut;
277    
278     ResetInternal();
279    
280     // inform audio driver for the need of two channels
281     try {
282     pAudioOutputDevice->AcquireChannels(2); // default stereo
283     }
284     catch (AudioOutputException e) {
285     String msg = "Audio output device unable to provide 2 audio channels, cause: " + e.Message();
286     throw Exception(msg);
287     }
288    
289     this->MaxSamplesPerCycle = pAudioOutputDevice->MaxSamplesPerCycle();
290     this->SampleRate = pAudioOutputDevice->SampleRate();
291    
292     MinFadeOutSamples = int(double(SampleRate) * CONFIG_EG_MIN_RELEASE_TIME) - 1;
293     if (MaxSamplesPerCycle < MinFadeOutSamples) {
294     std::cerr << "EngineBase: WARNING, CONFIG_EG_MIN_RELEASE_TIME "
295     << "too big for current audio fragment size & sampling rate! "
296     << "May lead to click sounds if voice stealing chimes in!\n" << std::flush;
297     // force volume ramp downs at the beginning of each fragment
298     MinFadeOutSamples = MaxSamplesPerCycle;
299     // lower minimum release time
300     const float minReleaseTime = (float) MaxSamplesPerCycle / (float) SampleRate;
301     for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
302     iterVoice->EG1.CalculateFadeOutCoeff(minReleaseTime, SampleRate);
303     }
304     pVoicePool->clear();
305     }
306    
307     // (re)create disk thread
308     if (this->pDiskThread) {
309     dmsg(1,("Stopping disk thread..."));
310     this->pDiskThread->StopThread();
311     delete this->pDiskThread;
312     dmsg(1,("OK\n"));
313     }
314     this->pDiskThread = CreateDiskThread();
315    
316     if (!pDiskThread) {
317     dmsg(0,("EngineBase new diskthread = NULL\n"));
318     exit(EXIT_FAILURE);
319     }
320    
321     for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
322     iterVoice->pDiskThread = this->pDiskThread;
323     dmsg(3,("d"));
324     }
325     pVoicePool->clear();
326    
327     // (re)create event generator
328     if (pEventGenerator) delete pEventGenerator;
329     pEventGenerator = new EventGenerator(pAudioOut->SampleRate());
330    
331     dmsg(1,("Starting disk thread..."));
332     pDiskThread->StartThread();
333     dmsg(1,("OK\n"));
334    
335     for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
336     if (!iterVoice->pDiskThread) {
337     dmsg(0,("Engine -> voice::trigger: !pDiskThread\n"));
338     exit(EXIT_FAILURE);
339     }
340     }
341     pVoicePool->clear();
342     }
343    
344     /**
345     * Similar to @c Disable() but this method additionally kills all voices
346     * and disk streams and blocks until all voices and disk streams are actually
347     * killed / deleted.
348     *
349     * @e Note: only the original calling thread is able to re-enable the
350     * engine afterwards by calling @c ResumeAll() later on!
351     */
352     virtual void SuspendAll() {
353     dmsg(2,("Engine: Suspending all ...\n"));
354     // stop the engine, so we can safely modify the engine's
355     // data structures from this foreign thread
356     DisableAndLock();
357     // we could also use the respective class member variable here,
358     // but this is probably safer and cleaner
359     int iPendingStreamDeletions = 0;
360     // kill all voices on all engine channels the *die hard* way
361     for (int iChannel = 0; iChannel < engineChannels.size(); iChannel++) {
362     EngineChannelBase<V, R, I>* pEngineChannel =
363     static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannel]);
364    
365     iPendingStreamDeletions += pEngineChannel->KillAllVoicesImmediately();
366     }
367     // wait until all streams were actually deleted by the disk thread
368     while (iPendingStreamDeletions) {
369     while (
370     iPendingStreamDeletions &&
371     pDiskThread->AskForDeletedStream() != Stream::INVALID_HANDLE
372     ) iPendingStreamDeletions--;
373     if (!iPendingStreamDeletions) break;
374     usleep(10000); // sleep for 10ms
375     }
376     dmsg(2,("EngineBase: Everything suspended.\n"));
377     }
378    
379     /**
380     * At the moment same as calling @c Enable() directly, but this might
381     * change in future, so better call this method as counterpart to
382     * @c SuspendAll() instead of @c Enable() !
383     */
384     virtual void ResumeAll() { Enable(); }
385    
386     /**
387     * Order the engine to stop rendering audio for the given region.
388     * Additionally this method will block until all voices and their disk
389     * streams associated with that region are actually killed / deleted, so
390     * one can i.e. safely modify the region with an instrument editor after
391     * returning from this method.
392     *
393     * @param pRegion - region the engine shall stop using
394     */
395     virtual void Suspend(RR* pRegion) {
396     dmsg(2,("EngineBase: Suspending Region %x ...\n",pRegion));
397     SuspendedRegionsMutex.Lock();
398     SuspensionChangeOngoing.Set(true);
399     pPendingRegionSuspension = pRegion;
400     SuspensionChangeOngoing.WaitAndUnlockIf(true);
401     SuspendedRegionsMutex.Unlock();
402     dmsg(2,("EngineBase: Region %x suspended.",pRegion));
403     }
404    
405     /**
406     * Orders the engine to resume playing back the given region, previously
407     * suspended with @c Suspend() .
408     *
409     * @param pRegion - region the engine shall be allowed to use again
410     */
411     virtual void Resume(RR* pRegion) {
412     dmsg(2,("EngineBase: Resuming Region %x ...\n",pRegion));
413     SuspendedRegionsMutex.Lock();
414     SuspensionChangeOngoing.Set(true);
415     pPendingRegionResumption = pRegion;
416     SuspensionChangeOngoing.WaitAndUnlockIf(true);
417     SuspendedRegionsMutex.Unlock();
418     dmsg(2,("EngineBase: Region %x resumed.\n",pRegion));
419     }
420    
421     virtual void ResetSuspendedRegions() {
422     SuspendedRegions.clear();
423     iPendingStreamDeletions = 0;
424     pPendingRegionSuspension = pPendingRegionResumption = NULL;
425     SuspensionChangeOngoing.Set(false);
426     }
427    
428     /**
429     * Called by the engine's (audio) thread once per cycle to process requests
430     * from the outer world to suspend or resume a given @c gig::Region .
431     */
432     virtual void ProcessSuspensionsChanges() {
433     // process request for suspending one region
434     if (pPendingRegionSuspension) {
435     // kill all voices on all engine channels that use this region
436     for (int iChannel = 0; iChannel < engineChannels.size(); iChannel++) {
437     EngineChannelBase<V, R, I>* pEngineChannel =
438     static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannel]);
439     SuspensionVoiceHandler handler(pPendingRegionSuspension);
440     pEngineChannel->ProcessActiveVoices(&handler);
441     iPendingStreamDeletions += handler.PendingStreamDeletions;
442     }
443     // make sure the region is not yet on the list
444     bool bAlreadySuspended = false;
445     RootRegionIterator iter = SuspendedRegions.first();
446     RootRegionIterator end = SuspendedRegions.end();
447     for (; iter != end; ++iter) { // iterate through all suspended regions
448     if (*iter == pPendingRegionSuspension) { // found
449     bAlreadySuspended = true;
450     dmsg(1,("EngineBase: attempt to suspend an already suspended region !!!\n"));
451     break;
452     }
453     }
454     if (!bAlreadySuspended) {
455     // put the region on the list of suspended regions
456     RootRegionIterator iter = SuspendedRegions.allocAppend();
457     if (iter) {
458     *iter = pPendingRegionSuspension;
459     } else std::cerr << "EngineBase: Could not suspend Region, list is full. This is a bug!!!\n" << std::flush;
460     }
461     // free request slot for next caller (and to make sure that
462     // we're not going to process the same request in the next cycle)
463     pPendingRegionSuspension = NULL;
464     // if no disk stream deletions are pending, awaken other side, as
465     // we're done in this case
466     if (!iPendingStreamDeletions) SuspensionChangeOngoing.Set(false);
467     }
468    
469     // process request for resuming one region
470     if (pPendingRegionResumption) {
471     // remove region from the list of suspended regions
472     RootRegionIterator iter = SuspendedRegions.first();
473     RootRegionIterator end = SuspendedRegions.end();
474     for (; iter != end; ++iter) { // iterate through all suspended regions
475     if (*iter == pPendingRegionResumption) { // found
476     SuspendedRegions.free(iter);
477     break; // done
478     }
479     }
480     // free request slot for next caller
481     pPendingRegionResumption = NULL;
482     // awake other side as we're done
483     SuspensionChangeOngoing.Set(false);
484     }
485     }
486    
487     /**
488     * Called by the engine's (audio) thread once per cycle to check if
489     * streams of voices that were killed due to suspension request have
490     * finally really been deleted by the disk thread.
491     */
492     virtual void ProcessPendingStreamDeletions() {
493     if (!iPendingStreamDeletions) return;
494     //TODO: or shall we better store a list with stream handles instead of a scalar amount of streams to be deleted? might be safer
495     while (
496     iPendingStreamDeletions &&
497     pDiskThread->AskForDeletedStream() != Stream::INVALID_HANDLE
498     ) iPendingStreamDeletions--;
499     // just for safety ...
500     while (pDiskThread->AskForDeletedStream() != Stream::INVALID_HANDLE);
501     // now that all disk streams are deleted, awake other side as
502     // we're finally done with suspending the requested region
503     if (!iPendingStreamDeletions) SuspensionChangeOngoing.Set(false);
504     }
505    
506     /**
507     * Returns @c true if the given region is currently set to be suspended
508     * from being used, @c false otherwise.
509     */
510     virtual bool RegionSuspended(RR* pRegion) {
511     if (SuspendedRegions.isEmpty()) return false;
512     //TODO: or shall we use a sorted container instead of the RTList? might be faster ... or trivial ;-)
513     RootRegionIterator iter = SuspendedRegions.first();
514     RootRegionIterator end = SuspendedRegions.end();
515     for (; iter != end; ++iter) // iterate through all suspended regions
516     if (*iter == pRegion) return true;
517     return false;
518     }
519    
520     // implementation of abstract method derived from class 'LinuxSampler::RegionPools'
521     virtual Pool<R*>* GetRegionPool(int index) {
522     if (index < 0 || index > 1) throw Exception("Index out of bounds");
523     return pRegionPool[index];
524     }
525    
526     // implementation of abstract method derived from class 'LinuxSampler::VoicePool'
527     virtual Pool<V>* GetVoicePool() { return pVoicePool; }
528    
529     D* GetDiskThread() { return pDiskThread; }
530    
531     //friend class EngineChannelBase<V, R, I>;
532    
533     protected:
534     class SuspensionVoiceHandler : public MidiKeyboardManager<V>::VoiceHandler {
535     public:
536     int PendingStreamDeletions;
537     RR* pPendingRegionSuspension;
538     SuspensionVoiceHandler(RR* pPendingRegionSuspension) {
539     PendingStreamDeletions = 0;
540     this->pPendingRegionSuspension = pPendingRegionSuspension;
541     }
542    
543     virtual bool Process(MidiKey* pMidiKey) {
544     VoiceIterator itVoice = pMidiKey->pActiveVoices->first();
545     // if current key is not associated with this region, skip this key
546     if (itVoice->GetRegion()->GetParent() != pPendingRegionSuspension) return false;
547    
548     return true;
549     }
550    
551     virtual void Process(VoiceIterator& itVoice) {
552     // request a notification from disk thread side for stream deletion
553     const Stream::Handle hStream = itVoice->KillImmediately(true);
554     if (hStream != Stream::INVALID_HANDLE) { // voice actually used a stream
555     PendingStreamDeletions++;
556     }
557     //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
558     }
559     };
560    
561     static IM instruments;
562    
563     Pool<R*>* pRegionPool[2]; ///< Double buffered pool, used by the engine channels to keep track of regions in use.
564     int MinFadeOutSamples; ///< The number of samples needed to make an instant fade out (e.g. for voice stealing) without leading to clicks.
565     D* pDiskThread;
566    
567     int VoiceSpawnsLeft; ///< We only allow CONFIG_MAX_VOICES voices to be spawned per audio fragment, we use this variable to ensure this limit.
568     int ActiveVoiceCountTemp; ///< number of currently active voices (for internal usage, will be used for incrementation)
569     VoiceIterator itLastStolenVoice; ///< Only for voice stealing: points to the last voice which was theft in current audio fragment, NULL otherwise.
570     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.
571     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.
572     VoiceIterator itLastStolenVoiceGlobally; ///< Same as itLastStolenVoice, but engine globally
573     RTList<uint>::Iterator iuiLastStolenKeyGlobally; ///< Same as iuiLastStolenKey, but engine globally
574     RTList<Event>* pVoiceStealingQueue; ///< All voice-launching events which had to be postponed due to free voice shortage.
575     Mutex ResetInternalMutex; ///< Mutex to protect the ResetInternal function for concurrent usage (e.g. by the lscp and instrument loader threads).
576     int iMaxDiskStreams;
577    
578     /**
579     * Dispatch and handle all events in this audio fragment for the given
580     * engine channel.
581     *
582     * @param pEngineChannel - engine channel on which events should be
583     * processed
584     * @param Samples - amount of sample points to be processed in
585     * this audio fragment cycle
586     */
587     void ProcessEvents(EngineChannel* pEngineChannel, uint Samples) {
588     // get all events from the engine channels's input event queue which belong to the current fragment
589     // (these are the common events like NoteOn, NoteOff, ControlChange, etc.)
590     AbstractEngineChannel* pChannel = static_cast<AbstractEngineChannel*>(pEngineChannel);
591     pChannel->ImportEvents(Samples);
592    
593     // process events
594     {
595     RTList<Event>::Iterator itEvent = pChannel->pEvents->first();
596     RTList<Event>::Iterator end = pChannel->pEvents->end();
597     for (; itEvent != end; ++itEvent) {
598     switch (itEvent->Type) {
599     case Event::type_note_on:
600     dmsg(5,("Engine: Note on received\n"));
601     ProcessNoteOn((EngineChannel*)itEvent->pEngineChannel, itEvent);
602     break;
603     case Event::type_note_off:
604     dmsg(5,("Engine: Note off received\n"));
605     ProcessNoteOff((EngineChannel*)itEvent->pEngineChannel, itEvent);
606     break;
607     case Event::type_control_change:
608     dmsg(5,("Engine: MIDI CC received\n"));
609     ProcessControlChange((EngineChannel*)itEvent->pEngineChannel, itEvent);
610     break;
611     case Event::type_pitchbend:
612     dmsg(5,("Engine: Pitchbend received\n"));
613     ProcessPitchbend(static_cast<AbstractEngineChannel*>(itEvent->pEngineChannel), itEvent);
614     break;
615     }
616     }
617     }
618    
619     // reset voice stealing for the next engine channel (or next audio fragment)
620     itLastStolenVoice = VoiceIterator();
621     itLastStolenVoiceGlobally = VoiceIterator();
622     iuiLastStolenKey = RTList<uint>::Iterator();
623     iuiLastStolenKeyGlobally = RTList<uint>::Iterator();
624     pLastStolenChannel = NULL;
625     }
626    
627     /**
628     * Will be called by LaunchVoice() method in case there are no free
629     * voices left. This method will select and kill one old voice for
630     * voice stealing and postpone the note-on event until the selected
631     * voice actually died.
632     *
633     * @param pEngineChannel - engine channel on which this event occured on
634     * @param itNoteOnEvent - key, velocity and time stamp of the event
635     * @returns 0 on success, a value < 0 if no active voice could be picked for voice stealing
636     */
637     int StealVoice(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {
638     if (VoiceSpawnsLeft <= 0) {
639     dmsg(1,("Max. voice thefts per audio fragment reached (you may raise CONFIG_MAX_VOICES).\n"));
640     return -1;
641     }
642    
643     EngineChannelBase<V, R, I>* pEngineChn = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
644    
645     if (!pEventPool->poolIsEmpty()) {
646    
647     if(!pEngineChn->StealVoice(itNoteOnEvent, &itLastStolenVoice, &iuiLastStolenKey)) {
648     --VoiceSpawnsLeft;
649     return 0;
650     }
651    
652     // if we couldn't steal a voice from the same engine channel then
653     // steal oldest voice on the oldest key from any other engine channel
654     // (the smaller engine channel number, the higher priority)
655     EngineChannelBase<V, R, I>* pSelectedChannel;
656     int iChannelIndex;
657     VoiceIterator itSelectedVoice;
658    
659     // select engine channel
660     if (pLastStolenChannel) {
661     pSelectedChannel = pLastStolenChannel;
662     iChannelIndex = pSelectedChannel->iEngineIndexSelf;
663     } else { // pick the engine channel followed by this engine channel
664     iChannelIndex = (pEngineChn->iEngineIndexSelf + 1) % engineChannels.size();
665     pSelectedChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannelIndex]);
666     }
667    
668     // if we already stole in this fragment, try to proceed on same key
669     if (this->itLastStolenVoiceGlobally) {
670     itSelectedVoice = this->itLastStolenVoiceGlobally;
671     do {
672     ++itSelectedVoice;
673     } while (itSelectedVoice && !itSelectedVoice->IsStealable()); // proceed iterating if voice was created in this fragment cycle
674     }
675    
676     #if CONFIG_DEVMODE
677     EngineChannel* pBegin = pSelectedChannel; // to detect endless loop
678     #endif // CONFIG_DEVMODE
679    
680     // did we find a 'stealable' voice?
681     if (itSelectedVoice && itSelectedVoice->IsStealable()) {
682     // remember which voice we stole, so we can simply proceed on next voice stealing
683     this->itLastStolenVoiceGlobally = itSelectedVoice;
684     } else while (true) { // iterate through engine channels
685     // get (next) oldest key
686     RTList<uint>::Iterator iuiSelectedKey = (this->iuiLastStolenKeyGlobally) ? ++this->iuiLastStolenKeyGlobally : pSelectedChannel->pActiveKeys->first();
687     this->iuiLastStolenKeyGlobally = RTList<uint>::Iterator(); // to prevent endless loop (see line above)
688     while (iuiSelectedKey) {
689     MidiKey* pSelectedKey = &pSelectedChannel->pMIDIKeyInfo[*iuiSelectedKey];
690     itSelectedVoice = pSelectedKey->pActiveVoices->first();
691     // proceed iterating if voice was created in this fragment cycle
692     while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice;
693     // found a "stealable" voice ?
694     if (itSelectedVoice && itSelectedVoice->IsStealable()) {
695     // remember which voice on which key on which engine channel we stole, so we can simply proceed on next voice stealing
696     this->iuiLastStolenKeyGlobally = iuiSelectedKey;
697     this->itLastStolenVoiceGlobally = itSelectedVoice;
698     this->pLastStolenChannel = pSelectedChannel;
699     goto stealable_voice_found; // selection succeeded
700     }
701     ++iuiSelectedKey; // get next key on current engine channel
702     }
703     // get next engine channel
704     iChannelIndex = (iChannelIndex + 1) % engineChannels.size();
705     pSelectedChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannelIndex]);
706    
707     #if CONFIG_DEVMODE
708     if (pSelectedChannel == pBegin) {
709     dmsg(1,("FATAL ERROR: voice stealing endless loop!\n"));
710     dmsg(1,("VoiceSpawnsLeft=%d.\n", VoiceSpawnsLeft));
711     dmsg(1,("Exiting.\n"));
712     exit(-1);
713     }
714     #endif // CONFIG_DEVMODE
715     }
716    
717     // jump point if a 'stealable' voice was found
718     stealable_voice_found:
719    
720     #if CONFIG_DEVMODE
721     if (!itSelectedVoice->IsActive()) {
722     dmsg(1,("EngineBase: ERROR, tried to steal a voice which was not active !!!\n"));
723     return -1;
724     }
725     #endif // CONFIG_DEVMODE
726    
727     // now kill the selected voice
728     itSelectedVoice->Kill(itNoteOnEvent);
729    
730     --VoiceSpawnsLeft;
731    
732     return 0; // success
733     }
734     else {
735     dmsg(1,("Event pool emtpy!\n"));
736     return -1;
737     }
738     }
739    
740     void HandleInstrumentChanges() {
741     bool instrumentChanged = false;
742     for (int i = 0; i < engineChannels.size(); i++) {
743     EngineChannelBase<V, R, I>* pEngineChannel =
744     static_cast<EngineChannelBase<V, R, I>*>(engineChannels[i]);
745    
746     // as we're going to (carefully) write some status to the
747     // synchronized struct, we cast away the const
748     InstrumentChangeCmd<R, I>& cmd =
749     const_cast<InstrumentChangeCmd<R, I>&>(pEngineChannel->InstrumentChangeCommandReader.Lock());
750    
751     pEngineChannel->pRegionsInUse = cmd.pRegionsInUse;
752     pEngineChannel->pRegionsInUse->clear();
753    
754     if (cmd.bChangeInstrument) {
755     // change instrument
756     dmsg(5,("Engine: instrument change command received\n"));
757     cmd.bChangeInstrument = false;
758     pEngineChannel->pInstrument = cmd.pInstrument;
759     instrumentChanged = true;
760    
761     pEngineChannel->MarkAllActiveVoicesAsOrphans();
762     }
763     }
764    
765     if (instrumentChanged) {
766     //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
767     ResetSuspendedRegions();
768     }
769    
770     for (int i = 0; i < engineChannels.size(); i++) {
771     EngineChannelBase<V, R, I>* channel =
772     static_cast<EngineChannelBase<V, R, I>*>(engineChannels[i]);
773     channel->InstrumentChangeCommandReader.Unlock();
774     }
775     }
776    
777     /**
778     * Render all 'normal' voices (that is voices which were not stolen in
779     * this fragment) on the given engine channel.
780     *
781     * @param pEngineChannel - engine channel on which audio should be
782     * rendered
783     * @param Samples - amount of sample points to be rendered in
784     * this audio fragment cycle
785     */
786     void RenderActiveVoices(EngineChannel* pEngineChannel, uint Samples) {
787     #if !CONFIG_PROCESS_MUTED_CHANNELS
788     if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
789     #endif
790    
791     EngineChannelBase<V, R, I>* pChannel =
792     static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
793     pChannel->RenderActiveVoices(Samples);
794    
795     ActiveVoiceCountTemp += pEngineChannel->GetVoiceCount();
796     }
797    
798     /**
799     * Render all stolen voices (only voices which were stolen in this
800     * fragment) on the given engine channel. Stolen voices are rendered
801     * after all normal voices have been rendered; this is needed to render
802     * audio of those voices which were selected for voice stealing until
803     * the point were the stealing (that is the take over of the voice)
804     * actually happened.
805     *
806     * @param pEngineChannel - engine channel on which audio should be
807     * rendered
808     * @param Samples - amount of sample points to be rendered in
809     * this audio fragment cycle
810     */
811     void RenderStolenVoices(uint Samples) {
812     RTList<Event>::Iterator itVoiceStealEvent = pVoiceStealingQueue->first();
813     RTList<Event>::Iterator end = pVoiceStealingQueue->end();
814     for (; itVoiceStealEvent != end; ++itVoiceStealEvent) {
815     EngineChannelBase<V, R, I>* pEngineChannel =
816     static_cast<EngineChannelBase<V, R, I>*>(itVoiceStealEvent->pEngineChannel);;
817     if (!pEngineChannel->pInstrument) continue; // ignore if no instrument loaded
818     PoolVoiceIterator itNewVoice =
819     LaunchVoice(pEngineChannel, itVoiceStealEvent, itVoiceStealEvent->Param.Note.Layer, itVoiceStealEvent->Param.Note.ReleaseTrigger, false, false);
820     if (itNewVoice) {
821     itNewVoice->Render(Samples);
822     if (itNewVoice->IsActive()) { // still active
823     *(pEngineChannel->pRegionsInUse->allocAppend()) = itNewVoice->GetRegion();
824     ActiveVoiceCountTemp++;
825     pEngineChannel->SetVoiceCount(pEngineChannel->GetVoiceCount() + 1);
826    
827     if (itNewVoice->PlaybackState == Voice::playback_state_disk) {
828     if (itNewVoice->DiskStreamRef.State != Stream::state_unused) {
829     pEngineChannel->SetDiskStreamCount(pEngineChannel->GetDiskStreamCount() + 1);
830     }
831     }
832     } else { // voice reached end, is now inactive
833     pEngineChannel->FreeVoice(itNewVoice); // remove voice from the list of active voices
834     }
835     }
836     else dmsg(1,("EngineBase: ERROR, voice stealing didn't work out!\n"));
837    
838     // we need to clear the key's event list explicitly here in case key was never active
839     MidiKey* pKey = &pEngineChannel->pMIDIKeyInfo[itVoiceStealEvent->Param.Note.Key];
840     pKey->VoiceTheftsQueued--;
841     if (!pKey->Active && !pKey->VoiceTheftsQueued) pKey->pEvents->clear();
842     }
843     }
844    
845     /**
846     * Free all keys which have turned inactive in this audio fragment, from
847     * the list of active keys and clear all event lists on that engine
848     * channel.
849     *
850     * @param pEngineChannel - engine channel to cleanup
851     */
852     void PostProcess(EngineChannel* pEngineChannel) {
853     EngineChannelBase<V, R, I>* pChannel =
854     static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
855     pChannel->FreeAllInactiveKyes();
856    
857     // empty the engine channel's own event lists
858     pChannel->ClearEventLists();
859     }
860    
861     void ProcessHardcodedControllers (
862     EngineChannel* pEngineChannel,
863     Pool<Event>::Iterator& itControlChangeEvent
864     ) {
865     EngineChannelBase<V, R, I>* pChannel =
866     static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
867    
868     switch (itControlChangeEvent->Param.CC.Controller) {
869     case 5: { // portamento time
870     pChannel->PortamentoTime = (float) itControlChangeEvent->Param.CC.Value / 127.0f * (float) CONFIG_PORTAMENTO_TIME_MAX + (float) CONFIG_PORTAMENTO_TIME_MIN;
871     break;
872     }
873     case 6: { // data entry (currently only used for RPN controllers)
874     if (pChannel->GetMidiRpnController() == 2) { // coarse tuning in half tones
875     int transpose = (int) itControlChangeEvent->Param.CC.Value - 64;
876     // limit to +- two octaves for now
877     transpose = RTMath::Min(transpose, 24);
878     transpose = RTMath::Max(transpose, -24);
879     pChannel->GlobalTranspose = transpose;
880     // workaround, so we won't have hanging notes
881     pChannel->ReleaseAllVoices(itControlChangeEvent);
882     }
883     // to avoid other MIDI CC #6 messages to be misenterpreted as RPN controller data
884     pChannel->ResetMidiRpnController();
885     break;
886     }
887     case 7: { // volume
888     //TODO: not sample accurate yet
889     pChannel->MidiVolume = VolumeCurve[itControlChangeEvent->Param.CC.Value];
890     pChannel->bStatusChanged = true; // engine channel status has changed, so set notify flag
891     break;
892     }
893     case 10: { // panpot
894     //TODO: not sample accurate yet
895     pChannel->GlobalPanLeft = PanCurve[128 - itControlChangeEvent->Param.CC.Value];
896     pChannel->GlobalPanRight = PanCurve[itControlChangeEvent->Param.CC.Value];
897     pChannel->iLastPanRequest = itControlChangeEvent->Param.CC.Value;
898     break;
899     }
900     case 64: { // sustain
901     if (itControlChangeEvent->Param.CC.Value >= 64 && !pChannel->SustainPedal) {
902     dmsg(4,("DAMPER (RIGHT) PEDAL DOWN\n"));
903     pChannel->SustainPedal = true;
904     pChannel->listeners.PreProcessSustainPedalDown();
905    
906     #if !CONFIG_PROCESS_MUTED_CHANNELS
907     if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
908     pChannel->listeners.PostProcessSustainPedalDown();
909     return;
910     }
911     #endif
912    
913     pChannel->ProcessSustainPedalDown(itControlChangeEvent);
914     pChannel->listeners.PostProcessSustainPedalDown();
915     }
916     if (itControlChangeEvent->Param.CC.Value < 64 && pChannel->SustainPedal) {
917     dmsg(4,("DAMPER (RIGHT) PEDAL UP\n"));
918     pChannel->SustainPedal = false;
919     pChannel->listeners.PreProcessSustainPedalUp();
920    
921     #if !CONFIG_PROCESS_MUTED_CHANNELS
922     if (pChannel->GetMute()) { // skip if sampler channel is muted
923     pChannel->listeners.PostProcessSustainPedalUp();
924     return;
925     }
926     #endif
927    
928     pChannel->ProcessSustainPedalUp(itControlChangeEvent);
929     pChannel->listeners.PostProcessSustainPedalUp();
930     }
931     break;
932     }
933     case 65: { // portamento on / off
934     const bool bPortamento = itControlChangeEvent->Param.CC.Value >= 64;
935     if (bPortamento != pChannel->PortamentoMode)
936     KillAllVoices(pChannel, itControlChangeEvent);
937     pChannel->PortamentoMode = bPortamento;
938     break;
939     }
940     case 66: { // sostenuto
941     if (itControlChangeEvent->Param.CC.Value >= 64 && !pChannel->SostenutoPedal) {
942     dmsg(4,("SOSTENUTO (CENTER) PEDAL DOWN\n"));
943     pChannel->SostenutoPedal = true;
944     pChannel->listeners.PreProcessSostenutoPedalDown();
945    
946     #if !CONFIG_PROCESS_MUTED_CHANNELS
947     if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
948     pChannel->listeners.PostProcessSostenutoPedalDown();
949     return;
950     }
951     #endif
952    
953     pChannel->ProcessSostenutoPedalDown();
954     pChannel->listeners.PostProcessSostenutoPedalDown();
955     }
956     if (itControlChangeEvent->Param.CC.Value < 64 && pChannel->SostenutoPedal) {
957     dmsg(4,("SOSTENUTO (CENTER) PEDAL UP\n"));
958     pChannel->SostenutoPedal = false;
959     pChannel->listeners.PreProcessSostenutoPedalUp();
960    
961     #if !CONFIG_PROCESS_MUTED_CHANNELS
962     if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
963     pChannel->listeners.PostProcessSostenutoPedalUp();
964     return;
965     }
966     #endif
967    
968     pChannel->ProcessSostenutoPedalUp(itControlChangeEvent);
969     pChannel->listeners.PostProcessSostenutoPedalUp();
970     }
971     break;
972     }
973     case 100: { // RPN controller LSB
974     pEngineChannel->SetMidiRpnControllerLsb(itControlChangeEvent->Param.CC.Value);
975     break;
976     }
977     case 101: { // RPN controller MSB
978     pEngineChannel->SetMidiRpnControllerMsb(itControlChangeEvent->Param.CC.Value);
979     break;
980     }
981    
982    
983     // Channel Mode Messages
984    
985     case 120: { // all sound off
986     KillAllVoices(pEngineChannel, itControlChangeEvent);
987     break;
988     }
989     case 121: { // reset all controllers
990     pChannel->ResetControllers();
991     break;
992     }
993     case 123: { // all notes off
994     #if CONFIG_PROCESS_ALL_NOTES_OFF
995     pChannel->ReleaseAllVoices(itControlChangeEvent);
996     #endif // CONFIG_PROCESS_ALL_NOTES_OFF
997     break;
998     }
999     case 126: { // mono mode on
1000     if (!pChannel->SoloMode)
1001     KillAllVoices(pEngineChannel, itControlChangeEvent);
1002     pChannel->SoloMode = true;
1003     break;
1004     }
1005     case 127: { // poly mode on
1006     if (pChannel->SoloMode)
1007     KillAllVoices(pEngineChannel, itControlChangeEvent);
1008     pChannel->SoloMode = false;
1009     break;
1010     }
1011     }
1012     }
1013    
1014     virtual D* CreateDiskThread() = 0;
1015    
1016     /**
1017     * Assigns and triggers a new voice for the respective MIDI key.
1018     *
1019     * @param pEngineChannel - engine channel on which this event occured on
1020     * @param itNoteOnEvent - key, velocity and time stamp of the event
1021     */
1022     virtual void ProcessNoteOn(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {
1023     EngineChannelBase<V, R, I>* pChannel =
1024     static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1025    
1026     //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
1027     int k = itNoteOnEvent->Param.Note.Key + pChannel->GlobalTranspose;
1028     if (k < 0 || k > 127) return; //ignore keys outside the key range
1029    
1030     itNoteOnEvent->Param.Note.Key += pChannel->GlobalTranspose;
1031     int vel = itNoteOnEvent->Param.Note.Velocity;
1032    
1033     const int key = itNoteOnEvent->Param.Note.Key;
1034     MidiKey* pKey = &pChannel->pMIDIKeyInfo[key];
1035    
1036     pChannel->listeners.PreProcessNoteOn(key, vel);
1037     #if !CONFIG_PROCESS_MUTED_CHANNELS
1038     if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
1039     pChannel->listeners.PostProcessNoteOn(key, vel);
1040     return;
1041     }
1042     #endif
1043    
1044     if (!pChannel->pInstrument) {
1045     pChannel->listeners.PostProcessNoteOn(key, vel);
1046     return; // ignore if no instrument loaded
1047     }
1048    
1049     // move note on event to the key's own event list
1050     RTList<Event>::Iterator itNoteOnEventOnKeyList = itNoteOnEvent.moveToEndOf(pKey->pEvents);
1051    
1052     // if Solo Mode then kill all already active voices
1053     if (pChannel->SoloMode) {
1054     Pool<uint>::Iterator itYoungestKey = pChannel->pActiveKeys->last();
1055     if (itYoungestKey) {
1056     const int iYoungestKey = *itYoungestKey;
1057     const MidiKey* pOtherKey = &pChannel->pMIDIKeyInfo[iYoungestKey];
1058     if (pOtherKey->Active) {
1059     // get final portamento position of currently active voice
1060     if (pChannel->PortamentoMode) {
1061     VoiceIterator itVoice = pOtherKey->pActiveVoices->last();
1062     if (itVoice) itVoice->UpdatePortamentoPos(itNoteOnEventOnKeyList);
1063     }
1064     // kill all voices on the (other) key
1065     VoiceIterator itVoiceToBeKilled = pOtherKey->pActiveVoices->first();
1066     VoiceIterator end = pOtherKey->pActiveVoices->end();
1067     for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1068     if (itVoiceToBeKilled->Type != Voice::type_release_trigger)
1069     itVoiceToBeKilled->Kill(itNoteOnEventOnKeyList);
1070     }
1071     }
1072     }
1073     // set this key as 'currently active solo key'
1074     pChannel->SoloKey = key;
1075     }
1076    
1077     pChannel->ProcessKeySwitchChange(key);
1078    
1079     pKey->KeyPressed = true; // the MIDI key was now pressed down
1080     pKey->Velocity = itNoteOnEventOnKeyList->Param.Note.Velocity;
1081     pKey->NoteOnTime = FrameTime + itNoteOnEventOnKeyList->FragmentPos(); // will be used to calculate note length
1082    
1083     // cancel release process of voices on this key if needed
1084     if (pKey->Active && !pChannel->SustainPedal) {
1085     RTList<Event>::Iterator itCancelReleaseEvent = pKey->pEvents->allocAppend();
1086     if (itCancelReleaseEvent) {
1087     *itCancelReleaseEvent = *itNoteOnEventOnKeyList; // copy event
1088     itCancelReleaseEvent->Type = Event::type_cancel_release; // transform event type
1089     }
1090     else dmsg(1,("Event pool emtpy!\n"));
1091     }
1092    
1093     TriggerNewVoices(pEngineChannel, itNoteOnEventOnKeyList);
1094    
1095     // if neither a voice was spawned or postponed then remove note on event from key again
1096     if (!pKey->Active && !pKey->VoiceTheftsQueued)
1097     pKey->pEvents->free(itNoteOnEventOnKeyList);
1098    
1099     if (!pChannel->SoloMode || pChannel->PortamentoPos < 0.0f) pChannel->PortamentoPos = (float) key;
1100     pKey->RoundRobinIndex++;
1101     pChannel->listeners.PostProcessNoteOn(key, vel);
1102     }
1103    
1104     /**
1105     * Allocate and trigger new voice(s) for the key.
1106     */
1107     virtual void TriggerNewVoices (
1108     EngineChannel* pEngineChannel,
1109     RTList<Event>::Iterator& itNoteOnEvent,
1110     bool HandleKeyGroupConflicts = true
1111     ) = 0;
1112    
1113     /**
1114     * Allocate and trigger release voice(s) for the key.
1115     */
1116     virtual void TriggerReleaseVoices (
1117     EngineChannel* pEngineChannel,
1118     RTList<Event>::Iterator& itNoteOffEvent
1119     ) = 0;
1120    
1121     /**
1122     * Releases the voices on the given key if sustain pedal is not pressed.
1123     * If sustain is pressed, the release of the note will be postponed until
1124     * sustain pedal will be released or voice turned inactive by itself (e.g.
1125     * due to completion of sample playback).
1126     *
1127     * @param pEngineChannel - engine channel on which this event occured on
1128     * @param itNoteOffEvent - key, velocity and time stamp of the event
1129     */
1130     virtual void ProcessNoteOff(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOffEvent) {
1131     EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1132    
1133     int k = itNoteOffEvent->Param.Note.Key + pChannel->GlobalTranspose;
1134     if (k < 0 || k > 127) return; //ignore keys outside the key range
1135    
1136     //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
1137     itNoteOffEvent->Param.Note.Key += pChannel->GlobalTranspose;
1138     int vel = itNoteOffEvent->Param.Note.Velocity;
1139    
1140     const int iKey = itNoteOffEvent->Param.Note.Key;
1141     MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];
1142    
1143     pChannel->listeners.PreProcessNoteOff(iKey, vel);
1144    
1145     #if !CONFIG_PROCESS_MUTED_CHANNELS
1146     if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
1147     pChannel->listeners.PostProcessNoteOff(iKey, vel);
1148     return;
1149     }
1150     #endif
1151    
1152     pKey->KeyPressed = false; // the MIDI key was now released
1153    
1154     // move event to the key's own event list
1155     RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);
1156    
1157     bool bShouldRelease = pKey->Active && pChannel->ShouldReleaseVoice(itNoteOffEventOnKeyList->Param.Note.Key);
1158    
1159     // in case Solo Mode is enabled, kill all voices on this key and respawn a voice on the highest pressed key (if any)
1160     if (pChannel->SoloMode && pChannel->pInstrument) { //TODO: this feels like too much code just for handling solo mode :P
1161     bool bOtherKeysPressed = false;
1162     if (iKey == pChannel->SoloKey) {
1163     pChannel->SoloKey = -1;
1164     // if there's still a key pressed down, respawn a voice (group) on the highest key
1165     for (int i = 127; i > 0; i--) {
1166     MidiKey* pOtherKey = &pChannel->pMIDIKeyInfo[i];
1167     if (pOtherKey->KeyPressed) {
1168     bOtherKeysPressed = true;
1169     // make the other key the new 'currently active solo key'
1170     pChannel->SoloKey = i;
1171     // get final portamento position of currently active voice
1172     if (pChannel->PortamentoMode) {
1173     VoiceIterator itVoice = pKey->pActiveVoices->first();
1174     if (itVoice) itVoice->UpdatePortamentoPos(itNoteOffEventOnKeyList);
1175     }
1176     // create a pseudo note on event
1177     RTList<Event>::Iterator itPseudoNoteOnEvent = pOtherKey->pEvents->allocAppend();
1178     if (itPseudoNoteOnEvent) {
1179     // copy event
1180     *itPseudoNoteOnEvent = *itNoteOffEventOnKeyList;
1181     // transform event to a note on event
1182     itPseudoNoteOnEvent->Type = Event::type_note_on;
1183     itPseudoNoteOnEvent->Param.Note.Key = i;
1184     itPseudoNoteOnEvent->Param.Note.Velocity = pOtherKey->Velocity;
1185     // allocate and trigger new voice(s) for the other key
1186     TriggerNewVoices(pChannel, itPseudoNoteOnEvent, false);
1187     // if neither a voice was spawned or postponed then remove note on event from key again
1188     if (!pOtherKey->Active && !pOtherKey->VoiceTheftsQueued)
1189     pOtherKey->pEvents->free(itPseudoNoteOnEvent);
1190    
1191     } else dmsg(1,("Could not respawn voice, no free event left\n"));
1192     break; // done
1193     }
1194     }
1195     }
1196     if (bOtherKeysPressed) {
1197     if (pKey->Active) { // kill all voices on this key
1198     bShouldRelease = false; // no need to release, as we kill it here
1199     VoiceIterator itVoiceToBeKilled = pKey->pActiveVoices->first();
1200     VoiceIterator end = pKey->pActiveVoices->end();
1201     for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1202     if (itVoiceToBeKilled->Type != Voice::type_release_trigger)
1203     itVoiceToBeKilled->Kill(itNoteOffEventOnKeyList);
1204     }
1205     }
1206     } else pChannel->PortamentoPos = -1.0f;
1207     }
1208    
1209     // if no solo mode (the usual case) or if solo mode and no other key pressed, then release voices on this key if needed
1210     if (bShouldRelease) {
1211     itNoteOffEventOnKeyList->Type = Event::type_release; // transform event type
1212    
1213     // spawn release triggered voice(s) if needed
1214     if (pKey->ReleaseTrigger && pChannel->pInstrument) {
1215     TriggerReleaseVoices(pChannel, itNoteOffEventOnKeyList);
1216     pKey->ReleaseTrigger = false;
1217     }
1218     }
1219    
1220     // if neither a voice was spawned or postponed on this key then remove note off event from key again
1221     if (!pKey->Active && !pKey->VoiceTheftsQueued)
1222     pKey->pEvents->free(itNoteOffEventOnKeyList);
1223    
1224     pChannel->listeners.PostProcessNoteOff(iKey, vel);
1225     }
1226    
1227     /**
1228     * Reset all voices and disk thread and clear input event queue and all
1229     * control and status variables. This method is protected by a mutex.
1230     */
1231     virtual void ResetInternal() {
1232     ResetInternalMutex.Lock();
1233    
1234     // make sure that the engine does not get any sysex messages
1235     // while it's reseting
1236     bool sysexDisabled = MidiInputPort::RemoveSysexListener(this);
1237     SetVoiceCount(0);
1238     ActiveVoiceCountMax = 0;
1239    
1240     // reset voice stealing parameters
1241     pVoiceStealingQueue->clear();
1242     itLastStolenVoice = VoiceIterator();
1243     itLastStolenVoiceGlobally = VoiceIterator();
1244     iuiLastStolenKey = RTList<uint>::Iterator();
1245     iuiLastStolenKeyGlobally = RTList<uint>::Iterator();
1246     pLastStolenChannel = NULL;
1247    
1248     // reset all voices
1249     for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
1250     iterVoice->Reset();
1251     }
1252     pVoicePool->clear();
1253    
1254     // reset disk thread
1255     if (pDiskThread) pDiskThread->Reset();
1256    
1257     // delete all input events
1258     pEventQueue->init();
1259     pSysexBuffer->init();
1260     if (sysexDisabled) MidiInputPort::AddSysexListener(this);
1261     ResetInternalMutex.Unlock();
1262     }
1263    
1264     /**
1265     * Kills all voices on an engine channel as soon as possible. Voices
1266     * won't get into release state, their volume level will be ramped down
1267     * as fast as possible.
1268     *
1269     * @param pEngineChannel - engine channel on which all voices should be killed
1270     * @param itKillEvent - event which caused this killing of all voices
1271     */
1272     virtual void KillAllVoices(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itKillEvent) {
1273     EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1274     int count = pChannel->KillAllVoices(itKillEvent);
1275     VoiceSpawnsLeft -= count; //FIXME: just a temporary workaround, we should check the cause in StealVoice() instead
1276     }
1277    
1278     /**
1279     * Allocates and triggers a new voice. This method will usually be
1280     * called by the ProcessNoteOn() method and by the voices itself
1281     * (e.g. to spawn further voices on the same key for layered sounds).
1282     *
1283     * @param pEngineChannel - engine channel on which this event occured on
1284     * @param itNoteOnEvent - key, velocity and time stamp of the event
1285     * @param iLayer - layer index for the new voice (optional - only
1286     * in case of layered sounds of course)
1287     * @param ReleaseTriggerVoice - if new voice is a release triggered voice
1288     * (optional, default = false)
1289     * @param VoiceStealing - if voice stealing should be performed
1290     * when there is no free voice
1291     * (optional, default = true)
1292     * @param HandleKeyGroupConflicts - if voices should be killed due to a
1293     * key group conflict
1294     * @returns pointer to new voice or NULL if there was no free voice or
1295     * if the voice wasn't triggered (for example when no region is
1296     * defined for the given key).
1297     */
1298     virtual PoolVoiceIterator LaunchVoice (
1299     EngineChannel* pEngineChannel,
1300     Pool<Event>::Iterator& itNoteOnEvent,
1301     int iLayer,
1302     bool ReleaseTriggerVoice,
1303     bool VoiceStealing,
1304     bool HandleKeyGroupConflicts
1305     ) = 0;
1306    
1307 iliev 2015 virtual int GetMinFadeOutSamples() { return MinFadeOutSamples; }
1308    
1309 iliev 2012 private:
1310     Pool<V>* pVoicePool; ///< Contains all voices that can be activated.
1311     Pool<RR*> SuspendedRegions;
1312     Mutex SuspendedRegionsMutex;
1313     Condition SuspensionChangeOngoing;
1314     RR* pPendingRegionSuspension;
1315     RR* pPendingRegionResumption;
1316     int iPendingStreamDeletions;
1317     };
1318    
1319     template <class V, class RR, class R, class D, class IM, class I>
1320     IM EngineBase<V, RR, R, D, IM, I>::instruments;
1321    
1322     } // namespace LinuxSampler
1323    
1324     #endif /* __LS_ENGINEBASE_H__ */
1325    

  ViewVC Help
Powered by ViewVC