/[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 2162 - (hide annotations) (download) (as text)
Tue Feb 8 18:22:50 2011 UTC (13 years, 2 months ago) by persson
File MIME type: text/x-c++hdr
File size: 78972 byte(s)
* bugfix: playing a note while changing the instrument could cause a
  crash, or give "Handing back unknown region" error messages

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

  ViewVC Help
Powered by ViewVC