/[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 2382 - (hide annotations) (download) (as text)
Sun Dec 2 16:30:42 2012 UTC (11 years, 4 months ago) by persson
File MIME type: text/x-c++hdr
File size: 79258 byte(s)
* all engines: add pan CC value to instrument pan parameter before
  applying panning, instead of using two separate pan functions in
  series (#182)
* sfz parser: allow -200 to 200 for pan_oncc opcode (#182)
* gig engine: handle special case when pan parameter in gig file has
  max or min value
* CoreMIDI: fixed memory deallocation error

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

  ViewVC Help
Powered by ViewVC