/[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 3818 - (hide annotations) (download) (as text)
Sat Aug 29 16:37:35 2020 UTC (3 years, 9 months ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 148897 byte(s)
* NKSP VM: Fixed the "release" handler being executed too often under
  certain situations if polyphonic data was passed from "note" handler to
  "release" handler.

* Bumped version (2.1.1.svn64).

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

  ViewVC Help
Powered by ViewVC