/[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 3704 - (hide annotations) (download) (as text)
Wed Jan 8 20:20:46 2020 UTC (4 years, 4 months ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 147333 byte(s)
Fixed missing case warnings.

1 iliev 2012 /***************************************************************************
2     * *
3     * LinuxSampler - modular, streaming capable sampler *
4     * *
5     * Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck *
6 schoenebeck 3704 * Copyright (C) 2005-2020 Christian Schoenebeck *
7     * Copyright (C) 2009-2012 Grigor Iliev *
8     * Copyright (C) 2012-2017 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 3034 EngineBase() : noteIDPool(GLOBAL_MAX_NOTES), SuspendedRegions(128) {
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 schoenebeck 3034 default: ; // noop
167 iliev 2012 }
168     }
169     }
170 schoenebeck 2448
171     // In case scale tuning has been changed, recalculate pitch for
172     // all active voices.
173     ProcessScaleTuningChange();
174 iliev 2012
175     // reset internal voice counter (just for statistic of active voices)
176     ActiveVoiceCountTemp = 0;
177    
178     HandleInstrumentChanges();
179    
180     // handle events on all engine channels
181     for (int i = 0; i < engineChannels.size(); i++) {
182     ProcessEvents(engineChannels[i], Samples);
183     }
184    
185     // render all 'normal', active voices on all engine channels
186     for (int i = 0; i < engineChannels.size(); i++) {
187     RenderActiveVoices(engineChannels[i], Samples);
188     }
189    
190     // now that all ordinary voices on ALL engine channels are rendered, render new stolen voices
191     RenderStolenVoices(Samples);
192    
193     // handle audio routing for engine channels with FX sends
194     for (int i = 0; i < engineChannels.size(); i++) {
195     AbstractEngineChannel* pChannel = static_cast<AbstractEngineChannel*>(engineChannels[i]);
196     if (pChannel->fxSends.empty()) continue; // ignore if no FX sends
197     RouteAudio(engineChannels[i], Samples);
198     }
199    
200     // handle cleanup on all engine channels for the next audio fragment
201     for (int i = 0; i < engineChannels.size(); i++) {
202     PostProcess(engineChannels[i]);
203     }
204    
205 schoenebeck 3306 // Just for debugging: dump the amount of free Note objects to
206     // the terminal (note due to the static variables being used,
207     // this is currently just intended for debugging with only one
208     // engine channel).
209     #if (CONFIG_DEBUG_LEVEL >= 3)
210     {
211     static int slice = 0;
212     static int noteCount = -1;
213     if (slice++ % 10 == 0) {
214     int n = pNotePool->countFreeElements();
215     if (n != noteCount) {
216     noteCount = n;
217     dmsg(1,("[%d] free Note objects count = %d\n", slice / 10, n));
218     }
219     }
220     }
221     #endif
222 iliev 2012
223     // empty the engine's event list for the next audio fragment
224     ClearEventLists();
225    
226     // reset voice stealing for the next audio fragment
227     pVoiceStealingQueue->clear();
228    
229     // just some statistics about this engine instance
230     SetVoiceCount(ActiveVoiceCountTemp);
231     if (VoiceCount() > ActiveVoiceCountMax) ActiveVoiceCountMax = VoiceCount();
232    
233     // in case regions were previously suspended and we killed voices
234     // with disk streams due to that, check if those streams have finally
235     // been deleted by the disk thread
236     if (iPendingStreamDeletions) ProcessPendingStreamDeletions();
237    
238 persson 2162 // Release the instrument change command. (This has to
239     // be done after all voices have been rendered and not
240     // in HandleInstrumentChanges, as the RegionsInUse
241     // list has been built up by the voice renderers.)
242     for (int i = 0; i < engineChannels.size(); i++) {
243     EngineChannelBase<V, R, I>* channel =
244     static_cast<EngineChannelBase<V, R, I>*>(engineChannels[i]);
245     channel->InstrumentChangeCommandReader.Unlock();
246     }
247 iliev 2012 FrameTime += Samples;
248    
249     EngineDisabled.RttDone();
250     return 0;
251     }
252    
253 schoenebeck 2434 virtual int MaxVoices() OVERRIDE { return pVoicePool->poolSize(); }
254 iliev 2012
255 schoenebeck 2434 virtual void SetMaxVoices(int iVoices) throw (Exception) OVERRIDE {
256 iliev 2012 if (iVoices < 1)
257     throw Exception("Maximum voices for an engine cannot be set lower than 1");
258    
259     SuspendAll();
260    
261     // NOTE: we need to clear pRegionsInUse before deleting pDimRegionPool,
262     // otherwise memory corruption will occur if there are active voices (see bug #118)
263     for (int iChannel = 0; iChannel < engineChannels.size(); iChannel++) {
264     EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannel]);
265     pChannel->ClearRegionsInUse();
266     }
267    
268     if (pRegionPool[0]) delete pRegionPool[0];
269     if (pRegionPool[1]) delete pRegionPool[1];
270    
271     pRegionPool[0] = new Pool<R*>(iVoices);
272     pRegionPool[1] = new Pool<R*>(iVoices);
273    
274     for (int iChannel = 0; iChannel < engineChannels.size(); iChannel++) {
275     EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannel]);
276     pChannel->ResetRegionsInUse(pRegionPool);
277     }
278    
279 schoenebeck 2879 // FIXME: Shouldn't all those pool elements be freed before resizing the pools?
280 iliev 2012 try {
281     pVoicePool->resizePool(iVoices);
282 schoenebeck 2879 pNotePool->resizePool(iVoices * MAX_NOTES_HEADROOM);
283     noteIDPool.resizePool(iVoices * MAX_NOTES_HEADROOM);
284 iliev 2012 } catch (...) {
285     throw Exception("FATAL: Could not resize voice pool!");
286     }
287    
288 schoenebeck 2879 for (VoiceIterator iterVoice = pVoicePool->allocAppend();
289     iterVoice; iterVoice = pVoicePool->allocAppend())
290     {
291 iliev 2012 iterVoice->SetEngine(this);
292     iterVoice->pDiskThread = this->pDiskThread;
293     }
294     pVoicePool->clear();
295    
296 schoenebeck 2879 for (NoteIterator itNote = pNotePool->allocAppend(); itNote;
297     itNote = pNotePool->allocAppend())
298     {
299     itNote->init(pVoicePool, &noteIDPool);
300     }
301     pNotePool->clear();
302    
303 iliev 2244 PostSetMaxVoices(iVoices);
304 iliev 2012 ResumeAll();
305     }
306 iliev 2244
307     /** Called after the new max number of voices is set and before resuming the engine. */
308     virtual void PostSetMaxVoices(int iVoices) { }
309 iliev 2012
310 schoenebeck 2434 virtual uint DiskStreamCount() OVERRIDE { return (pDiskThread) ? pDiskThread->GetActiveStreamCount() : 0; }
311     virtual uint DiskStreamCountMax() OVERRIDE { return (pDiskThread) ? pDiskThread->ActiveStreamCountMax : 0; }
312     virtual int MaxDiskStreams() OVERRIDE { return iMaxDiskStreams; }
313 iliev 2012
314 schoenebeck 2434 virtual void SetMaxDiskStreams(int iStreams) throw (Exception) OVERRIDE {
315 iliev 2012 if (iStreams < 0)
316     throw Exception("Maximum disk streams for an engine cannot be set lower than 0");
317    
318     SuspendAll();
319    
320     iMaxDiskStreams = iStreams;
321    
322     // reconnect to audio output device, because that will automatically
323     // recreate the disk thread with the required amount of streams
324     if (pAudioOutputDevice) Connect(pAudioOutputDevice);
325    
326     ResumeAll();
327     }
328    
329 schoenebeck 2434 virtual String DiskStreamBufferFillBytes() OVERRIDE { return (pDiskThread) ? pDiskThread->GetBufferFillBytes() : ""; }
330     virtual String DiskStreamBufferFillPercentage() OVERRIDE { return (pDiskThread) ? pDiskThread->GetBufferFillPercentage() : ""; }
331     virtual InstrumentManager* GetInstrumentManager() OVERRIDE { return &instruments; }
332 iliev 2012
333     /**
334     * Connect this engine instance with the given audio output device.
335     * This method will be called when an Engine instance is created.
336     * All of the engine's data structures which are dependant to the used
337     * audio output device / driver will be (re)allocated and / or
338     * adjusted appropriately.
339     *
340     * @param pAudioOut - audio output device to connect to
341     */
342 schoenebeck 2434 virtual void Connect(AudioOutputDevice* pAudioOut) OVERRIDE {
343 iliev 2012 // caution: don't ignore if connecting to the same device here,
344     // because otherwise SetMaxDiskStreams() implementation won't work anymore!
345    
346     pAudioOutputDevice = pAudioOut;
347    
348     ResetInternal();
349    
350     // inform audio driver for the need of two channels
351     try {
352     pAudioOutputDevice->AcquireChannels(2); // default stereo
353     }
354     catch (AudioOutputException e) {
355     String msg = "Audio output device unable to provide 2 audio channels, cause: " + e.Message();
356     throw Exception(msg);
357     }
358    
359     this->MaxSamplesPerCycle = pAudioOutputDevice->MaxSamplesPerCycle();
360     this->SampleRate = pAudioOutputDevice->SampleRate();
361    
362     MinFadeOutSamples = int(double(SampleRate) * CONFIG_EG_MIN_RELEASE_TIME) - 1;
363     if (MaxSamplesPerCycle < MinFadeOutSamples) {
364     std::cerr << "EngineBase: WARNING, CONFIG_EG_MIN_RELEASE_TIME "
365     << "too big for current audio fragment size & sampling rate! "
366     << "May lead to click sounds if voice stealing chimes in!\n" << std::flush;
367     // force volume ramp downs at the beginning of each fragment
368     MinFadeOutSamples = MaxSamplesPerCycle;
369     // lower minimum release time
370     const float minReleaseTime = (float) MaxSamplesPerCycle / (float) SampleRate;
371 schoenebeck 2879 pVoicePool->clear();
372 iliev 2012 for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
373 persson 2327 iterVoice->CalculateFadeOutCoeff(minReleaseTime, SampleRate);
374 iliev 2012 }
375     pVoicePool->clear();
376     }
377    
378     // (re)create disk thread
379     if (this->pDiskThread) {
380     dmsg(1,("Stopping disk thread..."));
381     this->pDiskThread->StopThread();
382     delete this->pDiskThread;
383     dmsg(1,("OK\n"));
384     }
385     this->pDiskThread = CreateDiskThread();
386    
387     if (!pDiskThread) {
388     dmsg(0,("EngineBase new diskthread = NULL\n"));
389     exit(EXIT_FAILURE);
390     }
391    
392 schoenebeck 2879 pVoicePool->clear();
393 iliev 2012 for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
394     iterVoice->pDiskThread = this->pDiskThread;
395     dmsg(3,("d"));
396     }
397     pVoicePool->clear();
398    
399 schoenebeck 3283 // update event generator
400     pEventGenerator->SetSampleRate(pAudioOut->SampleRate());
401 iliev 2012
402     dmsg(1,("Starting disk thread..."));
403     pDiskThread->StartThread();
404     dmsg(1,("OK\n"));
405    
406 iliev 2298 bool printEqInfo = true;
407 iliev 2012 for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
408     if (!iterVoice->pDiskThread) {
409     dmsg(0,("Engine -> voice::trigger: !pDiskThread\n"));
410     exit(EXIT_FAILURE);
411     }
412 iliev 2298
413     iterVoice->CreateEq();
414    
415     if(printEqInfo) {
416     iterVoice->PrintEqInfo();
417     printEqInfo = false;
418     }
419 iliev 2012 }
420     pVoicePool->clear();
421 schoenebeck 2121
422     // (re)create dedicated voice audio buffers
423     //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
424     if (pDedicatedVoiceChannelLeft) delete pDedicatedVoiceChannelLeft;
425     if (pDedicatedVoiceChannelRight) delete pDedicatedVoiceChannelRight;
426     pDedicatedVoiceChannelLeft = new AudioChannel(0, MaxSamplesPerCycle);
427     pDedicatedVoiceChannelRight = new AudioChannel(1, MaxSamplesPerCycle);
428 iliev 2012 }
429 schoenebeck 2410
430     // Implementattion for abstract method derived from Engine.
431 schoenebeck 2434 virtual void ReconnectAudioOutputDevice() OVERRIDE {
432 schoenebeck 2410 SuspendAll();
433     if (pAudioOutputDevice) Connect(pAudioOutputDevice);
434     ResumeAll();
435     }
436 iliev 2012
437     /**
438     * Similar to @c Disable() but this method additionally kills all voices
439     * and disk streams and blocks until all voices and disk streams are actually
440     * killed / deleted.
441     *
442     * @e Note: only the original calling thread is able to re-enable the
443     * engine afterwards by calling @c ResumeAll() later on!
444     */
445     virtual void SuspendAll() {
446     dmsg(2,("Engine: Suspending all ...\n"));
447     // stop the engine, so we can safely modify the engine's
448     // data structures from this foreign thread
449     DisableAndLock();
450     // we could also use the respective class member variable here,
451     // but this is probably safer and cleaner
452     int iPendingStreamDeletions = 0;
453     // kill all voices on all engine channels the *die hard* way
454     for (int iChannel = 0; iChannel < engineChannels.size(); iChannel++) {
455     EngineChannelBase<V, R, I>* pEngineChannel =
456     static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannel]);
457    
458     iPendingStreamDeletions += pEngineChannel->KillAllVoicesImmediately();
459     }
460     // wait until all streams were actually deleted by the disk thread
461     while (iPendingStreamDeletions) {
462     while (
463     iPendingStreamDeletions &&
464     pDiskThread->AskForDeletedStream() != Stream::INVALID_HANDLE
465     ) iPendingStreamDeletions--;
466     if (!iPendingStreamDeletions) break;
467     usleep(10000); // sleep for 10ms
468     }
469     dmsg(2,("EngineBase: Everything suspended.\n"));
470     }
471    
472     /**
473     * At the moment same as calling @c Enable() directly, but this might
474     * change in future, so better call this method as counterpart to
475     * @c SuspendAll() instead of @c Enable() !
476     */
477     virtual void ResumeAll() { Enable(); }
478    
479     /**
480     * Order the engine to stop rendering audio for the given region.
481     * Additionally this method will block until all voices and their disk
482     * streams associated with that region are actually killed / deleted, so
483     * one can i.e. safely modify the region with an instrument editor after
484     * returning from this method.
485     *
486     * @param pRegion - region the engine shall stop using
487     */
488     virtual void Suspend(RR* pRegion) {
489 persson 2837 dmsg(2,("EngineBase: Suspending Region %p ...\n",(void*)pRegion));
490 persson 2427 {
491     LockGuard lock(SuspendedRegionsMutex);
492     SuspensionChangeOngoing.Set(true);
493     pPendingRegionSuspension = pRegion;
494     SuspensionChangeOngoing.WaitAndUnlockIf(true);
495     }
496 persson 2837 dmsg(2,("EngineBase: Region %p suspended.",(void*)pRegion));
497 iliev 2012 }
498    
499     /**
500     * Orders the engine to resume playing back the given region, previously
501     * suspended with @c Suspend() .
502     *
503     * @param pRegion - region the engine shall be allowed to use again
504     */
505     virtual void Resume(RR* pRegion) {
506 persson 2837 dmsg(2,("EngineBase: Resuming Region %p ...\n",(void*)pRegion));
507 persson 2427 {
508     LockGuard lock(SuspendedRegionsMutex);
509     SuspensionChangeOngoing.Set(true);
510     pPendingRegionResumption = pRegion;
511     SuspensionChangeOngoing.WaitAndUnlockIf(true);
512     }
513 persson 2837 dmsg(2,("EngineBase: Region %p resumed.\n",(void*)pRegion));
514 iliev 2012 }
515    
516     virtual void ResetSuspendedRegions() {
517     SuspendedRegions.clear();
518     iPendingStreamDeletions = 0;
519     pPendingRegionSuspension = pPendingRegionResumption = NULL;
520     SuspensionChangeOngoing.Set(false);
521     }
522    
523     /**
524     * Called by the engine's (audio) thread once per cycle to process requests
525     * from the outer world to suspend or resume a given @c gig::Region .
526     */
527     virtual void ProcessSuspensionsChanges() {
528     // process request for suspending one region
529     if (pPendingRegionSuspension) {
530     // kill all voices on all engine channels that use this region
531     for (int iChannel = 0; iChannel < engineChannels.size(); iChannel++) {
532     EngineChannelBase<V, R, I>* pEngineChannel =
533     static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannel]);
534     SuspensionVoiceHandler handler(pPendingRegionSuspension);
535     pEngineChannel->ProcessActiveVoices(&handler);
536     iPendingStreamDeletions += handler.PendingStreamDeletions;
537     }
538     // make sure the region is not yet on the list
539     bool bAlreadySuspended = false;
540     RootRegionIterator iter = SuspendedRegions.first();
541     RootRegionIterator end = SuspendedRegions.end();
542     for (; iter != end; ++iter) { // iterate through all suspended regions
543     if (*iter == pPendingRegionSuspension) { // found
544     bAlreadySuspended = true;
545     dmsg(1,("EngineBase: attempt to suspend an already suspended region !!!\n"));
546     break;
547     }
548     }
549     if (!bAlreadySuspended) {
550     // put the region on the list of suspended regions
551     RootRegionIterator iter = SuspendedRegions.allocAppend();
552     if (iter) {
553     *iter = pPendingRegionSuspension;
554     } else std::cerr << "EngineBase: Could not suspend Region, list is full. This is a bug!!!\n" << std::flush;
555     }
556     // free request slot for next caller (and to make sure that
557     // we're not going to process the same request in the next cycle)
558     pPendingRegionSuspension = NULL;
559     // if no disk stream deletions are pending, awaken other side, as
560     // we're done in this case
561     if (!iPendingStreamDeletions) SuspensionChangeOngoing.Set(false);
562     }
563    
564     // process request for resuming one region
565     if (pPendingRegionResumption) {
566     // remove region from the list of suspended regions
567     RootRegionIterator iter = SuspendedRegions.first();
568     RootRegionIterator end = SuspendedRegions.end();
569     for (; iter != end; ++iter) { // iterate through all suspended regions
570     if (*iter == pPendingRegionResumption) { // found
571     SuspendedRegions.free(iter);
572     break; // done
573     }
574     }
575     // free request slot for next caller
576     pPendingRegionResumption = NULL;
577     // awake other side as we're done
578     SuspensionChangeOngoing.Set(false);
579     }
580     }
581    
582     /**
583     * Called by the engine's (audio) thread once per cycle to check if
584     * streams of voices that were killed due to suspension request have
585     * finally really been deleted by the disk thread.
586     */
587     virtual void ProcessPendingStreamDeletions() {
588     if (!iPendingStreamDeletions) return;
589     //TODO: or shall we better store a list with stream handles instead of a scalar amount of streams to be deleted? might be safer
590     while (
591     iPendingStreamDeletions &&
592     pDiskThread->AskForDeletedStream() != Stream::INVALID_HANDLE
593     ) iPendingStreamDeletions--;
594     // just for safety ...
595     while (pDiskThread->AskForDeletedStream() != Stream::INVALID_HANDLE);
596     // now that all disk streams are deleted, awake other side as
597     // we're finally done with suspending the requested region
598     if (!iPendingStreamDeletions) SuspensionChangeOngoing.Set(false);
599     }
600    
601     /**
602     * Returns @c true if the given region is currently set to be suspended
603     * from being used, @c false otherwise.
604     */
605     virtual bool RegionSuspended(RR* pRegion) {
606     if (SuspendedRegions.isEmpty()) return false;
607     //TODO: or shall we use a sorted container instead of the RTList? might be faster ... or trivial ;-)
608     RootRegionIterator iter = SuspendedRegions.first();
609     RootRegionIterator end = SuspendedRegions.end();
610     for (; iter != end; ++iter) // iterate through all suspended regions
611     if (*iter == pRegion) return true;
612     return false;
613     }
614    
615     // implementation of abstract method derived from class 'LinuxSampler::RegionPools'
616 schoenebeck 3054 virtual Pool<R*>* GetRegionPool(int index) OVERRIDE {
617 iliev 2012 if (index < 0 || index > 1) throw Exception("Index out of bounds");
618     return pRegionPool[index];
619     }
620    
621 schoenebeck 2879 // implementation of abstract methods derived from class 'LinuxSampler::NotePool'
622     virtual Pool<V>* GetVoicePool() OVERRIDE { return pVoicePool; }
623     virtual Pool< Note<V> >* GetNotePool() OVERRIDE { return pNotePool; }
624 schoenebeck 3073 virtual Pool<note_id_t>* GetNoteIDPool() OVERRIDE { return &noteIDPool; }
625 iliev 2012
626     D* GetDiskThread() { return pDiskThread; }
627    
628     //friend class EngineChannelBase<V, R, I>;
629    
630 persson 2127 static IM instruments;
631    
632 iliev 2012 protected:
633     class SuspensionVoiceHandler : public MidiKeyboardManager<V>::VoiceHandler {
634     public:
635     int PendingStreamDeletions;
636     RR* pPendingRegionSuspension;
637 schoenebeck 2434
638 iliev 2012 SuspensionVoiceHandler(RR* pPendingRegionSuspension) {
639     PendingStreamDeletions = 0;
640     this->pPendingRegionSuspension = pPendingRegionSuspension;
641     }
642    
643 schoenebeck 2434 virtual bool Process(MidiKey* pMidiKey) OVERRIDE {
644 schoenebeck 2879 NoteIterator itNote = pMidiKey->pActiveNotes->first();
645     VoiceIterator itVoice = itNote->pActiveVoices->first();
646 iliev 2012 // if current key is not associated with this region, skip this key
647     if (itVoice->GetRegion()->GetParent() != pPendingRegionSuspension) return false;
648    
649     return true;
650     }
651    
652 schoenebeck 2434 virtual void Process(VoiceIterator& itVoice) OVERRIDE {
653 iliev 2012 // request a notification from disk thread side for stream deletion
654     const Stream::Handle hStream = itVoice->KillImmediately(true);
655     if (hStream != Stream::INVALID_HANDLE) { // voice actually used a stream
656     PendingStreamDeletions++;
657     }
658     //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
659     }
660     };
661    
662     Pool<R*>* pRegionPool[2]; ///< Double buffered pool, used by the engine channels to keep track of regions in use.
663     int MinFadeOutSamples; ///< The number of samples needed to make an instant fade out (e.g. for voice stealing) without leading to clicks.
664     D* pDiskThread;
665    
666     int ActiveVoiceCountTemp; ///< number of currently active voices (for internal usage, will be used for incrementation)
667     VoiceIterator itLastStolenVoice; ///< Only for voice stealing: points to the last voice which was theft in current audio fragment, NULL otherwise.
668 schoenebeck 2879 NoteIterator itLastStolenNote; ///< Only for voice stealing: points to the last note from which was theft in current audio fragment, NULL otherwise.
669 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.
670     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.
671     VoiceIterator itLastStolenVoiceGlobally; ///< Same as itLastStolenVoice, but engine globally
672 schoenebeck 2879 NoteIterator itLastStolenNoteGlobally; ///< Same as itLastStolenNote, but engine globally
673 iliev 2012 RTList<uint>::Iterator iuiLastStolenKeyGlobally; ///< Same as iuiLastStolenKey, but engine globally
674     RTList<Event>* pVoiceStealingQueue; ///< All voice-launching events which had to be postponed due to free voice shortage.
675     Mutex ResetInternalMutex; ///< Mutex to protect the ResetInternal function for concurrent usage (e.g. by the lscp and instrument loader threads).
676     int iMaxDiskStreams;
677    
678 schoenebeck 2879 NoteBase* NoteByID(note_id_t id) OVERRIDE {
679     NoteIterator itNote = GetNotePool()->fromID(id);
680     if (!itNote) return NULL;
681     return &*itNote;
682     }
683    
684 iliev 2012 /**
685 schoenebeck 2879 * Gets a new @c Note object from the note pool, initializes it
686     * appropriately, links it with requested parent note (if
687     * requested), moves it to the appropriate key's list of active
688     * notes it, and sticks the new note's unique ID to the
689     * passed @a pNoteOnEvent.
690     *
691     * @param pEngineChannel - engine channel on which this event happened
692     * @param pNoteOnEvent - event which caused this
693     * @returns new note's unique ID (or zero on error)
694     */
695 schoenebeck 3205 note_id_t LaunchNewNote(LinuxSampler::EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) OVERRIDE {
696 schoenebeck 2879 EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
697     Pool< Note<V> >* pNotePool = GetNotePool();
698    
699     if (pNotePool->poolIsEmpty()) {
700     dmsg(1,("Engine: Could not launch new note; Note pool empty!\n"));
701     return 0; // error
702     }
703    
704     // create a new note (for new voices to be assigned to)
705     //NoteIterator itNewNote = pKey->pActiveNotes->allocAppend();
706     NoteIterator itNewNote = pNotePool->allocAppend();
707     const note_id_t newNoteID = pNotePool->getID(itNewNote);
708    
709 schoenebeck 2962 // remember the engine's time when this note was triggered exactly
710 schoenebeck 3205 itNewNote->triggerSchedTime = itNoteOnEvent->SchedTime();
711 schoenebeck 2962
712 schoenebeck 2879 // usually the new note (and its subsequent voices) will be
713     // allocated on the key provided by the event's note number,
714     // however if this new note is requested not to be a regular
715     // note, but rather a child note, then this new note will be
716     // allocated on the parent note's key instead in order to
717     // release the child note simultaniously with its parent note
718 schoenebeck 3205 itNewNote->hostKey = itNoteOnEvent->Param.Note.Key;
719 schoenebeck 2879
720     // in case this new note was requested to be a child note,
721     // then retrieve its parent note and link them with each other
722 schoenebeck 3205 const note_id_t parentNoteID = itNoteOnEvent->Param.Note.ParentNoteID;
723 schoenebeck 2879 if (parentNoteID) {
724     NoteIterator itParentNote = pNotePool->fromID(parentNoteID);
725     if (itParentNote) {
726     RTList<note_id_t>::Iterator itChildNoteID = itParentNote->pChildNotes->allocAppend();
727     if (itChildNoteID) {
728     // link parent and child note with each other
729     *itChildNoteID = newNoteID;
730     itNewNote->parentNoteID = parentNoteID;
731     itNewNote->hostKey = itParentNote->hostKey;
732     } else {
733     dmsg(1,("Engine: Could not assign new note as child note; Note ID pool empty!\n"));
734     pNotePool->free(itNewNote);
735     return 0; // error
736     }
737     } else {
738     // the parent note was apparently released already, so
739     // free the new note again and inform caller that it
740     // should drop the event
741     dmsg(3,("Engine: Could not assign new note as child note; Parent note is gone!\n"));
742     pNotePool->free(itNewNote);
743     return 0; // error
744     }
745     }
746    
747     dmsg(2,("Launched new note on host key %d\n", itNewNote->hostKey));
748    
749     // copy event which caused this note
750 schoenebeck 3205 itNewNote->cause = *itNoteOnEvent;
751     itNewNote->eventID = pEventPool->getID(itNoteOnEvent);
752     if (!itNewNote->eventID) {
753     dmsg(0,("Engine: No valid event ID resolved for note. This is a bug!!!\n"));
754     }
755 schoenebeck 2879
756     // move new note to its host key
757     MidiKey* pKey = &pChannel->pMIDIKeyInfo[itNewNote->hostKey];
758     itNewNote.moveToEndOf(pKey->pActiveNotes);
759 schoenebeck 3306 pChannel->markKeyAsActive(pKey);
760 schoenebeck 2879
761     // assign unique note ID of this new note to the original note on event
762 schoenebeck 3205 itNoteOnEvent->Param.Note.ID = newNoteID;
763 schoenebeck 2879
764     return newNoteID; // success
765     }
766    
767     /**
768 iliev 2012 * Dispatch and handle all events in this audio fragment for the given
769     * engine channel.
770     *
771     * @param pEngineChannel - engine channel on which events should be
772     * processed
773     * @param Samples - amount of sample points to be processed in
774     * this audio fragment cycle
775     */
776     void ProcessEvents(EngineChannel* pEngineChannel, uint Samples) {
777     // get all events from the engine channels's input event queue which belong to the current fragment
778     // (these are the common events like NoteOn, NoteOff, ControlChange, etc.)
779     AbstractEngineChannel* pChannel = static_cast<AbstractEngineChannel*>(pEngineChannel);
780     pChannel->ImportEvents(Samples);
781    
782 schoenebeck 2594 // if a valid real-time instrument script is loaded, pre-process
783     // the event list by running the script now, since the script
784     // might filter events or add new ones for this cycle
785 schoenebeck 2659 if (pChannel->pScript) {
786 schoenebeck 2871 const sched_time_t fragmentEndTime = pEventGenerator->schedTimeAtCurrentFragmentEnd();
787 schoenebeck 2594
788 schoenebeck 2871 // resume suspended script executions been scheduled for
789     // this audio fragment cycle (which were suspended in a
790     // previous audio fragment cycle)
791     ProcessSuspendedScriptEvents(pChannel, fragmentEndTime);
792    
793 schoenebeck 2594 // spawn new script executions for the new MIDI events of
794     // this audio fragment cycle
795 schoenebeck 2871 //
796     // 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
797 schoenebeck 2594 for (RTList<Event>::Iterator itEvent = pChannel->pEvents->first(),
798 schoenebeck 2884 end = pChannel->pEvents->end(); itEvent != end; )
799 schoenebeck 2594 {
800 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).
801     RTList<Event>::Iterator itNext = itEvent;
802     ++itNext;
803    
804 schoenebeck 2594 switch (itEvent->Type) {
805     case Event::type_note_on:
806 schoenebeck 2611 if (pChannel->pScript->handlerNote)
807     ProcessEventByScript(pChannel, itEvent, pChannel->pScript->handlerNote);
808 schoenebeck 2594 break;
809     case Event::type_note_off:
810 schoenebeck 2611 if (pChannel->pScript->handlerRelease)
811     ProcessEventByScript(pChannel, itEvent, pChannel->pScript->handlerRelease);
812 schoenebeck 2594 break;
813     case Event::type_control_change:
814     case Event::type_channel_pressure:
815     case Event::type_pitchbend:
816 schoenebeck 2611 if (pChannel->pScript->handlerController)
817     ProcessEventByScript(pChannel, itEvent, pChannel->pScript->handlerController);
818 schoenebeck 2594 break;
819     case Event::type_note_pressure:
820     //TODO: ...
821     break;
822 schoenebeck 3034
823     case Event::type_sysex:
824     //TODO: ...
825     break;
826    
827 schoenebeck 3704 case Event::type_rpn: // rpn handled in ProcessHardcodedControllers() instead ATM
828     case Event::type_nrpn: // nrpn handled in ProcessHardcodedControllers() instead ATM
829 schoenebeck 3034 case Event::type_cancel_release_key:
830     case Event::type_release_key:
831     case Event::type_release_note:
832     case Event::type_play_note:
833     case Event::type_stop_note:
834 schoenebeck 3188 case Event::type_kill_note:
835 schoenebeck 3034 case Event::type_note_synth_param:
836     break; // noop
837 schoenebeck 2594 }
838 schoenebeck 2884
839     // see HACK comment above
840     itEvent = itNext;
841 schoenebeck 2594 }
842 schoenebeck 2871
843     // this has to be run again, since the newly spawned scripts
844     // above may have cause suspended scripts that must be
845     // resumed within this same audio fragment cycle
846     //
847     // FIXME: see FIXME comment above
848     ProcessSuspendedScriptEvents(pChannel, fragmentEndTime);
849 schoenebeck 2594 }
850    
851 schoenebeck 2871 // if there are any delayed events scheduled for the current
852     // audio fragment cycle, then move and sort them into the main
853     // event list
854     if (!pChannel->delayedEvents.queue.isEmpty()) {
855     dmsg(5,("Engine: There are delayed MIDI events (total queue size: %d) ...\n", pChannel->delayedEvents.queue.size()));
856     const sched_time_t fragmentEndTime = pEventGenerator->schedTimeAtCurrentFragmentEnd();
857     RTList<Event>::Iterator itEvent = pChannel->pEvents->first();
858     while (true) {
859     RTList<ScheduledEvent>::Iterator itDelayedEventNode =
860     pEventGenerator->popNextScheduledEvent(
861     pChannel->delayedEvents.queue,
862     pChannel->delayedEvents.schedulerNodes,
863     fragmentEndTime
864     );
865     if (!itDelayedEventNode) break;
866     // get the actual delayed event object and free the used scheduler node
867     RTList<Event>::Iterator itDelayedEvent = itDelayedEventNode->itEvent;
868     pChannel->delayedEvents.schedulerNodes.free(itDelayedEventNode);
869     if (!itDelayedEvent) { // should never happen, but just to be sure ...
870     dmsg(1,("Engine: Oops, invalid delayed event!\n"));
871     continue;
872     }
873     // skip all events on main event list which have a time
874     // before (or equal to) the delayed event to be inserted
875     for (; itEvent && itEvent->FragmentPos() <= itDelayedEvent->FragmentPos();
876     ++itEvent);
877     // now move delayed event from delayedEvents.pList to
878     // the current position on the main event list
879     itEvent = itDelayedEvent.moveBefore(itEvent);
880     dmsg(5,("Engine: Inserted event of type %d into main event list (queue size: %d).\n", itEvent->Type, pChannel->delayedEvents.queue.size()));
881     }
882     dmsg(5,("Engine: End of delayed events (total queue size: %d).\n", pChannel->delayedEvents.queue.size()));
883     }
884    
885 schoenebeck 2594 // now process all events regularly
886 iliev 2012 {
887     RTList<Event>::Iterator itEvent = pChannel->pEvents->first();
888     RTList<Event>::Iterator end = pChannel->pEvents->end();
889     for (; itEvent != end; ++itEvent) {
890 schoenebeck 3697 bool bIsCC = false; // just for resetting RPN/NRPN below
891 iliev 2012 switch (itEvent->Type) {
892     case Event::type_note_on:
893     dmsg(5,("Engine: Note on received\n"));
894     ProcessNoteOn((EngineChannel*)itEvent->pEngineChannel, itEvent);
895     break;
896 schoenebeck 2938 case Event::type_play_note:
897     dmsg(5,("Engine: Play Note received\n"));
898     ProcessNoteOn((EngineChannel*)itEvent->pEngineChannel, itEvent);
899     break;
900 iliev 2012 case Event::type_note_off:
901     dmsg(5,("Engine: Note off received\n"));
902     ProcessNoteOff((EngineChannel*)itEvent->pEngineChannel, itEvent);
903     break;
904 schoenebeck 2938 case Event::type_stop_note:
905     dmsg(5,("Engine: Stop Note received\n"));
906     ProcessNoteOff((EngineChannel*)itEvent->pEngineChannel, itEvent);
907     break;
908 schoenebeck 3188 case Event::type_kill_note:
909     dmsg(5,("Engine: Kill Note received\n"));
910     ProcessKillNote((EngineChannel*)itEvent->pEngineChannel, itEvent);
911     break;
912 iliev 2012 case Event::type_control_change:
913     dmsg(5,("Engine: MIDI CC received\n"));
914     ProcessControlChange((EngineChannel*)itEvent->pEngineChannel, itEvent);
915 schoenebeck 3697 bIsCC = true;
916 iliev 2012 break;
917 schoenebeck 3691 case Event::type_rpn: // this can only be reached here by an instrument script having called set_rpn()
918     dmsg(5,("Engine: MIDI RPN received\n"));
919     ProcessHardcodedRpn((EngineChannel*)itEvent->pEngineChannel, itEvent);
920 schoenebeck 3697 bIsCC = true;
921 schoenebeck 3691 break;
922     case Event::type_nrpn: // this can only be reached here by an instrument script having called set_nrpn()
923     dmsg(5,("Engine: MIDI NRPN received\n"));
924     ProcessHardcodedNrpn((EngineChannel*)itEvent->pEngineChannel, itEvent);
925 schoenebeck 3697 bIsCC = true;
926 schoenebeck 3691 break;
927 schoenebeck 2559 case Event::type_channel_pressure:
928     dmsg(5,("Engine: MIDI Chan. Pressure received\n"));
929     ProcessChannelPressure((EngineChannel*)itEvent->pEngineChannel, itEvent);
930     break;
931     case Event::type_note_pressure:
932     dmsg(5,("Engine: MIDI Note Pressure received\n"));
933     ProcessPolyphonicKeyPressure((EngineChannel*)itEvent->pEngineChannel, itEvent);
934     break;
935 iliev 2012 case Event::type_pitchbend:
936     dmsg(5,("Engine: Pitchbend received\n"));
937     ProcessPitchbend(static_cast<AbstractEngineChannel*>(itEvent->pEngineChannel), itEvent);
938     break;
939 schoenebeck 2931 case Event::type_note_synth_param:
940     dmsg(5,("Engine: Note Synth Param received\n"));
941     ProcessNoteSynthParam(itEvent->pEngineChannel, itEvent);
942     break;
943 schoenebeck 3034 case Event::type_sysex:
944     break; // TODO ...
945    
946     case Event::type_cancel_release_key:
947     case Event::type_release_key:
948     case Event::type_release_note:
949     break; // noop
950 iliev 2012 }
951 schoenebeck 3697 // reset cached RPN/NRPN parameter number and data in
952     // case this event was not a control change event
953     if (!bIsCC) {
954     if (pChannel->GetMidiRpnParameter() >= 0)
955     pChannel->ResetMidiRpnParameter();
956     if (pChannel->GetMidiNrpnParameter() >= 0)
957     pChannel->ResetMidiNrpnParameter();
958     }
959 iliev 2012 }
960     }
961    
962     // reset voice stealing for the next engine channel (or next audio fragment)
963     itLastStolenVoice = VoiceIterator();
964     itLastStolenVoiceGlobally = VoiceIterator();
965 schoenebeck 2879 itLastStolenNote = NoteIterator();
966     itLastStolenNoteGlobally = NoteIterator();
967 iliev 2012 iuiLastStolenKey = RTList<uint>::Iterator();
968     iuiLastStolenKeyGlobally = RTList<uint>::Iterator();
969     pLastStolenChannel = NULL;
970     }
971    
972 schoenebeck 2871 /**
973     * Run all suspended script execution instances which are scheduled
974     * to be resumed for the current audio fragment cycle.
975     *
976     * @param pChannel - engine channel on which suspended events occurred
977     */
978     void ProcessSuspendedScriptEvents(AbstractEngineChannel* pChannel, const sched_time_t fragmentEndTime) {
979     while (true) {
980     RTList<ScriptEvent>::Iterator itEvent =
981     pEventGenerator->popNextScheduledScriptEvent(
982     pChannel->pScript->suspendedEvents,
983     *pChannel->pScript->pEvents, fragmentEndTime
984     );
985     if (!itEvent) break;
986     ResumeScriptEvent(pChannel, itEvent);
987     }
988     }
989    
990 schoenebeck 2594 /** @brief Call instrument script's event handler for this event.
991     *
992     * Causes a new execution instance of the currently loaded real-time
993     * instrument script's event handler (callback) to be spawned for
994     * the given MIDI event.
995     *
996 schoenebeck 2871 * @param pChannel - engine channel on which the MIDI event occurred
997 schoenebeck 2594 * @param itEvent - MIDI event that causes this new script execution
998     * @param pEventHandler - script's event handler to be executed
999     */
1000     void ProcessEventByScript(AbstractEngineChannel* pChannel, RTList<Event>::Iterator& itEvent, VMEventHandler* pEventHandler) {
1001 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
1002     // check if polyphonic data is passed from "note" to "release"
1003     // script event handlers
1004     if (pEventHandler == pChannel->pScript->handlerRelease &&
1005     pChannel->pScript->handlerNote &&
1006     pChannel->pScript->handlerNote->isPolyphonic() &&
1007     pChannel->pScript->handlerRelease->isPolyphonic() &&
1008     !pChannel->pScript->pKeyEvents[key]->isEmpty())
1009     {
1010     // polyphonic variable data is used/passed from "note" to
1011     // "release" script callback, so we have to recycle the
1012     // original "note on" script event(s)
1013     RTList<ScriptEvent>::Iterator it = pChannel->pScript->pKeyEvents[key]->first();
1014     RTList<ScriptEvent>::Iterator end = pChannel->pScript->pKeyEvents[key]->end();
1015     for (; it != end; ++it) {
1016     ProcessScriptEvent(
1017     pChannel, itEvent, pEventHandler, it
1018     );
1019     }
1020     } else {
1021     // no polyphonic data is used/passed from "note" to
1022     // "release" script callback, so just use a new fresh
1023     // script event object
1024     RTList<ScriptEvent>::Iterator itScriptEvent =
1025     pChannel->pScript->pEvents->allocAppend();
1026 schoenebeck 3207 // if event handler uses polyphonic variables, reset them
1027     // to zero values before starting to execute the handler
1028     if (pEventHandler->isPolyphonic())
1029     itScriptEvent->execCtx->resetPolyphonicData();
1030 schoenebeck 2645 ProcessScriptEvent(
1031     pChannel, itEvent, pEventHandler, itScriptEvent
1032     );
1033     }
1034     }
1035 schoenebeck 2594
1036 schoenebeck 2871 /** @brief Spawn new execution instance of an instrument script handler.
1037     *
1038     * Will be called to initiate a new execution of a real-time
1039     * instrument script event right from the start of the script's
1040     * respective handler. If script execution did not complete after
1041     * calling this method, the respective script exeuction is then
1042     * suspended and a call to ResumeScriptEvent() will be used next
1043     * time to continue its execution.
1044     *
1045     * @param pChannel - engine channel this script is running for
1046     * @param itEvent - event which caused execution of this script
1047     * event handler
1048     * @param pEventHandler - VM representation of event handler to be
1049     * executed
1050     * @param itScriptEvent - script event that shall be processed
1051     */
1052 schoenebeck 2645 void ProcessScriptEvent(AbstractEngineChannel* pChannel, RTList<Event>::Iterator& itEvent, VMEventHandler* pEventHandler, RTList<ScriptEvent>::Iterator& itScriptEvent) {
1053     if (!itScriptEvent) return; // not a valid script event (i.e. because no free script event was left in the script event pool)
1054 schoenebeck 2594
1055     // fill the list of script handlers to be executed by this event
1056     int i = 0;
1057     itScriptEvent->handlers[i++] = pEventHandler; // actual event handler (i.e. note, controller)
1058     itScriptEvent->handlers[i] = NULL; // NULL termination of list
1059    
1060     // initialize/reset other members
1061     itScriptEvent->cause = *itEvent;
1062 schoenebeck 3205 itScriptEvent->scheduleTime = itEvent->SchedTime();
1063 schoenebeck 2594 itScriptEvent->currentHandler = 0;
1064     itScriptEvent->executionSlices = 0;
1065 schoenebeck 2948 itScriptEvent->ignoreAllWaitCalls = false;
1066     itScriptEvent->handlerType = pEventHandler->eventHandlerType();
1067 schoenebeck 3293 itScriptEvent->parentHandlerID = 0;
1068     itScriptEvent->childHandlerID[0] = 0;
1069     itScriptEvent->autoAbortByParent = false;
1070     itScriptEvent->forkIndex = 0;
1071 schoenebeck 2879 // this is the native representation of the $EVENT_ID script variable
1072     itScriptEvent->id =
1073     (itEvent->Type == Event::type_note_on)
1074     ? ScriptID::fromNoteID( itEvent->Param.Note.ID )
1075     : ScriptID::fromEventID( pEventPool->getID(itEvent) );
1076 schoenebeck 2594
1077     // run script handler(s)
1078     VMExecStatus_t res = pScriptVM->exec(
1079 schoenebeck 2611 pChannel->pScript->parserContext, &*itScriptEvent
1080 schoenebeck 2594 );
1081    
1082 schoenebeck 2871 // was the script suspended?
1083     if (res & VM_EXEC_SUSPENDED) { // script was suspended ...
1084     // in case the script was suspended, keep it on the allocated
1085     // ScriptEvent list to be resume at the scheduled time in future,
1086     // additionally insert it into a sorted time queue
1087     pEventGenerator->scheduleAheadMicroSec(
1088     pChannel->pScript->suspendedEvents, // scheduler queue
1089     *itScriptEvent, // script event
1090     itScriptEvent->cause.FragmentPos(), // current time of script event (basis for its next execution)
1091     itScriptEvent->execCtx->suspensionTimeMicroseconds() // how long shall it be suspended
1092     );
1093     } else { // script execution has finished without 'suspended' status ...
1094 schoenebeck 2645 // if "polyphonic" variable data is passed from script's
1095     // "note" event handler to its "release" event handler, then
1096     // the script event must be kept and recycled for the later
1097     // occuring "release" script event ...
1098     if (pEventHandler == pChannel->pScript->handlerNote &&
1099     pChannel->pScript->handlerRelease &&
1100     pChannel->pScript->handlerNote->isPolyphonic() &&
1101     pChannel->pScript->handlerRelease->isPolyphonic())
1102     {
1103     const int key = itEvent->Param.Note.Key;
1104     itScriptEvent.moveToEndOf(pChannel->pScript->pKeyEvents[key & 127]);
1105     } else {
1106     // ... otherwise if no polyphonic data is passed and
1107     // script's execution has finished without suspension
1108     // status, then free the script event for a new future
1109     // script event to be triggered from start
1110     pChannel->pScript->pEvents->free(itScriptEvent);
1111     }
1112     }
1113 schoenebeck 2594 }
1114    
1115     /** @brief Resume execution of instrument script.
1116     *
1117     * Will be called to resume execution of a real-time instrument
1118 schoenebeck 2879 * script event which has been suspended previously.
1119 schoenebeck 2594 *
1120     * Script execution might be suspended for various reasons. Usually
1121     * a script will be suspended if the script called the built-in
1122     * "wait()" function, but it might also be suspended automatically
1123     * if the script took too much execution time in an audio fragment
1124     * cycle. So in the latter case automatic suspension is performed in
1125     * order to avoid harm for the sampler's overall real-time
1126     * requirements.
1127     *
1128     * @param pChannel - engine channel this script is running for
1129     * @param itScriptEvent - script execution that shall be resumed
1130     */
1131     void ResumeScriptEvent(AbstractEngineChannel* pChannel, RTList<ScriptEvent>::Iterator& itScriptEvent) {
1132 schoenebeck 2645 VMEventHandler* handler = itScriptEvent->handlers[itScriptEvent->currentHandler];
1133    
1134 schoenebeck 2594 // run script
1135     VMExecStatus_t res = pScriptVM->exec(
1136 schoenebeck 2611 pChannel->pScript->parserContext, &*itScriptEvent
1137 schoenebeck 2594 );
1138 schoenebeck 2645
1139 schoenebeck 2871 // was the script suspended?
1140     if (res & VM_EXEC_SUSPENDED) {
1141     // in case the script was suspended, keep it on the allocated
1142     // ScriptEvent list to be resume at the scheduled time in future,
1143     // additionally insert it into a sorted time queue
1144     pEventGenerator->scheduleAheadMicroSec(
1145     pChannel->pScript->suspendedEvents, // scheduler queue
1146     *itScriptEvent, // script event
1147     itScriptEvent->cause.FragmentPos(), // current time of script event (basis for its next execution)
1148     itScriptEvent->execCtx->suspensionTimeMicroseconds() // how long shall it be suspended
1149     );
1150     } else { // script execution has finished without 'suspended' status ...
1151 schoenebeck 2645 // if "polyphonic" variable data is passed from script's
1152     // "note" event handler to its "release" event handler, then
1153     // the script event must be kept and recycled for the later
1154     // occuring "release" script event ...
1155     if (handler && handler == pChannel->pScript->handlerNote &&
1156     pChannel->pScript->handlerRelease &&
1157     pChannel->pScript->handlerNote->isPolyphonic() &&
1158     pChannel->pScript->handlerRelease->isPolyphonic())
1159     {
1160     const int key = itScriptEvent->cause.Param.Note.Key;
1161     itScriptEvent.moveToEndOf(pChannel->pScript->pKeyEvents[key & 127]);
1162     } else {
1163     // ... otherwise if no polyphonic data is passed and
1164     // script's execution has finished without suspension
1165     // status, then free the script event for a new future
1166     // script event to be triggered from start
1167     pChannel->pScript->pEvents->free(itScriptEvent);
1168     }
1169     }
1170 schoenebeck 2594 }
1171    
1172 iliev 2012 /**
1173     * Will be called by LaunchVoice() method in case there are no free
1174     * voices left. This method will select and kill one old voice for
1175     * voice stealing and postpone the note-on event until the selected
1176     * voice actually died.
1177     *
1178 schoenebeck 2871 * @param pEngineChannel - engine channel on which this event occurred on
1179 iliev 2012 * @param itNoteOnEvent - key, velocity and time stamp of the event
1180     * @returns 0 on success, a value < 0 if no active voice could be picked for voice stealing
1181     */
1182 schoenebeck 2879 int StealVoice(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {
1183 schoenebeck 3306 dmsg(3,("StealVoice()\n"));
1184 iliev 2012 if (VoiceSpawnsLeft <= 0) {
1185     dmsg(1,("Max. voice thefts per audio fragment reached (you may raise CONFIG_MAX_VOICES).\n"));
1186     return -1;
1187     }
1188    
1189     EngineChannelBase<V, R, I>* pEngineChn = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1190    
1191 schoenebeck 2879 if (pEventPool->poolIsEmpty()) {
1192     dmsg(1,("Event pool emtpy!\n"));
1193     return -1;
1194     }
1195 iliev 2012
1196 schoenebeck 2879 if (!pEngineChn->StealVoice(itNoteOnEvent, &itLastStolenVoice, &itLastStolenNote, &iuiLastStolenKey)) {
1197     --VoiceSpawnsLeft;
1198     return 0;
1199     }
1200 iliev 2012
1201 schoenebeck 2879 // if we couldn't steal a voice from the same engine channel then
1202     // steal oldest voice on the oldest key from any other engine channel
1203     // (the smaller engine channel number, the higher priority)
1204     EngineChannelBase<V, R, I>* pSelectedChannel;
1205     int iChannelIndex;
1206     VoiceIterator itSelectedVoice;
1207 iliev 2012
1208 schoenebeck 3306 #if CONFIG_DEVMODE
1209     EngineChannel* pBegin = NULL; // to detect endless loop
1210     #endif
1211    
1212 schoenebeck 2879 // select engine channel
1213     if (pLastStolenChannel) {
1214     pSelectedChannel = pLastStolenChannel;
1215     iChannelIndex = pSelectedChannel->iEngineIndexSelf;
1216     } else { // pick the engine channel followed by this engine channel
1217     iChannelIndex = (pEngineChn->iEngineIndexSelf + 1) % engineChannels.size();
1218     pSelectedChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannelIndex]);
1219     }
1220 iliev 2012
1221 schoenebeck 2879 // if we already stole in this fragment, try to proceed on same note
1222     if (this->itLastStolenVoiceGlobally) {
1223     itSelectedVoice = this->itLastStolenVoiceGlobally;
1224     do {
1225     ++itSelectedVoice;
1226     } while (itSelectedVoice && !itSelectedVoice->IsStealable()); // proceed iterating if voice was created in this fragment cycle
1227     }
1228     // did we find a 'stealable' voice?
1229     if (itSelectedVoice && itSelectedVoice->IsStealable()) {
1230     // remember which voice we stole, so we can simply proceed on next voice stealing
1231     this->itLastStolenVoiceGlobally = itSelectedVoice;
1232     // done
1233     goto stealable_voice_found;
1234     }
1235    
1236     // get (next) oldest note
1237     if (this->itLastStolenNoteGlobally) {
1238     for (NoteIterator itNote = ++this->itLastStolenNoteGlobally;
1239     itNote; ++itNote)
1240     {
1241     for (itSelectedVoice = itNote->pActiveVoices->first(); itSelectedVoice; ++itSelectedVoice) {
1242     // proceed iterating if voice was created in this audio fragment cycle
1243     if (itSelectedVoice->IsStealable()) {
1244     // remember which voice of which note we stole, so we can simply proceed on next voice stealing
1245     this->itLastStolenNoteGlobally = itNote;
1246     this->itLastStolenVoiceGlobally = itSelectedVoice;
1247     goto stealable_voice_found; // selection succeeded
1248     }
1249     }
1250 iliev 2012 }
1251 schoenebeck 2879 }
1252 iliev 2012
1253 schoenebeck 2879 #if CONFIG_DEVMODE
1254 schoenebeck 3306 pBegin = pSelectedChannel; // to detect endless loop
1255 schoenebeck 2879 #endif // CONFIG_DEVMODE
1256 iliev 2012
1257 schoenebeck 2879 while (true) { // iterate through engine channels
1258     // get (next) oldest key
1259     RTList<uint>::Iterator iuiSelectedKey = (this->iuiLastStolenKeyGlobally) ? ++this->iuiLastStolenKeyGlobally : pSelectedChannel->pActiveKeys->first();
1260     this->iuiLastStolenKeyGlobally = RTList<uint>::Iterator(); // to prevent endless loop (see line above)
1261     while (iuiSelectedKey) {
1262     MidiKey* pSelectedKey = &pSelectedChannel->pMIDIKeyInfo[*iuiSelectedKey];
1263    
1264     for (NoteIterator itNote = pSelectedKey->pActiveNotes->first(),
1265     itNotesEnd = pSelectedKey->pActiveNotes->end();
1266     itNote != itNotesEnd; ++itNote)
1267     {
1268     itSelectedVoice = itNote->pActiveVoices->first();
1269 iliev 2012 // proceed iterating if voice was created in this fragment cycle
1270     while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice;
1271     // found a "stealable" voice ?
1272     if (itSelectedVoice && itSelectedVoice->IsStealable()) {
1273 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
1274 iliev 2012 this->iuiLastStolenKeyGlobally = iuiSelectedKey;
1275 schoenebeck 2879 this->itLastStolenNoteGlobally = itNote;
1276 iliev 2012 this->itLastStolenVoiceGlobally = itSelectedVoice;
1277     this->pLastStolenChannel = pSelectedChannel;
1278     goto stealable_voice_found; // selection succeeded
1279     }
1280     }
1281 schoenebeck 2879 ++iuiSelectedKey; // get next key on current engine channel
1282 iliev 2012 }
1283 schoenebeck 2879 // get next engine channel
1284     iChannelIndex = (iChannelIndex + 1) % engineChannels.size();
1285     pSelectedChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannelIndex]);
1286 iliev 2012
1287     #if CONFIG_DEVMODE
1288 schoenebeck 2879 if (pSelectedChannel == pBegin) {
1289     dmsg(1,("FATAL ERROR: voice stealing endless loop!\n"));
1290     dmsg(1,("VoiceSpawnsLeft=%d.\n", VoiceSpawnsLeft));
1291     dmsg(1,("Exiting.\n"));
1292     exit(-1);
1293 iliev 2012 }
1294     #endif // CONFIG_DEVMODE
1295 schoenebeck 2879 }
1296 iliev 2012
1297 schoenebeck 2879 // jump point if a 'stealable' voice was found
1298     stealable_voice_found:
1299 iliev 2012
1300 schoenebeck 2879 #if CONFIG_DEVMODE
1301     if (!itSelectedVoice->IsActive()) {
1302     dmsg(1,("EngineBase: ERROR, tried to steal a voice which was not active !!!\n"));
1303 iliev 2012 return -1;
1304     }
1305 schoenebeck 2879 #endif // CONFIG_DEVMODE
1306    
1307     // now kill the selected voice
1308     itSelectedVoice->Kill(itNoteOnEvent);
1309    
1310     --VoiceSpawnsLeft;
1311    
1312     return 0; // success
1313 iliev 2012 }
1314    
1315     void HandleInstrumentChanges() {
1316     bool instrumentChanged = false;
1317     for (int i = 0; i < engineChannels.size(); i++) {
1318     EngineChannelBase<V, R, I>* pEngineChannel =
1319     static_cast<EngineChannelBase<V, R, I>*>(engineChannels[i]);
1320    
1321     // as we're going to (carefully) write some status to the
1322     // synchronized struct, we cast away the const
1323     InstrumentChangeCmd<R, I>& cmd =
1324     const_cast<InstrumentChangeCmd<R, I>&>(pEngineChannel->InstrumentChangeCommandReader.Lock());
1325    
1326     pEngineChannel->pRegionsInUse = cmd.pRegionsInUse;
1327     pEngineChannel->pRegionsInUse->clear();
1328    
1329     if (cmd.bChangeInstrument) {
1330     // change instrument
1331     dmsg(5,("Engine: instrument change command received\n"));
1332     cmd.bChangeInstrument = false;
1333     pEngineChannel->pInstrument = cmd.pInstrument;
1334 schoenebeck 2659 pEngineChannel->pScript =
1335     cmd.pScript->bHasValidScript ? cmd.pScript : NULL;
1336 iliev 2012 instrumentChanged = true;
1337    
1338     pEngineChannel->MarkAllActiveVoicesAsOrphans();
1339 schoenebeck 2611
1340     // the script's "init" event handler is only executed
1341     // once (when the script is loaded or reloaded)
1342     if (pEngineChannel->pScript && pEngineChannel->pScript->handlerInit) {
1343 schoenebeck 2972 dmsg(5,("Engine: exec handlerInit %p\n", pEngineChannel->pScript->handlerInit));
1344 schoenebeck 2611 RTList<ScriptEvent>::Iterator itScriptEvent =
1345     pEngineChannel->pScript->pEvents->allocAppend();
1346    
1347 schoenebeck 3283 itScriptEvent->cause = pEventGenerator->CreateEvent(0);
1348     itScriptEvent->cause.Type = (Event::type_t) -1; // some invalid type to avoid random event processing
1349 schoenebeck 2614 itScriptEvent->cause.pEngineChannel = pEngineChannel;
1350 schoenebeck 3283 itScriptEvent->cause.pMidiInputPort = pEngineChannel->GetMidiInputPort();
1351 schoenebeck 3293 itScriptEvent->id = 0;
1352 schoenebeck 2618 itScriptEvent->handlers[0] = pEngineChannel->pScript->handlerInit;
1353     itScriptEvent->handlers[1] = NULL;
1354 schoenebeck 2972 itScriptEvent->currentHandler = 0;
1355     itScriptEvent->executionSlices = 0;
1356     itScriptEvent->ignoreAllWaitCalls = false;
1357     itScriptEvent->handlerType = VM_EVENT_HANDLER_INIT;
1358 schoenebeck 3293 itScriptEvent->parentHandlerID = 0;
1359     itScriptEvent->childHandlerID[0] = 0;
1360     itScriptEvent->autoAbortByParent = false;
1361     itScriptEvent->forkIndex = 0;
1362 schoenebeck 2614
1363 schoenebeck 3221 VMExecStatus_t res;
1364     size_t instructionsCount = 0;
1365     const size_t maxInstructions = 200000; // aiming approx. 1 second max. (based on very roughly 5us / instruction)
1366     bool bWarningShown = false;
1367     do {
1368     res = pScriptVM->exec(
1369     pEngineChannel->pScript->parserContext, &*itScriptEvent
1370     );
1371     instructionsCount += itScriptEvent->execCtx->instructionsPerformed();
1372     if (instructionsCount > maxInstructions && !bWarningShown) {
1373     bWarningShown = true;
1374     dmsg(0,("[ScriptVM] WARNING: \"init\" event handler of instrument script executing for long time!\n"));
1375     }
1376     } while (res & VM_EXEC_SUSPENDED && !(res & VM_EXEC_ERROR));
1377 schoenebeck 2611
1378     pEngineChannel->pScript->pEvents->free(itScriptEvent);
1379     }
1380 iliev 2012 }
1381     }
1382    
1383     if (instrumentChanged) {
1384     //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
1385     ResetSuspendedRegions();
1386     }
1387     }
1388    
1389     /**
1390     * Render all 'normal' voices (that is voices which were not stolen in
1391     * this fragment) on the given engine channel.
1392     *
1393     * @param pEngineChannel - engine channel on which audio should be
1394     * rendered
1395     * @param Samples - amount of sample points to be rendered in
1396     * this audio fragment cycle
1397     */
1398     void RenderActiveVoices(EngineChannel* pEngineChannel, uint Samples) {
1399     #if !CONFIG_PROCESS_MUTED_CHANNELS
1400     if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
1401     #endif
1402    
1403     EngineChannelBase<V, R, I>* pChannel =
1404     static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1405     pChannel->RenderActiveVoices(Samples);
1406    
1407     ActiveVoiceCountTemp += pEngineChannel->GetVoiceCount();
1408     }
1409    
1410     /**
1411     * Render all stolen voices (only voices which were stolen in this
1412     * fragment) on the given engine channel. Stolen voices are rendered
1413     * after all normal voices have been rendered; this is needed to render
1414     * audio of those voices which were selected for voice stealing until
1415     * the point were the stealing (that is the take over of the voice)
1416     * actually happened.
1417     *
1418     * @param pEngineChannel - engine channel on which audio should be
1419     * rendered
1420     * @param Samples - amount of sample points to be rendered in
1421     * this audio fragment cycle
1422     */
1423     void RenderStolenVoices(uint Samples) {
1424     RTList<Event>::Iterator itVoiceStealEvent = pVoiceStealingQueue->first();
1425     RTList<Event>::Iterator end = pVoiceStealingQueue->end();
1426     for (; itVoiceStealEvent != end; ++itVoiceStealEvent) {
1427     EngineChannelBase<V, R, I>* pEngineChannel =
1428     static_cast<EngineChannelBase<V, R, I>*>(itVoiceStealEvent->pEngineChannel);;
1429     if (!pEngineChannel->pInstrument) continue; // ignore if no instrument loaded
1430 schoenebeck 2879
1431 iliev 2012 PoolVoiceIterator itNewVoice =
1432     LaunchVoice(pEngineChannel, itVoiceStealEvent, itVoiceStealEvent->Param.Note.Layer, itVoiceStealEvent->Param.Note.ReleaseTrigger, false, false);
1433     if (itNewVoice) {
1434 schoenebeck 2879 // usually there should already be a new Note object
1435     NoteIterator itNote = GetNotePool()->fromID(itVoiceStealEvent->Param.Note.ID);
1436     if (!itNote) { // should not happen, but just to be sure ...
1437 schoenebeck 3306 dmsg(2,("Engine: No Note object for stolen voice!\n"));
1438 schoenebeck 3205 const note_id_t noteID = LaunchNewNote(pEngineChannel, itVoiceStealEvent);
1439 schoenebeck 2879 if (!noteID) {
1440     dmsg(1,("Engine: Voice stealing failed; No Note object and Note pool empty!\n"));
1441     continue;
1442     }
1443     itNote = GetNotePool()->fromID(noteID);
1444     }
1445     // move voice from whereever it was, to the new note's list of active voices
1446     itNewVoice = itNewVoice.moveToEndOf(itNote->pActiveVoices);
1447     // render audio of this new voice for the first time
1448 iliev 2012 itNewVoice->Render(Samples);
1449     if (itNewVoice->IsActive()) { // still active
1450     *(pEngineChannel->pRegionsInUse->allocAppend()) = itNewVoice->GetRegion();
1451     ActiveVoiceCountTemp++;
1452     pEngineChannel->SetVoiceCount(pEngineChannel->GetVoiceCount() + 1);
1453    
1454     if (itNewVoice->PlaybackState == Voice::playback_state_disk) {
1455     if (itNewVoice->DiskStreamRef.State != Stream::state_unused) {
1456     pEngineChannel->SetDiskStreamCount(pEngineChannel->GetDiskStreamCount() + 1);
1457     }
1458     }
1459     } else { // voice reached end, is now inactive
1460     pEngineChannel->FreeVoice(itNewVoice); // remove voice from the list of active voices
1461     }
1462     }
1463     else dmsg(1,("EngineBase: ERROR, voice stealing didn't work out!\n"));
1464    
1465     // we need to clear the key's event list explicitly here in case key was never active
1466     MidiKey* pKey = &pEngineChannel->pMIDIKeyInfo[itVoiceStealEvent->Param.Note.Key];
1467     pKey->VoiceTheftsQueued--;
1468     if (!pKey->Active && !pKey->VoiceTheftsQueued) pKey->pEvents->clear();
1469     }
1470     }
1471    
1472     /**
1473     * Free all keys which have turned inactive in this audio fragment, from
1474     * the list of active keys and clear all event lists on that engine
1475     * channel.
1476     *
1477     * @param pEngineChannel - engine channel to cleanup
1478     */
1479     void PostProcess(EngineChannel* pEngineChannel) {
1480     EngineChannelBase<V, R, I>* pChannel =
1481     static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1482 schoenebeck 3306 pChannel->FreeAllInactiveKeys();
1483 iliev 2012
1484     // empty the engine channel's own event lists
1485 schoenebeck 2871 // (only events of the current audio fragment cycle)
1486     pChannel->ClearEventListsOfCurrentFragment();
1487 iliev 2012 }
1488    
1489 schoenebeck 2121 /**
1490     * Process MIDI control change events with hard coded behavior,
1491     * that is controllers whose behavior is defined independently
1492     * of the actual sampler engine type and instrument.
1493     *
1494     * @param pEngineChannel - engine channel on which the MIDI CC event was received
1495     * @param itControlChangeEvent - the actual MIDI CC event
1496     */
1497 iliev 2012 void ProcessHardcodedControllers (
1498     EngineChannel* pEngineChannel,
1499     Pool<Event>::Iterator& itControlChangeEvent
1500     ) {
1501     EngineChannelBase<V, R, I>* pChannel =
1502     static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1503    
1504 schoenebeck 3697 // will be set to true if this CC event has anything to do with RPN/NRPN
1505     bool bIsRpn = false, bIsNrpn = false;
1506    
1507 iliev 2012 switch (itControlChangeEvent->Param.CC.Controller) {
1508     case 5: { // portamento time
1509     pChannel->PortamentoTime = (float) itControlChangeEvent->Param.CC.Value / 127.0f * (float) CONFIG_PORTAMENTO_TIME_MAX + (float) CONFIG_PORTAMENTO_TIME_MIN;
1510     break;
1511     }
1512 schoenebeck 3688 case 6: { // data entry (MSB)
1513     //dmsg(1,("DATA ENTRY MSB %d\n", itControlChangeEvent->Param.CC.Value));
1514 schoenebeck 3697 if (pChannel->GetMidiRpnParameter() >= 0) { // RPN parameter number was sent previously ...
1515     pChannel->SetMidiRpnDataMsb(
1516     itControlChangeEvent->Param.CC.Value
1517     );
1518     bIsRpn = true;
1519 schoenebeck 3688
1520 schoenebeck 3697 // look-ahead: if next MIDI event is data entry LSB,
1521     // then skip this event here for now (to avoid double
1522     // handling of what's supposed to be one RPN event)
1523     if (isNextEventCCNr(itControlChangeEvent, 38))
1524     break;
1525 schoenebeck 3688
1526     int ch = itControlChangeEvent->Param.CC.Channel;
1527     int param = pChannel->GetMidiRpnParameter();
1528 schoenebeck 3697 int value = pChannel->GetMidiRpnData();
1529 schoenebeck 3688
1530     // transform event type: CC event -> RPN event
1531     itControlChangeEvent->Type = Event::type_rpn;
1532     itControlChangeEvent->Param.RPN.Channel = ch;
1533     itControlChangeEvent->Param.RPN.Parameter = param;
1534     itControlChangeEvent->Param.RPN.Value = value;
1535    
1536 schoenebeck 3690 // if there's a RPN script handler, run it ...
1537     if (pChannel->pScript->handlerRpn) {
1538     const event_id_t eventID =
1539     pEventPool->getID(itControlChangeEvent);
1540     // run the RPN script handler
1541     ProcessEventByScript(
1542     pChannel, itControlChangeEvent,
1543     pChannel->pScript->handlerRpn
1544     );
1545     // if RPN event was dropped by script, abort
1546     // here to avoid hard coded RPN processing below
1547 schoenebeck 3697 if (!pEventPool->fromID(eventID))
1548 schoenebeck 3690 break;
1549     }
1550    
1551     // do the actual (hard-coded) RPN value change processing
1552 schoenebeck 3688 ProcessHardcodedRpn(pEngineChannel, itControlChangeEvent);
1553    
1554 schoenebeck 3687 } else if (pChannel->GetMidiNrpnParameter() >= 0) { // NRPN parameter number was sent previously ...
1555 schoenebeck 3697 pChannel->SetMidiNrpnDataMsb(
1556     itControlChangeEvent->Param.CC.Value
1557     );
1558     bIsNrpn = true;
1559    
1560     // look-ahead: if next MIDI event is data entry LSB,
1561     // then skip this event here for now (to avoid double
1562     // handling of what's supposed to be one NRPN event)
1563     if (isNextEventCCNr(itControlChangeEvent, 38))
1564     break;
1565    
1566 schoenebeck 3688 int ch = itControlChangeEvent->Param.CC.Channel;
1567     int param = pChannel->GetMidiNrpnParameter();
1568 schoenebeck 3697 int value = pChannel->GetMidiNrpnData();
1569 schoenebeck 3688
1570     // transform event type: CC event -> NRPN event
1571     itControlChangeEvent->Type = Event::type_nrpn;
1572 schoenebeck 3696 itControlChangeEvent->Param.NRPN.Channel = ch;
1573     itControlChangeEvent->Param.NRPN.Parameter = param;
1574     itControlChangeEvent->Param.NRPN.Value = value;
1575 schoenebeck 3688
1576 schoenebeck 3690 // if there's a NRPN script handler, run it ...
1577     if (pChannel->pScript->handlerNrpn) {
1578     const event_id_t eventID =
1579     pEventPool->getID(itControlChangeEvent);
1580     // run the NRPN script handler
1581     ProcessEventByScript(
1582     pChannel, itControlChangeEvent,
1583     pChannel->pScript->handlerNrpn
1584     );
1585     // if NRPN event was dropped by script, abort
1586     // here to avoid hard coded NRPN processing below
1587 schoenebeck 3697 if (!pEventPool->fromID(eventID))
1588 schoenebeck 3690 break;
1589     }
1590    
1591     // do the actual (hard-coded) NRPN value change processing
1592 schoenebeck 3688 ProcessHardcodedNrpn(pEngineChannel, itControlChangeEvent);
1593 iliev 2012 }
1594     break;
1595     }
1596     case 7: { // volume
1597     //TODO: not sample accurate yet
1598     pChannel->MidiVolume = VolumeCurve[itControlChangeEvent->Param.CC.Value];
1599     pChannel->bStatusChanged = true; // engine channel status has changed, so set notify flag
1600     break;
1601     }
1602     case 10: { // panpot
1603     //TODO: not sample accurate yet
1604     pChannel->iLastPanRequest = itControlChangeEvent->Param.CC.Value;
1605     break;
1606     }
1607 schoenebeck 3688 case 38: { // data entry (LSB)
1608     //dmsg(1,("DATA ENTRY LSB %d\n", itControlChangeEvent->Param.CC.Value));
1609 schoenebeck 3697 if (pChannel->GetMidiRpnParameter() >= 0) { // RPN parameter number was sent previously ...
1610     pChannel->SetMidiRpnDataLsb(
1611     itControlChangeEvent->Param.CC.Value
1612     );
1613     bIsRpn = true;
1614 schoenebeck 3688
1615     int ch = itControlChangeEvent->Param.CC.Channel;
1616     int param = pChannel->GetMidiRpnParameter();
1617 schoenebeck 3697 int value = pChannel->GetMidiRpnData();
1618 schoenebeck 3688
1619     // transform event type: CC event -> RPN event
1620     itControlChangeEvent->Type = Event::type_rpn;
1621     itControlChangeEvent->Param.RPN.Channel = ch;
1622     itControlChangeEvent->Param.RPN.Parameter = param;
1623     itControlChangeEvent->Param.RPN.Value = value;
1624    
1625 schoenebeck 3690 // if there's a RPN script handler, run it ...
1626     if (pChannel->pScript->handlerRpn) {
1627     const event_id_t eventID =
1628     pEventPool->getID(itControlChangeEvent);
1629     // run the RPN script handler
1630     ProcessEventByScript(
1631     pChannel, itControlChangeEvent,
1632     pChannel->pScript->handlerRpn
1633     );
1634     // if RPN event was dropped by script, abort
1635     // here to avoid hard coded RPN processing below
1636 schoenebeck 3697 if (!pEventPool->fromID(eventID))
1637 schoenebeck 3690 break;
1638     }
1639    
1640     // do the actual (hard-coded) RPN value change processing
1641 schoenebeck 3688 ProcessHardcodedRpn(pEngineChannel, itControlChangeEvent);
1642    
1643     } else if (pChannel->GetMidiNrpnParameter() >= 0) { // NRPN parameter number was sent previously ...
1644 schoenebeck 3697 pChannel->SetMidiNrpnDataLsb(
1645     itControlChangeEvent->Param.CC.Value
1646     );
1647     bIsNrpn = true;
1648    
1649 schoenebeck 3688 int ch = itControlChangeEvent->Param.CC.Channel;
1650     int param = pChannel->GetMidiNrpnParameter();
1651 schoenebeck 3697 int value = pChannel->GetMidiNrpnData();
1652 schoenebeck 3688
1653     // transform event type: CC event -> NRPN event
1654     itControlChangeEvent->Type = Event::type_nrpn;
1655 schoenebeck 3696 itControlChangeEvent->Param.NRPN.Channel = ch;
1656     itControlChangeEvent->Param.NRPN.Parameter = param;
1657     itControlChangeEvent->Param.NRPN.Value = value;
1658 schoenebeck 3688
1659 schoenebeck 3690 // if there's a NRPN script handler, run it ...
1660     if (pChannel->pScript->handlerNrpn) {
1661     const event_id_t eventID =
1662     pEventPool->getID(itControlChangeEvent);
1663     // run the NRPN script handler
1664     ProcessEventByScript(
1665     pChannel, itControlChangeEvent,
1666     pChannel->pScript->handlerNrpn
1667     );
1668     // if NRPN event was dropped by script, abort
1669     // here to avoid hard coded NRPN processing below
1670 schoenebeck 3697 if (!pEventPool->fromID(eventID))
1671 schoenebeck 3690 break;
1672     }
1673    
1674     // do the actual (hard-coded) NRPN value change processing
1675 schoenebeck 3688 ProcessHardcodedNrpn(pEngineChannel, itControlChangeEvent);
1676     }
1677     break;
1678     }
1679 iliev 2012 case 64: { // sustain
1680     if (itControlChangeEvent->Param.CC.Value >= 64 && !pChannel->SustainPedal) {
1681     dmsg(4,("DAMPER (RIGHT) PEDAL DOWN\n"));
1682     pChannel->SustainPedal = true;
1683     pChannel->listeners.PreProcessSustainPedalDown();
1684    
1685     #if !CONFIG_PROCESS_MUTED_CHANNELS
1686     if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
1687     pChannel->listeners.PostProcessSustainPedalDown();
1688     return;
1689     }
1690     #endif
1691    
1692     pChannel->ProcessSustainPedalDown(itControlChangeEvent);
1693     pChannel->listeners.PostProcessSustainPedalDown();
1694     }
1695     if (itControlChangeEvent->Param.CC.Value < 64 && pChannel->SustainPedal) {
1696     dmsg(4,("DAMPER (RIGHT) PEDAL UP\n"));
1697     pChannel->SustainPedal = false;
1698     pChannel->listeners.PreProcessSustainPedalUp();
1699    
1700     #if !CONFIG_PROCESS_MUTED_CHANNELS
1701     if (pChannel->GetMute()) { // skip if sampler channel is muted
1702     pChannel->listeners.PostProcessSustainPedalUp();
1703     return;
1704     }
1705     #endif
1706    
1707     pChannel->ProcessSustainPedalUp(itControlChangeEvent);
1708     pChannel->listeners.PostProcessSustainPedalUp();
1709     }
1710     break;
1711     }
1712     case 65: { // portamento on / off
1713     const bool bPortamento = itControlChangeEvent->Param.CC.Value >= 64;
1714     if (bPortamento != pChannel->PortamentoMode)
1715     KillAllVoices(pChannel, itControlChangeEvent);
1716     pChannel->PortamentoMode = bPortamento;
1717     break;
1718     }
1719     case 66: { // sostenuto
1720     if (itControlChangeEvent->Param.CC.Value >= 64 && !pChannel->SostenutoPedal) {
1721     dmsg(4,("SOSTENUTO (CENTER) PEDAL DOWN\n"));
1722     pChannel->SostenutoPedal = true;
1723     pChannel->listeners.PreProcessSostenutoPedalDown();
1724    
1725     #if !CONFIG_PROCESS_MUTED_CHANNELS
1726     if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
1727     pChannel->listeners.PostProcessSostenutoPedalDown();
1728     return;
1729     }
1730     #endif
1731    
1732     pChannel->ProcessSostenutoPedalDown();
1733     pChannel->listeners.PostProcessSostenutoPedalDown();
1734     }
1735     if (itControlChangeEvent->Param.CC.Value < 64 && pChannel->SostenutoPedal) {
1736     dmsg(4,("SOSTENUTO (CENTER) PEDAL UP\n"));
1737     pChannel->SostenutoPedal = false;
1738     pChannel->listeners.PreProcessSostenutoPedalUp();
1739    
1740     #if !CONFIG_PROCESS_MUTED_CHANNELS
1741     if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
1742     pChannel->listeners.PostProcessSostenutoPedalUp();
1743     return;
1744     }
1745     #endif
1746    
1747     pChannel->ProcessSostenutoPedalUp(itControlChangeEvent);
1748     pChannel->listeners.PostProcessSostenutoPedalUp();
1749     }
1750     break;
1751     }
1752 schoenebeck 3699 case 96: { // data increment (data entry +1)
1753     //dmsg(1,("DATA INC\n"));
1754     if (pChannel->GetMidiRpnParameter() >= 0) { // RPN parameter number was sent previously ...
1755     pChannel->SetMidiRpnData(
1756     pChannel->GetMidiRpnData() + 1
1757     );
1758     bIsRpn = true;
1759    
1760     int ch = itControlChangeEvent->Param.CC.Channel;
1761     int param = pChannel->GetMidiRpnParameter();
1762     int value = pChannel->GetMidiRpnData();
1763    
1764     // transform event type: CC event -> RPN event
1765     itControlChangeEvent->Type = Event::type_rpn;
1766     itControlChangeEvent->Param.RPN.Channel = ch;
1767     itControlChangeEvent->Param.RPN.Parameter = param;
1768     itControlChangeEvent->Param.RPN.Value = value;
1769    
1770     // if there's a RPN script handler, run it ...
1771     if (pChannel->pScript->handlerRpn) {
1772     const event_id_t eventID =
1773     pEventPool->getID(itControlChangeEvent);
1774     // run the RPN script handler
1775     ProcessEventByScript(
1776     pChannel, itControlChangeEvent,
1777     pChannel->pScript->handlerRpn
1778     );
1779     // if RPN event was dropped by script, abort
1780     // here to avoid hard coded RPN processing below
1781     if (!pEventPool->fromID(eventID))
1782     break;
1783     }
1784    
1785     // do the actual (hard-coded) RPN value change processing
1786     ProcessHardcodedRpn(pEngineChannel, itControlChangeEvent);
1787    
1788     } else if (pChannel->GetMidiNrpnParameter() >= 0) { // NRPN parameter number was sent previously ...
1789     pChannel->SetMidiNrpnData(
1790     pChannel->GetMidiNrpnData() + 1
1791     );
1792     bIsNrpn = true;
1793    
1794     int ch = itControlChangeEvent->Param.CC.Channel;
1795     int param = pChannel->GetMidiNrpnParameter();
1796     int value = pChannel->GetMidiNrpnData();
1797    
1798     // transform event type: CC event -> NRPN event
1799     itControlChangeEvent->Type = Event::type_nrpn;
1800     itControlChangeEvent->Param.NRPN.Channel = ch;
1801     itControlChangeEvent->Param.NRPN.Parameter = param;
1802     itControlChangeEvent->Param.NRPN.Value = value;
1803    
1804     // if there's a NRPN script handler, run it ...
1805     if (pChannel->pScript->handlerNrpn) {
1806     const event_id_t eventID =
1807     pEventPool->getID(itControlChangeEvent);
1808     // run the NRPN script handler
1809     ProcessEventByScript(
1810     pChannel, itControlChangeEvent,
1811     pChannel->pScript->handlerNrpn
1812     );
1813     // if NRPN event was dropped by script, abort
1814     // here to avoid hard coded NRPN processing below
1815     if (!pEventPool->fromID(eventID))
1816     break;
1817     }
1818    
1819     // do the actual (hard-coded) NRPN value change processing
1820     ProcessHardcodedNrpn(pEngineChannel, itControlChangeEvent);
1821     }
1822     break;
1823     }
1824     case 97: { // data decrement (data entry -1)
1825     //dmsg(1,("DATA DEC\n"));
1826     if (pChannel->GetMidiRpnParameter() >= 0) { // RPN parameter number was sent previously ...
1827     pChannel->SetMidiRpnData(
1828     pChannel->GetMidiRpnData() - 1
1829     );
1830     bIsRpn = true;
1831    
1832     int ch = itControlChangeEvent->Param.CC.Channel;
1833     int param = pChannel->GetMidiRpnParameter();
1834     int value = pChannel->GetMidiRpnData();
1835    
1836     // transform event type: CC event -> RPN event
1837     itControlChangeEvent->Type = Event::type_rpn;
1838     itControlChangeEvent->Param.RPN.Channel = ch;
1839     itControlChangeEvent->Param.RPN.Parameter = param;
1840     itControlChangeEvent->Param.RPN.Value = value;
1841    
1842     // if there's a RPN script handler, run it ...
1843     if (pChannel->pScript->handlerRpn) {
1844     const event_id_t eventID =
1845     pEventPool->getID(itControlChangeEvent);
1846     // run the RPN script handler
1847     ProcessEventByScript(
1848     pChannel, itControlChangeEvent,
1849     pChannel->pScript->handlerRpn
1850     );
1851     // if RPN event was dropped by script, abort
1852     // here to avoid hard coded RPN processing below
1853     if (!pEventPool->fromID(eventID))
1854     break;
1855     }
1856    
1857     // do the actual (hard-coded) RPN value change processing
1858     ProcessHardcodedRpn(pEngineChannel, itControlChangeEvent);
1859    
1860     } else if (pChannel->GetMidiNrpnParameter() >= 0) { // NRPN parameter number was sent previously ...
1861     pChannel->SetMidiNrpnData(
1862     pChannel->GetMidiNrpnData() - 1
1863     );
1864     bIsNrpn = true;
1865    
1866     int ch = itControlChangeEvent->Param.CC.Channel;
1867     int param = pChannel->GetMidiNrpnParameter();
1868     int value = pChannel->GetMidiNrpnData();
1869    
1870     // transform event type: CC event -> NRPN event
1871     itControlChangeEvent->Type = Event::type_nrpn;
1872     itControlChangeEvent->Param.NRPN.Channel = ch;
1873     itControlChangeEvent->Param.NRPN.Parameter = param;
1874     itControlChangeEvent->Param.NRPN.Value = value;
1875    
1876     // if there's a NRPN script handler, run it ...
1877     if (pChannel->pScript->handlerNrpn) {
1878     const event_id_t eventID =
1879     pEventPool->getID(itControlChangeEvent);
1880     // run the NRPN script handler
1881     ProcessEventByScript(
1882     pChannel, itControlChangeEvent,
1883     pChannel->pScript->handlerNrpn
1884     );
1885     // if NRPN event was dropped by script, abort
1886     // here to avoid hard coded NRPN processing below
1887     if (!pEventPool->fromID(eventID))
1888     break;
1889     }
1890    
1891     // do the actual (hard-coded) NRPN value change processing
1892     ProcessHardcodedNrpn(pEngineChannel, itControlChangeEvent);
1893     }
1894     break;
1895     }
1896 schoenebeck 3687 case 98: { // NRPN parameter LSB
1897 schoenebeck 2121 dmsg(4,("NRPN LSB %d\n", itControlChangeEvent->Param.CC.Value));
1898 schoenebeck 3697 bIsNrpn = true;
1899 schoenebeck 3687 pEngineChannel->SetMidiNrpnParameterLsb(itControlChangeEvent->Param.CC.Value);
1900 schoenebeck 2121 break;
1901     }
1902 schoenebeck 3687 case 99: { // NRPN parameter MSB
1903 schoenebeck 2121 dmsg(4,("NRPN MSB %d\n", itControlChangeEvent->Param.CC.Value));
1904 schoenebeck 3697 bIsNrpn = true;
1905 schoenebeck 3687 pEngineChannel->SetMidiNrpnParameterMsb(itControlChangeEvent->Param.CC.Value);
1906 schoenebeck 2121 break;
1907     }
1908 schoenebeck 3687 case 100: { // RPN parameter LSB
1909 schoenebeck 2121 dmsg(4,("RPN LSB %d\n", itControlChangeEvent->Param.CC.Value));
1910 schoenebeck 3697 bIsRpn = true;
1911 schoenebeck 3687 pEngineChannel->SetMidiRpnParameterLsb(itControlChangeEvent->Param.CC.Value);
1912 iliev 2012 break;
1913     }
1914 schoenebeck 3687 case 101: { // RPN parameter MSB
1915 schoenebeck 2121 dmsg(4,("RPN MSB %d\n", itControlChangeEvent->Param.CC.Value));
1916 schoenebeck 3697 bIsRpn = true;
1917 schoenebeck 3687 pEngineChannel->SetMidiRpnParameterMsb(itControlChangeEvent->Param.CC.Value);
1918 iliev 2012 break;
1919     }
1920    
1921    
1922     // Channel Mode Messages
1923    
1924     case 120: { // all sound off
1925     KillAllVoices(pEngineChannel, itControlChangeEvent);
1926     break;
1927     }
1928     case 121: { // reset all controllers
1929     pChannel->ResetControllers();
1930     break;
1931     }
1932     case 123: { // all notes off
1933     #if CONFIG_PROCESS_ALL_NOTES_OFF
1934     pChannel->ReleaseAllVoices(itControlChangeEvent);
1935     #endif // CONFIG_PROCESS_ALL_NOTES_OFF
1936     break;
1937     }
1938     case 126: { // mono mode on
1939     if (!pChannel->SoloMode)
1940     KillAllVoices(pEngineChannel, itControlChangeEvent);
1941     pChannel->SoloMode = true;
1942     break;
1943     }
1944     case 127: { // poly mode on
1945     if (pChannel->SoloMode)
1946     KillAllVoices(pEngineChannel, itControlChangeEvent);
1947     pChannel->SoloMode = false;
1948     break;
1949     }
1950     }
1951 schoenebeck 3697
1952     // reset cached RPN/NRPN parameter number and data in case this
1953     // CC event had nothing to do with RPN/NRPN
1954     if (!bIsRpn && pChannel->GetMidiRpnParameter() >= 0)
1955     pChannel->ResetMidiRpnParameter();
1956     if (!bIsNrpn && pChannel->GetMidiNrpnParameter() >= 0)
1957     pChannel->ResetMidiNrpnParameter();
1958 iliev 2012 }
1959    
1960 schoenebeck 3688 /**
1961     * Process MIDI RPN events with hard coded behavior.
1962     *
1963     * @param pEngineChannel - engine channel on which the MIDI RPN
1964     * event was received
1965     * @param itRpnEvent - the actual MIDI RPN event
1966     */
1967     void ProcessHardcodedRpn(EngineChannel* pEngineChannel,
1968     Pool<Event>::Iterator& itRpnEvent)
1969     {
1970     EngineChannelBase<V, R, I>* pChannel =
1971     static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1972    
1973     if (itRpnEvent->Param.RPN.Parameter == 2) { // coarse tuning in half tones
1974     int transpose = (int) itRpnEvent->Param.RPN.ValueMSB() - 64;
1975     // limit to +- two octaves for now
1976     transpose = RTMath::Min(transpose, 24);
1977     transpose = RTMath::Max(transpose, -24);
1978     pChannel->GlobalTranspose = transpose;
1979     // workaround, so we won't have hanging notes
1980     pChannel->ReleaseAllVoices(itRpnEvent);
1981 schoenebeck 3701 } else if (itRpnEvent->Param.RPN.Parameter == 16383) { // null function RPN
1982     // disable subsequent data entry/increment/decrement processing
1983     pChannel->ResetMidiRpnParameter();
1984 schoenebeck 3688 }
1985     }
1986    
1987     /**
1988     * Process MIDI NRPN events with hard coded behavior.
1989     *
1990     * @param pEngineChannel - engine channel on which the MIDI NRPN
1991     * event was received
1992     * @param itRpnEvent - the actual MIDI NRPN event
1993     */
1994     void ProcessHardcodedNrpn(EngineChannel* pEngineChannel,
1995     Pool<Event>::Iterator& itNrpnEvent)
1996     {
1997     EngineChannelBase<V, R, I>* pChannel =
1998     static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1999    
2000     switch (itNrpnEvent->Param.NRPN.ParameterMSB()) {
2001     case 0x1a: { // volume level of note (Roland GS NRPN)
2002     const uint note = itNrpnEvent->Param.NRPN.ParameterLSB();
2003     const uint vol = itNrpnEvent->Param.NRPN.ValueMSB();
2004     dmsg(4,("Note Volume NRPN received (note=%d,vol=%d).\n", note, vol));
2005     if (note < 128 && vol < 128)
2006     pChannel->pMIDIKeyInfo[note].Volume = VolumeCurve[vol];
2007     break;
2008     }
2009     case 0x1c: { // panpot of note (Roland GS NRPN)
2010     const uint note = itNrpnEvent->Param.NRPN.ParameterLSB();
2011     const uint pan = itNrpnEvent->Param.NRPN.ValueMSB();
2012     dmsg(4,("Note Pan NRPN received (note=%d,pan=%d).\n", note, pan));
2013     if (note < 128 && pan < 128) {
2014     pChannel->pMIDIKeyInfo[note].PanLeft = PanCurve[128 - pan];
2015     pChannel->pMIDIKeyInfo[note].PanRight = PanCurve[pan];
2016     }
2017     break;
2018     }
2019     case 0x1d: { // reverb send of note (Roland GS NRPN)
2020     const uint note = itNrpnEvent->Param.NRPN.ParameterLSB();
2021     const float reverb = float(itNrpnEvent->Param.NRPN.Value) / 16383.f;
2022     dmsg(4,("Note Reverb Send NRPN received (note=%d,send=%f).\n", note, reverb));
2023     if (note < 128)
2024     pChannel->pMIDIKeyInfo[note].ReverbSend = reverb;
2025     break;
2026     }
2027     case 0x1e: { // chorus send of note (Roland GS NRPN)
2028     const uint note = itNrpnEvent->Param.NRPN.ParameterLSB();
2029     const float chorus = float(itNrpnEvent->Param.NRPN.Value) / 16383.f;
2030     dmsg(4,("Note Chorus Send NRPN received (note=%d,send=%f).\n", note, chorus));
2031     if (note < 128)
2032     pChannel->pMIDIKeyInfo[note].ChorusSend = chorus;
2033     break;
2034     }
2035 schoenebeck 3701 case 0x7f: {
2036     if (itNrpnEvent->Param.NRPN.ParameterLSB() == 0x7f) { // null function NRPN
2037     // disable subsequent data entry/increment/decrement processing
2038     pChannel->ResetMidiNrpnParameter();
2039     }
2040     break;
2041     }
2042 schoenebeck 3688 }
2043     }
2044    
2045 iliev 2012 virtual D* CreateDiskThread() = 0;
2046    
2047     /**
2048     * Assigns and triggers a new voice for the respective MIDI key.
2049     *
2050 schoenebeck 2871 * @param pEngineChannel - engine channel on which this event occurred on
2051 iliev 2012 * @param itNoteOnEvent - key, velocity and time stamp of the event
2052     */
2053 schoenebeck 3054 virtual void ProcessNoteOn(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) OVERRIDE {
2054 iliev 2012 EngineChannelBase<V, R, I>* pChannel =
2055     static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
2056    
2057 schoenebeck 2879 const int key = itNoteOnEvent->Param.Note.Key;
2058     const int vel = itNoteOnEvent->Param.Note.Velocity;
2059     if (key < 0 || key > 127) return; // ignore event, key outside allowed key range
2060 iliev 2012
2061     MidiKey* pKey = &pChannel->pMIDIKeyInfo[key];
2062    
2063 schoenebeck 2938 // There are real MIDI note-on events (Event::type_note_on) and
2064     // programmatically spawned notes (Event::type_play_note). We have
2065     // to distinguish between them, since certain processing below
2066     // must only be done on real MIDI note-on events (i.e. for
2067     // correctly updating which MIDI keys are currently pressed down).
2068     const bool isRealMIDINoteOnEvent = itNoteOnEvent->Type == Event::type_note_on;
2069    
2070     if (isRealMIDINoteOnEvent)
2071     pChannel->listeners.PreProcessNoteOn(key, vel);
2072    
2073 iliev 2012 #if !CONFIG_PROCESS_MUTED_CHANNELS
2074     if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
2075 schoenebeck 2938 if (isRealMIDINoteOnEvent)
2076     pChannel->listeners.PostProcessNoteOn(key, vel);
2077 iliev 2012 return;
2078     }
2079     #endif
2080    
2081     if (!pChannel->pInstrument) {
2082 schoenebeck 2938 if (isRealMIDINoteOnEvent)
2083     pChannel->listeners.PostProcessNoteOn(key, vel);
2084 iliev 2012 return; // ignore if no instrument loaded
2085     }
2086    
2087     // move note on event to the key's own event list
2088     RTList<Event>::Iterator itNoteOnEventOnKeyList = itNoteOnEvent.moveToEndOf(pKey->pEvents);
2089    
2090     // if Solo Mode then kill all already active voices
2091 schoenebeck 2938 if (pChannel->SoloMode && isRealMIDINoteOnEvent) {
2092 iliev 2012 Pool<uint>::Iterator itYoungestKey = pChannel->pActiveKeys->last();
2093     if (itYoungestKey) {
2094     const int iYoungestKey = *itYoungestKey;
2095     const MidiKey* pOtherKey = &pChannel->pMIDIKeyInfo[iYoungestKey];
2096     if (pOtherKey->Active) {
2097     // get final portamento position of currently active voice
2098     if (pChannel->PortamentoMode) {
2099 schoenebeck 2879 NoteIterator itNote = pOtherKey->pActiveNotes->last();
2100     if (itNote) {
2101     VoiceIterator itVoice = itNote->pActiveVoices->last();
2102     if (itVoice) itVoice->UpdatePortamentoPos(itNoteOnEventOnKeyList);
2103     }
2104 iliev 2012 }
2105     // kill all voices on the (other) key
2106 schoenebeck 2879 for (NoteIterator itNote = pOtherKey->pActiveNotes->first(); itNote; ++itNote) {
2107     VoiceIterator itVoiceToBeKilled = itNote->pActiveVoices->first();
2108     VoiceIterator end = itNote->pActiveVoices->end();
2109     for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
2110     if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))
2111     itVoiceToBeKilled->Kill(itNoteOnEventOnKeyList);
2112     }
2113 iliev 2012 }
2114     }
2115     }
2116     // set this key as 'currently active solo key'
2117     pChannel->SoloKey = key;
2118     }
2119    
2120 schoenebeck 2938 if (isRealMIDINoteOnEvent) {
2121     pChannel->ProcessKeySwitchChange(key);
2122 iliev 2012
2123 schoenebeck 2938 pKey->KeyPressed = true; // the MIDI key was now pressed down
2124     pChannel->KeyDown[key] = true; // just used as built-in %KEY_DOWN script variable
2125     pKey->Velocity = itNoteOnEventOnKeyList->Param.Note.Velocity;
2126     pKey->NoteOnTime = FrameTime + itNoteOnEventOnKeyList->FragmentPos(); // will be used to calculate note length
2127     }
2128 iliev 2012
2129     // cancel release process of voices on this key if needed
2130 schoenebeck 2938 if (pKey->Active && !pChannel->SustainPedal && isRealMIDINoteOnEvent) {
2131 iliev 2012 RTList<Event>::Iterator itCancelReleaseEvent = pKey->pEvents->allocAppend();
2132     if (itCancelReleaseEvent) {
2133     *itCancelReleaseEvent = *itNoteOnEventOnKeyList; // copy event
2134 schoenebeck 2938 itCancelReleaseEvent->Type = Event::type_cancel_release_key; // transform event type
2135 iliev 2012 }
2136     else dmsg(1,("Event pool emtpy!\n"));
2137     }
2138    
2139     TriggerNewVoices(pEngineChannel, itNoteOnEventOnKeyList);
2140    
2141     // if neither a voice was spawned or postponed then remove note on event from key again
2142     if (!pKey->Active && !pKey->VoiceTheftsQueued)
2143     pKey->pEvents->free(itNoteOnEventOnKeyList);
2144    
2145 schoenebeck 2938 if (isRealMIDINoteOnEvent && (!pChannel->SoloMode || pChannel->PortamentoPos < 0.0f))
2146     pChannel->PortamentoPos = (float) key;
2147    
2148     //NOTE: Hmm, I guess its a matter of taste whether round robin should be advanced only on real MIDI note-on events, isn't it?
2149 persson 2043 if (pKey->pRoundRobinIndex) {
2150     (*pKey->pRoundRobinIndex)++; // counter specific for the key or region
2151     pChannel->RoundRobinIndex++; // common counter for the channel
2152     }
2153 schoenebeck 2938
2154     if (isRealMIDINoteOnEvent)
2155     pChannel->listeners.PostProcessNoteOn(key, vel);
2156 iliev 2012 }
2157    
2158     /**
2159     * Allocate and trigger new voice(s) for the key.
2160     */
2161     virtual void TriggerNewVoices (
2162     EngineChannel* pEngineChannel,
2163     RTList<Event>::Iterator& itNoteOnEvent,
2164     bool HandleKeyGroupConflicts = true
2165     ) = 0;
2166    
2167     /**
2168     * Allocate and trigger release voice(s) for the key.
2169     */
2170     virtual void TriggerReleaseVoices (
2171     EngineChannel* pEngineChannel,
2172     RTList<Event>::Iterator& itNoteOffEvent
2173     ) = 0;
2174    
2175     /**
2176     * Releases the voices on the given key if sustain pedal is not pressed.
2177     * If sustain is pressed, the release of the note will be postponed until
2178     * sustain pedal will be released or voice turned inactive by itself (e.g.
2179     * due to completion of sample playback).
2180     *
2181 schoenebeck 2871 * @param pEngineChannel - engine channel on which this event occurred on
2182 iliev 2012 * @param itNoteOffEvent - key, velocity and time stamp of the event
2183     */
2184 schoenebeck 3054 virtual void ProcessNoteOff(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOffEvent) OVERRIDE {
2185 iliev 2012 EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
2186    
2187 schoenebeck 2879 const int iKey = itNoteOffEvent->Param.Note.Key;
2188     const int vel = itNoteOffEvent->Param.Note.Velocity;
2189     if (iKey < 0 || iKey > 127) return; // ignore event, key outside allowed key range
2190 iliev 2012
2191     MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];
2192    
2193 schoenebeck 2938 // There are real MIDI note-off events (Event::type_note_off) and
2194     // programmatically spawned notes (Event::type_stop_note). We have
2195     // to distinguish between them, since certain processing below
2196     // must only be done on real MIDI note-off events (i.e. for
2197     // correctly updating which MIDI keys are currently pressed down),
2198     // plus a stop-note event just releases voices of one particular
2199     // note, whereas a note-off event releases all voices on a
2200     // particular MIDI key instead.
2201     const bool isRealMIDINoteOffEvent = itNoteOffEvent->Type == Event::type_note_off;
2202 iliev 2012
2203 schoenebeck 2938 if (isRealMIDINoteOffEvent)
2204     pChannel->listeners.PreProcessNoteOff(iKey, vel);
2205    
2206 iliev 2012 #if !CONFIG_PROCESS_MUTED_CHANNELS
2207     if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
2208 schoenebeck 2938 if (isRealMIDINoteOffEvent)
2209     pChannel->listeners.PostProcessNoteOff(iKey, vel);
2210 iliev 2012 return;
2211     }
2212     #endif
2213    
2214 schoenebeck 2938 if (isRealMIDINoteOffEvent) {
2215     pKey->KeyPressed = false; // the MIDI key was now released
2216     pChannel->KeyDown[iKey] = false; // just used as built-in %KEY_DOWN script variable
2217     }
2218 iliev 2012
2219     // move event to the key's own event list
2220     RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);
2221    
2222 schoenebeck 2938 if (isRealMIDINoteOffEvent) {
2223     bool bShouldRelease = pKey->Active && pChannel->ShouldReleaseVoice(itNoteOffEventOnKeyList->Param.Note.Key);
2224 iliev 2012
2225 schoenebeck 2938 // in case Solo Mode is enabled, kill all voices on this key and respawn a voice on the highest pressed key (if any)
2226     if (pChannel->SoloMode && pChannel->pInstrument) { //TODO: this feels like too much code just for handling solo mode :P
2227     bool bOtherKeysPressed = false;
2228     if (iKey == pChannel->SoloKey) {
2229     pChannel->SoloKey = -1;
2230     // if there's still a key pressed down, respawn a voice (group) on the highest key
2231     for (int i = 127; i > 0; i--) {
2232     MidiKey* pOtherKey = &pChannel->pMIDIKeyInfo[i];
2233     if (pOtherKey->KeyPressed) {
2234     bOtherKeysPressed = true;
2235     // make the other key the new 'currently active solo key'
2236     pChannel->SoloKey = i;
2237     // get final portamento position of currently active voice
2238     if (pChannel->PortamentoMode) {
2239     NoteIterator itNote = pKey->pActiveNotes->first();
2240     VoiceIterator itVoice = itNote->pActiveVoices->first();
2241     if (itVoice) itVoice->UpdatePortamentoPos(itNoteOffEventOnKeyList);
2242 schoenebeck 2879 }
2243 schoenebeck 2938 // create a pseudo note on event
2244     RTList<Event>::Iterator itPseudoNoteOnEvent = pOtherKey->pEvents->allocAppend();
2245     if (itPseudoNoteOnEvent) {
2246     // copy event
2247     *itPseudoNoteOnEvent = *itNoteOffEventOnKeyList;
2248     // transform event to a note on event
2249     itPseudoNoteOnEvent->Type = Event::type_note_on; //FIXME: should probably use Event::type_play_note instead (to avoid i.e. hanging notes)
2250     itPseudoNoteOnEvent->Param.Note.Key = i;
2251     itPseudoNoteOnEvent->Param.Note.Velocity = pOtherKey->Velocity;
2252     // assign a new note to this note-on event
2253 schoenebeck 3205 if (LaunchNewNote(pChannel, itPseudoNoteOnEvent)) {
2254 schoenebeck 2938 // allocate and trigger new voice(s) for the other key
2255     TriggerNewVoices(pChannel, itPseudoNoteOnEvent, false);
2256     }
2257     // if neither a voice was spawned or postponed then remove note on event from key again
2258     if (!pOtherKey->Active && !pOtherKey->VoiceTheftsQueued)
2259     pOtherKey->pEvents->free(itPseudoNoteOnEvent);
2260 iliev 2012
2261 schoenebeck 2938 } else dmsg(1,("Could not respawn voice, no free event left\n"));
2262     break; // done
2263     }
2264 iliev 2012 }
2265     }
2266 schoenebeck 2938 if (bOtherKeysPressed) {
2267     if (pKey->Active) { // kill all voices on this key
2268     bShouldRelease = false; // no need to release, as we kill it here
2269     for (NoteIterator itNote = pKey->pActiveNotes->first(); itNote; ++itNote) {
2270     VoiceIterator itVoiceToBeKilled = itNote->pActiveVoices->first();
2271     VoiceIterator end = itNote->pActiveVoices->end();
2272     for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
2273     if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))
2274     itVoiceToBeKilled->Kill(itNoteOffEventOnKeyList);
2275     }
2276 schoenebeck 2879 }
2277 iliev 2012 }
2278 schoenebeck 2938 } else pChannel->PortamentoPos = -1.0f;
2279     }
2280 iliev 2012
2281 schoenebeck 2938 // if no solo mode (the usual case) or if solo mode and no other key pressed, then release voices on this key if needed
2282     if (bShouldRelease) {
2283     itNoteOffEventOnKeyList->Type = Event::type_release_key; // transform event type
2284     // spawn release triggered voice(s) if needed
2285 schoenebeck 3444 if (pKey->ReleaseTrigger & release_trigger_noteoff)
2286     ProcessReleaseTrigger(pChannel, itNoteOffEventOnKeyList, pKey);
2287 schoenebeck 2938 }
2288     } else if (itNoteOffEventOnKeyList->Type == Event::type_stop_note) {
2289     // This programmatically caused event is caused by a call to
2290     // the built-in instrument script function note_off(). In
2291     // contrast to a real MIDI note-off event the stop-note
2292     // event just intends to release voices of one particular note.
2293     NoteBase* pNote = pChannel->pEngine->NoteByID( itNoteOffEventOnKeyList->Param.Note.ID );
2294     if (pNote) { // the requested note is still alive ...
2295     itNoteOffEventOnKeyList->Type = Event::type_release_note; // transform event type
2296     } else { // note is dead and gone ..
2297     pKey->pEvents->free(itNoteOffEventOnKeyList); // remove stop-note event from key again
2298     return; // prevent event to be removed a 2nd time below
2299     }
2300 iliev 2012 }
2301    
2302     // if neither a voice was spawned or postponed on this key then remove note off event from key again
2303     if (!pKey->Active && !pKey->VoiceTheftsQueued)
2304     pKey->pEvents->free(itNoteOffEventOnKeyList);
2305    
2306 schoenebeck 2938 if (isRealMIDINoteOffEvent)
2307     pChannel->listeners.PostProcessNoteOff(iKey, vel);
2308 iliev 2012 }
2309    
2310     /**
2311 schoenebeck 2927 * Called on sustain pedal up events to check and if required,
2312     * launch release trigger voices on the respective active key.
2313     *
2314     * @param pEngineChannel - engine channel on which this event occurred on
2315     * @param itEvent - release trigger event (contains note number)
2316     */
2317 schoenebeck 3444 virtual void ProcessReleaseTriggerBySustain(EngineChannel* pEngineChannel, RTList<Event>::Iterator& itEvent) OVERRIDE {
2318 schoenebeck 2927 EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
2319    
2320     const int iKey = itEvent->Param.Note.Key;
2321     if (iKey < 0 || iKey > 127) return; // ignore event, key outside allowed key range
2322    
2323     MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];
2324    
2325     ProcessReleaseTrigger(pChannel, itEvent, pKey);
2326     }
2327    
2328     /**
2329     * Called on note-off and sustain pedal up events to check and if
2330     * required, launch release trigger voices on the respective active
2331     * key.
2332     *
2333     * @param pEngineChannel - engine channel on which this event occurred on
2334     * @param itEvent - note off event / release trigger event
2335     * @param pKey - key on which the release trigger voices shall be spawned
2336     */
2337     inline void ProcessReleaseTrigger(EngineChannelBase<V, R, I>* pChannel, RTList<Event>::Iterator& itEvent, MidiKey* pKey) {
2338     // spawn release triggered voice(s) if needed
2339     if (pKey->ReleaseTrigger && pChannel->pInstrument) {
2340     // assign a new note to this release event
2341 schoenebeck 3205 if (LaunchNewNote(pChannel, itEvent)) {
2342 schoenebeck 2927 // allocate and trigger new release voice(s)
2343     TriggerReleaseVoices(pChannel, itEvent);
2344     }
2345 schoenebeck 3444 pKey->ReleaseTrigger = release_trigger_none;
2346 schoenebeck 2927 }
2347     }
2348    
2349     /**
2350 schoenebeck 3188 * Called on "kill note" events, which currently only happens on
2351     * built-in real-time instrument script function fade_out(). This
2352     * method only fulfills one task: moving the even to the Note's own
2353     * event list so that its voices can process the kill event sample
2354     * accurately.
2355     */
2356     void ProcessKillNote(EngineChannel* pEngineChannel, RTList<Event>::Iterator& itEvent) {
2357     EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
2358    
2359     NoteBase* pNote = pChannel->pEngine->NoteByID( itEvent->Param.Note.ID );
2360     if (!pNote || pNote->hostKey < 0 || pNote->hostKey >= 128) return;
2361    
2362     // move note kill event to its MIDI key
2363     MidiKey* pKey = &pChannel->pMIDIKeyInfo[pNote->hostKey];
2364     itEvent.moveToEndOf(pKey->pEvents);
2365     }
2366    
2367     /**
2368 schoenebeck 2931 * Called on note synthesis parameter change events. These are
2369     * internal events caused by calling built-in real-time instrument
2370 schoenebeck 3188 * script functions like change_vol(), change_tune(), etc.
2371 schoenebeck 2931 *
2372     * This method performs two tasks:
2373     *
2374     * - It converts the event's relative values changes (Deltas) to
2375     * the respective final new synthesis parameter value (AbsValue),
2376     * for that particular moment of the event that is.
2377     *
2378     * - It moves the individual events to the Note's own event list
2379     * (or actually to the event list of the MIDI key), so that
2380     * voices can process those events sample accurately.
2381     *
2382     * @param pEngineChannel - engine channel on which this event occurred on
2383     * @param itEvent - note synthesis parameter change event
2384     */
2385 persson 2952 virtual void ProcessNoteSynthParam(EngineChannel* pEngineChannel, RTList<Event>::Iterator& itEvent) {
2386 schoenebeck 2931 EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
2387    
2388     NoteBase* pNote = pChannel->pEngine->NoteByID( itEvent->Param.NoteSynthParam.NoteID );
2389     if (!pNote || pNote->hostKey < 0 || pNote->hostKey >= 128) return;
2390    
2391     switch (itEvent->Param.NoteSynthParam.Type) {
2392     case Event::synth_param_volume:
2393 schoenebeck 3561 pNote->apply(itEvent, &NoteBase::_Override::Volume);
2394 schoenebeck 2931 break;
2395 schoenebeck 3188 case Event::synth_param_volume_time:
2396     pNote->Override.VolumeTime = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2397     break;
2398 schoenebeck 3246 case Event::synth_param_volume_curve:
2399     itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2400     pNote->Override.VolumeCurve = (fade_curve_t) itEvent->Param.NoteSynthParam.AbsValue;
2401     break;
2402 schoenebeck 2931 case Event::synth_param_pitch:
2403 schoenebeck 3561 pNote->apply(itEvent, &NoteBase::_Override::Pitch);
2404 schoenebeck 2931 break;
2405 schoenebeck 3188 case Event::synth_param_pitch_time:
2406     pNote->Override.PitchTime = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2407     break;
2408 schoenebeck 3246 case Event::synth_param_pitch_curve:
2409     itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2410     pNote->Override.PitchCurve = (fade_curve_t) itEvent->Param.NoteSynthParam.AbsValue;
2411     break;
2412 schoenebeck 2931 case Event::synth_param_pan:
2413 schoenebeck 3561 pNote->apply(itEvent, &NoteBase::_Override::Pan);
2414 schoenebeck 2931 break;
2415 schoenebeck 3335 case Event::synth_param_pan_time:
2416     pNote->Override.PanTime = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2417     break;
2418     case Event::synth_param_pan_curve:
2419     itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2420     pNote->Override.PanCurve = (fade_curve_t) itEvent->Param.NoteSynthParam.AbsValue;
2421     break;
2422 schoenebeck 2935 case Event::synth_param_cutoff:
2423 schoenebeck 3561 pNote->apply(itEvent, &NoteBase::_Override::Cutoff);
2424 schoenebeck 2935 break;
2425     case Event::synth_param_resonance:
2426 schoenebeck 3561 pNote->apply(itEvent, &NoteBase::_Override::Resonance);
2427 schoenebeck 2935 break;
2428 schoenebeck 2953 case Event::synth_param_attack:
2429 schoenebeck 3561 pNote->apply(itEvent, &NoteBase::_Override::Attack);
2430 schoenebeck 2953 break;
2431     case Event::synth_param_decay:
2432 schoenebeck 3561 pNote->apply(itEvent, &NoteBase::_Override::Decay);
2433 schoenebeck 2953 break;
2434 schoenebeck 3316 case Event::synth_param_sustain:
2435 schoenebeck 3561 pNote->apply(itEvent, &NoteBase::_Override::Sustain);
2436 schoenebeck 3316 break;
2437 schoenebeck 2953 case Event::synth_param_release:
2438 schoenebeck 3561 pNote->apply(itEvent, &NoteBase::_Override::Release);
2439 schoenebeck 2953 break;
2440 schoenebeck 3360
2441     case Event::synth_param_cutoff_attack:
2442 schoenebeck 3561 pNote->apply(itEvent, &NoteBase::_Override::CutoffAttack);
2443 schoenebeck 3360 break;
2444     case Event::synth_param_cutoff_decay:
2445 schoenebeck 3561 pNote->apply(itEvent, &NoteBase::_Override::CutoffDecay);
2446 schoenebeck 3360 break;
2447     case Event::synth_param_cutoff_sustain:
2448 schoenebeck 3561 pNote->apply(itEvent, &NoteBase::_Override::CutoffSustain);
2449 schoenebeck 3360 break;
2450     case Event::synth_param_cutoff_release:
2451 schoenebeck 3561 pNote->apply(itEvent, &NoteBase::_Override::CutoffRelease);
2452 schoenebeck 3360 break;
2453    
2454 schoenebeck 3118 case Event::synth_param_amp_lfo_depth:
2455 schoenebeck 3561 pNote->apply(itEvent, &NoteBase::_Override::AmpLFODepth);
2456 schoenebeck 3118 break;
2457     case Event::synth_param_amp_lfo_freq:
2458 schoenebeck 3561 pNote->apply(itEvent, &NoteBase::_Override::AmpLFOFreq);
2459 schoenebeck 3118 break;
2460 schoenebeck 3360 case Event::synth_param_cutoff_lfo_depth:
2461 schoenebeck 3561 pNote->apply(itEvent, &NoteBase::_Override::CutoffLFODepth);
2462 schoenebeck 3360 break;
2463     case Event::synth_param_cutoff_lfo_freq:
2464 schoenebeck 3561 pNote->apply(itEvent, &NoteBase::_Override::CutoffLFOFreq);
2465 schoenebeck 3360 break;
2466 schoenebeck 3118 case Event::synth_param_pitch_lfo_depth:
2467 schoenebeck 3561 pNote->apply(itEvent, &NoteBase::_Override::PitchLFODepth);
2468 schoenebeck 3118 break;
2469     case Event::synth_param_pitch_lfo_freq:
2470 schoenebeck 3561 pNote->apply(itEvent, &NoteBase::_Override::PitchLFOFreq);
2471 schoenebeck 3118 break;
2472 schoenebeck 2931 }
2473    
2474     // move note parameter event to its MIDI key
2475     MidiKey* pKey = &pChannel->pMIDIKeyInfo[pNote->hostKey];
2476     itEvent.moveToEndOf(pKey->pEvents);
2477     }
2478    
2479     /**
2480 iliev 2012 * Reset all voices and disk thread and clear input event queue and all
2481     * control and status variables. This method is protected by a mutex.
2482     */
2483 schoenebeck 3054 virtual void ResetInternal() OVERRIDE {
2484 persson 2427 LockGuard lock(ResetInternalMutex);
2485 iliev 2012
2486     // make sure that the engine does not get any sysex messages
2487     // while it's reseting
2488     bool sysexDisabled = MidiInputPort::RemoveSysexListener(this);
2489     SetVoiceCount(0);
2490     ActiveVoiceCountMax = 0;
2491    
2492     // reset voice stealing parameters
2493     pVoiceStealingQueue->clear();
2494     itLastStolenVoice = VoiceIterator();
2495     itLastStolenVoiceGlobally = VoiceIterator();
2496 schoenebeck 2879 itLastStolenNote = NoteIterator();
2497     itLastStolenNoteGlobally = NoteIterator();
2498 iliev 2012 iuiLastStolenKey = RTList<uint>::Iterator();
2499     iuiLastStolenKeyGlobally = RTList<uint>::Iterator();
2500     pLastStolenChannel = NULL;
2501    
2502 schoenebeck 2879 // reset all notes
2503     pNotePool->clear();
2504     for (NoteIterator itNote = pNotePool->allocAppend(); itNote;
2505     itNote = pNotePool->allocAppend())
2506     {
2507     itNote->reset();
2508     }
2509     pNotePool->clear();
2510    
2511 iliev 2012 // reset all voices
2512 schoenebeck 2879 pVoicePool->clear();
2513 iliev 2012 for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
2514     iterVoice->Reset();
2515     }
2516     pVoicePool->clear();
2517    
2518 schoenebeck 2871 // reset all engine channels
2519     for (int i = 0; i < engineChannels.size(); i++) {
2520     AbstractEngineChannel* pEngineChannel =
2521     static_cast<AbstractEngineChannel*>(engineChannels[i]);
2522     pEngineChannel->ResetInternal(false/*don't reset engine*/);
2523     }
2524    
2525 iliev 2012 // reset disk thread
2526     if (pDiskThread) pDiskThread->Reset();
2527    
2528     // delete all input events
2529     pEventQueue->init();
2530     pSysexBuffer->init();
2531     if (sysexDisabled) MidiInputPort::AddSysexListener(this);
2532     }
2533    
2534     /**
2535     * Kills all voices on an engine channel as soon as possible. Voices
2536     * won't get into release state, their volume level will be ramped down
2537     * as fast as possible.
2538     *
2539     * @param pEngineChannel - engine channel on which all voices should be killed
2540     * @param itKillEvent - event which caused this killing of all voices
2541     */
2542 schoenebeck 3054 virtual void KillAllVoices(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itKillEvent) OVERRIDE {
2543 iliev 2012 EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
2544     int count = pChannel->KillAllVoices(itKillEvent);
2545     VoiceSpawnsLeft -= count; //FIXME: just a temporary workaround, we should check the cause in StealVoice() instead
2546     }
2547    
2548     /**
2549     * Allocates and triggers a new voice. This method will usually be
2550     * called by the ProcessNoteOn() method and by the voices itself
2551     * (e.g. to spawn further voices on the same key for layered sounds).
2552     *
2553 schoenebeck 2871 * @param pEngineChannel - engine channel on which this event occurred on
2554 iliev 2012 * @param itNoteOnEvent - key, velocity and time stamp of the event
2555     * @param iLayer - layer index for the new voice (optional - only
2556     * in case of layered sounds of course)
2557     * @param ReleaseTriggerVoice - if new voice is a release triggered voice
2558     * (optional, default = false)
2559     * @param VoiceStealing - if voice stealing should be performed
2560     * when there is no free voice
2561     * (optional, default = true)
2562     * @param HandleKeyGroupConflicts - if voices should be killed due to a
2563     * key group conflict
2564     * @returns pointer to new voice or NULL if there was no free voice or
2565     * if the voice wasn't triggered (for example when no region is
2566     * defined for the given key).
2567     */
2568     virtual PoolVoiceIterator LaunchVoice (
2569     EngineChannel* pEngineChannel,
2570     Pool<Event>::Iterator& itNoteOnEvent,
2571     int iLayer,
2572     bool ReleaseTriggerVoice,
2573     bool VoiceStealing,
2574     bool HandleKeyGroupConflicts
2575     ) = 0;
2576    
2577 schoenebeck 3054 virtual int GetMinFadeOutSamples() OVERRIDE { return MinFadeOutSamples; }
2578 iliev 2015
2579 iliev 2027 int InitNewVoice (
2580     EngineChannelBase<V, R, I>* pChannel,
2581     R* pRegion,
2582     Pool<Event>::Iterator& itNoteOnEvent,
2583     Voice::type_t VoiceType,
2584     int iLayer,
2585     int iKeyGroup,
2586     bool ReleaseTriggerVoice,
2587     bool VoiceStealing,
2588     typename Pool<V>::Iterator& itNewVoice
2589     ) {
2590     int key = itNoteOnEvent->Param.Note.Key;
2591     typename MidiKeyboardManager<V>::MidiKey* pKey = &pChannel->pMIDIKeyInfo[key];
2592     if (itNewVoice) {
2593     // launch the new voice
2594     if (itNewVoice->Trigger(pChannel, itNoteOnEvent, pChannel->Pitch, pRegion, VoiceType, iKeyGroup) < 0) {
2595     dmsg(4,("Voice not triggered\n"));
2596 schoenebeck 2879 GetVoicePool()->free(itNewVoice);
2597 iliev 2027 }
2598     else { // on success
2599     --VoiceSpawnsLeft;
2600 schoenebeck 3306
2601     // should actually be superfluous now, since this is
2602     // already done in LaunchNewNote()
2603     pChannel->markKeyAsActive(pKey);
2604    
2605 schoenebeck 3444 if (itNewVoice->Type & Voice::type_release_trigger_required)
2606     pKey->ReleaseTrigger |= itNewVoice->GetReleaseTriggerFlags(); // mark key for the need of release triggered voice(s)
2607 iliev 2027 return 0; // success
2608     }
2609     }
2610     else if (VoiceStealing) {
2611     // try to steal one voice
2612     int result = StealVoice(pChannel, itNoteOnEvent);
2613     if (!result) { // voice stolen successfully
2614     // put note-on event into voice-stealing queue, so it will be reprocessed after killed voice died
2615     RTList<Event>::Iterator itStealEvent = pVoiceStealingQueue->allocAppend();
2616     if (itStealEvent) {
2617     *itStealEvent = *itNoteOnEvent; // copy event
2618     itStealEvent->Param.Note.Layer = iLayer;
2619     itStealEvent->Param.Note.ReleaseTrigger = ReleaseTriggerVoice;
2620     pKey->VoiceTheftsQueued++;
2621     }
2622     else dmsg(1,("Voice stealing queue full!\n"));
2623     }
2624     }
2625    
2626     return -1;
2627     }
2628 schoenebeck 2448
2629     /**
2630     * Checks whether scale tuning setting has been changed since last
2631     * time this method was called, if yes, it recalculates the pitch
2632     * for all active voices.
2633     */
2634     void ProcessScaleTuningChange() {
2635     const bool changed = ScaleTuningChanged.readAndReset();
2636     if (!changed) return;
2637    
2638     for (int i = 0; i < engineChannels.size(); i++) {
2639     EngineChannelBase<V, R, I>* channel =
2640     static_cast<EngineChannelBase<V, R, I>*>(engineChannels[i]);
2641     channel->OnScaleTuningChanged();
2642     }
2643     }
2644 iliev 2027
2645 iliev 2012 private:
2646 schoenebeck 2879 Pool< Note<V> >* pNotePool;
2647     Pool<note_id_t> noteIDPool;
2648 iliev 2012 Pool<V>* pVoicePool; ///< Contains all voices that can be activated.
2649     Pool<RR*> SuspendedRegions;
2650     Mutex SuspendedRegionsMutex;
2651     Condition SuspensionChangeOngoing;
2652     RR* pPendingRegionSuspension;
2653     RR* pPendingRegionResumption;
2654     int iPendingStreamDeletions;
2655     };
2656    
2657     template <class V, class RR, class R, class D, class IM, class I>
2658     IM EngineBase<V, RR, R, D, IM, I>::instruments;
2659    
2660     } // namespace LinuxSampler
2661    
2662     #endif /* __LS_ENGINEBASE_H__ */
2663    

  ViewVC Help
Powered by ViewVC