/[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 2927 - (hide annotations) (download) (as text)
Thu Jun 30 16:44:46 2016 UTC (7 years, 8 months ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 111015 byte(s)
* Fix: Release trigger voices were not spawned on sustain pedal up
  (CC #64) events.
* Fix: Release trigger voices can now also distinguish correctly between
  note-off and sustain pedal up events.
* Bumped version (2.0.0.svn10).

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

  ViewVC Help
Powered by ViewVC