/[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 2296 - (hide annotations) (download) (as text)
Thu Dec 8 20:03:47 2011 UTC (12 years, 4 months ago) by iliev
File MIME type: text/x-c++hdr
File size: 79339 byte(s)
* fixed crash when trying to create an effect instance with controls
  which min and/or max values depend on the sample rate
* experimental support for per voice equalization (work in progress)
* sfz engine: implemented opcodes eq1_freq, eq2_freq, eq3_freq,
  eq1_freqccN, eq2_freqccN, eq3_freqccN, eq1_bw, eq2_bw, eq3_bw,
  eq1_bwccN, eq2_bwccN, eq3_bwccN, eq1_gain, eq2_gain, eq3_gain,
  eq1_gainccN, eq2_gainccN, eq3_gainccN

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

  ViewVC Help
Powered by ViewVC