/[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 2837 - (hide annotations) (download) (as text)
Sun Aug 23 06:14:00 2015 UTC (8 years, 7 months ago) by persson
File MIME type: text/x-c++hdr
File size: 92658 byte(s)
* fixed printf type errors (mostly in debug 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 2837 * Copyright (C) 2009-2015 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 schoenebeck 2434 virtual int RenderAudio(uint Samples) OVERRIDE {
108 iliev 2012 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 schoenebeck 2448
147     // In case scale tuning has been changed, recalculate pitch for
148     // all active voices.
149     ProcessScaleTuningChange();
150 iliev 2012
151     // reset internal voice counter (just for statistic of active voices)
152     ActiveVoiceCountTemp = 0;
153    
154     HandleInstrumentChanges();
155    
156     // handle events on all engine channels
157     for (int i = 0; i < engineChannels.size(); i++) {
158     ProcessEvents(engineChannels[i], Samples);
159     }
160    
161     // render all 'normal', active voices on all engine channels
162     for (int i = 0; i < engineChannels.size(); i++) {
163     RenderActiveVoices(engineChannels[i], Samples);
164     }
165    
166     // now that all ordinary voices on ALL engine channels are rendered, render new stolen voices
167     RenderStolenVoices(Samples);
168    
169     // handle audio routing for engine channels with FX sends
170     for (int i = 0; i < engineChannels.size(); i++) {
171     AbstractEngineChannel* pChannel = static_cast<AbstractEngineChannel*>(engineChannels[i]);
172     if (pChannel->fxSends.empty()) continue; // ignore if no FX sends
173     RouteAudio(engineChannels[i], Samples);
174     }
175    
176     // handle cleanup on all engine channels for the next audio fragment
177     for (int i = 0; i < engineChannels.size(); i++) {
178     PostProcess(engineChannels[i]);
179     }
180    
181    
182     // empty the engine's event list for the next audio fragment
183     ClearEventLists();
184    
185     // reset voice stealing for the next audio fragment
186     pVoiceStealingQueue->clear();
187    
188     // just some statistics about this engine instance
189     SetVoiceCount(ActiveVoiceCountTemp);
190     if (VoiceCount() > ActiveVoiceCountMax) ActiveVoiceCountMax = VoiceCount();
191    
192     // in case regions were previously suspended and we killed voices
193     // with disk streams due to that, check if those streams have finally
194     // been deleted by the disk thread
195     if (iPendingStreamDeletions) ProcessPendingStreamDeletions();
196    
197 persson 2162 // Release the instrument change command. (This has to
198     // be done after all voices have been rendered and not
199     // in HandleInstrumentChanges, as the RegionsInUse
200     // list has been built up by the voice renderers.)
201     for (int i = 0; i < engineChannels.size(); i++) {
202     EngineChannelBase<V, R, I>* channel =
203     static_cast<EngineChannelBase<V, R, I>*>(engineChannels[i]);
204     channel->InstrumentChangeCommandReader.Unlock();
205     }
206 iliev 2012 FrameTime += Samples;
207    
208     EngineDisabled.RttDone();
209     return 0;
210     }
211    
212 schoenebeck 2434 virtual int MaxVoices() OVERRIDE { return pVoicePool->poolSize(); }
213 iliev 2012
214 schoenebeck 2434 virtual void SetMaxVoices(int iVoices) throw (Exception) OVERRIDE {
215 iliev 2012 if (iVoices < 1)
216     throw Exception("Maximum voices for an engine cannot be set lower than 1");
217    
218     SuspendAll();
219    
220     // NOTE: we need to clear pRegionsInUse before deleting pDimRegionPool,
221     // otherwise memory corruption will occur if there are active voices (see bug #118)
222     for (int iChannel = 0; iChannel < engineChannels.size(); iChannel++) {
223     EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannel]);
224     pChannel->ClearRegionsInUse();
225     }
226    
227     if (pRegionPool[0]) delete pRegionPool[0];
228     if (pRegionPool[1]) delete pRegionPool[1];
229    
230     pRegionPool[0] = new Pool<R*>(iVoices);
231     pRegionPool[1] = new Pool<R*>(iVoices);
232    
233     for (int iChannel = 0; iChannel < engineChannels.size(); iChannel++) {
234     EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannel]);
235     pChannel->ResetRegionsInUse(pRegionPool);
236     }
237    
238     try {
239     pVoicePool->resizePool(iVoices);
240     } catch (...) {
241     throw Exception("FATAL: Could not resize voice pool!");
242     }
243    
244     for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
245     iterVoice->SetEngine(this);
246     iterVoice->pDiskThread = this->pDiskThread;
247     }
248     pVoicePool->clear();
249    
250 iliev 2244 PostSetMaxVoices(iVoices);
251 iliev 2012 ResumeAll();
252     }
253 iliev 2244
254     /** Called after the new max number of voices is set and before resuming the engine. */
255     virtual void PostSetMaxVoices(int iVoices) { }
256 iliev 2012
257 schoenebeck 2434 virtual uint DiskStreamCount() OVERRIDE { return (pDiskThread) ? pDiskThread->GetActiveStreamCount() : 0; }
258     virtual uint DiskStreamCountMax() OVERRIDE { return (pDiskThread) ? pDiskThread->ActiveStreamCountMax : 0; }
259     virtual int MaxDiskStreams() OVERRIDE { return iMaxDiskStreams; }
260 iliev 2012
261 schoenebeck 2434 virtual void SetMaxDiskStreams(int iStreams) throw (Exception) OVERRIDE {
262 iliev 2012 if (iStreams < 0)
263     throw Exception("Maximum disk streams for an engine cannot be set lower than 0");
264    
265     SuspendAll();
266    
267     iMaxDiskStreams = iStreams;
268    
269     // reconnect to audio output device, because that will automatically
270     // recreate the disk thread with the required amount of streams
271     if (pAudioOutputDevice) Connect(pAudioOutputDevice);
272    
273     ResumeAll();
274     }
275    
276 schoenebeck 2434 virtual String DiskStreamBufferFillBytes() OVERRIDE { return (pDiskThread) ? pDiskThread->GetBufferFillBytes() : ""; }
277     virtual String DiskStreamBufferFillPercentage() OVERRIDE { return (pDiskThread) ? pDiskThread->GetBufferFillPercentage() : ""; }
278     virtual InstrumentManager* GetInstrumentManager() OVERRIDE { return &instruments; }
279 iliev 2012
280     /**
281     * Connect this engine instance with the given audio output device.
282     * This method will be called when an Engine instance is created.
283     * All of the engine's data structures which are dependant to the used
284     * audio output device / driver will be (re)allocated and / or
285     * adjusted appropriately.
286     *
287     * @param pAudioOut - audio output device to connect to
288     */
289 schoenebeck 2434 virtual void Connect(AudioOutputDevice* pAudioOut) OVERRIDE {
290 iliev 2012 // caution: don't ignore if connecting to the same device here,
291     // because otherwise SetMaxDiskStreams() implementation won't work anymore!
292    
293     pAudioOutputDevice = pAudioOut;
294    
295     ResetInternal();
296    
297     // inform audio driver for the need of two channels
298     try {
299     pAudioOutputDevice->AcquireChannels(2); // default stereo
300     }
301     catch (AudioOutputException e) {
302     String msg = "Audio output device unable to provide 2 audio channels, cause: " + e.Message();
303     throw Exception(msg);
304     }
305    
306     this->MaxSamplesPerCycle = pAudioOutputDevice->MaxSamplesPerCycle();
307     this->SampleRate = pAudioOutputDevice->SampleRate();
308    
309     MinFadeOutSamples = int(double(SampleRate) * CONFIG_EG_MIN_RELEASE_TIME) - 1;
310     if (MaxSamplesPerCycle < MinFadeOutSamples) {
311     std::cerr << "EngineBase: WARNING, CONFIG_EG_MIN_RELEASE_TIME "
312     << "too big for current audio fragment size & sampling rate! "
313     << "May lead to click sounds if voice stealing chimes in!\n" << std::flush;
314     // force volume ramp downs at the beginning of each fragment
315     MinFadeOutSamples = MaxSamplesPerCycle;
316     // lower minimum release time
317     const float minReleaseTime = (float) MaxSamplesPerCycle / (float) SampleRate;
318     for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
319 persson 2327 iterVoice->CalculateFadeOutCoeff(minReleaseTime, SampleRate);
320 iliev 2012 }
321     pVoicePool->clear();
322     }
323    
324     // (re)create disk thread
325     if (this->pDiskThread) {
326     dmsg(1,("Stopping disk thread..."));
327     this->pDiskThread->StopThread();
328     delete this->pDiskThread;
329     dmsg(1,("OK\n"));
330     }
331     this->pDiskThread = CreateDiskThread();
332    
333     if (!pDiskThread) {
334     dmsg(0,("EngineBase new diskthread = NULL\n"));
335     exit(EXIT_FAILURE);
336     }
337    
338     for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
339     iterVoice->pDiskThread = this->pDiskThread;
340     dmsg(3,("d"));
341     }
342     pVoicePool->clear();
343    
344     // (re)create event generator
345     if (pEventGenerator) delete pEventGenerator;
346     pEventGenerator = new EventGenerator(pAudioOut->SampleRate());
347    
348     dmsg(1,("Starting disk thread..."));
349     pDiskThread->StartThread();
350     dmsg(1,("OK\n"));
351    
352 iliev 2298 bool printEqInfo = true;
353 iliev 2012 for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
354     if (!iterVoice->pDiskThread) {
355     dmsg(0,("Engine -> voice::trigger: !pDiskThread\n"));
356     exit(EXIT_FAILURE);
357     }
358 iliev 2298
359     iterVoice->CreateEq();
360    
361     if(printEqInfo) {
362     iterVoice->PrintEqInfo();
363     printEqInfo = false;
364     }
365 iliev 2012 }
366     pVoicePool->clear();
367 schoenebeck 2121
368     // (re)create dedicated voice audio buffers
369     //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
370     if (pDedicatedVoiceChannelLeft) delete pDedicatedVoiceChannelLeft;
371     if (pDedicatedVoiceChannelRight) delete pDedicatedVoiceChannelRight;
372     pDedicatedVoiceChannelLeft = new AudioChannel(0, MaxSamplesPerCycle);
373     pDedicatedVoiceChannelRight = new AudioChannel(1, MaxSamplesPerCycle);
374 iliev 2012 }
375 schoenebeck 2410
376     // Implementattion for abstract method derived from Engine.
377 schoenebeck 2434 virtual void ReconnectAudioOutputDevice() OVERRIDE {
378 schoenebeck 2410 SuspendAll();
379     if (pAudioOutputDevice) Connect(pAudioOutputDevice);
380     ResumeAll();
381     }
382 iliev 2012
383     /**
384     * Similar to @c Disable() but this method additionally kills all voices
385     * and disk streams and blocks until all voices and disk streams are actually
386     * killed / deleted.
387     *
388     * @e Note: only the original calling thread is able to re-enable the
389     * engine afterwards by calling @c ResumeAll() later on!
390     */
391     virtual void SuspendAll() {
392     dmsg(2,("Engine: Suspending all ...\n"));
393     // stop the engine, so we can safely modify the engine's
394     // data structures from this foreign thread
395     DisableAndLock();
396     // we could also use the respective class member variable here,
397     // but this is probably safer and cleaner
398     int iPendingStreamDeletions = 0;
399     // kill all voices on all engine channels the *die hard* way
400     for (int iChannel = 0; iChannel < engineChannels.size(); iChannel++) {
401     EngineChannelBase<V, R, I>* pEngineChannel =
402     static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannel]);
403    
404     iPendingStreamDeletions += pEngineChannel->KillAllVoicesImmediately();
405     }
406     // wait until all streams were actually deleted by the disk thread
407     while (iPendingStreamDeletions) {
408     while (
409     iPendingStreamDeletions &&
410     pDiskThread->AskForDeletedStream() != Stream::INVALID_HANDLE
411     ) iPendingStreamDeletions--;
412     if (!iPendingStreamDeletions) break;
413     usleep(10000); // sleep for 10ms
414     }
415     dmsg(2,("EngineBase: Everything suspended.\n"));
416     }
417    
418     /**
419     * At the moment same as calling @c Enable() directly, but this might
420     * change in future, so better call this method as counterpart to
421     * @c SuspendAll() instead of @c Enable() !
422     */
423     virtual void ResumeAll() { Enable(); }
424    
425     /**
426     * Order the engine to stop rendering audio for the given region.
427     * Additionally this method will block until all voices and their disk
428     * streams associated with that region are actually killed / deleted, so
429     * one can i.e. safely modify the region with an instrument editor after
430     * returning from this method.
431     *
432     * @param pRegion - region the engine shall stop using
433     */
434     virtual void Suspend(RR* pRegion) {
435 persson 2837 dmsg(2,("EngineBase: Suspending Region %p ...\n",(void*)pRegion));
436 persson 2427 {
437     LockGuard lock(SuspendedRegionsMutex);
438     SuspensionChangeOngoing.Set(true);
439     pPendingRegionSuspension = pRegion;
440     SuspensionChangeOngoing.WaitAndUnlockIf(true);
441     }
442 persson 2837 dmsg(2,("EngineBase: Region %p suspended.",(void*)pRegion));
443 iliev 2012 }
444    
445     /**
446     * Orders the engine to resume playing back the given region, previously
447     * suspended with @c Suspend() .
448     *
449     * @param pRegion - region the engine shall be allowed to use again
450     */
451     virtual void Resume(RR* pRegion) {
452 persson 2837 dmsg(2,("EngineBase: Resuming Region %p ...\n",(void*)pRegion));
453 persson 2427 {
454     LockGuard lock(SuspendedRegionsMutex);
455     SuspensionChangeOngoing.Set(true);
456     pPendingRegionResumption = pRegion;
457     SuspensionChangeOngoing.WaitAndUnlockIf(true);
458     }
459 persson 2837 dmsg(2,("EngineBase: Region %p resumed.\n",(void*)pRegion));
460 iliev 2012 }
461    
462     virtual void ResetSuspendedRegions() {
463     SuspendedRegions.clear();
464     iPendingStreamDeletions = 0;
465     pPendingRegionSuspension = pPendingRegionResumption = NULL;
466     SuspensionChangeOngoing.Set(false);
467     }
468    
469     /**
470     * Called by the engine's (audio) thread once per cycle to process requests
471     * from the outer world to suspend or resume a given @c gig::Region .
472     */
473     virtual void ProcessSuspensionsChanges() {
474     // process request for suspending one region
475     if (pPendingRegionSuspension) {
476     // kill all voices on all engine channels that use this region
477     for (int iChannel = 0; iChannel < engineChannels.size(); iChannel++) {
478     EngineChannelBase<V, R, I>* pEngineChannel =
479     static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannel]);
480     SuspensionVoiceHandler handler(pPendingRegionSuspension);
481     pEngineChannel->ProcessActiveVoices(&handler);
482     iPendingStreamDeletions += handler.PendingStreamDeletions;
483     }
484     // make sure the region is not yet on the list
485     bool bAlreadySuspended = false;
486     RootRegionIterator iter = SuspendedRegions.first();
487     RootRegionIterator end = SuspendedRegions.end();
488     for (; iter != end; ++iter) { // iterate through all suspended regions
489     if (*iter == pPendingRegionSuspension) { // found
490     bAlreadySuspended = true;
491     dmsg(1,("EngineBase: attempt to suspend an already suspended region !!!\n"));
492     break;
493     }
494     }
495     if (!bAlreadySuspended) {
496     // put the region on the list of suspended regions
497     RootRegionIterator iter = SuspendedRegions.allocAppend();
498     if (iter) {
499     *iter = pPendingRegionSuspension;
500     } else std::cerr << "EngineBase: Could not suspend Region, list is full. This is a bug!!!\n" << std::flush;
501     }
502     // free request slot for next caller (and to make sure that
503     // we're not going to process the same request in the next cycle)
504     pPendingRegionSuspension = NULL;
505     // if no disk stream deletions are pending, awaken other side, as
506     // we're done in this case
507     if (!iPendingStreamDeletions) SuspensionChangeOngoing.Set(false);
508     }
509    
510     // process request for resuming one region
511     if (pPendingRegionResumption) {
512     // remove region from the list of suspended regions
513     RootRegionIterator iter = SuspendedRegions.first();
514     RootRegionIterator end = SuspendedRegions.end();
515     for (; iter != end; ++iter) { // iterate through all suspended regions
516     if (*iter == pPendingRegionResumption) { // found
517     SuspendedRegions.free(iter);
518     break; // done
519     }
520     }
521     // free request slot for next caller
522     pPendingRegionResumption = NULL;
523     // awake other side as we're done
524     SuspensionChangeOngoing.Set(false);
525     }
526     }
527    
528     /**
529     * Called by the engine's (audio) thread once per cycle to check if
530     * streams of voices that were killed due to suspension request have
531     * finally really been deleted by the disk thread.
532     */
533     virtual void ProcessPendingStreamDeletions() {
534     if (!iPendingStreamDeletions) return;
535     //TODO: or shall we better store a list with stream handles instead of a scalar amount of streams to be deleted? might be safer
536     while (
537     iPendingStreamDeletions &&
538     pDiskThread->AskForDeletedStream() != Stream::INVALID_HANDLE
539     ) iPendingStreamDeletions--;
540     // just for safety ...
541     while (pDiskThread->AskForDeletedStream() != Stream::INVALID_HANDLE);
542     // now that all disk streams are deleted, awake other side as
543     // we're finally done with suspending the requested region
544     if (!iPendingStreamDeletions) SuspensionChangeOngoing.Set(false);
545     }
546    
547     /**
548     * Returns @c true if the given region is currently set to be suspended
549     * from being used, @c false otherwise.
550     */
551     virtual bool RegionSuspended(RR* pRegion) {
552     if (SuspendedRegions.isEmpty()) return false;
553     //TODO: or shall we use a sorted container instead of the RTList? might be faster ... or trivial ;-)
554     RootRegionIterator iter = SuspendedRegions.first();
555     RootRegionIterator end = SuspendedRegions.end();
556     for (; iter != end; ++iter) // iterate through all suspended regions
557     if (*iter == pRegion) return true;
558     return false;
559     }
560    
561     // implementation of abstract method derived from class 'LinuxSampler::RegionPools'
562     virtual Pool<R*>* GetRegionPool(int index) {
563     if (index < 0 || index > 1) throw Exception("Index out of bounds");
564     return pRegionPool[index];
565     }
566    
567     // implementation of abstract method derived from class 'LinuxSampler::VoicePool'
568     virtual Pool<V>* GetVoicePool() { return pVoicePool; }
569    
570     D* GetDiskThread() { return pDiskThread; }
571    
572     //friend class EngineChannelBase<V, R, I>;
573    
574 persson 2127 static IM instruments;
575    
576 iliev 2012 protected:
577     class SuspensionVoiceHandler : public MidiKeyboardManager<V>::VoiceHandler {
578     public:
579     int PendingStreamDeletions;
580     RR* pPendingRegionSuspension;
581 schoenebeck 2434
582 iliev 2012 SuspensionVoiceHandler(RR* pPendingRegionSuspension) {
583     PendingStreamDeletions = 0;
584     this->pPendingRegionSuspension = pPendingRegionSuspension;
585     }
586    
587 schoenebeck 2434 virtual bool Process(MidiKey* pMidiKey) OVERRIDE {
588 iliev 2012 VoiceIterator itVoice = pMidiKey->pActiveVoices->first();
589     // if current key is not associated with this region, skip this key
590     if (itVoice->GetRegion()->GetParent() != pPendingRegionSuspension) return false;
591    
592     return true;
593     }
594    
595 schoenebeck 2434 virtual void Process(VoiceIterator& itVoice) OVERRIDE {
596 iliev 2012 // request a notification from disk thread side for stream deletion
597     const Stream::Handle hStream = itVoice->KillImmediately(true);
598     if (hStream != Stream::INVALID_HANDLE) { // voice actually used a stream
599     PendingStreamDeletions++;
600     }
601     //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
602     }
603     };
604    
605     Pool<R*>* pRegionPool[2]; ///< Double buffered pool, used by the engine channels to keep track of regions in use.
606     int MinFadeOutSamples; ///< The number of samples needed to make an instant fade out (e.g. for voice stealing) without leading to clicks.
607     D* pDiskThread;
608    
609     int ActiveVoiceCountTemp; ///< number of currently active voices (for internal usage, will be used for incrementation)
610     VoiceIterator itLastStolenVoice; ///< Only for voice stealing: points to the last voice which was theft in current audio fragment, NULL otherwise.
611     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.
612     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.
613     VoiceIterator itLastStolenVoiceGlobally; ///< Same as itLastStolenVoice, but engine globally
614     RTList<uint>::Iterator iuiLastStolenKeyGlobally; ///< Same as iuiLastStolenKey, but engine globally
615     RTList<Event>* pVoiceStealingQueue; ///< All voice-launching events which had to be postponed due to free voice shortage.
616     Mutex ResetInternalMutex; ///< Mutex to protect the ResetInternal function for concurrent usage (e.g. by the lscp and instrument loader threads).
617     int iMaxDiskStreams;
618    
619     /**
620     * Dispatch and handle all events in this audio fragment for the given
621     * engine channel.
622     *
623     * @param pEngineChannel - engine channel on which events should be
624     * processed
625     * @param Samples - amount of sample points to be processed in
626     * this audio fragment cycle
627     */
628     void ProcessEvents(EngineChannel* pEngineChannel, uint Samples) {
629     // get all events from the engine channels's input event queue which belong to the current fragment
630     // (these are the common events like NoteOn, NoteOff, ControlChange, etc.)
631     AbstractEngineChannel* pChannel = static_cast<AbstractEngineChannel*>(pEngineChannel);
632     pChannel->ImportEvents(Samples);
633    
634 schoenebeck 2594 // if a valid real-time instrument script is loaded, pre-process
635     // the event list by running the script now, since the script
636     // might filter events or add new ones for this cycle
637 schoenebeck 2659 if (pChannel->pScript) {
638 schoenebeck 2594 // resume any suspended script executions still hanging
639     // around of previous audio fragment cycles
640 schoenebeck 2611 for (RTList<ScriptEvent>::Iterator itEvent = pChannel->pScript->pEvents->first(),
641     end = pChannel->pScript->pEvents->end(); itEvent != end; ++itEvent)
642 schoenebeck 2594 {
643 schoenebeck 2596 ResumeScriptEvent(pChannel, itEvent); //TODO: implement support for actual suspension time (i.e. passed to a script's wait() function call)
644 schoenebeck 2594 }
645    
646     // spawn new script executions for the new MIDI events of
647     // this audio fragment cycle
648     for (RTList<Event>::Iterator itEvent = pChannel->pEvents->first(),
649     end = pChannel->pEvents->end(); itEvent != end; ++itEvent)
650     {
651     switch (itEvent->Type) {
652     case Event::type_note_on:
653 schoenebeck 2611 if (pChannel->pScript->handlerNote)
654     ProcessEventByScript(pChannel, itEvent, pChannel->pScript->handlerNote);
655 schoenebeck 2594 break;
656     case Event::type_note_off:
657 schoenebeck 2611 if (pChannel->pScript->handlerRelease)
658     ProcessEventByScript(pChannel, itEvent, pChannel->pScript->handlerRelease);
659 schoenebeck 2594 break;
660     case Event::type_control_change:
661     case Event::type_channel_pressure:
662     case Event::type_pitchbend:
663 schoenebeck 2611 if (pChannel->pScript->handlerController)
664     ProcessEventByScript(pChannel, itEvent, pChannel->pScript->handlerController);
665 schoenebeck 2594 break;
666     case Event::type_note_pressure:
667     //TODO: ...
668     break;
669     }
670     }
671     }
672    
673     // now process all events regularly
674 iliev 2012 {
675     RTList<Event>::Iterator itEvent = pChannel->pEvents->first();
676     RTList<Event>::Iterator end = pChannel->pEvents->end();
677     for (; itEvent != end; ++itEvent) {
678     switch (itEvent->Type) {
679     case Event::type_note_on:
680     dmsg(5,("Engine: Note on received\n"));
681     ProcessNoteOn((EngineChannel*)itEvent->pEngineChannel, itEvent);
682     break;
683     case Event::type_note_off:
684     dmsg(5,("Engine: Note off received\n"));
685     ProcessNoteOff((EngineChannel*)itEvent->pEngineChannel, itEvent);
686     break;
687     case Event::type_control_change:
688     dmsg(5,("Engine: MIDI CC received\n"));
689     ProcessControlChange((EngineChannel*)itEvent->pEngineChannel, itEvent);
690     break;
691 schoenebeck 2559 case Event::type_channel_pressure:
692     dmsg(5,("Engine: MIDI Chan. Pressure received\n"));
693     ProcessChannelPressure((EngineChannel*)itEvent->pEngineChannel, itEvent);
694     break;
695     case Event::type_note_pressure:
696     dmsg(5,("Engine: MIDI Note Pressure received\n"));
697     ProcessPolyphonicKeyPressure((EngineChannel*)itEvent->pEngineChannel, itEvent);
698     break;
699 iliev 2012 case Event::type_pitchbend:
700     dmsg(5,("Engine: Pitchbend received\n"));
701     ProcessPitchbend(static_cast<AbstractEngineChannel*>(itEvent->pEngineChannel), itEvent);
702     break;
703     }
704     }
705     }
706    
707     // reset voice stealing for the next engine channel (or next audio fragment)
708     itLastStolenVoice = VoiceIterator();
709     itLastStolenVoiceGlobally = VoiceIterator();
710     iuiLastStolenKey = RTList<uint>::Iterator();
711     iuiLastStolenKeyGlobally = RTList<uint>::Iterator();
712     pLastStolenChannel = NULL;
713     }
714    
715 schoenebeck 2594 /** @brief Call instrument script's event handler for this event.
716     *
717     * Causes a new execution instance of the currently loaded real-time
718     * instrument script's event handler (callback) to be spawned for
719     * the given MIDI event.
720     *
721     * @param pChannel - engine channel on which the MIDI event occured
722     * @param itEvent - MIDI event that causes this new script execution
723     * @param pEventHandler - script's event handler to be executed
724     */
725     void ProcessEventByScript(AbstractEngineChannel* pChannel, RTList<Event>::Iterator& itEvent, VMEventHandler* pEventHandler) {
726 schoenebeck 2645 const int key = itEvent->Param.Note.Key; // even if this is not a note on/off event, accessing it does not mean any harm
727     // check if polyphonic data is passed from "note" to "release"
728     // script event handlers
729     if (pEventHandler == pChannel->pScript->handlerRelease &&
730     pChannel->pScript->handlerNote &&
731     pChannel->pScript->handlerNote->isPolyphonic() &&
732     pChannel->pScript->handlerRelease->isPolyphonic() &&
733     !pChannel->pScript->pKeyEvents[key]->isEmpty())
734     {
735     // polyphonic variable data is used/passed from "note" to
736     // "release" script callback, so we have to recycle the
737     // original "note on" script event(s)
738     RTList<ScriptEvent>::Iterator it = pChannel->pScript->pKeyEvents[key]->first();
739     RTList<ScriptEvent>::Iterator end = pChannel->pScript->pKeyEvents[key]->end();
740     for (; it != end; ++it) {
741     ProcessScriptEvent(
742     pChannel, itEvent, pEventHandler, it
743     );
744     }
745     } else {
746     // no polyphonic data is used/passed from "note" to
747     // "release" script callback, so just use a new fresh
748     // script event object
749     RTList<ScriptEvent>::Iterator itScriptEvent =
750     pChannel->pScript->pEvents->allocAppend();
751     ProcessScriptEvent(
752     pChannel, itEvent, pEventHandler, itScriptEvent
753     );
754     }
755     }
756 schoenebeck 2594
757 schoenebeck 2645 void ProcessScriptEvent(AbstractEngineChannel* pChannel, RTList<Event>::Iterator& itEvent, VMEventHandler* pEventHandler, RTList<ScriptEvent>::Iterator& itScriptEvent) {
758     if (!itScriptEvent) return; // not a valid script event (i.e. because no free script event was left in the script event pool)
759 schoenebeck 2594
760     // fill the list of script handlers to be executed by this event
761     int i = 0;
762     itScriptEvent->handlers[i++] = pEventHandler; // actual event handler (i.e. note, controller)
763     itScriptEvent->handlers[i] = NULL; // NULL termination of list
764    
765     // initialize/reset other members
766     itScriptEvent->cause = *itEvent;
767 schoenebeck 2598 itScriptEvent->id = pEventPool->getID(itEvent);
768 schoenebeck 2594 itScriptEvent->currentHandler = 0;
769     itScriptEvent->executionSlices = 0;
770    
771     // run script handler(s)
772     VMExecStatus_t res = pScriptVM->exec(
773 schoenebeck 2611 pChannel->pScript->parserContext, &*itScriptEvent
774 schoenebeck 2594 );
775    
776     // in case the script was suspended, keep it on the allocated
777 schoenebeck 2645 // ScriptEvent list to be continued on the next audio cycle
778     if (!(res & VM_EXEC_SUSPENDED)) { // script execution has finished without 'suspended' status ...
779     // if "polyphonic" variable data is passed from script's
780     // "note" event handler to its "release" event handler, then
781     // the script event must be kept and recycled for the later
782     // occuring "release" script event ...
783     if (pEventHandler == pChannel->pScript->handlerNote &&
784     pChannel->pScript->handlerRelease &&
785     pChannel->pScript->handlerNote->isPolyphonic() &&
786     pChannel->pScript->handlerRelease->isPolyphonic())
787     {
788     const int key = itEvent->Param.Note.Key;
789     itScriptEvent.moveToEndOf(pChannel->pScript->pKeyEvents[key & 127]);
790     } else {
791     // ... otherwise if no polyphonic data is passed and
792     // script's execution has finished without suspension
793     // status, then free the script event for a new future
794     // script event to be triggered from start
795     pChannel->pScript->pEvents->free(itScriptEvent);
796     }
797     }
798 schoenebeck 2594 }
799    
800     /** @brief Resume execution of instrument script.
801     *
802     * Will be called to resume execution of a real-time instrument
803     * script event which has been suspended in a previous audio
804     * fragment cycle.
805     *
806     * Script execution might be suspended for various reasons. Usually
807     * a script will be suspended if the script called the built-in
808     * "wait()" function, but it might also be suspended automatically
809     * if the script took too much execution time in an audio fragment
810     * cycle. So in the latter case automatic suspension is performed in
811     * order to avoid harm for the sampler's overall real-time
812     * requirements.
813     *
814     * @param pChannel - engine channel this script is running for
815     * @param itScriptEvent - script execution that shall be resumed
816     */
817     void ResumeScriptEvent(AbstractEngineChannel* pChannel, RTList<ScriptEvent>::Iterator& itScriptEvent) {
818 schoenebeck 2645 VMEventHandler* handler = itScriptEvent->handlers[itScriptEvent->currentHandler];
819    
820 schoenebeck 2594 // run script
821     VMExecStatus_t res = pScriptVM->exec(
822 schoenebeck 2611 pChannel->pScript->parserContext, &*itScriptEvent
823 schoenebeck 2594 );
824 schoenebeck 2645
825     // in case the script was suspended, keep it on the allocated
826     // ScriptEvent list to be continued on the next audio cycle
827     if (!(res & VM_EXEC_SUSPENDED)) { // script execution has finished without 'suspended' status ...
828     // if "polyphonic" variable data is passed from script's
829     // "note" event handler to its "release" event handler, then
830     // the script event must be kept and recycled for the later
831     // occuring "release" script event ...
832     if (handler && handler == pChannel->pScript->handlerNote &&
833     pChannel->pScript->handlerRelease &&
834     pChannel->pScript->handlerNote->isPolyphonic() &&
835     pChannel->pScript->handlerRelease->isPolyphonic())
836     {
837     const int key = itScriptEvent->cause.Param.Note.Key;
838     itScriptEvent.moveToEndOf(pChannel->pScript->pKeyEvents[key & 127]);
839     } else {
840     // ... otherwise if no polyphonic data is passed and
841     // script's execution has finished without suspension
842     // status, then free the script event for a new future
843     // script event to be triggered from start
844     pChannel->pScript->pEvents->free(itScriptEvent);
845     }
846     }
847 schoenebeck 2594 }
848    
849 iliev 2012 /**
850     * Will be called by LaunchVoice() method in case there are no free
851     * voices left. This method will select and kill one old voice for
852     * voice stealing and postpone the note-on event until the selected
853     * voice actually died.
854     *
855     * @param pEngineChannel - engine channel on which this event occured on
856     * @param itNoteOnEvent - key, velocity and time stamp of the event
857     * @returns 0 on success, a value < 0 if no active voice could be picked for voice stealing
858     */
859     int StealVoice(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {
860     if (VoiceSpawnsLeft <= 0) {
861     dmsg(1,("Max. voice thefts per audio fragment reached (you may raise CONFIG_MAX_VOICES).\n"));
862     return -1;
863     }
864    
865     EngineChannelBase<V, R, I>* pEngineChn = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
866    
867     if (!pEventPool->poolIsEmpty()) {
868    
869     if(!pEngineChn->StealVoice(itNoteOnEvent, &itLastStolenVoice, &iuiLastStolenKey)) {
870     --VoiceSpawnsLeft;
871     return 0;
872     }
873    
874     // if we couldn't steal a voice from the same engine channel then
875     // steal oldest voice on the oldest key from any other engine channel
876     // (the smaller engine channel number, the higher priority)
877     EngineChannelBase<V, R, I>* pSelectedChannel;
878     int iChannelIndex;
879     VoiceIterator itSelectedVoice;
880    
881     // select engine channel
882     if (pLastStolenChannel) {
883     pSelectedChannel = pLastStolenChannel;
884     iChannelIndex = pSelectedChannel->iEngineIndexSelf;
885     } else { // pick the engine channel followed by this engine channel
886     iChannelIndex = (pEngineChn->iEngineIndexSelf + 1) % engineChannels.size();
887     pSelectedChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannelIndex]);
888     }
889    
890     // if we already stole in this fragment, try to proceed on same key
891     if (this->itLastStolenVoiceGlobally) {
892     itSelectedVoice = this->itLastStolenVoiceGlobally;
893     do {
894     ++itSelectedVoice;
895     } while (itSelectedVoice && !itSelectedVoice->IsStealable()); // proceed iterating if voice was created in this fragment cycle
896     }
897    
898     #if CONFIG_DEVMODE
899     EngineChannel* pBegin = pSelectedChannel; // to detect endless loop
900     #endif // CONFIG_DEVMODE
901    
902     // did we find a 'stealable' voice?
903     if (itSelectedVoice && itSelectedVoice->IsStealable()) {
904     // remember which voice we stole, so we can simply proceed on next voice stealing
905     this->itLastStolenVoiceGlobally = itSelectedVoice;
906     } else while (true) { // iterate through engine channels
907     // get (next) oldest key
908     RTList<uint>::Iterator iuiSelectedKey = (this->iuiLastStolenKeyGlobally) ? ++this->iuiLastStolenKeyGlobally : pSelectedChannel->pActiveKeys->first();
909     this->iuiLastStolenKeyGlobally = RTList<uint>::Iterator(); // to prevent endless loop (see line above)
910     while (iuiSelectedKey) {
911     MidiKey* pSelectedKey = &pSelectedChannel->pMIDIKeyInfo[*iuiSelectedKey];
912     itSelectedVoice = pSelectedKey->pActiveVoices->first();
913     // proceed iterating if voice was created in this fragment cycle
914     while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice;
915     // found a "stealable" voice ?
916     if (itSelectedVoice && itSelectedVoice->IsStealable()) {
917     // remember which voice on which key on which engine channel we stole, so we can simply proceed on next voice stealing
918     this->iuiLastStolenKeyGlobally = iuiSelectedKey;
919     this->itLastStolenVoiceGlobally = itSelectedVoice;
920     this->pLastStolenChannel = pSelectedChannel;
921     goto stealable_voice_found; // selection succeeded
922     }
923     ++iuiSelectedKey; // get next key on current engine channel
924     }
925     // get next engine channel
926     iChannelIndex = (iChannelIndex + 1) % engineChannels.size();
927     pSelectedChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannelIndex]);
928    
929     #if CONFIG_DEVMODE
930     if (pSelectedChannel == pBegin) {
931     dmsg(1,("FATAL ERROR: voice stealing endless loop!\n"));
932     dmsg(1,("VoiceSpawnsLeft=%d.\n", VoiceSpawnsLeft));
933     dmsg(1,("Exiting.\n"));
934     exit(-1);
935     }
936     #endif // CONFIG_DEVMODE
937     }
938    
939     // jump point if a 'stealable' voice was found
940     stealable_voice_found:
941    
942     #if CONFIG_DEVMODE
943     if (!itSelectedVoice->IsActive()) {
944     dmsg(1,("EngineBase: ERROR, tried to steal a voice which was not active !!!\n"));
945     return -1;
946     }
947     #endif // CONFIG_DEVMODE
948    
949     // now kill the selected voice
950     itSelectedVoice->Kill(itNoteOnEvent);
951    
952     --VoiceSpawnsLeft;
953    
954     return 0; // success
955     }
956     else {
957     dmsg(1,("Event pool emtpy!\n"));
958     return -1;
959     }
960     }
961    
962     void HandleInstrumentChanges() {
963     bool instrumentChanged = false;
964     for (int i = 0; i < engineChannels.size(); i++) {
965     EngineChannelBase<V, R, I>* pEngineChannel =
966     static_cast<EngineChannelBase<V, R, I>*>(engineChannels[i]);
967    
968     // as we're going to (carefully) write some status to the
969     // synchronized struct, we cast away the const
970     InstrumentChangeCmd<R, I>& cmd =
971     const_cast<InstrumentChangeCmd<R, I>&>(pEngineChannel->InstrumentChangeCommandReader.Lock());
972    
973     pEngineChannel->pRegionsInUse = cmd.pRegionsInUse;
974     pEngineChannel->pRegionsInUse->clear();
975    
976     if (cmd.bChangeInstrument) {
977     // change instrument
978     dmsg(5,("Engine: instrument change command received\n"));
979     cmd.bChangeInstrument = false;
980     pEngineChannel->pInstrument = cmd.pInstrument;
981 schoenebeck 2659 pEngineChannel->pScript =
982     cmd.pScript->bHasValidScript ? cmd.pScript : NULL;
983 iliev 2012 instrumentChanged = true;
984    
985     pEngineChannel->MarkAllActiveVoicesAsOrphans();
986 schoenebeck 2611
987     // the script's "init" event handler is only executed
988     // once (when the script is loaded or reloaded)
989     if (pEngineChannel->pScript && pEngineChannel->pScript->handlerInit) {
990     RTList<ScriptEvent>::Iterator itScriptEvent =
991     pEngineChannel->pScript->pEvents->allocAppend();
992    
993 schoenebeck 2614 itScriptEvent->cause.pEngineChannel = pEngineChannel;
994 schoenebeck 2618 itScriptEvent->handlers[0] = pEngineChannel->pScript->handlerInit;
995     itScriptEvent->handlers[1] = NULL;
996 schoenebeck 2614
997 schoenebeck 2611 VMExecStatus_t res = pScriptVM->exec(
998     pEngineChannel->pScript->parserContext, &*itScriptEvent
999     );
1000    
1001     pEngineChannel->pScript->pEvents->free(itScriptEvent);
1002     }
1003 iliev 2012 }
1004     }
1005    
1006     if (instrumentChanged) {
1007     //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
1008     ResetSuspendedRegions();
1009     }
1010     }
1011    
1012     /**
1013     * Render all 'normal' voices (that is voices which were not stolen in
1014     * this fragment) on the given engine channel.
1015     *
1016     * @param pEngineChannel - engine channel on which audio should be
1017     * rendered
1018     * @param Samples - amount of sample points to be rendered in
1019     * this audio fragment cycle
1020     */
1021     void RenderActiveVoices(EngineChannel* pEngineChannel, uint Samples) {
1022     #if !CONFIG_PROCESS_MUTED_CHANNELS
1023     if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
1024     #endif
1025    
1026     EngineChannelBase<V, R, I>* pChannel =
1027     static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1028     pChannel->RenderActiveVoices(Samples);
1029    
1030     ActiveVoiceCountTemp += pEngineChannel->GetVoiceCount();
1031     }
1032    
1033     /**
1034     * Render all stolen voices (only voices which were stolen in this
1035     * fragment) on the given engine channel. Stolen voices are rendered
1036     * after all normal voices have been rendered; this is needed to render
1037     * audio of those voices which were selected for voice stealing until
1038     * the point were the stealing (that is the take over of the voice)
1039     * actually happened.
1040     *
1041     * @param pEngineChannel - engine channel on which audio should be
1042     * rendered
1043     * @param Samples - amount of sample points to be rendered in
1044     * this audio fragment cycle
1045     */
1046     void RenderStolenVoices(uint Samples) {
1047     RTList<Event>::Iterator itVoiceStealEvent = pVoiceStealingQueue->first();
1048     RTList<Event>::Iterator end = pVoiceStealingQueue->end();
1049     for (; itVoiceStealEvent != end; ++itVoiceStealEvent) {
1050     EngineChannelBase<V, R, I>* pEngineChannel =
1051     static_cast<EngineChannelBase<V, R, I>*>(itVoiceStealEvent->pEngineChannel);;
1052     if (!pEngineChannel->pInstrument) continue; // ignore if no instrument loaded
1053     PoolVoiceIterator itNewVoice =
1054     LaunchVoice(pEngineChannel, itVoiceStealEvent, itVoiceStealEvent->Param.Note.Layer, itVoiceStealEvent->Param.Note.ReleaseTrigger, false, false);
1055     if (itNewVoice) {
1056     itNewVoice->Render(Samples);
1057     if (itNewVoice->IsActive()) { // still active
1058     *(pEngineChannel->pRegionsInUse->allocAppend()) = itNewVoice->GetRegion();
1059     ActiveVoiceCountTemp++;
1060     pEngineChannel->SetVoiceCount(pEngineChannel->GetVoiceCount() + 1);
1061    
1062     if (itNewVoice->PlaybackState == Voice::playback_state_disk) {
1063     if (itNewVoice->DiskStreamRef.State != Stream::state_unused) {
1064     pEngineChannel->SetDiskStreamCount(pEngineChannel->GetDiskStreamCount() + 1);
1065     }
1066     }
1067     } else { // voice reached end, is now inactive
1068     pEngineChannel->FreeVoice(itNewVoice); // remove voice from the list of active voices
1069     }
1070     }
1071     else dmsg(1,("EngineBase: ERROR, voice stealing didn't work out!\n"));
1072    
1073     // we need to clear the key's event list explicitly here in case key was never active
1074     MidiKey* pKey = &pEngineChannel->pMIDIKeyInfo[itVoiceStealEvent->Param.Note.Key];
1075     pKey->VoiceTheftsQueued--;
1076     if (!pKey->Active && !pKey->VoiceTheftsQueued) pKey->pEvents->clear();
1077     }
1078     }
1079    
1080     /**
1081     * Free all keys which have turned inactive in this audio fragment, from
1082     * the list of active keys and clear all event lists on that engine
1083     * channel.
1084     *
1085     * @param pEngineChannel - engine channel to cleanup
1086     */
1087     void PostProcess(EngineChannel* pEngineChannel) {
1088     EngineChannelBase<V, R, I>* pChannel =
1089     static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1090     pChannel->FreeAllInactiveKyes();
1091    
1092     // empty the engine channel's own event lists
1093     pChannel->ClearEventLists();
1094     }
1095    
1096 schoenebeck 2121 /**
1097     * Process MIDI control change events with hard coded behavior,
1098     * that is controllers whose behavior is defined independently
1099     * of the actual sampler engine type and instrument.
1100     *
1101     * @param pEngineChannel - engine channel on which the MIDI CC event was received
1102     * @param itControlChangeEvent - the actual MIDI CC event
1103     */
1104 iliev 2012 void ProcessHardcodedControllers (
1105     EngineChannel* pEngineChannel,
1106     Pool<Event>::Iterator& itControlChangeEvent
1107     ) {
1108     EngineChannelBase<V, R, I>* pChannel =
1109     static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1110    
1111     switch (itControlChangeEvent->Param.CC.Controller) {
1112     case 5: { // portamento time
1113     pChannel->PortamentoTime = (float) itControlChangeEvent->Param.CC.Value / 127.0f * (float) CONFIG_PORTAMENTO_TIME_MAX + (float) CONFIG_PORTAMENTO_TIME_MIN;
1114     break;
1115     }
1116 schoenebeck 2121 case 6: { // data entry (currently only used for RPN and NRPN controllers)
1117     //dmsg(1,("DATA ENTRY %d\n", itControlChangeEvent->Param.CC.Value));
1118     if (pChannel->GetMidiRpnController() >= 0) { // RPN controller number was sent previously ...
1119     dmsg(4,("Guess it's an RPN ...\n"));
1120     if (pChannel->GetMidiRpnController() == 2) { // coarse tuning in half tones
1121     int transpose = (int) itControlChangeEvent->Param.CC.Value - 64;
1122     // limit to +- two octaves for now
1123     transpose = RTMath::Min(transpose, 24);
1124     transpose = RTMath::Max(transpose, -24);
1125     pChannel->GlobalTranspose = transpose;
1126     // workaround, so we won't have hanging notes
1127     pChannel->ReleaseAllVoices(itControlChangeEvent);
1128     }
1129     // to prevent other MIDI CC #6 messages to be misenterpreted as RPN controller data
1130     pChannel->ResetMidiRpnController();
1131     } else if (pChannel->GetMidiNrpnController() >= 0) { // NRPN controller number was sent previously ...
1132     dmsg(4,("Guess it's an NRPN ...\n"));
1133     const int NrpnCtrlMSB = pChannel->GetMidiNrpnController() >> 8;
1134     const int NrpnCtrlLSB = pChannel->GetMidiNrpnController() & 0xff;
1135     dmsg(4,("NRPN MSB=%d LSB=%d Data=%d\n", NrpnCtrlMSB, NrpnCtrlLSB, itControlChangeEvent->Param.CC.Value));
1136     switch (NrpnCtrlMSB) {
1137     case 0x1a: { // volume level of note (Roland GS NRPN)
1138     const uint note = NrpnCtrlLSB;
1139     const uint vol = itControlChangeEvent->Param.CC.Value;
1140     dmsg(4,("Note Volume NRPN received (note=%d,vol=%d).\n", note, vol));
1141     if (note < 128 && vol < 128)
1142     pChannel->pMIDIKeyInfo[note].Volume = VolumeCurve[vol];
1143     break;
1144     }
1145     case 0x1c: { // panpot of note (Roland GS NRPN)
1146     const uint note = NrpnCtrlLSB;
1147     const uint pan = itControlChangeEvent->Param.CC.Value;
1148     dmsg(4,("Note Pan NRPN received (note=%d,pan=%d).\n", note, pan));
1149     if (note < 128 && pan < 128) {
1150     pChannel->pMIDIKeyInfo[note].PanLeft = PanCurve[128 - pan];
1151     pChannel->pMIDIKeyInfo[note].PanRight = PanCurve[pan];
1152     }
1153     break;
1154     }
1155     case 0x1d: { // reverb send of note (Roland GS NRPN)
1156     const uint note = NrpnCtrlLSB;
1157     const float reverb = float(itControlChangeEvent->Param.CC.Value) / 127.0f;
1158 persson 2837 dmsg(4,("Note Reverb Send NRPN received (note=%d,send=%f).\n", note, reverb));
1159 schoenebeck 2121 if (note < 128)
1160     pChannel->pMIDIKeyInfo[note].ReverbSend = reverb;
1161     break;
1162     }
1163     case 0x1e: { // chorus send of note (Roland GS NRPN)
1164     const uint note = NrpnCtrlLSB;
1165     const float chorus = float(itControlChangeEvent->Param.CC.Value) / 127.0f;
1166 persson 2837 dmsg(4,("Note Chorus Send NRPN received (note=%d,send=%f).\n", note, chorus));
1167 schoenebeck 2121 if (note < 128)
1168     pChannel->pMIDIKeyInfo[note].ChorusSend = chorus;
1169     break;
1170     }
1171     }
1172     // to prevent other MIDI CC #6 messages to be misenterpreted as NRPN controller data
1173     pChannel->ResetMidiNrpnController();
1174 iliev 2012 }
1175     break;
1176     }
1177     case 7: { // volume
1178     //TODO: not sample accurate yet
1179     pChannel->MidiVolume = VolumeCurve[itControlChangeEvent->Param.CC.Value];
1180     pChannel->bStatusChanged = true; // engine channel status has changed, so set notify flag
1181     break;
1182     }
1183     case 10: { // panpot
1184     //TODO: not sample accurate yet
1185     pChannel->iLastPanRequest = itControlChangeEvent->Param.CC.Value;
1186     break;
1187     }
1188     case 64: { // sustain
1189     if (itControlChangeEvent->Param.CC.Value >= 64 && !pChannel->SustainPedal) {
1190     dmsg(4,("DAMPER (RIGHT) PEDAL DOWN\n"));
1191     pChannel->SustainPedal = true;
1192     pChannel->listeners.PreProcessSustainPedalDown();
1193    
1194     #if !CONFIG_PROCESS_MUTED_CHANNELS
1195     if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
1196     pChannel->listeners.PostProcessSustainPedalDown();
1197     return;
1198     }
1199     #endif
1200    
1201     pChannel->ProcessSustainPedalDown(itControlChangeEvent);
1202     pChannel->listeners.PostProcessSustainPedalDown();
1203     }
1204     if (itControlChangeEvent->Param.CC.Value < 64 && pChannel->SustainPedal) {
1205     dmsg(4,("DAMPER (RIGHT) PEDAL UP\n"));
1206     pChannel->SustainPedal = false;
1207     pChannel->listeners.PreProcessSustainPedalUp();
1208    
1209     #if !CONFIG_PROCESS_MUTED_CHANNELS
1210     if (pChannel->GetMute()) { // skip if sampler channel is muted
1211     pChannel->listeners.PostProcessSustainPedalUp();
1212     return;
1213     }
1214     #endif
1215    
1216     pChannel->ProcessSustainPedalUp(itControlChangeEvent);
1217     pChannel->listeners.PostProcessSustainPedalUp();
1218     }
1219     break;
1220     }
1221     case 65: { // portamento on / off
1222     const bool bPortamento = itControlChangeEvent->Param.CC.Value >= 64;
1223     if (bPortamento != pChannel->PortamentoMode)
1224     KillAllVoices(pChannel, itControlChangeEvent);
1225     pChannel->PortamentoMode = bPortamento;
1226     break;
1227     }
1228     case 66: { // sostenuto
1229     if (itControlChangeEvent->Param.CC.Value >= 64 && !pChannel->SostenutoPedal) {
1230     dmsg(4,("SOSTENUTO (CENTER) PEDAL DOWN\n"));
1231     pChannel->SostenutoPedal = true;
1232     pChannel->listeners.PreProcessSostenutoPedalDown();
1233    
1234     #if !CONFIG_PROCESS_MUTED_CHANNELS
1235     if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
1236     pChannel->listeners.PostProcessSostenutoPedalDown();
1237     return;
1238     }
1239     #endif
1240    
1241     pChannel->ProcessSostenutoPedalDown();
1242     pChannel->listeners.PostProcessSostenutoPedalDown();
1243     }
1244     if (itControlChangeEvent->Param.CC.Value < 64 && pChannel->SostenutoPedal) {
1245     dmsg(4,("SOSTENUTO (CENTER) PEDAL UP\n"));
1246     pChannel->SostenutoPedal = false;
1247     pChannel->listeners.PreProcessSostenutoPedalUp();
1248    
1249     #if !CONFIG_PROCESS_MUTED_CHANNELS
1250     if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
1251     pChannel->listeners.PostProcessSostenutoPedalUp();
1252     return;
1253     }
1254     #endif
1255    
1256     pChannel->ProcessSostenutoPedalUp(itControlChangeEvent);
1257     pChannel->listeners.PostProcessSostenutoPedalUp();
1258     }
1259     break;
1260     }
1261 schoenebeck 2121 case 98: { // NRPN controller LSB
1262     dmsg(4,("NRPN LSB %d\n", itControlChangeEvent->Param.CC.Value));
1263     pEngineChannel->SetMidiNrpnControllerLsb(itControlChangeEvent->Param.CC.Value);
1264     break;
1265     }
1266     case 99: { // NRPN controller MSB
1267     dmsg(4,("NRPN MSB %d\n", itControlChangeEvent->Param.CC.Value));
1268     pEngineChannel->SetMidiNrpnControllerMsb(itControlChangeEvent->Param.CC.Value);
1269     break;
1270     }
1271 iliev 2012 case 100: { // RPN controller LSB
1272 schoenebeck 2121 dmsg(4,("RPN LSB %d\n", itControlChangeEvent->Param.CC.Value));
1273 iliev 2012 pEngineChannel->SetMidiRpnControllerLsb(itControlChangeEvent->Param.CC.Value);
1274     break;
1275     }
1276     case 101: { // RPN controller MSB
1277 schoenebeck 2121 dmsg(4,("RPN MSB %d\n", itControlChangeEvent->Param.CC.Value));
1278 iliev 2012 pEngineChannel->SetMidiRpnControllerMsb(itControlChangeEvent->Param.CC.Value);
1279     break;
1280     }
1281    
1282    
1283     // Channel Mode Messages
1284    
1285     case 120: { // all sound off
1286     KillAllVoices(pEngineChannel, itControlChangeEvent);
1287     break;
1288     }
1289     case 121: { // reset all controllers
1290     pChannel->ResetControllers();
1291     break;
1292     }
1293     case 123: { // all notes off
1294     #if CONFIG_PROCESS_ALL_NOTES_OFF
1295     pChannel->ReleaseAllVoices(itControlChangeEvent);
1296     #endif // CONFIG_PROCESS_ALL_NOTES_OFF
1297     break;
1298     }
1299     case 126: { // mono mode on
1300     if (!pChannel->SoloMode)
1301     KillAllVoices(pEngineChannel, itControlChangeEvent);
1302     pChannel->SoloMode = true;
1303     break;
1304     }
1305     case 127: { // poly mode on
1306     if (pChannel->SoloMode)
1307     KillAllVoices(pEngineChannel, itControlChangeEvent);
1308     pChannel->SoloMode = false;
1309     break;
1310     }
1311     }
1312     }
1313    
1314     virtual D* CreateDiskThread() = 0;
1315    
1316     /**
1317     * Assigns and triggers a new voice for the respective MIDI key.
1318     *
1319     * @param pEngineChannel - engine channel on which this event occured on
1320     * @param itNoteOnEvent - key, velocity and time stamp of the event
1321     */
1322     virtual void ProcessNoteOn(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {
1323     EngineChannelBase<V, R, I>* pChannel =
1324     static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1325    
1326     //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
1327     int k = itNoteOnEvent->Param.Note.Key + pChannel->GlobalTranspose;
1328     if (k < 0 || k > 127) return; //ignore keys outside the key range
1329    
1330     itNoteOnEvent->Param.Note.Key += pChannel->GlobalTranspose;
1331     int vel = itNoteOnEvent->Param.Note.Velocity;
1332    
1333     const int key = itNoteOnEvent->Param.Note.Key;
1334     MidiKey* pKey = &pChannel->pMIDIKeyInfo[key];
1335    
1336     pChannel->listeners.PreProcessNoteOn(key, vel);
1337     #if !CONFIG_PROCESS_MUTED_CHANNELS
1338     if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
1339     pChannel->listeners.PostProcessNoteOn(key, vel);
1340     return;
1341     }
1342     #endif
1343    
1344     if (!pChannel->pInstrument) {
1345     pChannel->listeners.PostProcessNoteOn(key, vel);
1346     return; // ignore if no instrument loaded
1347     }
1348    
1349     // move note on event to the key's own event list
1350     RTList<Event>::Iterator itNoteOnEventOnKeyList = itNoteOnEvent.moveToEndOf(pKey->pEvents);
1351    
1352     // if Solo Mode then kill all already active voices
1353     if (pChannel->SoloMode) {
1354     Pool<uint>::Iterator itYoungestKey = pChannel->pActiveKeys->last();
1355     if (itYoungestKey) {
1356     const int iYoungestKey = *itYoungestKey;
1357     const MidiKey* pOtherKey = &pChannel->pMIDIKeyInfo[iYoungestKey];
1358     if (pOtherKey->Active) {
1359     // get final portamento position of currently active voice
1360     if (pChannel->PortamentoMode) {
1361     VoiceIterator itVoice = pOtherKey->pActiveVoices->last();
1362     if (itVoice) itVoice->UpdatePortamentoPos(itNoteOnEventOnKeyList);
1363     }
1364     // kill all voices on the (other) key
1365     VoiceIterator itVoiceToBeKilled = pOtherKey->pActiveVoices->first();
1366     VoiceIterator end = pOtherKey->pActiveVoices->end();
1367     for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1368 persson 2115 if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))
1369 iliev 2012 itVoiceToBeKilled->Kill(itNoteOnEventOnKeyList);
1370     }
1371     }
1372     }
1373     // set this key as 'currently active solo key'
1374     pChannel->SoloKey = key;
1375     }
1376    
1377     pChannel->ProcessKeySwitchChange(key);
1378    
1379     pKey->KeyPressed = true; // the MIDI key was now pressed down
1380 schoenebeck 2613 pChannel->KeyDown[key] = true; // just used as built-in %KEY_DOWN script variable
1381 iliev 2012 pKey->Velocity = itNoteOnEventOnKeyList->Param.Note.Velocity;
1382     pKey->NoteOnTime = FrameTime + itNoteOnEventOnKeyList->FragmentPos(); // will be used to calculate note length
1383    
1384     // cancel release process of voices on this key if needed
1385     if (pKey->Active && !pChannel->SustainPedal) {
1386     RTList<Event>::Iterator itCancelReleaseEvent = pKey->pEvents->allocAppend();
1387     if (itCancelReleaseEvent) {
1388     *itCancelReleaseEvent = *itNoteOnEventOnKeyList; // copy event
1389     itCancelReleaseEvent->Type = Event::type_cancel_release; // transform event type
1390     }
1391     else dmsg(1,("Event pool emtpy!\n"));
1392     }
1393    
1394     TriggerNewVoices(pEngineChannel, itNoteOnEventOnKeyList);
1395    
1396     // if neither a voice was spawned or postponed then remove note on event from key again
1397     if (!pKey->Active && !pKey->VoiceTheftsQueued)
1398     pKey->pEvents->free(itNoteOnEventOnKeyList);
1399    
1400     if (!pChannel->SoloMode || pChannel->PortamentoPos < 0.0f) pChannel->PortamentoPos = (float) key;
1401 persson 2043 if (pKey->pRoundRobinIndex) {
1402     (*pKey->pRoundRobinIndex)++; // counter specific for the key or region
1403     pChannel->RoundRobinIndex++; // common counter for the channel
1404     }
1405 iliev 2012 pChannel->listeners.PostProcessNoteOn(key, vel);
1406     }
1407    
1408     /**
1409     * Allocate and trigger new voice(s) for the key.
1410     */
1411     virtual void TriggerNewVoices (
1412     EngineChannel* pEngineChannel,
1413     RTList<Event>::Iterator& itNoteOnEvent,
1414     bool HandleKeyGroupConflicts = true
1415     ) = 0;
1416    
1417     /**
1418     * Allocate and trigger release voice(s) for the key.
1419     */
1420     virtual void TriggerReleaseVoices (
1421     EngineChannel* pEngineChannel,
1422     RTList<Event>::Iterator& itNoteOffEvent
1423     ) = 0;
1424    
1425     /**
1426     * Releases the voices on the given key if sustain pedal is not pressed.
1427     * If sustain is pressed, the release of the note will be postponed until
1428     * sustain pedal will be released or voice turned inactive by itself (e.g.
1429     * due to completion of sample playback).
1430     *
1431     * @param pEngineChannel - engine channel on which this event occured on
1432     * @param itNoteOffEvent - key, velocity and time stamp of the event
1433     */
1434     virtual void ProcessNoteOff(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOffEvent) {
1435     EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1436    
1437     int k = itNoteOffEvent->Param.Note.Key + pChannel->GlobalTranspose;
1438     if (k < 0 || k > 127) return; //ignore keys outside the key range
1439    
1440     //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
1441     itNoteOffEvent->Param.Note.Key += pChannel->GlobalTranspose;
1442     int vel = itNoteOffEvent->Param.Note.Velocity;
1443    
1444     const int iKey = itNoteOffEvent->Param.Note.Key;
1445     MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];
1446    
1447     pChannel->listeners.PreProcessNoteOff(iKey, vel);
1448    
1449     #if !CONFIG_PROCESS_MUTED_CHANNELS
1450     if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
1451     pChannel->listeners.PostProcessNoteOff(iKey, vel);
1452     return;
1453     }
1454     #endif
1455    
1456     pKey->KeyPressed = false; // the MIDI key was now released
1457 schoenebeck 2613 pChannel->KeyDown[iKey] = false; // just used as built-in %KEY_DOWN script variable
1458 iliev 2012
1459     // move event to the key's own event list
1460     RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);
1461    
1462     bool bShouldRelease = pKey->Active && pChannel->ShouldReleaseVoice(itNoteOffEventOnKeyList->Param.Note.Key);
1463    
1464     // in case Solo Mode is enabled, kill all voices on this key and respawn a voice on the highest pressed key (if any)
1465     if (pChannel->SoloMode && pChannel->pInstrument) { //TODO: this feels like too much code just for handling solo mode :P
1466     bool bOtherKeysPressed = false;
1467     if (iKey == pChannel->SoloKey) {
1468     pChannel->SoloKey = -1;
1469     // if there's still a key pressed down, respawn a voice (group) on the highest key
1470     for (int i = 127; i > 0; i--) {
1471     MidiKey* pOtherKey = &pChannel->pMIDIKeyInfo[i];
1472     if (pOtherKey->KeyPressed) {
1473     bOtherKeysPressed = true;
1474     // make the other key the new 'currently active solo key'
1475     pChannel->SoloKey = i;
1476     // get final portamento position of currently active voice
1477     if (pChannel->PortamentoMode) {
1478     VoiceIterator itVoice = pKey->pActiveVoices->first();
1479     if (itVoice) itVoice->UpdatePortamentoPos(itNoteOffEventOnKeyList);
1480     }
1481     // create a pseudo note on event
1482     RTList<Event>::Iterator itPseudoNoteOnEvent = pOtherKey->pEvents->allocAppend();
1483     if (itPseudoNoteOnEvent) {
1484     // copy event
1485     *itPseudoNoteOnEvent = *itNoteOffEventOnKeyList;
1486     // transform event to a note on event
1487     itPseudoNoteOnEvent->Type = Event::type_note_on;
1488     itPseudoNoteOnEvent->Param.Note.Key = i;
1489     itPseudoNoteOnEvent->Param.Note.Velocity = pOtherKey->Velocity;
1490     // allocate and trigger new voice(s) for the other key
1491     TriggerNewVoices(pChannel, itPseudoNoteOnEvent, false);
1492     // if neither a voice was spawned or postponed then remove note on event from key again
1493     if (!pOtherKey->Active && !pOtherKey->VoiceTheftsQueued)
1494     pOtherKey->pEvents->free(itPseudoNoteOnEvent);
1495    
1496     } else dmsg(1,("Could not respawn voice, no free event left\n"));
1497     break; // done
1498     }
1499     }
1500     }
1501     if (bOtherKeysPressed) {
1502     if (pKey->Active) { // kill all voices on this key
1503     bShouldRelease = false; // no need to release, as we kill it here
1504     VoiceIterator itVoiceToBeKilled = pKey->pActiveVoices->first();
1505     VoiceIterator end = pKey->pActiveVoices->end();
1506     for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1507 persson 2115 if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))
1508 iliev 2012 itVoiceToBeKilled->Kill(itNoteOffEventOnKeyList);
1509     }
1510     }
1511     } else pChannel->PortamentoPos = -1.0f;
1512     }
1513    
1514     // if no solo mode (the usual case) or if solo mode and no other key pressed, then release voices on this key if needed
1515     if (bShouldRelease) {
1516     itNoteOffEventOnKeyList->Type = Event::type_release; // transform event type
1517    
1518     // spawn release triggered voice(s) if needed
1519     if (pKey->ReleaseTrigger && pChannel->pInstrument) {
1520     TriggerReleaseVoices(pChannel, itNoteOffEventOnKeyList);
1521     pKey->ReleaseTrigger = false;
1522     }
1523     }
1524    
1525     // if neither a voice was spawned or postponed on this key then remove note off event from key again
1526     if (!pKey->Active && !pKey->VoiceTheftsQueued)
1527     pKey->pEvents->free(itNoteOffEventOnKeyList);
1528    
1529     pChannel->listeners.PostProcessNoteOff(iKey, vel);
1530     }
1531    
1532     /**
1533     * Reset all voices and disk thread and clear input event queue and all
1534     * control and status variables. This method is protected by a mutex.
1535     */
1536     virtual void ResetInternal() {
1537 persson 2427 LockGuard lock(ResetInternalMutex);
1538 iliev 2012
1539     // make sure that the engine does not get any sysex messages
1540     // while it's reseting
1541     bool sysexDisabled = MidiInputPort::RemoveSysexListener(this);
1542     SetVoiceCount(0);
1543     ActiveVoiceCountMax = 0;
1544    
1545     // reset voice stealing parameters
1546     pVoiceStealingQueue->clear();
1547     itLastStolenVoice = VoiceIterator();
1548     itLastStolenVoiceGlobally = VoiceIterator();
1549     iuiLastStolenKey = RTList<uint>::Iterator();
1550     iuiLastStolenKeyGlobally = RTList<uint>::Iterator();
1551     pLastStolenChannel = NULL;
1552    
1553     // reset all voices
1554     for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
1555     iterVoice->Reset();
1556     }
1557     pVoicePool->clear();
1558    
1559     // reset disk thread
1560     if (pDiskThread) pDiskThread->Reset();
1561    
1562     // delete all input events
1563     pEventQueue->init();
1564     pSysexBuffer->init();
1565     if (sysexDisabled) MidiInputPort::AddSysexListener(this);
1566     }
1567    
1568     /**
1569     * Kills all voices on an engine channel as soon as possible. Voices
1570     * won't get into release state, their volume level will be ramped down
1571     * as fast as possible.
1572     *
1573     * @param pEngineChannel - engine channel on which all voices should be killed
1574     * @param itKillEvent - event which caused this killing of all voices
1575     */
1576     virtual void KillAllVoices(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itKillEvent) {
1577     EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1578     int count = pChannel->KillAllVoices(itKillEvent);
1579     VoiceSpawnsLeft -= count; //FIXME: just a temporary workaround, we should check the cause in StealVoice() instead
1580     }
1581    
1582     /**
1583     * Allocates and triggers a new voice. This method will usually be
1584     * called by the ProcessNoteOn() method and by the voices itself
1585     * (e.g. to spawn further voices on the same key for layered sounds).
1586     *
1587     * @param pEngineChannel - engine channel on which this event occured on
1588     * @param itNoteOnEvent - key, velocity and time stamp of the event
1589     * @param iLayer - layer index for the new voice (optional - only
1590     * in case of layered sounds of course)
1591     * @param ReleaseTriggerVoice - if new voice is a release triggered voice
1592     * (optional, default = false)
1593     * @param VoiceStealing - if voice stealing should be performed
1594     * when there is no free voice
1595     * (optional, default = true)
1596     * @param HandleKeyGroupConflicts - if voices should be killed due to a
1597     * key group conflict
1598     * @returns pointer to new voice or NULL if there was no free voice or
1599     * if the voice wasn't triggered (for example when no region is
1600     * defined for the given key).
1601     */
1602     virtual PoolVoiceIterator LaunchVoice (
1603     EngineChannel* pEngineChannel,
1604     Pool<Event>::Iterator& itNoteOnEvent,
1605     int iLayer,
1606     bool ReleaseTriggerVoice,
1607     bool VoiceStealing,
1608     bool HandleKeyGroupConflicts
1609     ) = 0;
1610    
1611 iliev 2015 virtual int GetMinFadeOutSamples() { return MinFadeOutSamples; }
1612    
1613 iliev 2027 int InitNewVoice (
1614     EngineChannelBase<V, R, I>* pChannel,
1615     R* pRegion,
1616     Pool<Event>::Iterator& itNoteOnEvent,
1617     Voice::type_t VoiceType,
1618     int iLayer,
1619     int iKeyGroup,
1620     bool ReleaseTriggerVoice,
1621     bool VoiceStealing,
1622     typename Pool<V>::Iterator& itNewVoice
1623     ) {
1624     int key = itNoteOnEvent->Param.Note.Key;
1625     typename MidiKeyboardManager<V>::MidiKey* pKey = &pChannel->pMIDIKeyInfo[key];
1626     if (itNewVoice) {
1627     // launch the new voice
1628     if (itNewVoice->Trigger(pChannel, itNoteOnEvent, pChannel->Pitch, pRegion, VoiceType, iKeyGroup) < 0) {
1629     dmsg(4,("Voice not triggered\n"));
1630     pKey->pActiveVoices->free(itNewVoice);
1631     }
1632     else { // on success
1633     --VoiceSpawnsLeft;
1634     if (!pKey->Active) { // mark as active key
1635     pKey->Active = true;
1636     pKey->itSelf = pChannel->pActiveKeys->allocAppend();
1637     *pKey->itSelf = itNoteOnEvent->Param.Note.Key;
1638     }
1639 persson 2115 if (itNewVoice->Type & Voice::type_release_trigger_required) pKey->ReleaseTrigger = true; // mark key for the need of release triggered voice(s)
1640 iliev 2027 return 0; // success
1641     }
1642     }
1643     else if (VoiceStealing) {
1644     // try to steal one voice
1645     int result = StealVoice(pChannel, itNoteOnEvent);
1646     if (!result) { // voice stolen successfully
1647     // put note-on event into voice-stealing queue, so it will be reprocessed after killed voice died
1648     RTList<Event>::Iterator itStealEvent = pVoiceStealingQueue->allocAppend();
1649     if (itStealEvent) {
1650     *itStealEvent = *itNoteOnEvent; // copy event
1651     itStealEvent->Param.Note.Layer = iLayer;
1652     itStealEvent->Param.Note.ReleaseTrigger = ReleaseTriggerVoice;
1653     pKey->VoiceTheftsQueued++;
1654     }
1655     else dmsg(1,("Voice stealing queue full!\n"));
1656     }
1657     }
1658    
1659     return -1;
1660     }
1661 schoenebeck 2448
1662     /**
1663     * Checks whether scale tuning setting has been changed since last
1664     * time this method was called, if yes, it recalculates the pitch
1665     * for all active voices.
1666     */
1667     void ProcessScaleTuningChange() {
1668     const bool changed = ScaleTuningChanged.readAndReset();
1669     if (!changed) return;
1670    
1671     for (int i = 0; i < engineChannels.size(); i++) {
1672     EngineChannelBase<V, R, I>* channel =
1673     static_cast<EngineChannelBase<V, R, I>*>(engineChannels[i]);
1674     channel->OnScaleTuningChanged();
1675     }
1676     }
1677 iliev 2027
1678 iliev 2012 private:
1679     Pool<V>* pVoicePool; ///< Contains all voices that can be activated.
1680     Pool<RR*> SuspendedRegions;
1681     Mutex SuspendedRegionsMutex;
1682     Condition SuspensionChangeOngoing;
1683     RR* pPendingRegionSuspension;
1684     RR* pPendingRegionResumption;
1685     int iPendingStreamDeletions;
1686     };
1687    
1688     template <class V, class RR, class R, class D, class IM, class I>
1689     IM EngineBase<V, RR, R, D, IM, I>::instruments;
1690    
1691     } // namespace LinuxSampler
1692    
1693     #endif /* __LS_ENGINEBASE_H__ */
1694    

  ViewVC Help
Powered by ViewVC