/[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 2055 - (hide annotations) (download) (as text)
Sat Jan 30 10:30:02 2010 UTC (14 years, 2 months ago) by persson
File MIME type: text/x-c++hdr
File size: 73402 byte(s)
* sfz engine: added support for v2 multiple stage envelope generators
* sfz engine: added a fine-tuned v1 envelope generator instead of
  using the one from the gig engine

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     * Copyright (C) 2009-2010 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     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 persson 2055 iterVoice->pEG1->CalculateFadeOutCoeff(minReleaseTime, SampleRate);
303 iliev 2012 }
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 ActiveVoiceCountTemp; ///< number of currently active voices (for internal usage, will be used for incrementation)
568     VoiceIterator itLastStolenVoice; ///< Only for voice stealing: points to the last voice which was theft in current audio fragment, NULL otherwise.
569     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.
570     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.
571     VoiceIterator itLastStolenVoiceGlobally; ///< Same as itLastStolenVoice, but engine globally
572     RTList<uint>::Iterator iuiLastStolenKeyGlobally; ///< Same as iuiLastStolenKey, but engine globally
573     RTList<Event>* pVoiceStealingQueue; ///< All voice-launching events which had to be postponed due to free voice shortage.
574     Mutex ResetInternalMutex; ///< Mutex to protect the ResetInternal function for concurrent usage (e.g. by the lscp and instrument loader threads).
575     int iMaxDiskStreams;
576    
577     /**
578     * Dispatch and handle all events in this audio fragment for the given
579     * engine channel.
580     *
581     * @param pEngineChannel - engine channel on which events should be
582     * processed
583     * @param Samples - amount of sample points to be processed in
584     * this audio fragment cycle
585     */
586     void ProcessEvents(EngineChannel* pEngineChannel, uint Samples) {
587     // get all events from the engine channels's input event queue which belong to the current fragment
588     // (these are the common events like NoteOn, NoteOff, ControlChange, etc.)
589     AbstractEngineChannel* pChannel = static_cast<AbstractEngineChannel*>(pEngineChannel);
590     pChannel->ImportEvents(Samples);
591    
592     // process events
593     {
594     RTList<Event>::Iterator itEvent = pChannel->pEvents->first();
595     RTList<Event>::Iterator end = pChannel->pEvents->end();
596     for (; itEvent != end; ++itEvent) {
597     switch (itEvent->Type) {
598     case Event::type_note_on:
599     dmsg(5,("Engine: Note on received\n"));
600     ProcessNoteOn((EngineChannel*)itEvent->pEngineChannel, itEvent);
601     break;
602     case Event::type_note_off:
603     dmsg(5,("Engine: Note off received\n"));
604     ProcessNoteOff((EngineChannel*)itEvent->pEngineChannel, itEvent);
605     break;
606     case Event::type_control_change:
607     dmsg(5,("Engine: MIDI CC received\n"));
608     ProcessControlChange((EngineChannel*)itEvent->pEngineChannel, itEvent);
609     break;
610     case Event::type_pitchbend:
611     dmsg(5,("Engine: Pitchbend received\n"));
612     ProcessPitchbend(static_cast<AbstractEngineChannel*>(itEvent->pEngineChannel), itEvent);
613     break;
614     }
615     }
616     }
617    
618     // reset voice stealing for the next engine channel (or next audio fragment)
619     itLastStolenVoice = VoiceIterator();
620     itLastStolenVoiceGlobally = VoiceIterator();
621     iuiLastStolenKey = RTList<uint>::Iterator();
622     iuiLastStolenKeyGlobally = RTList<uint>::Iterator();
623     pLastStolenChannel = NULL;
624     }
625    
626     /**
627     * Will be called by LaunchVoice() method in case there are no free
628     * voices left. This method will select and kill one old voice for
629     * voice stealing and postpone the note-on event until the selected
630     * voice actually died.
631     *
632     * @param pEngineChannel - engine channel on which this event occured on
633     * @param itNoteOnEvent - key, velocity and time stamp of the event
634     * @returns 0 on success, a value < 0 if no active voice could be picked for voice stealing
635     */
636     int StealVoice(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {
637     if (VoiceSpawnsLeft <= 0) {
638     dmsg(1,("Max. voice thefts per audio fragment reached (you may raise CONFIG_MAX_VOICES).\n"));
639     return -1;
640     }
641    
642     EngineChannelBase<V, R, I>* pEngineChn = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
643    
644     if (!pEventPool->poolIsEmpty()) {
645    
646     if(!pEngineChn->StealVoice(itNoteOnEvent, &itLastStolenVoice, &iuiLastStolenKey)) {
647     --VoiceSpawnsLeft;
648     return 0;
649     }
650    
651     // if we couldn't steal a voice from the same engine channel then
652     // steal oldest voice on the oldest key from any other engine channel
653     // (the smaller engine channel number, the higher priority)
654     EngineChannelBase<V, R, I>* pSelectedChannel;
655     int iChannelIndex;
656     VoiceIterator itSelectedVoice;
657    
658     // select engine channel
659     if (pLastStolenChannel) {
660     pSelectedChannel = pLastStolenChannel;
661     iChannelIndex = pSelectedChannel->iEngineIndexSelf;
662     } else { // pick the engine channel followed by this engine channel
663     iChannelIndex = (pEngineChn->iEngineIndexSelf + 1) % engineChannels.size();
664     pSelectedChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannelIndex]);
665     }
666    
667     // if we already stole in this fragment, try to proceed on same key
668     if (this->itLastStolenVoiceGlobally) {
669     itSelectedVoice = this->itLastStolenVoiceGlobally;
670     do {
671     ++itSelectedVoice;
672     } while (itSelectedVoice && !itSelectedVoice->IsStealable()); // proceed iterating if voice was created in this fragment cycle
673     }
674    
675     #if CONFIG_DEVMODE
676     EngineChannel* pBegin = pSelectedChannel; // to detect endless loop
677     #endif // CONFIG_DEVMODE
678    
679     // did we find a 'stealable' voice?
680     if (itSelectedVoice && itSelectedVoice->IsStealable()) {
681     // remember which voice we stole, so we can simply proceed on next voice stealing
682     this->itLastStolenVoiceGlobally = itSelectedVoice;
683     } else while (true) { // iterate through engine channels
684     // get (next) oldest key
685     RTList<uint>::Iterator iuiSelectedKey = (this->iuiLastStolenKeyGlobally) ? ++this->iuiLastStolenKeyGlobally : pSelectedChannel->pActiveKeys->first();
686     this->iuiLastStolenKeyGlobally = RTList<uint>::Iterator(); // to prevent endless loop (see line above)
687     while (iuiSelectedKey) {
688     MidiKey* pSelectedKey = &pSelectedChannel->pMIDIKeyInfo[*iuiSelectedKey];
689     itSelectedVoice = pSelectedKey->pActiveVoices->first();
690     // proceed iterating if voice was created in this fragment cycle
691     while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice;
692     // found a "stealable" voice ?
693     if (itSelectedVoice && itSelectedVoice->IsStealable()) {
694     // remember which voice on which key on which engine channel we stole, so we can simply proceed on next voice stealing
695     this->iuiLastStolenKeyGlobally = iuiSelectedKey;
696     this->itLastStolenVoiceGlobally = itSelectedVoice;
697     this->pLastStolenChannel = pSelectedChannel;
698     goto stealable_voice_found; // selection succeeded
699     }
700     ++iuiSelectedKey; // get next key on current engine channel
701     }
702     // get next engine channel
703     iChannelIndex = (iChannelIndex + 1) % engineChannels.size();
704     pSelectedChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannelIndex]);
705    
706     #if CONFIG_DEVMODE
707     if (pSelectedChannel == pBegin) {
708     dmsg(1,("FATAL ERROR: voice stealing endless loop!\n"));
709     dmsg(1,("VoiceSpawnsLeft=%d.\n", VoiceSpawnsLeft));
710     dmsg(1,("Exiting.\n"));
711     exit(-1);
712     }
713     #endif // CONFIG_DEVMODE
714     }
715    
716     // jump point if a 'stealable' voice was found
717     stealable_voice_found:
718    
719     #if CONFIG_DEVMODE
720     if (!itSelectedVoice->IsActive()) {
721     dmsg(1,("EngineBase: ERROR, tried to steal a voice which was not active !!!\n"));
722     return -1;
723     }
724     #endif // CONFIG_DEVMODE
725    
726     // now kill the selected voice
727     itSelectedVoice->Kill(itNoteOnEvent);
728    
729     --VoiceSpawnsLeft;
730    
731     return 0; // success
732     }
733     else {
734     dmsg(1,("Event pool emtpy!\n"));
735     return -1;
736     }
737     }
738    
739     void HandleInstrumentChanges() {
740     bool instrumentChanged = false;
741     for (int i = 0; i < engineChannels.size(); i++) {
742     EngineChannelBase<V, R, I>* pEngineChannel =
743     static_cast<EngineChannelBase<V, R, I>*>(engineChannels[i]);
744    
745     // as we're going to (carefully) write some status to the
746     // synchronized struct, we cast away the const
747     InstrumentChangeCmd<R, I>& cmd =
748     const_cast<InstrumentChangeCmd<R, I>&>(pEngineChannel->InstrumentChangeCommandReader.Lock());
749    
750     pEngineChannel->pRegionsInUse = cmd.pRegionsInUse;
751     pEngineChannel->pRegionsInUse->clear();
752    
753     if (cmd.bChangeInstrument) {
754     // change instrument
755     dmsg(5,("Engine: instrument change command received\n"));
756     cmd.bChangeInstrument = false;
757     pEngineChannel->pInstrument = cmd.pInstrument;
758     instrumentChanged = true;
759    
760     pEngineChannel->MarkAllActiveVoicesAsOrphans();
761     }
762     }
763    
764     if (instrumentChanged) {
765     //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
766     ResetSuspendedRegions();
767     }
768    
769     for (int i = 0; i < engineChannels.size(); i++) {
770     EngineChannelBase<V, R, I>* channel =
771     static_cast<EngineChannelBase<V, R, I>*>(engineChannels[i]);
772     channel->InstrumentChangeCommandReader.Unlock();
773     }
774     }
775    
776     /**
777     * Render all 'normal' voices (that is voices which were not stolen in
778     * this fragment) on the given engine channel.
779     *
780     * @param pEngineChannel - engine channel on which audio should be
781     * rendered
782     * @param Samples - amount of sample points to be rendered in
783     * this audio fragment cycle
784     */
785     void RenderActiveVoices(EngineChannel* pEngineChannel, uint Samples) {
786     #if !CONFIG_PROCESS_MUTED_CHANNELS
787     if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
788     #endif
789    
790     EngineChannelBase<V, R, I>* pChannel =
791     static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
792     pChannel->RenderActiveVoices(Samples);
793    
794     ActiveVoiceCountTemp += pEngineChannel->GetVoiceCount();
795     }
796    
797     /**
798     * Render all stolen voices (only voices which were stolen in this
799     * fragment) on the given engine channel. Stolen voices are rendered
800     * after all normal voices have been rendered; this is needed to render
801     * audio of those voices which were selected for voice stealing until
802     * the point were the stealing (that is the take over of the voice)
803     * actually happened.
804     *
805     * @param pEngineChannel - engine channel on which audio should be
806     * rendered
807     * @param Samples - amount of sample points to be rendered in
808     * this audio fragment cycle
809     */
810     void RenderStolenVoices(uint Samples) {
811     RTList<Event>::Iterator itVoiceStealEvent = pVoiceStealingQueue->first();
812     RTList<Event>::Iterator end = pVoiceStealingQueue->end();
813     for (; itVoiceStealEvent != end; ++itVoiceStealEvent) {
814     EngineChannelBase<V, R, I>* pEngineChannel =
815     static_cast<EngineChannelBase<V, R, I>*>(itVoiceStealEvent->pEngineChannel);;
816     if (!pEngineChannel->pInstrument) continue; // ignore if no instrument loaded
817     PoolVoiceIterator itNewVoice =
818     LaunchVoice(pEngineChannel, itVoiceStealEvent, itVoiceStealEvent->Param.Note.Layer, itVoiceStealEvent->Param.Note.ReleaseTrigger, false, false);
819     if (itNewVoice) {
820     itNewVoice->Render(Samples);
821     if (itNewVoice->IsActive()) { // still active
822     *(pEngineChannel->pRegionsInUse->allocAppend()) = itNewVoice->GetRegion();
823     ActiveVoiceCountTemp++;
824     pEngineChannel->SetVoiceCount(pEngineChannel->GetVoiceCount() + 1);
825    
826     if (itNewVoice->PlaybackState == Voice::playback_state_disk) {
827     if (itNewVoice->DiskStreamRef.State != Stream::state_unused) {
828     pEngineChannel->SetDiskStreamCount(pEngineChannel->GetDiskStreamCount() + 1);
829     }
830     }
831     } else { // voice reached end, is now inactive
832     pEngineChannel->FreeVoice(itNewVoice); // remove voice from the list of active voices
833     }
834     }
835     else dmsg(1,("EngineBase: ERROR, voice stealing didn't work out!\n"));
836    
837     // we need to clear the key's event list explicitly here in case key was never active
838     MidiKey* pKey = &pEngineChannel->pMIDIKeyInfo[itVoiceStealEvent->Param.Note.Key];
839     pKey->VoiceTheftsQueued--;
840     if (!pKey->Active && !pKey->VoiceTheftsQueued) pKey->pEvents->clear();
841     }
842     }
843    
844     /**
845     * Free all keys which have turned inactive in this audio fragment, from
846     * the list of active keys and clear all event lists on that engine
847     * channel.
848     *
849     * @param pEngineChannel - engine channel to cleanup
850     */
851     void PostProcess(EngineChannel* pEngineChannel) {
852     EngineChannelBase<V, R, I>* pChannel =
853     static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
854     pChannel->FreeAllInactiveKyes();
855    
856     // empty the engine channel's own event lists
857     pChannel->ClearEventLists();
858     }
859    
860     void ProcessHardcodedControllers (
861     EngineChannel* pEngineChannel,
862     Pool<Event>::Iterator& itControlChangeEvent
863     ) {
864     EngineChannelBase<V, R, I>* pChannel =
865     static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
866    
867     switch (itControlChangeEvent->Param.CC.Controller) {
868     case 5: { // portamento time
869     pChannel->PortamentoTime = (float) itControlChangeEvent->Param.CC.Value / 127.0f * (float) CONFIG_PORTAMENTO_TIME_MAX + (float) CONFIG_PORTAMENTO_TIME_MIN;
870     break;
871     }
872     case 6: { // data entry (currently only used for RPN controllers)
873     if (pChannel->GetMidiRpnController() == 2) { // coarse tuning in half tones
874     int transpose = (int) itControlChangeEvent->Param.CC.Value - 64;
875     // limit to +- two octaves for now
876     transpose = RTMath::Min(transpose, 24);
877     transpose = RTMath::Max(transpose, -24);
878     pChannel->GlobalTranspose = transpose;
879     // workaround, so we won't have hanging notes
880     pChannel->ReleaseAllVoices(itControlChangeEvent);
881     }
882     // to avoid other MIDI CC #6 messages to be misenterpreted as RPN controller data
883     pChannel->ResetMidiRpnController();
884     break;
885     }
886     case 7: { // volume
887     //TODO: not sample accurate yet
888     pChannel->MidiVolume = VolumeCurve[itControlChangeEvent->Param.CC.Value];
889     pChannel->bStatusChanged = true; // engine channel status has changed, so set notify flag
890     break;
891     }
892     case 10: { // panpot
893     //TODO: not sample accurate yet
894     pChannel->GlobalPanLeft = PanCurve[128 - itControlChangeEvent->Param.CC.Value];
895     pChannel->GlobalPanRight = PanCurve[itControlChangeEvent->Param.CC.Value];
896     pChannel->iLastPanRequest = itControlChangeEvent->Param.CC.Value;
897     break;
898     }
899     case 64: { // sustain
900     if (itControlChangeEvent->Param.CC.Value >= 64 && !pChannel->SustainPedal) {
901     dmsg(4,("DAMPER (RIGHT) PEDAL DOWN\n"));
902     pChannel->SustainPedal = true;
903     pChannel->listeners.PreProcessSustainPedalDown();
904    
905     #if !CONFIG_PROCESS_MUTED_CHANNELS
906     if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
907     pChannel->listeners.PostProcessSustainPedalDown();
908     return;
909     }
910     #endif
911    
912     pChannel->ProcessSustainPedalDown(itControlChangeEvent);
913     pChannel->listeners.PostProcessSustainPedalDown();
914     }
915     if (itControlChangeEvent->Param.CC.Value < 64 && pChannel->SustainPedal) {
916     dmsg(4,("DAMPER (RIGHT) PEDAL UP\n"));
917     pChannel->SustainPedal = false;
918     pChannel->listeners.PreProcessSustainPedalUp();
919    
920     #if !CONFIG_PROCESS_MUTED_CHANNELS
921     if (pChannel->GetMute()) { // skip if sampler channel is muted
922     pChannel->listeners.PostProcessSustainPedalUp();
923     return;
924     }
925     #endif
926    
927     pChannel->ProcessSustainPedalUp(itControlChangeEvent);
928     pChannel->listeners.PostProcessSustainPedalUp();
929     }
930     break;
931     }
932     case 65: { // portamento on / off
933     const bool bPortamento = itControlChangeEvent->Param.CC.Value >= 64;
934     if (bPortamento != pChannel->PortamentoMode)
935     KillAllVoices(pChannel, itControlChangeEvent);
936     pChannel->PortamentoMode = bPortamento;
937     break;
938     }
939     case 66: { // sostenuto
940     if (itControlChangeEvent->Param.CC.Value >= 64 && !pChannel->SostenutoPedal) {
941     dmsg(4,("SOSTENUTO (CENTER) PEDAL DOWN\n"));
942     pChannel->SostenutoPedal = true;
943     pChannel->listeners.PreProcessSostenutoPedalDown();
944    
945     #if !CONFIG_PROCESS_MUTED_CHANNELS
946     if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
947     pChannel->listeners.PostProcessSostenutoPedalDown();
948     return;
949     }
950     #endif
951    
952     pChannel->ProcessSostenutoPedalDown();
953     pChannel->listeners.PostProcessSostenutoPedalDown();
954     }
955     if (itControlChangeEvent->Param.CC.Value < 64 && pChannel->SostenutoPedal) {
956     dmsg(4,("SOSTENUTO (CENTER) PEDAL UP\n"));
957     pChannel->SostenutoPedal = false;
958     pChannel->listeners.PreProcessSostenutoPedalUp();
959    
960     #if !CONFIG_PROCESS_MUTED_CHANNELS
961     if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
962     pChannel->listeners.PostProcessSostenutoPedalUp();
963     return;
964     }
965     #endif
966    
967     pChannel->ProcessSostenutoPedalUp(itControlChangeEvent);
968     pChannel->listeners.PostProcessSostenutoPedalUp();
969     }
970     break;
971     }
972     case 100: { // RPN controller LSB
973     pEngineChannel->SetMidiRpnControllerLsb(itControlChangeEvent->Param.CC.Value);
974     break;
975     }
976     case 101: { // RPN controller MSB
977     pEngineChannel->SetMidiRpnControllerMsb(itControlChangeEvent->Param.CC.Value);
978     break;
979     }
980    
981    
982     // Channel Mode Messages
983    
984     case 120: { // all sound off
985     KillAllVoices(pEngineChannel, itControlChangeEvent);
986     break;
987     }
988     case 121: { // reset all controllers
989     pChannel->ResetControllers();
990     break;
991     }
992     case 123: { // all notes off
993     #if CONFIG_PROCESS_ALL_NOTES_OFF
994     pChannel->ReleaseAllVoices(itControlChangeEvent);
995     #endif // CONFIG_PROCESS_ALL_NOTES_OFF
996     break;
997     }
998     case 126: { // mono mode on
999     if (!pChannel->SoloMode)
1000     KillAllVoices(pEngineChannel, itControlChangeEvent);
1001     pChannel->SoloMode = true;
1002     break;
1003     }
1004     case 127: { // poly mode on
1005     if (pChannel->SoloMode)
1006     KillAllVoices(pEngineChannel, itControlChangeEvent);
1007     pChannel->SoloMode = false;
1008     break;
1009     }
1010     }
1011     }
1012    
1013     virtual D* CreateDiskThread() = 0;
1014    
1015     /**
1016     * Assigns and triggers a new voice for the respective MIDI key.
1017     *
1018     * @param pEngineChannel - engine channel on which this event occured on
1019     * @param itNoteOnEvent - key, velocity and time stamp of the event
1020     */
1021     virtual void ProcessNoteOn(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {
1022     EngineChannelBase<V, R, I>* pChannel =
1023     static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1024    
1025     //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
1026     int k = itNoteOnEvent->Param.Note.Key + pChannel->GlobalTranspose;
1027     if (k < 0 || k > 127) return; //ignore keys outside the key range
1028    
1029     itNoteOnEvent->Param.Note.Key += pChannel->GlobalTranspose;
1030     int vel = itNoteOnEvent->Param.Note.Velocity;
1031    
1032     const int key = itNoteOnEvent->Param.Note.Key;
1033     MidiKey* pKey = &pChannel->pMIDIKeyInfo[key];
1034    
1035     pChannel->listeners.PreProcessNoteOn(key, vel);
1036     #if !CONFIG_PROCESS_MUTED_CHANNELS
1037     if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
1038     pChannel->listeners.PostProcessNoteOn(key, vel);
1039     return;
1040     }
1041     #endif
1042    
1043     if (!pChannel->pInstrument) {
1044     pChannel->listeners.PostProcessNoteOn(key, vel);
1045     return; // ignore if no instrument loaded
1046     }
1047    
1048     // move note on event to the key's own event list
1049     RTList<Event>::Iterator itNoteOnEventOnKeyList = itNoteOnEvent.moveToEndOf(pKey->pEvents);
1050    
1051     // if Solo Mode then kill all already active voices
1052     if (pChannel->SoloMode) {
1053     Pool<uint>::Iterator itYoungestKey = pChannel->pActiveKeys->last();
1054     if (itYoungestKey) {
1055     const int iYoungestKey = *itYoungestKey;
1056     const MidiKey* pOtherKey = &pChannel->pMIDIKeyInfo[iYoungestKey];
1057     if (pOtherKey->Active) {
1058     // get final portamento position of currently active voice
1059     if (pChannel->PortamentoMode) {
1060     VoiceIterator itVoice = pOtherKey->pActiveVoices->last();
1061     if (itVoice) itVoice->UpdatePortamentoPos(itNoteOnEventOnKeyList);
1062     }
1063     // kill all voices on the (other) key
1064     VoiceIterator itVoiceToBeKilled = pOtherKey->pActiveVoices->first();
1065     VoiceIterator end = pOtherKey->pActiveVoices->end();
1066     for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1067     if (itVoiceToBeKilled->Type != Voice::type_release_trigger)
1068     itVoiceToBeKilled->Kill(itNoteOnEventOnKeyList);
1069     }
1070     }
1071     }
1072     // set this key as 'currently active solo key'
1073     pChannel->SoloKey = key;
1074     }
1075    
1076     pChannel->ProcessKeySwitchChange(key);
1077    
1078     pKey->KeyPressed = true; // the MIDI key was now pressed down
1079     pKey->Velocity = itNoteOnEventOnKeyList->Param.Note.Velocity;
1080     pKey->NoteOnTime = FrameTime + itNoteOnEventOnKeyList->FragmentPos(); // will be used to calculate note length
1081    
1082     // cancel release process of voices on this key if needed
1083     if (pKey->Active && !pChannel->SustainPedal) {
1084     RTList<Event>::Iterator itCancelReleaseEvent = pKey->pEvents->allocAppend();
1085     if (itCancelReleaseEvent) {
1086     *itCancelReleaseEvent = *itNoteOnEventOnKeyList; // copy event
1087     itCancelReleaseEvent->Type = Event::type_cancel_release; // transform event type
1088     }
1089     else dmsg(1,("Event pool emtpy!\n"));
1090     }
1091    
1092     TriggerNewVoices(pEngineChannel, itNoteOnEventOnKeyList);
1093    
1094     // if neither a voice was spawned or postponed then remove note on event from key again
1095     if (!pKey->Active && !pKey->VoiceTheftsQueued)
1096     pKey->pEvents->free(itNoteOnEventOnKeyList);
1097    
1098     if (!pChannel->SoloMode || pChannel->PortamentoPos < 0.0f) pChannel->PortamentoPos = (float) key;
1099 persson 2043 if (pKey->pRoundRobinIndex) {
1100     (*pKey->pRoundRobinIndex)++; // counter specific for the key or region
1101     pChannel->RoundRobinIndex++; // common counter for the channel
1102     }
1103 iliev 2012 pChannel->listeners.PostProcessNoteOn(key, vel);
1104     }
1105    
1106     /**
1107     * Allocate and trigger new voice(s) for the key.
1108     */
1109     virtual void TriggerNewVoices (
1110     EngineChannel* pEngineChannel,
1111     RTList<Event>::Iterator& itNoteOnEvent,
1112     bool HandleKeyGroupConflicts = true
1113     ) = 0;
1114    
1115     /**
1116     * Allocate and trigger release voice(s) for the key.
1117     */
1118     virtual void TriggerReleaseVoices (
1119     EngineChannel* pEngineChannel,
1120     RTList<Event>::Iterator& itNoteOffEvent
1121     ) = 0;
1122    
1123     /**
1124     * Releases the voices on the given key if sustain pedal is not pressed.
1125     * If sustain is pressed, the release of the note will be postponed until
1126     * sustain pedal will be released or voice turned inactive by itself (e.g.
1127     * due to completion of sample playback).
1128     *
1129     * @param pEngineChannel - engine channel on which this event occured on
1130     * @param itNoteOffEvent - key, velocity and time stamp of the event
1131     */
1132     virtual void ProcessNoteOff(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOffEvent) {
1133     EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1134    
1135     int k = itNoteOffEvent->Param.Note.Key + pChannel->GlobalTranspose;
1136     if (k < 0 || k > 127) return; //ignore keys outside the key range
1137    
1138     //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
1139     itNoteOffEvent->Param.Note.Key += pChannel->GlobalTranspose;
1140     int vel = itNoteOffEvent->Param.Note.Velocity;
1141    
1142     const int iKey = itNoteOffEvent->Param.Note.Key;
1143     MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];
1144    
1145     pChannel->listeners.PreProcessNoteOff(iKey, vel);
1146    
1147     #if !CONFIG_PROCESS_MUTED_CHANNELS
1148     if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
1149     pChannel->listeners.PostProcessNoteOff(iKey, vel);
1150     return;
1151     }
1152     #endif
1153    
1154     pKey->KeyPressed = false; // the MIDI key was now released
1155    
1156     // move event to the key's own event list
1157     RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);
1158    
1159     bool bShouldRelease = pKey->Active && pChannel->ShouldReleaseVoice(itNoteOffEventOnKeyList->Param.Note.Key);
1160    
1161     // in case Solo Mode is enabled, kill all voices on this key and respawn a voice on the highest pressed key (if any)
1162     if (pChannel->SoloMode && pChannel->pInstrument) { //TODO: this feels like too much code just for handling solo mode :P
1163     bool bOtherKeysPressed = false;
1164     if (iKey == pChannel->SoloKey) {
1165     pChannel->SoloKey = -1;
1166     // if there's still a key pressed down, respawn a voice (group) on the highest key
1167     for (int i = 127; i > 0; i--) {
1168     MidiKey* pOtherKey = &pChannel->pMIDIKeyInfo[i];
1169     if (pOtherKey->KeyPressed) {
1170     bOtherKeysPressed = true;
1171     // make the other key the new 'currently active solo key'
1172     pChannel->SoloKey = i;
1173     // get final portamento position of currently active voice
1174     if (pChannel->PortamentoMode) {
1175     VoiceIterator itVoice = pKey->pActiveVoices->first();
1176     if (itVoice) itVoice->UpdatePortamentoPos(itNoteOffEventOnKeyList);
1177     }
1178     // create a pseudo note on event
1179     RTList<Event>::Iterator itPseudoNoteOnEvent = pOtherKey->pEvents->allocAppend();
1180     if (itPseudoNoteOnEvent) {
1181     // copy event
1182     *itPseudoNoteOnEvent = *itNoteOffEventOnKeyList;
1183     // transform event to a note on event
1184     itPseudoNoteOnEvent->Type = Event::type_note_on;
1185     itPseudoNoteOnEvent->Param.Note.Key = i;
1186     itPseudoNoteOnEvent->Param.Note.Velocity = pOtherKey->Velocity;
1187     // allocate and trigger new voice(s) for the other key
1188     TriggerNewVoices(pChannel, itPseudoNoteOnEvent, false);
1189     // if neither a voice was spawned or postponed then remove note on event from key again
1190     if (!pOtherKey->Active && !pOtherKey->VoiceTheftsQueued)
1191     pOtherKey->pEvents->free(itPseudoNoteOnEvent);
1192    
1193     } else dmsg(1,("Could not respawn voice, no free event left\n"));
1194     break; // done
1195     }
1196     }
1197     }
1198     if (bOtherKeysPressed) {
1199     if (pKey->Active) { // kill all voices on this key
1200     bShouldRelease = false; // no need to release, as we kill it here
1201     VoiceIterator itVoiceToBeKilled = pKey->pActiveVoices->first();
1202     VoiceIterator end = pKey->pActiveVoices->end();
1203     for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1204     if (itVoiceToBeKilled->Type != Voice::type_release_trigger)
1205     itVoiceToBeKilled->Kill(itNoteOffEventOnKeyList);
1206     }
1207     }
1208     } else pChannel->PortamentoPos = -1.0f;
1209     }
1210    
1211     // if no solo mode (the usual case) or if solo mode and no other key pressed, then release voices on this key if needed
1212     if (bShouldRelease) {
1213     itNoteOffEventOnKeyList->Type = Event::type_release; // transform event type
1214    
1215     // spawn release triggered voice(s) if needed
1216     if (pKey->ReleaseTrigger && pChannel->pInstrument) {
1217     TriggerReleaseVoices(pChannel, itNoteOffEventOnKeyList);
1218     pKey->ReleaseTrigger = false;
1219     }
1220     }
1221    
1222     // if neither a voice was spawned or postponed on this key then remove note off event from key again
1223     if (!pKey->Active && !pKey->VoiceTheftsQueued)
1224     pKey->pEvents->free(itNoteOffEventOnKeyList);
1225    
1226     pChannel->listeners.PostProcessNoteOff(iKey, vel);
1227     }
1228    
1229     /**
1230     * Reset all voices and disk thread and clear input event queue and all
1231     * control and status variables. This method is protected by a mutex.
1232     */
1233     virtual void ResetInternal() {
1234     ResetInternalMutex.Lock();
1235    
1236     // make sure that the engine does not get any sysex messages
1237     // while it's reseting
1238     bool sysexDisabled = MidiInputPort::RemoveSysexListener(this);
1239     SetVoiceCount(0);
1240     ActiveVoiceCountMax = 0;
1241    
1242     // reset voice stealing parameters
1243     pVoiceStealingQueue->clear();
1244     itLastStolenVoice = VoiceIterator();
1245     itLastStolenVoiceGlobally = VoiceIterator();
1246     iuiLastStolenKey = RTList<uint>::Iterator();
1247     iuiLastStolenKeyGlobally = RTList<uint>::Iterator();
1248     pLastStolenChannel = NULL;
1249    
1250     // reset all voices
1251     for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
1252     iterVoice->Reset();
1253     }
1254     pVoicePool->clear();
1255    
1256     // reset disk thread
1257     if (pDiskThread) pDiskThread->Reset();
1258    
1259     // delete all input events
1260     pEventQueue->init();
1261     pSysexBuffer->init();
1262     if (sysexDisabled) MidiInputPort::AddSysexListener(this);
1263     ResetInternalMutex.Unlock();
1264     }
1265    
1266     /**
1267     * Kills all voices on an engine channel as soon as possible. Voices
1268     * won't get into release state, their volume level will be ramped down
1269     * as fast as possible.
1270     *
1271     * @param pEngineChannel - engine channel on which all voices should be killed
1272     * @param itKillEvent - event which caused this killing of all voices
1273     */
1274     virtual void KillAllVoices(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itKillEvent) {
1275     EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1276     int count = pChannel->KillAllVoices(itKillEvent);
1277     VoiceSpawnsLeft -= count; //FIXME: just a temporary workaround, we should check the cause in StealVoice() instead
1278     }
1279    
1280     /**
1281     * Allocates and triggers a new voice. This method will usually be
1282     * called by the ProcessNoteOn() method and by the voices itself
1283     * (e.g. to spawn further voices on the same key for layered sounds).
1284     *
1285     * @param pEngineChannel - engine channel on which this event occured on
1286     * @param itNoteOnEvent - key, velocity and time stamp of the event
1287     * @param iLayer - layer index for the new voice (optional - only
1288     * in case of layered sounds of course)
1289     * @param ReleaseTriggerVoice - if new voice is a release triggered voice
1290     * (optional, default = false)
1291     * @param VoiceStealing - if voice stealing should be performed
1292     * when there is no free voice
1293     * (optional, default = true)
1294     * @param HandleKeyGroupConflicts - if voices should be killed due to a
1295     * key group conflict
1296     * @returns pointer to new voice or NULL if there was no free voice or
1297     * if the voice wasn't triggered (for example when no region is
1298     * defined for the given key).
1299     */
1300     virtual PoolVoiceIterator LaunchVoice (
1301     EngineChannel* pEngineChannel,
1302     Pool<Event>::Iterator& itNoteOnEvent,
1303     int iLayer,
1304     bool ReleaseTriggerVoice,
1305     bool VoiceStealing,
1306     bool HandleKeyGroupConflicts
1307     ) = 0;
1308    
1309 iliev 2015 virtual int GetMinFadeOutSamples() { return MinFadeOutSamples; }
1310    
1311 iliev 2027 int InitNewVoice (
1312     EngineChannelBase<V, R, I>* pChannel,
1313     R* pRegion,
1314     Pool<Event>::Iterator& itNoteOnEvent,
1315     Voice::type_t VoiceType,
1316     int iLayer,
1317     int iKeyGroup,
1318     bool ReleaseTriggerVoice,
1319     bool VoiceStealing,
1320     typename Pool<V>::Iterator& itNewVoice
1321     ) {
1322     int key = itNoteOnEvent->Param.Note.Key;
1323     typename MidiKeyboardManager<V>::MidiKey* pKey = &pChannel->pMIDIKeyInfo[key];
1324     if (itNewVoice) {
1325     // launch the new voice
1326     if (itNewVoice->Trigger(pChannel, itNoteOnEvent, pChannel->Pitch, pRegion, VoiceType, iKeyGroup) < 0) {
1327     dmsg(4,("Voice not triggered\n"));
1328     pKey->pActiveVoices->free(itNewVoice);
1329     }
1330     else { // on success
1331     --VoiceSpawnsLeft;
1332     if (!pKey->Active) { // mark as active key
1333     pKey->Active = true;
1334     pKey->itSelf = pChannel->pActiveKeys->allocAppend();
1335     *pKey->itSelf = itNoteOnEvent->Param.Note.Key;
1336     }
1337     if (itNewVoice->KeyGroup) {
1338     uint** ppKeyGroup = &pChannel->ActiveKeyGroups[itNewVoice->KeyGroup];
1339     *ppKeyGroup = &*pKey->itSelf; // put key as the (new) active key to its key group
1340     }
1341     if (itNewVoice->Type == Voice::type_release_trigger_required) pKey->ReleaseTrigger = true; // mark key for the need of release triggered voice(s)
1342     return 0; // success
1343     }
1344     }
1345     else if (VoiceStealing) {
1346     // try to steal one voice
1347     int result = StealVoice(pChannel, itNoteOnEvent);
1348     if (!result) { // voice stolen successfully
1349     // put note-on event into voice-stealing queue, so it will be reprocessed after killed voice died
1350     RTList<Event>::Iterator itStealEvent = pVoiceStealingQueue->allocAppend();
1351     if (itStealEvent) {
1352     *itStealEvent = *itNoteOnEvent; // copy event
1353     itStealEvent->Param.Note.Layer = iLayer;
1354     itStealEvent->Param.Note.ReleaseTrigger = ReleaseTriggerVoice;
1355     pKey->VoiceTheftsQueued++;
1356     }
1357     else dmsg(1,("Voice stealing queue full!\n"));
1358     }
1359     }
1360    
1361     return -1;
1362     }
1363    
1364 iliev 2012 private:
1365     Pool<V>* pVoicePool; ///< Contains all voices that can be activated.
1366     Pool<RR*> SuspendedRegions;
1367     Mutex SuspendedRegionsMutex;
1368     Condition SuspensionChangeOngoing;
1369     RR* pPendingRegionSuspension;
1370     RR* pPendingRegionResumption;
1371     int iPendingStreamDeletions;
1372     };
1373    
1374     template <class V, class RR, class R, class D, class IM, class I>
1375     IM EngineBase<V, RR, R, D, IM, I>::instruments;
1376    
1377     } // namespace LinuxSampler
1378    
1379     #endif /* __LS_ENGINEBASE_H__ */
1380    

  ViewVC Help
Powered by ViewVC