/[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 3697 - (hide annotations) (download) (as text)
Sat Jan 4 12:09:45 2020 UTC (4 years, 2 months ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 138320 byte(s)
Implemented support for compressed RPN/NRPN message sequences:

* Allow processing MIDI data entry messages without having to be
  preceded strictly always by RPN/NRPN parameter selection messages
  prior to each value change (i.e. data entry CC).

* Bumped version (2.1.1.svn33).

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

  ViewVC Help
Powered by ViewVC