/[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 2448 - (hide annotations) (download) (as text)
Fri May 3 14:26:32 2013 UTC (10 years, 10 months ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 80540 byte(s)
* Immediately apply scale tuning changes to active voices.
* Exposed scale tuning to C++ API (along to the already existing standard
  SysEx way).
* Bumped version to 1.0.0.svn21

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

  ViewVC Help
Powered by ViewVC