/[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 2871 - (hide annotations) (download) (as text)
Sun Apr 10 18:22:23 2016 UTC (7 years, 11 months ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 99098 byte(s)
* All engines: Implemented scheduler for delayed MIDI events and for
  suspended real-time instrument scripts.
* Real-Time instrument scripts: Implemented support for built-in "wait()"
  function's "duration-us" argument, thus scripts using this function are
  now correctly resumed after the requested amount of microseconds.
* Real-Time instrument scripts: Implemented support for built-in
  "play_note()" function's "duration-us" argument, thus notes triggered
  with this argument are now correctly released after the requested amount
  of microseconds.
* Real-Time instrument scripts: Fixed crash which happened when trying to
  reference an undeclared script variable.
* Real-Time instrument scripts: Script events were not cleared when
  engine channel was reset, potentially causing undefined behavior.
* All engines: Attempt to partly fix resetting engine channels vs.
  resetting engine, an overall cleanup of the Reset*(),
  ConnectAudioDevice(), DisconnectAudioDevice() API methods would still be
  desirable though, because the current situation is still inconsistent
  and error prone.
* Bumped version (2.0.0.svn2).

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

  ViewVC Help
Powered by ViewVC