/[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 2427 - (hide annotations) (download) (as text)
Sat Mar 2 07:03:04 2013 UTC (11 years, 1 month ago) by persson
File MIME type: text/x-c++hdr
File size: 79527 byte(s)
* code refactoring: added a lock guard class for exception safe mutex
  handling and used it everywhere appropriate

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

  ViewVC Help
Powered by ViewVC