/[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 2121 - (hide annotations) (download) (as text)
Tue Sep 14 17:09:08 2010 UTC (13 years, 6 months ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 78697 byte(s)
* implemented Roland GS NRPN 1ArrH which allows to set volume per note
* implemented Roland GS NRPN 1CrrH which allows to set pan per note
* implemented Roland GS NRPN 1DrrH which allows to set reverb send per
  note (in this implementation of the sampler its simply hard routed to
  the 1st effect send of the sampler channel, no matter what the actual
  effect type is)
* implemented Roland GS NRPN 1ErrH which allows to set chorus send per
  note (in this implementation of the sampler its simply hard routed to
  the 2nd effect send of the sampler channel, no matter what the actual
  effect type is)
* bumped version to 1.0.0cvs4

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

  ViewVC Help
Powered by ViewVC