/[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 2298 - (hide annotations) (download) (as text)
Fri Dec 9 17:04:24 2011 UTC (12 years, 3 months ago) by iliev
File MIME type: text/x-c++hdr
File size: 79468 byte(s)
* use different EQ effect instance for every voice

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 iliev 2298 bool printEqInfo = true;
349 iliev 2012 for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
350     if (!iterVoice->pDiskThread) {
351     dmsg(0,("Engine -> voice::trigger: !pDiskThread\n"));
352     exit(EXIT_FAILURE);
353     }
354 iliev 2298
355     iterVoice->CreateEq();
356    
357     if(printEqInfo) {
358     iterVoice->PrintEqInfo();
359     printEqInfo = false;
360     }
361 iliev 2012 }
362     pVoicePool->clear();
363 schoenebeck 2121
364     // (re)create dedicated voice audio buffers
365     //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
366     if (pDedicatedVoiceChannelLeft) delete pDedicatedVoiceChannelLeft;
367     if (pDedicatedVoiceChannelRight) delete pDedicatedVoiceChannelRight;
368     pDedicatedVoiceChannelLeft = new AudioChannel(0, MaxSamplesPerCycle);
369     pDedicatedVoiceChannelRight = new AudioChannel(1, MaxSamplesPerCycle);
370 iliev 2012 }
371    
372     /**
373     * Similar to @c Disable() but this method additionally kills all voices
374     * and disk streams and blocks until all voices and disk streams are actually
375     * killed / deleted.
376     *
377     * @e Note: only the original calling thread is able to re-enable the
378     * engine afterwards by calling @c ResumeAll() later on!
379     */
380     virtual void SuspendAll() {
381     dmsg(2,("Engine: Suspending all ...\n"));
382     // stop the engine, so we can safely modify the engine's
383     // data structures from this foreign thread
384     DisableAndLock();
385     // we could also use the respective class member variable here,
386     // but this is probably safer and cleaner
387     int iPendingStreamDeletions = 0;
388     // kill all voices on all engine channels the *die hard* way
389     for (int iChannel = 0; iChannel < engineChannels.size(); iChannel++) {
390     EngineChannelBase<V, R, I>* pEngineChannel =
391     static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannel]);
392    
393     iPendingStreamDeletions += pEngineChannel->KillAllVoicesImmediately();
394     }
395     // wait until all streams were actually deleted by the disk thread
396     while (iPendingStreamDeletions) {
397     while (
398     iPendingStreamDeletions &&
399     pDiskThread->AskForDeletedStream() != Stream::INVALID_HANDLE
400     ) iPendingStreamDeletions--;
401     if (!iPendingStreamDeletions) break;
402     usleep(10000); // sleep for 10ms
403     }
404     dmsg(2,("EngineBase: Everything suspended.\n"));
405     }
406    
407     /**
408     * At the moment same as calling @c Enable() directly, but this might
409     * change in future, so better call this method as counterpart to
410     * @c SuspendAll() instead of @c Enable() !
411     */
412     virtual void ResumeAll() { Enable(); }
413    
414     /**
415     * Order the engine to stop rendering audio for the given region.
416     * Additionally this method will block until all voices and their disk
417     * streams associated with that region are actually killed / deleted, so
418     * one can i.e. safely modify the region with an instrument editor after
419     * returning from this method.
420     *
421     * @param pRegion - region the engine shall stop using
422     */
423     virtual void Suspend(RR* pRegion) {
424     dmsg(2,("EngineBase: Suspending Region %x ...\n",pRegion));
425     SuspendedRegionsMutex.Lock();
426     SuspensionChangeOngoing.Set(true);
427     pPendingRegionSuspension = pRegion;
428     SuspensionChangeOngoing.WaitAndUnlockIf(true);
429     SuspendedRegionsMutex.Unlock();
430     dmsg(2,("EngineBase: Region %x suspended.",pRegion));
431     }
432    
433     /**
434     * Orders the engine to resume playing back the given region, previously
435     * suspended with @c Suspend() .
436     *
437     * @param pRegion - region the engine shall be allowed to use again
438     */
439     virtual void Resume(RR* pRegion) {
440     dmsg(2,("EngineBase: Resuming Region %x ...\n",pRegion));
441     SuspendedRegionsMutex.Lock();
442     SuspensionChangeOngoing.Set(true);
443     pPendingRegionResumption = pRegion;
444     SuspensionChangeOngoing.WaitAndUnlockIf(true);
445     SuspendedRegionsMutex.Unlock();
446     dmsg(2,("EngineBase: Region %x resumed.\n",pRegion));
447     }
448    
449     virtual void ResetSuspendedRegions() {
450     SuspendedRegions.clear();
451     iPendingStreamDeletions = 0;
452     pPendingRegionSuspension = pPendingRegionResumption = NULL;
453     SuspensionChangeOngoing.Set(false);
454     }
455    
456     /**
457     * Called by the engine's (audio) thread once per cycle to process requests
458     * from the outer world to suspend or resume a given @c gig::Region .
459     */
460     virtual void ProcessSuspensionsChanges() {
461     // process request for suspending one region
462     if (pPendingRegionSuspension) {
463     // kill all voices on all engine channels that use this region
464     for (int iChannel = 0; iChannel < engineChannels.size(); iChannel++) {
465     EngineChannelBase<V, R, I>* pEngineChannel =
466     static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannel]);
467     SuspensionVoiceHandler handler(pPendingRegionSuspension);
468     pEngineChannel->ProcessActiveVoices(&handler);
469     iPendingStreamDeletions += handler.PendingStreamDeletions;
470     }
471     // make sure the region is not yet on the list
472     bool bAlreadySuspended = false;
473     RootRegionIterator iter = SuspendedRegions.first();
474     RootRegionIterator end = SuspendedRegions.end();
475     for (; iter != end; ++iter) { // iterate through all suspended regions
476     if (*iter == pPendingRegionSuspension) { // found
477     bAlreadySuspended = true;
478     dmsg(1,("EngineBase: attempt to suspend an already suspended region !!!\n"));
479     break;
480     }
481     }
482     if (!bAlreadySuspended) {
483     // put the region on the list of suspended regions
484     RootRegionIterator iter = SuspendedRegions.allocAppend();
485     if (iter) {
486     *iter = pPendingRegionSuspension;
487     } else std::cerr << "EngineBase: Could not suspend Region, list is full. This is a bug!!!\n" << std::flush;
488     }
489     // free request slot for next caller (and to make sure that
490     // we're not going to process the same request in the next cycle)
491     pPendingRegionSuspension = NULL;
492     // if no disk stream deletions are pending, awaken other side, as
493     // we're done in this case
494     if (!iPendingStreamDeletions) SuspensionChangeOngoing.Set(false);
495     }
496    
497     // process request for resuming one region
498     if (pPendingRegionResumption) {
499     // remove region from the list of suspended regions
500     RootRegionIterator iter = SuspendedRegions.first();
501     RootRegionIterator end = SuspendedRegions.end();
502     for (; iter != end; ++iter) { // iterate through all suspended regions
503     if (*iter == pPendingRegionResumption) { // found
504     SuspendedRegions.free(iter);
505     break; // done
506     }
507     }
508     // free request slot for next caller
509     pPendingRegionResumption = NULL;
510     // awake other side as we're done
511     SuspensionChangeOngoing.Set(false);
512     }
513     }
514    
515     /**
516     * Called by the engine's (audio) thread once per cycle to check if
517     * streams of voices that were killed due to suspension request have
518     * finally really been deleted by the disk thread.
519     */
520     virtual void ProcessPendingStreamDeletions() {
521     if (!iPendingStreamDeletions) return;
522     //TODO: or shall we better store a list with stream handles instead of a scalar amount of streams to be deleted? might be safer
523     while (
524     iPendingStreamDeletions &&
525     pDiskThread->AskForDeletedStream() != Stream::INVALID_HANDLE
526     ) iPendingStreamDeletions--;
527     // just for safety ...
528     while (pDiskThread->AskForDeletedStream() != Stream::INVALID_HANDLE);
529     // now that all disk streams are deleted, awake other side as
530     // we're finally done with suspending the requested region
531     if (!iPendingStreamDeletions) SuspensionChangeOngoing.Set(false);
532     }
533    
534     /**
535     * Returns @c true if the given region is currently set to be suspended
536     * from being used, @c false otherwise.
537     */
538     virtual bool RegionSuspended(RR* pRegion) {
539     if (SuspendedRegions.isEmpty()) return false;
540     //TODO: or shall we use a sorted container instead of the RTList? might be faster ... or trivial ;-)
541     RootRegionIterator iter = SuspendedRegions.first();
542     RootRegionIterator end = SuspendedRegions.end();
543     for (; iter != end; ++iter) // iterate through all suspended regions
544     if (*iter == pRegion) return true;
545     return false;
546     }
547    
548     // implementation of abstract method derived from class 'LinuxSampler::RegionPools'
549     virtual Pool<R*>* GetRegionPool(int index) {
550     if (index < 0 || index > 1) throw Exception("Index out of bounds");
551     return pRegionPool[index];
552     }
553    
554     // implementation of abstract method derived from class 'LinuxSampler::VoicePool'
555     virtual Pool<V>* GetVoicePool() { return pVoicePool; }
556    
557     D* GetDiskThread() { return pDiskThread; }
558    
559     //friend class EngineChannelBase<V, R, I>;
560    
561 persson 2127 static IM instruments;
562    
563 iliev 2012 protected:
564     class SuspensionVoiceHandler : public MidiKeyboardManager<V>::VoiceHandler {
565     public:
566     int PendingStreamDeletions;
567     RR* pPendingRegionSuspension;
568     SuspensionVoiceHandler(RR* pPendingRegionSuspension) {
569     PendingStreamDeletions = 0;
570     this->pPendingRegionSuspension = pPendingRegionSuspension;
571     }
572    
573     virtual bool Process(MidiKey* pMidiKey) {
574     VoiceIterator itVoice = pMidiKey->pActiveVoices->first();
575     // if current key is not associated with this region, skip this key
576     if (itVoice->GetRegion()->GetParent() != pPendingRegionSuspension) return false;
577    
578     return true;
579     }
580    
581     virtual void Process(VoiceIterator& itVoice) {
582     // request a notification from disk thread side for stream deletion
583     const Stream::Handle hStream = itVoice->KillImmediately(true);
584     if (hStream != Stream::INVALID_HANDLE) { // voice actually used a stream
585     PendingStreamDeletions++;
586     }
587     //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
588     }
589     };
590    
591     Pool<R*>* pRegionPool[2]; ///< Double buffered pool, used by the engine channels to keep track of regions in use.
592     int MinFadeOutSamples; ///< The number of samples needed to make an instant fade out (e.g. for voice stealing) without leading to clicks.
593     D* pDiskThread;
594    
595     int ActiveVoiceCountTemp; ///< number of currently active voices (for internal usage, will be used for incrementation)
596     VoiceIterator itLastStolenVoice; ///< Only for voice stealing: points to the last voice which was theft in current audio fragment, NULL otherwise.
597     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.
598     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.
599     VoiceIterator itLastStolenVoiceGlobally; ///< Same as itLastStolenVoice, but engine globally
600     RTList<uint>::Iterator iuiLastStolenKeyGlobally; ///< Same as iuiLastStolenKey, but engine globally
601     RTList<Event>* pVoiceStealingQueue; ///< All voice-launching events which had to be postponed due to free voice shortage.
602     Mutex ResetInternalMutex; ///< Mutex to protect the ResetInternal function for concurrent usage (e.g. by the lscp and instrument loader threads).
603     int iMaxDiskStreams;
604    
605     /**
606     * Dispatch and handle all events in this audio fragment for the given
607     * engine channel.
608     *
609     * @param pEngineChannel - engine channel on which events should be
610     * processed
611     * @param Samples - amount of sample points to be processed in
612     * this audio fragment cycle
613     */
614     void ProcessEvents(EngineChannel* pEngineChannel, uint Samples) {
615     // get all events from the engine channels's input event queue which belong to the current fragment
616     // (these are the common events like NoteOn, NoteOff, ControlChange, etc.)
617     AbstractEngineChannel* pChannel = static_cast<AbstractEngineChannel*>(pEngineChannel);
618     pChannel->ImportEvents(Samples);
619    
620     // process events
621     {
622     RTList<Event>::Iterator itEvent = pChannel->pEvents->first();
623     RTList<Event>::Iterator end = pChannel->pEvents->end();
624     for (; itEvent != end; ++itEvent) {
625     switch (itEvent->Type) {
626     case Event::type_note_on:
627     dmsg(5,("Engine: Note on received\n"));
628     ProcessNoteOn((EngineChannel*)itEvent->pEngineChannel, itEvent);
629     break;
630     case Event::type_note_off:
631     dmsg(5,("Engine: Note off received\n"));
632     ProcessNoteOff((EngineChannel*)itEvent->pEngineChannel, itEvent);
633     break;
634     case Event::type_control_change:
635     dmsg(5,("Engine: MIDI CC received\n"));
636     ProcessControlChange((EngineChannel*)itEvent->pEngineChannel, itEvent);
637     break;
638     case Event::type_pitchbend:
639     dmsg(5,("Engine: Pitchbend received\n"));
640     ProcessPitchbend(static_cast<AbstractEngineChannel*>(itEvent->pEngineChannel), itEvent);
641     break;
642     }
643     }
644     }
645    
646     // reset voice stealing for the next engine channel (or next audio fragment)
647     itLastStolenVoice = VoiceIterator();
648     itLastStolenVoiceGlobally = VoiceIterator();
649     iuiLastStolenKey = RTList<uint>::Iterator();
650     iuiLastStolenKeyGlobally = RTList<uint>::Iterator();
651     pLastStolenChannel = NULL;
652     }
653    
654     /**
655     * Will be called by LaunchVoice() method in case there are no free
656     * voices left. This method will select and kill one old voice for
657     * voice stealing and postpone the note-on event until the selected
658     * voice actually died.
659     *
660     * @param pEngineChannel - engine channel on which this event occured on
661     * @param itNoteOnEvent - key, velocity and time stamp of the event
662     * @returns 0 on success, a value < 0 if no active voice could be picked for voice stealing
663     */
664     int StealVoice(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {
665     if (VoiceSpawnsLeft <= 0) {
666     dmsg(1,("Max. voice thefts per audio fragment reached (you may raise CONFIG_MAX_VOICES).\n"));
667     return -1;
668     }
669    
670     EngineChannelBase<V, R, I>* pEngineChn = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
671    
672     if (!pEventPool->poolIsEmpty()) {
673    
674     if(!pEngineChn->StealVoice(itNoteOnEvent, &itLastStolenVoice, &iuiLastStolenKey)) {
675     --VoiceSpawnsLeft;
676     return 0;
677     }
678    
679     // if we couldn't steal a voice from the same engine channel then
680     // steal oldest voice on the oldest key from any other engine channel
681     // (the smaller engine channel number, the higher priority)
682     EngineChannelBase<V, R, I>* pSelectedChannel;
683     int iChannelIndex;
684     VoiceIterator itSelectedVoice;
685    
686     // select engine channel
687     if (pLastStolenChannel) {
688     pSelectedChannel = pLastStolenChannel;
689     iChannelIndex = pSelectedChannel->iEngineIndexSelf;
690     } else { // pick the engine channel followed by this engine channel
691     iChannelIndex = (pEngineChn->iEngineIndexSelf + 1) % engineChannels.size();
692     pSelectedChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannelIndex]);
693     }
694    
695     // if we already stole in this fragment, try to proceed on same key
696     if (this->itLastStolenVoiceGlobally) {
697     itSelectedVoice = this->itLastStolenVoiceGlobally;
698     do {
699     ++itSelectedVoice;
700     } while (itSelectedVoice && !itSelectedVoice->IsStealable()); // proceed iterating if voice was created in this fragment cycle
701     }
702    
703     #if CONFIG_DEVMODE
704     EngineChannel* pBegin = pSelectedChannel; // to detect endless loop
705     #endif // CONFIG_DEVMODE
706    
707     // did we find a 'stealable' voice?
708     if (itSelectedVoice && itSelectedVoice->IsStealable()) {
709     // remember which voice we stole, so we can simply proceed on next voice stealing
710     this->itLastStolenVoiceGlobally = itSelectedVoice;
711     } else while (true) { // iterate through engine channels
712     // get (next) oldest key
713     RTList<uint>::Iterator iuiSelectedKey = (this->iuiLastStolenKeyGlobally) ? ++this->iuiLastStolenKeyGlobally : pSelectedChannel->pActiveKeys->first();
714     this->iuiLastStolenKeyGlobally = RTList<uint>::Iterator(); // to prevent endless loop (see line above)
715     while (iuiSelectedKey) {
716     MidiKey* pSelectedKey = &pSelectedChannel->pMIDIKeyInfo[*iuiSelectedKey];
717     itSelectedVoice = pSelectedKey->pActiveVoices->first();
718     // proceed iterating if voice was created in this fragment cycle
719     while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice;
720     // found a "stealable" voice ?
721     if (itSelectedVoice && itSelectedVoice->IsStealable()) {
722     // remember which voice on which key on which engine channel we stole, so we can simply proceed on next voice stealing
723     this->iuiLastStolenKeyGlobally = iuiSelectedKey;
724     this->itLastStolenVoiceGlobally = itSelectedVoice;
725     this->pLastStolenChannel = pSelectedChannel;
726     goto stealable_voice_found; // selection succeeded
727     }
728     ++iuiSelectedKey; // get next key on current engine channel
729     }
730     // get next engine channel
731     iChannelIndex = (iChannelIndex + 1) % engineChannels.size();
732     pSelectedChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannelIndex]);
733    
734     #if CONFIG_DEVMODE
735     if (pSelectedChannel == pBegin) {
736     dmsg(1,("FATAL ERROR: voice stealing endless loop!\n"));
737     dmsg(1,("VoiceSpawnsLeft=%d.\n", VoiceSpawnsLeft));
738     dmsg(1,("Exiting.\n"));
739     exit(-1);
740     }
741     #endif // CONFIG_DEVMODE
742     }
743    
744     // jump point if a 'stealable' voice was found
745     stealable_voice_found:
746    
747     #if CONFIG_DEVMODE
748     if (!itSelectedVoice->IsActive()) {
749     dmsg(1,("EngineBase: ERROR, tried to steal a voice which was not active !!!\n"));
750     return -1;
751     }
752     #endif // CONFIG_DEVMODE
753    
754     // now kill the selected voice
755     itSelectedVoice->Kill(itNoteOnEvent);
756    
757     --VoiceSpawnsLeft;
758    
759     return 0; // success
760     }
761     else {
762     dmsg(1,("Event pool emtpy!\n"));
763     return -1;
764     }
765     }
766    
767     void HandleInstrumentChanges() {
768     bool instrumentChanged = false;
769     for (int i = 0; i < engineChannels.size(); i++) {
770     EngineChannelBase<V, R, I>* pEngineChannel =
771     static_cast<EngineChannelBase<V, R, I>*>(engineChannels[i]);
772    
773     // as we're going to (carefully) write some status to the
774     // synchronized struct, we cast away the const
775     InstrumentChangeCmd<R, I>& cmd =
776     const_cast<InstrumentChangeCmd<R, I>&>(pEngineChannel->InstrumentChangeCommandReader.Lock());
777    
778     pEngineChannel->pRegionsInUse = cmd.pRegionsInUse;
779     pEngineChannel->pRegionsInUse->clear();
780    
781     if (cmd.bChangeInstrument) {
782     // change instrument
783     dmsg(5,("Engine: instrument change command received\n"));
784     cmd.bChangeInstrument = false;
785     pEngineChannel->pInstrument = cmd.pInstrument;
786     instrumentChanged = true;
787    
788     pEngineChannel->MarkAllActiveVoicesAsOrphans();
789     }
790     }
791    
792     if (instrumentChanged) {
793     //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
794     ResetSuspendedRegions();
795     }
796     }
797    
798     /**
799     * Render all 'normal' voices (that is voices which were not stolen in
800     * this fragment) on the given engine channel.
801     *
802     * @param pEngineChannel - engine channel on which audio should be
803     * rendered
804     * @param Samples - amount of sample points to be rendered in
805     * this audio fragment cycle
806     */
807     void RenderActiveVoices(EngineChannel* pEngineChannel, uint Samples) {
808     #if !CONFIG_PROCESS_MUTED_CHANNELS
809     if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
810     #endif
811    
812     EngineChannelBase<V, R, I>* pChannel =
813     static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
814     pChannel->RenderActiveVoices(Samples);
815    
816     ActiveVoiceCountTemp += pEngineChannel->GetVoiceCount();
817     }
818    
819     /**
820     * Render all stolen voices (only voices which were stolen in this
821     * fragment) on the given engine channel. Stolen voices are rendered
822     * after all normal voices have been rendered; this is needed to render
823     * audio of those voices which were selected for voice stealing until
824     * the point were the stealing (that is the take over of the voice)
825     * actually happened.
826     *
827     * @param pEngineChannel - engine channel on which audio should be
828     * rendered
829     * @param Samples - amount of sample points to be rendered in
830     * this audio fragment cycle
831     */
832     void RenderStolenVoices(uint Samples) {
833     RTList<Event>::Iterator itVoiceStealEvent = pVoiceStealingQueue->first();
834     RTList<Event>::Iterator end = pVoiceStealingQueue->end();
835     for (; itVoiceStealEvent != end; ++itVoiceStealEvent) {
836     EngineChannelBase<V, R, I>* pEngineChannel =
837     static_cast<EngineChannelBase<V, R, I>*>(itVoiceStealEvent->pEngineChannel);;
838     if (!pEngineChannel->pInstrument) continue; // ignore if no instrument loaded
839     PoolVoiceIterator itNewVoice =
840     LaunchVoice(pEngineChannel, itVoiceStealEvent, itVoiceStealEvent->Param.Note.Layer, itVoiceStealEvent->Param.Note.ReleaseTrigger, false, false);
841     if (itNewVoice) {
842     itNewVoice->Render(Samples);
843     if (itNewVoice->IsActive()) { // still active
844     *(pEngineChannel->pRegionsInUse->allocAppend()) = itNewVoice->GetRegion();
845     ActiveVoiceCountTemp++;
846     pEngineChannel->SetVoiceCount(pEngineChannel->GetVoiceCount() + 1);
847    
848     if (itNewVoice->PlaybackState == Voice::playback_state_disk) {
849     if (itNewVoice->DiskStreamRef.State != Stream::state_unused) {
850     pEngineChannel->SetDiskStreamCount(pEngineChannel->GetDiskStreamCount() + 1);
851     }
852     }
853     } else { // voice reached end, is now inactive
854     pEngineChannel->FreeVoice(itNewVoice); // remove voice from the list of active voices
855     }
856     }
857     else dmsg(1,("EngineBase: ERROR, voice stealing didn't work out!\n"));
858    
859     // we need to clear the key's event list explicitly here in case key was never active
860     MidiKey* pKey = &pEngineChannel->pMIDIKeyInfo[itVoiceStealEvent->Param.Note.Key];
861     pKey->VoiceTheftsQueued--;
862     if (!pKey->Active && !pKey->VoiceTheftsQueued) pKey->pEvents->clear();
863     }
864     }
865    
866     /**
867     * Free all keys which have turned inactive in this audio fragment, from
868     * the list of active keys and clear all event lists on that engine
869     * channel.
870     *
871     * @param pEngineChannel - engine channel to cleanup
872     */
873     void PostProcess(EngineChannel* pEngineChannel) {
874     EngineChannelBase<V, R, I>* pChannel =
875     static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
876     pChannel->FreeAllInactiveKyes();
877    
878     // empty the engine channel's own event lists
879     pChannel->ClearEventLists();
880     }
881    
882 schoenebeck 2121 /**
883     * Process MIDI control change events with hard coded behavior,
884     * that is controllers whose behavior is defined independently
885     * of the actual sampler engine type and instrument.
886     *
887     * @param pEngineChannel - engine channel on which the MIDI CC event was received
888     * @param itControlChangeEvent - the actual MIDI CC event
889     */
890 iliev 2012 void ProcessHardcodedControllers (
891     EngineChannel* pEngineChannel,
892     Pool<Event>::Iterator& itControlChangeEvent
893     ) {
894     EngineChannelBase<V, R, I>* pChannel =
895     static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
896    
897     switch (itControlChangeEvent->Param.CC.Controller) {
898     case 5: { // portamento time
899     pChannel->PortamentoTime = (float) itControlChangeEvent->Param.CC.Value / 127.0f * (float) CONFIG_PORTAMENTO_TIME_MAX + (float) CONFIG_PORTAMENTO_TIME_MIN;
900     break;
901     }
902 schoenebeck 2121 case 6: { // data entry (currently only used for RPN and NRPN controllers)
903     //dmsg(1,("DATA ENTRY %d\n", itControlChangeEvent->Param.CC.Value));
904     if (pChannel->GetMidiRpnController() >= 0) { // RPN controller number was sent previously ...
905     dmsg(4,("Guess it's an RPN ...\n"));
906     if (pChannel->GetMidiRpnController() == 2) { // coarse tuning in half tones
907     int transpose = (int) itControlChangeEvent->Param.CC.Value - 64;
908     // limit to +- two octaves for now
909     transpose = RTMath::Min(transpose, 24);
910     transpose = RTMath::Max(transpose, -24);
911     pChannel->GlobalTranspose = transpose;
912     // workaround, so we won't have hanging notes
913     pChannel->ReleaseAllVoices(itControlChangeEvent);
914     }
915     // to prevent other MIDI CC #6 messages to be misenterpreted as RPN controller data
916     pChannel->ResetMidiRpnController();
917     } else if (pChannel->GetMidiNrpnController() >= 0) { // NRPN controller number was sent previously ...
918     dmsg(4,("Guess it's an NRPN ...\n"));
919     const int NrpnCtrlMSB = pChannel->GetMidiNrpnController() >> 8;
920     const int NrpnCtrlLSB = pChannel->GetMidiNrpnController() & 0xff;
921     dmsg(4,("NRPN MSB=%d LSB=%d Data=%d\n", NrpnCtrlMSB, NrpnCtrlLSB, itControlChangeEvent->Param.CC.Value));
922     switch (NrpnCtrlMSB) {
923     case 0x1a: { // volume level of note (Roland GS NRPN)
924     const uint note = NrpnCtrlLSB;
925     const uint vol = itControlChangeEvent->Param.CC.Value;
926     dmsg(4,("Note Volume NRPN received (note=%d,vol=%d).\n", note, vol));
927     if (note < 128 && vol < 128)
928     pChannel->pMIDIKeyInfo[note].Volume = VolumeCurve[vol];
929     break;
930     }
931     case 0x1c: { // panpot of note (Roland GS NRPN)
932     const uint note = NrpnCtrlLSB;
933     const uint pan = itControlChangeEvent->Param.CC.Value;
934     dmsg(4,("Note Pan NRPN received (note=%d,pan=%d).\n", note, pan));
935     if (note < 128 && pan < 128) {
936     pChannel->pMIDIKeyInfo[note].PanLeft = PanCurve[128 - pan];
937     pChannel->pMIDIKeyInfo[note].PanRight = PanCurve[pan];
938     }
939     break;
940     }
941     case 0x1d: { // reverb send of note (Roland GS NRPN)
942     const uint note = NrpnCtrlLSB;
943     const float reverb = float(itControlChangeEvent->Param.CC.Value) / 127.0f;
944     dmsg(4,("Note Reverb Send NRPN received (note=%d,send=%d).\n", note, reverb));
945     if (note < 128)
946     pChannel->pMIDIKeyInfo[note].ReverbSend = reverb;
947     break;
948     }
949     case 0x1e: { // chorus send of note (Roland GS NRPN)
950     const uint note = NrpnCtrlLSB;
951     const float chorus = float(itControlChangeEvent->Param.CC.Value) / 127.0f;
952     dmsg(4,("Note Chorus Send NRPN received (note=%d,send=%d).\n", note, chorus));
953     if (note < 128)
954     pChannel->pMIDIKeyInfo[note].ChorusSend = chorus;
955     break;
956     }
957     }
958     // to prevent other MIDI CC #6 messages to be misenterpreted as NRPN controller data
959     pChannel->ResetMidiNrpnController();
960 iliev 2012 }
961     break;
962     }
963     case 7: { // volume
964     //TODO: not sample accurate yet
965     pChannel->MidiVolume = VolumeCurve[itControlChangeEvent->Param.CC.Value];
966     pChannel->bStatusChanged = true; // engine channel status has changed, so set notify flag
967     break;
968     }
969     case 10: { // panpot
970     //TODO: not sample accurate yet
971     pChannel->GlobalPanLeft = PanCurve[128 - itControlChangeEvent->Param.CC.Value];
972     pChannel->GlobalPanRight = PanCurve[itControlChangeEvent->Param.CC.Value];
973     pChannel->iLastPanRequest = itControlChangeEvent->Param.CC.Value;
974     break;
975     }
976     case 64: { // sustain
977     if (itControlChangeEvent->Param.CC.Value >= 64 && !pChannel->SustainPedal) {
978     dmsg(4,("DAMPER (RIGHT) PEDAL DOWN\n"));
979     pChannel->SustainPedal = true;
980     pChannel->listeners.PreProcessSustainPedalDown();
981    
982     #if !CONFIG_PROCESS_MUTED_CHANNELS
983     if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
984     pChannel->listeners.PostProcessSustainPedalDown();
985     return;
986     }
987     #endif
988    
989     pChannel->ProcessSustainPedalDown(itControlChangeEvent);
990     pChannel->listeners.PostProcessSustainPedalDown();
991     }
992     if (itControlChangeEvent->Param.CC.Value < 64 && pChannel->SustainPedal) {
993     dmsg(4,("DAMPER (RIGHT) PEDAL UP\n"));
994     pChannel->SustainPedal = false;
995     pChannel->listeners.PreProcessSustainPedalUp();
996    
997     #if !CONFIG_PROCESS_MUTED_CHANNELS
998     if (pChannel->GetMute()) { // skip if sampler channel is muted
999     pChannel->listeners.PostProcessSustainPedalUp();
1000     return;
1001     }
1002     #endif
1003    
1004     pChannel->ProcessSustainPedalUp(itControlChangeEvent);
1005     pChannel->listeners.PostProcessSustainPedalUp();
1006     }
1007     break;
1008     }
1009     case 65: { // portamento on / off
1010     const bool bPortamento = itControlChangeEvent->Param.CC.Value >= 64;
1011     if (bPortamento != pChannel->PortamentoMode)
1012     KillAllVoices(pChannel, itControlChangeEvent);
1013     pChannel->PortamentoMode = bPortamento;
1014     break;
1015     }
1016     case 66: { // sostenuto
1017     if (itControlChangeEvent->Param.CC.Value >= 64 && !pChannel->SostenutoPedal) {
1018     dmsg(4,("SOSTENUTO (CENTER) PEDAL DOWN\n"));
1019     pChannel->SostenutoPedal = true;
1020     pChannel->listeners.PreProcessSostenutoPedalDown();
1021    
1022     #if !CONFIG_PROCESS_MUTED_CHANNELS
1023     if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
1024     pChannel->listeners.PostProcessSostenutoPedalDown();
1025     return;
1026     }
1027     #endif
1028    
1029     pChannel->ProcessSostenutoPedalDown();
1030     pChannel->listeners.PostProcessSostenutoPedalDown();
1031     }
1032     if (itControlChangeEvent->Param.CC.Value < 64 && pChannel->SostenutoPedal) {
1033     dmsg(4,("SOSTENUTO (CENTER) PEDAL UP\n"));
1034     pChannel->SostenutoPedal = false;
1035     pChannel->listeners.PreProcessSostenutoPedalUp();
1036    
1037     #if !CONFIG_PROCESS_MUTED_CHANNELS
1038     if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
1039     pChannel->listeners.PostProcessSostenutoPedalUp();
1040     return;
1041     }
1042     #endif
1043    
1044     pChannel->ProcessSostenutoPedalUp(itControlChangeEvent);
1045     pChannel->listeners.PostProcessSostenutoPedalUp();
1046     }
1047     break;
1048     }
1049 schoenebeck 2121 case 98: { // NRPN controller LSB
1050     dmsg(4,("NRPN LSB %d\n", itControlChangeEvent->Param.CC.Value));
1051     pEngineChannel->SetMidiNrpnControllerLsb(itControlChangeEvent->Param.CC.Value);
1052     break;
1053     }
1054     case 99: { // NRPN controller MSB
1055     dmsg(4,("NRPN MSB %d\n", itControlChangeEvent->Param.CC.Value));
1056     pEngineChannel->SetMidiNrpnControllerMsb(itControlChangeEvent->Param.CC.Value);
1057     break;
1058     }
1059 iliev 2012 case 100: { // RPN controller LSB
1060 schoenebeck 2121 dmsg(4,("RPN LSB %d\n", itControlChangeEvent->Param.CC.Value));
1061 iliev 2012 pEngineChannel->SetMidiRpnControllerLsb(itControlChangeEvent->Param.CC.Value);
1062     break;
1063     }
1064     case 101: { // RPN controller MSB
1065 schoenebeck 2121 dmsg(4,("RPN MSB %d\n", itControlChangeEvent->Param.CC.Value));
1066 iliev 2012 pEngineChannel->SetMidiRpnControllerMsb(itControlChangeEvent->Param.CC.Value);
1067     break;
1068     }
1069    
1070    
1071     // Channel Mode Messages
1072    
1073     case 120: { // all sound off
1074     KillAllVoices(pEngineChannel, itControlChangeEvent);
1075     break;
1076     }
1077     case 121: { // reset all controllers
1078     pChannel->ResetControllers();
1079     break;
1080     }
1081     case 123: { // all notes off
1082     #if CONFIG_PROCESS_ALL_NOTES_OFF
1083     pChannel->ReleaseAllVoices(itControlChangeEvent);
1084     #endif // CONFIG_PROCESS_ALL_NOTES_OFF
1085     break;
1086     }
1087     case 126: { // mono mode on
1088     if (!pChannel->SoloMode)
1089     KillAllVoices(pEngineChannel, itControlChangeEvent);
1090     pChannel->SoloMode = true;
1091     break;
1092     }
1093     case 127: { // poly mode on
1094     if (pChannel->SoloMode)
1095     KillAllVoices(pEngineChannel, itControlChangeEvent);
1096     pChannel->SoloMode = false;
1097     break;
1098     }
1099     }
1100     }
1101    
1102     virtual D* CreateDiskThread() = 0;
1103    
1104     /**
1105     * Assigns and triggers a new voice for the respective MIDI key.
1106     *
1107     * @param pEngineChannel - engine channel on which this event occured on
1108     * @param itNoteOnEvent - key, velocity and time stamp of the event
1109     */
1110     virtual void ProcessNoteOn(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {
1111     EngineChannelBase<V, R, I>* pChannel =
1112     static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1113    
1114     //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
1115     int k = itNoteOnEvent->Param.Note.Key + pChannel->GlobalTranspose;
1116     if (k < 0 || k > 127) return; //ignore keys outside the key range
1117    
1118     itNoteOnEvent->Param.Note.Key += pChannel->GlobalTranspose;
1119     int vel = itNoteOnEvent->Param.Note.Velocity;
1120    
1121     const int key = itNoteOnEvent->Param.Note.Key;
1122     MidiKey* pKey = &pChannel->pMIDIKeyInfo[key];
1123    
1124     pChannel->listeners.PreProcessNoteOn(key, vel);
1125     #if !CONFIG_PROCESS_MUTED_CHANNELS
1126     if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
1127     pChannel->listeners.PostProcessNoteOn(key, vel);
1128     return;
1129     }
1130     #endif
1131    
1132     if (!pChannel->pInstrument) {
1133     pChannel->listeners.PostProcessNoteOn(key, vel);
1134     return; // ignore if no instrument loaded
1135     }
1136    
1137     // move note on event to the key's own event list
1138     RTList<Event>::Iterator itNoteOnEventOnKeyList = itNoteOnEvent.moveToEndOf(pKey->pEvents);
1139    
1140     // if Solo Mode then kill all already active voices
1141     if (pChannel->SoloMode) {
1142     Pool<uint>::Iterator itYoungestKey = pChannel->pActiveKeys->last();
1143     if (itYoungestKey) {
1144     const int iYoungestKey = *itYoungestKey;
1145     const MidiKey* pOtherKey = &pChannel->pMIDIKeyInfo[iYoungestKey];
1146     if (pOtherKey->Active) {
1147     // get final portamento position of currently active voice
1148     if (pChannel->PortamentoMode) {
1149     VoiceIterator itVoice = pOtherKey->pActiveVoices->last();
1150     if (itVoice) itVoice->UpdatePortamentoPos(itNoteOnEventOnKeyList);
1151     }
1152     // kill all voices on the (other) key
1153     VoiceIterator itVoiceToBeKilled = pOtherKey->pActiveVoices->first();
1154     VoiceIterator end = pOtherKey->pActiveVoices->end();
1155     for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1156 persson 2115 if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))
1157 iliev 2012 itVoiceToBeKilled->Kill(itNoteOnEventOnKeyList);
1158     }
1159     }
1160     }
1161     // set this key as 'currently active solo key'
1162     pChannel->SoloKey = key;
1163     }
1164    
1165     pChannel->ProcessKeySwitchChange(key);
1166    
1167     pKey->KeyPressed = true; // the MIDI key was now pressed down
1168     pKey->Velocity = itNoteOnEventOnKeyList->Param.Note.Velocity;
1169     pKey->NoteOnTime = FrameTime + itNoteOnEventOnKeyList->FragmentPos(); // will be used to calculate note length
1170    
1171     // cancel release process of voices on this key if needed
1172     if (pKey->Active && !pChannel->SustainPedal) {
1173     RTList<Event>::Iterator itCancelReleaseEvent = pKey->pEvents->allocAppend();
1174     if (itCancelReleaseEvent) {
1175     *itCancelReleaseEvent = *itNoteOnEventOnKeyList; // copy event
1176     itCancelReleaseEvent->Type = Event::type_cancel_release; // transform event type
1177     }
1178     else dmsg(1,("Event pool emtpy!\n"));
1179     }
1180    
1181     TriggerNewVoices(pEngineChannel, itNoteOnEventOnKeyList);
1182    
1183     // if neither a voice was spawned or postponed then remove note on event from key again
1184     if (!pKey->Active && !pKey->VoiceTheftsQueued)
1185     pKey->pEvents->free(itNoteOnEventOnKeyList);
1186    
1187     if (!pChannel->SoloMode || pChannel->PortamentoPos < 0.0f) pChannel->PortamentoPos = (float) key;
1188 persson 2043 if (pKey->pRoundRobinIndex) {
1189     (*pKey->pRoundRobinIndex)++; // counter specific for the key or region
1190     pChannel->RoundRobinIndex++; // common counter for the channel
1191     }
1192 iliev 2012 pChannel->listeners.PostProcessNoteOn(key, vel);
1193     }
1194    
1195     /**
1196     * Allocate and trigger new voice(s) for the key.
1197     */
1198     virtual void TriggerNewVoices (
1199     EngineChannel* pEngineChannel,
1200     RTList<Event>::Iterator& itNoteOnEvent,
1201     bool HandleKeyGroupConflicts = true
1202     ) = 0;
1203    
1204     /**
1205     * Allocate and trigger release voice(s) for the key.
1206     */
1207     virtual void TriggerReleaseVoices (
1208     EngineChannel* pEngineChannel,
1209     RTList<Event>::Iterator& itNoteOffEvent
1210     ) = 0;
1211    
1212     /**
1213     * Releases the voices on the given key if sustain pedal is not pressed.
1214     * If sustain is pressed, the release of the note will be postponed until
1215     * sustain pedal will be released or voice turned inactive by itself (e.g.
1216     * due to completion of sample playback).
1217     *
1218     * @param pEngineChannel - engine channel on which this event occured on
1219     * @param itNoteOffEvent - key, velocity and time stamp of the event
1220     */
1221     virtual void ProcessNoteOff(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOffEvent) {
1222     EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1223    
1224     int k = itNoteOffEvent->Param.Note.Key + pChannel->GlobalTranspose;
1225     if (k < 0 || k > 127) return; //ignore keys outside the key range
1226    
1227     //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
1228     itNoteOffEvent->Param.Note.Key += pChannel->GlobalTranspose;
1229     int vel = itNoteOffEvent->Param.Note.Velocity;
1230    
1231     const int iKey = itNoteOffEvent->Param.Note.Key;
1232     MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];
1233    
1234     pChannel->listeners.PreProcessNoteOff(iKey, vel);
1235    
1236     #if !CONFIG_PROCESS_MUTED_CHANNELS
1237     if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
1238     pChannel->listeners.PostProcessNoteOff(iKey, vel);
1239     return;
1240     }
1241     #endif
1242    
1243     pKey->KeyPressed = false; // the MIDI key was now released
1244    
1245     // move event to the key's own event list
1246     RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);
1247    
1248     bool bShouldRelease = pKey->Active && pChannel->ShouldReleaseVoice(itNoteOffEventOnKeyList->Param.Note.Key);
1249    
1250     // in case Solo Mode is enabled, kill all voices on this key and respawn a voice on the highest pressed key (if any)
1251     if (pChannel->SoloMode && pChannel->pInstrument) { //TODO: this feels like too much code just for handling solo mode :P
1252     bool bOtherKeysPressed = false;
1253     if (iKey == pChannel->SoloKey) {
1254     pChannel->SoloKey = -1;
1255     // if there's still a key pressed down, respawn a voice (group) on the highest key
1256     for (int i = 127; i > 0; i--) {
1257     MidiKey* pOtherKey = &pChannel->pMIDIKeyInfo[i];
1258     if (pOtherKey->KeyPressed) {
1259     bOtherKeysPressed = true;
1260     // make the other key the new 'currently active solo key'
1261     pChannel->SoloKey = i;
1262     // get final portamento position of currently active voice
1263     if (pChannel->PortamentoMode) {
1264     VoiceIterator itVoice = pKey->pActiveVoices->first();
1265     if (itVoice) itVoice->UpdatePortamentoPos(itNoteOffEventOnKeyList);
1266     }
1267     // create a pseudo note on event
1268     RTList<Event>::Iterator itPseudoNoteOnEvent = pOtherKey->pEvents->allocAppend();
1269     if (itPseudoNoteOnEvent) {
1270     // copy event
1271     *itPseudoNoteOnEvent = *itNoteOffEventOnKeyList;
1272     // transform event to a note on event
1273     itPseudoNoteOnEvent->Type = Event::type_note_on;
1274     itPseudoNoteOnEvent->Param.Note.Key = i;
1275     itPseudoNoteOnEvent->Param.Note.Velocity = pOtherKey->Velocity;
1276     // allocate and trigger new voice(s) for the other key
1277     TriggerNewVoices(pChannel, itPseudoNoteOnEvent, false);
1278     // if neither a voice was spawned or postponed then remove note on event from key again
1279     if (!pOtherKey->Active && !pOtherKey->VoiceTheftsQueued)
1280     pOtherKey->pEvents->free(itPseudoNoteOnEvent);
1281    
1282     } else dmsg(1,("Could not respawn voice, no free event left\n"));
1283     break; // done
1284     }
1285     }
1286     }
1287     if (bOtherKeysPressed) {
1288     if (pKey->Active) { // kill all voices on this key
1289     bShouldRelease = false; // no need to release, as we kill it here
1290     VoiceIterator itVoiceToBeKilled = pKey->pActiveVoices->first();
1291     VoiceIterator end = pKey->pActiveVoices->end();
1292     for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1293 persson 2115 if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))
1294 iliev 2012 itVoiceToBeKilled->Kill(itNoteOffEventOnKeyList);
1295     }
1296     }
1297     } else pChannel->PortamentoPos = -1.0f;
1298     }
1299    
1300     // if no solo mode (the usual case) or if solo mode and no other key pressed, then release voices on this key if needed
1301     if (bShouldRelease) {
1302     itNoteOffEventOnKeyList->Type = Event::type_release; // transform event type
1303    
1304     // spawn release triggered voice(s) if needed
1305     if (pKey->ReleaseTrigger && pChannel->pInstrument) {
1306     TriggerReleaseVoices(pChannel, itNoteOffEventOnKeyList);
1307     pKey->ReleaseTrigger = false;
1308     }
1309     }
1310    
1311     // if neither a voice was spawned or postponed on this key then remove note off event from key again
1312     if (!pKey->Active && !pKey->VoiceTheftsQueued)
1313     pKey->pEvents->free(itNoteOffEventOnKeyList);
1314    
1315     pChannel->listeners.PostProcessNoteOff(iKey, vel);
1316     }
1317    
1318     /**
1319     * Reset all voices and disk thread and clear input event queue and all
1320     * control and status variables. This method is protected by a mutex.
1321     */
1322     virtual void ResetInternal() {
1323     ResetInternalMutex.Lock();
1324    
1325     // make sure that the engine does not get any sysex messages
1326     // while it's reseting
1327     bool sysexDisabled = MidiInputPort::RemoveSysexListener(this);
1328     SetVoiceCount(0);
1329     ActiveVoiceCountMax = 0;
1330    
1331     // reset voice stealing parameters
1332     pVoiceStealingQueue->clear();
1333     itLastStolenVoice = VoiceIterator();
1334     itLastStolenVoiceGlobally = VoiceIterator();
1335     iuiLastStolenKey = RTList<uint>::Iterator();
1336     iuiLastStolenKeyGlobally = RTList<uint>::Iterator();
1337     pLastStolenChannel = NULL;
1338    
1339     // reset all voices
1340     for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
1341     iterVoice->Reset();
1342     }
1343     pVoicePool->clear();
1344    
1345     // reset disk thread
1346     if (pDiskThread) pDiskThread->Reset();
1347    
1348     // delete all input events
1349     pEventQueue->init();
1350     pSysexBuffer->init();
1351     if (sysexDisabled) MidiInputPort::AddSysexListener(this);
1352     ResetInternalMutex.Unlock();
1353     }
1354    
1355     /**
1356     * Kills all voices on an engine channel as soon as possible. Voices
1357     * won't get into release state, their volume level will be ramped down
1358     * as fast as possible.
1359     *
1360     * @param pEngineChannel - engine channel on which all voices should be killed
1361     * @param itKillEvent - event which caused this killing of all voices
1362     */
1363     virtual void KillAllVoices(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itKillEvent) {
1364     EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1365     int count = pChannel->KillAllVoices(itKillEvent);
1366     VoiceSpawnsLeft -= count; //FIXME: just a temporary workaround, we should check the cause in StealVoice() instead
1367     }
1368    
1369     /**
1370     * Allocates and triggers a new voice. This method will usually be
1371     * called by the ProcessNoteOn() method and by the voices itself
1372     * (e.g. to spawn further voices on the same key for layered sounds).
1373     *
1374     * @param pEngineChannel - engine channel on which this event occured on
1375     * @param itNoteOnEvent - key, velocity and time stamp of the event
1376     * @param iLayer - layer index for the new voice (optional - only
1377     * in case of layered sounds of course)
1378     * @param ReleaseTriggerVoice - if new voice is a release triggered voice
1379     * (optional, default = false)
1380     * @param VoiceStealing - if voice stealing should be performed
1381     * when there is no free voice
1382     * (optional, default = true)
1383     * @param HandleKeyGroupConflicts - if voices should be killed due to a
1384     * key group conflict
1385     * @returns pointer to new voice or NULL if there was no free voice or
1386     * if the voice wasn't triggered (for example when no region is
1387     * defined for the given key).
1388     */
1389     virtual PoolVoiceIterator LaunchVoice (
1390     EngineChannel* pEngineChannel,
1391     Pool<Event>::Iterator& itNoteOnEvent,
1392     int iLayer,
1393     bool ReleaseTriggerVoice,
1394     bool VoiceStealing,
1395     bool HandleKeyGroupConflicts
1396     ) = 0;
1397    
1398 iliev 2015 virtual int GetMinFadeOutSamples() { return MinFadeOutSamples; }
1399    
1400 iliev 2027 int InitNewVoice (
1401     EngineChannelBase<V, R, I>* pChannel,
1402     R* pRegion,
1403     Pool<Event>::Iterator& itNoteOnEvent,
1404     Voice::type_t VoiceType,
1405     int iLayer,
1406     int iKeyGroup,
1407     bool ReleaseTriggerVoice,
1408     bool VoiceStealing,
1409     typename Pool<V>::Iterator& itNewVoice
1410     ) {
1411     int key = itNoteOnEvent->Param.Note.Key;
1412     typename MidiKeyboardManager<V>::MidiKey* pKey = &pChannel->pMIDIKeyInfo[key];
1413     if (itNewVoice) {
1414     // launch the new voice
1415     if (itNewVoice->Trigger(pChannel, itNoteOnEvent, pChannel->Pitch, pRegion, VoiceType, iKeyGroup) < 0) {
1416     dmsg(4,("Voice not triggered\n"));
1417     pKey->pActiveVoices->free(itNewVoice);
1418     }
1419     else { // on success
1420     --VoiceSpawnsLeft;
1421     if (!pKey->Active) { // mark as active key
1422     pKey->Active = true;
1423     pKey->itSelf = pChannel->pActiveKeys->allocAppend();
1424     *pKey->itSelf = itNoteOnEvent->Param.Note.Key;
1425     }
1426 persson 2115 if (itNewVoice->Type & Voice::type_release_trigger_required) pKey->ReleaseTrigger = true; // mark key for the need of release triggered voice(s)
1427 iliev 2027 return 0; // success
1428     }
1429     }
1430     else if (VoiceStealing) {
1431     // try to steal one voice
1432     int result = StealVoice(pChannel, itNoteOnEvent);
1433     if (!result) { // voice stolen successfully
1434     // put note-on event into voice-stealing queue, so it will be reprocessed after killed voice died
1435     RTList<Event>::Iterator itStealEvent = pVoiceStealingQueue->allocAppend();
1436     if (itStealEvent) {
1437     *itStealEvent = *itNoteOnEvent; // copy event
1438     itStealEvent->Param.Note.Layer = iLayer;
1439     itStealEvent->Param.Note.ReleaseTrigger = ReleaseTriggerVoice;
1440     pKey->VoiceTheftsQueued++;
1441     }
1442     else dmsg(1,("Voice stealing queue full!\n"));
1443     }
1444     }
1445    
1446     return -1;
1447     }
1448    
1449 iliev 2012 private:
1450     Pool<V>* pVoicePool; ///< Contains all voices that can be activated.
1451     Pool<RR*> SuspendedRegions;
1452     Mutex SuspendedRegionsMutex;
1453     Condition SuspensionChangeOngoing;
1454     RR* pPendingRegionSuspension;
1455     RR* pPendingRegionResumption;
1456     int iPendingStreamDeletions;
1457     };
1458    
1459     template <class V, class RR, class R, class D, class IM, class I>
1460     IM EngineBase<V, RR, R, D, IM, I>::instruments;
1461    
1462     } // namespace LinuxSampler
1463    
1464     #endif /* __LS_ENGINEBASE_H__ */
1465    

  ViewVC Help
Powered by ViewVC