/[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 3690 - (hide annotations) (download) (as text)
Fri Jan 3 10:18:21 2020 UTC (4 years, 2 months ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 136972 byte(s)
NKSP: Added support for RPN and NRPN event handlers:

* NKSP language: Added support for RPN event handler
  ("on rpn ... end on" in instrument scripts).

* NKSP language: Added support for NRPN event handler
  ("on nrpn ... end on" in instrument scripts).

* Added built-in read-only variables "$RPN_ADDRESS" and "$RPN_VALUE" which
  may be read from the new RPN/NRPN script handlers to get the (N)RPN
  parameter that had been changed and its new value.

* Added built-in const variables "$NI_CB_TYPE_RPN" and "$NI_CB_TYPE_NRPN"
  which are identifying the new (N)RPN handlers as such at script runtime.

* Bumped version (2.1.1.svn30).

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     switch (itEvent->Type) {
889     case Event::type_note_on:
890     dmsg(5,("Engine: Note on received\n"));
891     ProcessNoteOn((EngineChannel*)itEvent->pEngineChannel, itEvent);
892     break;
893 schoenebeck 2938 case Event::type_play_note:
894     dmsg(5,("Engine: Play Note received\n"));
895     ProcessNoteOn((EngineChannel*)itEvent->pEngineChannel, itEvent);
896     break;
897 iliev 2012 case Event::type_note_off:
898     dmsg(5,("Engine: Note off received\n"));
899     ProcessNoteOff((EngineChannel*)itEvent->pEngineChannel, itEvent);
900     break;
901 schoenebeck 2938 case Event::type_stop_note:
902     dmsg(5,("Engine: Stop Note received\n"));
903     ProcessNoteOff((EngineChannel*)itEvent->pEngineChannel, itEvent);
904     break;
905 schoenebeck 3188 case Event::type_kill_note:
906     dmsg(5,("Engine: Kill Note received\n"));
907     ProcessKillNote((EngineChannel*)itEvent->pEngineChannel, itEvent);
908     break;
909 iliev 2012 case Event::type_control_change:
910     dmsg(5,("Engine: MIDI CC received\n"));
911     ProcessControlChange((EngineChannel*)itEvent->pEngineChannel, itEvent);
912     break;
913 schoenebeck 2559 case Event::type_channel_pressure:
914     dmsg(5,("Engine: MIDI Chan. Pressure received\n"));
915     ProcessChannelPressure((EngineChannel*)itEvent->pEngineChannel, itEvent);
916     break;
917     case Event::type_note_pressure:
918     dmsg(5,("Engine: MIDI Note Pressure received\n"));
919     ProcessPolyphonicKeyPressure((EngineChannel*)itEvent->pEngineChannel, itEvent);
920     break;
921 iliev 2012 case Event::type_pitchbend:
922     dmsg(5,("Engine: Pitchbend received\n"));
923     ProcessPitchbend(static_cast<AbstractEngineChannel*>(itEvent->pEngineChannel), itEvent);
924     break;
925 schoenebeck 2931 case Event::type_note_synth_param:
926     dmsg(5,("Engine: Note Synth Param received\n"));
927     ProcessNoteSynthParam(itEvent->pEngineChannel, itEvent);
928     break;
929 schoenebeck 3034 case Event::type_sysex:
930     break; // TODO ...
931    
932     case Event::type_cancel_release_key:
933     case Event::type_release_key:
934     case Event::type_release_note:
935     break; // noop
936 iliev 2012 }
937     }
938     }
939    
940     // reset voice stealing for the next engine channel (or next audio fragment)
941     itLastStolenVoice = VoiceIterator();
942     itLastStolenVoiceGlobally = VoiceIterator();
943 schoenebeck 2879 itLastStolenNote = NoteIterator();
944     itLastStolenNoteGlobally = NoteIterator();
945 iliev 2012 iuiLastStolenKey = RTList<uint>::Iterator();
946     iuiLastStolenKeyGlobally = RTList<uint>::Iterator();
947     pLastStolenChannel = NULL;
948     }
949    
950 schoenebeck 2871 /**
951     * Run all suspended script execution instances which are scheduled
952     * to be resumed for the current audio fragment cycle.
953     *
954     * @param pChannel - engine channel on which suspended events occurred
955     */
956     void ProcessSuspendedScriptEvents(AbstractEngineChannel* pChannel, const sched_time_t fragmentEndTime) {
957     while (true) {
958     RTList<ScriptEvent>::Iterator itEvent =
959     pEventGenerator->popNextScheduledScriptEvent(
960     pChannel->pScript->suspendedEvents,
961     *pChannel->pScript->pEvents, fragmentEndTime
962     );
963     if (!itEvent) break;
964     ResumeScriptEvent(pChannel, itEvent);
965     }
966     }
967    
968 schoenebeck 2594 /** @brief Call instrument script's event handler for this event.
969     *
970     * Causes a new execution instance of the currently loaded real-time
971     * instrument script's event handler (callback) to be spawned for
972     * the given MIDI event.
973     *
974 schoenebeck 2871 * @param pChannel - engine channel on which the MIDI event occurred
975 schoenebeck 2594 * @param itEvent - MIDI event that causes this new script execution
976     * @param pEventHandler - script's event handler to be executed
977     */
978     void ProcessEventByScript(AbstractEngineChannel* pChannel, RTList<Event>::Iterator& itEvent, VMEventHandler* pEventHandler) {
979 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
980     // check if polyphonic data is passed from "note" to "release"
981     // script event handlers
982     if (pEventHandler == pChannel->pScript->handlerRelease &&
983     pChannel->pScript->handlerNote &&
984     pChannel->pScript->handlerNote->isPolyphonic() &&
985     pChannel->pScript->handlerRelease->isPolyphonic() &&
986     !pChannel->pScript->pKeyEvents[key]->isEmpty())
987     {
988     // polyphonic variable data is used/passed from "note" to
989     // "release" script callback, so we have to recycle the
990     // original "note on" script event(s)
991     RTList<ScriptEvent>::Iterator it = pChannel->pScript->pKeyEvents[key]->first();
992     RTList<ScriptEvent>::Iterator end = pChannel->pScript->pKeyEvents[key]->end();
993     for (; it != end; ++it) {
994     ProcessScriptEvent(
995     pChannel, itEvent, pEventHandler, it
996     );
997     }
998     } else {
999     // no polyphonic data is used/passed from "note" to
1000     // "release" script callback, so just use a new fresh
1001     // script event object
1002     RTList<ScriptEvent>::Iterator itScriptEvent =
1003     pChannel->pScript->pEvents->allocAppend();
1004 schoenebeck 3207 // if event handler uses polyphonic variables, reset them
1005     // to zero values before starting to execute the handler
1006     if (pEventHandler->isPolyphonic())
1007     itScriptEvent->execCtx->resetPolyphonicData();
1008 schoenebeck 2645 ProcessScriptEvent(
1009     pChannel, itEvent, pEventHandler, itScriptEvent
1010     );
1011     }
1012     }
1013 schoenebeck 2594
1014 schoenebeck 2871 /** @brief Spawn new execution instance of an instrument script handler.
1015     *
1016     * Will be called to initiate a new execution of a real-time
1017     * instrument script event right from the start of the script's
1018     * respective handler. If script execution did not complete after
1019     * calling this method, the respective script exeuction is then
1020     * suspended and a call to ResumeScriptEvent() will be used next
1021     * time to continue its execution.
1022     *
1023     * @param pChannel - engine channel this script is running for
1024     * @param itEvent - event which caused execution of this script
1025     * event handler
1026     * @param pEventHandler - VM representation of event handler to be
1027     * executed
1028     * @param itScriptEvent - script event that shall be processed
1029     */
1030 schoenebeck 2645 void ProcessScriptEvent(AbstractEngineChannel* pChannel, RTList<Event>::Iterator& itEvent, VMEventHandler* pEventHandler, RTList<ScriptEvent>::Iterator& itScriptEvent) {
1031     if (!itScriptEvent) return; // not a valid script event (i.e. because no free script event was left in the script event pool)
1032 schoenebeck 2594
1033     // fill the list of script handlers to be executed by this event
1034     int i = 0;
1035     itScriptEvent->handlers[i++] = pEventHandler; // actual event handler (i.e. note, controller)
1036     itScriptEvent->handlers[i] = NULL; // NULL termination of list
1037    
1038     // initialize/reset other members
1039     itScriptEvent->cause = *itEvent;
1040 schoenebeck 3205 itScriptEvent->scheduleTime = itEvent->SchedTime();
1041 schoenebeck 2594 itScriptEvent->currentHandler = 0;
1042     itScriptEvent->executionSlices = 0;
1043 schoenebeck 2948 itScriptEvent->ignoreAllWaitCalls = false;
1044     itScriptEvent->handlerType = pEventHandler->eventHandlerType();
1045 schoenebeck 3293 itScriptEvent->parentHandlerID = 0;
1046     itScriptEvent->childHandlerID[0] = 0;
1047     itScriptEvent->autoAbortByParent = false;
1048     itScriptEvent->forkIndex = 0;
1049 schoenebeck 2879 // this is the native representation of the $EVENT_ID script variable
1050     itScriptEvent->id =
1051     (itEvent->Type == Event::type_note_on)
1052     ? ScriptID::fromNoteID( itEvent->Param.Note.ID )
1053     : ScriptID::fromEventID( pEventPool->getID(itEvent) );
1054 schoenebeck 2594
1055     // run script handler(s)
1056     VMExecStatus_t res = pScriptVM->exec(
1057 schoenebeck 2611 pChannel->pScript->parserContext, &*itScriptEvent
1058 schoenebeck 2594 );
1059    
1060 schoenebeck 2871 // was the script suspended?
1061     if (res & VM_EXEC_SUSPENDED) { // script was suspended ...
1062     // in case the script was suspended, keep it on the allocated
1063     // ScriptEvent list to be resume at the scheduled time in future,
1064     // additionally insert it into a sorted time queue
1065     pEventGenerator->scheduleAheadMicroSec(
1066     pChannel->pScript->suspendedEvents, // scheduler queue
1067     *itScriptEvent, // script event
1068     itScriptEvent->cause.FragmentPos(), // current time of script event (basis for its next execution)
1069     itScriptEvent->execCtx->suspensionTimeMicroseconds() // how long shall it be suspended
1070     );
1071     } else { // script execution has finished without 'suspended' status ...
1072 schoenebeck 2645 // if "polyphonic" variable data is passed from script's
1073     // "note" event handler to its "release" event handler, then
1074     // the script event must be kept and recycled for the later
1075     // occuring "release" script event ...
1076     if (pEventHandler == pChannel->pScript->handlerNote &&
1077     pChannel->pScript->handlerRelease &&
1078     pChannel->pScript->handlerNote->isPolyphonic() &&
1079     pChannel->pScript->handlerRelease->isPolyphonic())
1080     {
1081     const int key = itEvent->Param.Note.Key;
1082     itScriptEvent.moveToEndOf(pChannel->pScript->pKeyEvents[key & 127]);
1083     } else {
1084     // ... otherwise if no polyphonic data is passed and
1085     // script's execution has finished without suspension
1086     // status, then free the script event for a new future
1087     // script event to be triggered from start
1088     pChannel->pScript->pEvents->free(itScriptEvent);
1089     }
1090     }
1091 schoenebeck 2594 }
1092    
1093     /** @brief Resume execution of instrument script.
1094     *
1095     * Will be called to resume execution of a real-time instrument
1096 schoenebeck 2879 * script event which has been suspended previously.
1097 schoenebeck 2594 *
1098     * Script execution might be suspended for various reasons. Usually
1099     * a script will be suspended if the script called the built-in
1100     * "wait()" function, but it might also be suspended automatically
1101     * if the script took too much execution time in an audio fragment
1102     * cycle. So in the latter case automatic suspension is performed in
1103     * order to avoid harm for the sampler's overall real-time
1104     * requirements.
1105     *
1106     * @param pChannel - engine channel this script is running for
1107     * @param itScriptEvent - script execution that shall be resumed
1108     */
1109     void ResumeScriptEvent(AbstractEngineChannel* pChannel, RTList<ScriptEvent>::Iterator& itScriptEvent) {
1110 schoenebeck 2645 VMEventHandler* handler = itScriptEvent->handlers[itScriptEvent->currentHandler];
1111    
1112 schoenebeck 2594 // run script
1113     VMExecStatus_t res = pScriptVM->exec(
1114 schoenebeck 2611 pChannel->pScript->parserContext, &*itScriptEvent
1115 schoenebeck 2594 );
1116 schoenebeck 2645
1117 schoenebeck 2871 // was the script suspended?
1118     if (res & VM_EXEC_SUSPENDED) {
1119     // in case the script was suspended, keep it on the allocated
1120     // ScriptEvent list to be resume at the scheduled time in future,
1121     // additionally insert it into a sorted time queue
1122     pEventGenerator->scheduleAheadMicroSec(
1123     pChannel->pScript->suspendedEvents, // scheduler queue
1124     *itScriptEvent, // script event
1125     itScriptEvent->cause.FragmentPos(), // current time of script event (basis for its next execution)
1126     itScriptEvent->execCtx->suspensionTimeMicroseconds() // how long shall it be suspended
1127     );
1128     } else { // script execution has finished without 'suspended' status ...
1129 schoenebeck 2645 // if "polyphonic" variable data is passed from script's
1130     // "note" event handler to its "release" event handler, then
1131     // the script event must be kept and recycled for the later
1132     // occuring "release" script event ...
1133     if (handler && handler == pChannel->pScript->handlerNote &&
1134     pChannel->pScript->handlerRelease &&
1135     pChannel->pScript->handlerNote->isPolyphonic() &&
1136     pChannel->pScript->handlerRelease->isPolyphonic())
1137     {
1138     const int key = itScriptEvent->cause.Param.Note.Key;
1139     itScriptEvent.moveToEndOf(pChannel->pScript->pKeyEvents[key & 127]);
1140     } else {
1141     // ... otherwise if no polyphonic data is passed and
1142     // script's execution has finished without suspension
1143     // status, then free the script event for a new future
1144     // script event to be triggered from start
1145     pChannel->pScript->pEvents->free(itScriptEvent);
1146     }
1147     }
1148 schoenebeck 2594 }
1149    
1150 iliev 2012 /**
1151     * Will be called by LaunchVoice() method in case there are no free
1152     * voices left. This method will select and kill one old voice for
1153     * voice stealing and postpone the note-on event until the selected
1154     * voice actually died.
1155     *
1156 schoenebeck 2871 * @param pEngineChannel - engine channel on which this event occurred on
1157 iliev 2012 * @param itNoteOnEvent - key, velocity and time stamp of the event
1158     * @returns 0 on success, a value < 0 if no active voice could be picked for voice stealing
1159     */
1160 schoenebeck 2879 int StealVoice(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {
1161 schoenebeck 3306 dmsg(3,("StealVoice()\n"));
1162 iliev 2012 if (VoiceSpawnsLeft <= 0) {
1163     dmsg(1,("Max. voice thefts per audio fragment reached (you may raise CONFIG_MAX_VOICES).\n"));
1164     return -1;
1165     }
1166    
1167     EngineChannelBase<V, R, I>* pEngineChn = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1168    
1169 schoenebeck 2879 if (pEventPool->poolIsEmpty()) {
1170     dmsg(1,("Event pool emtpy!\n"));
1171     return -1;
1172     }
1173 iliev 2012
1174 schoenebeck 2879 if (!pEngineChn->StealVoice(itNoteOnEvent, &itLastStolenVoice, &itLastStolenNote, &iuiLastStolenKey)) {
1175     --VoiceSpawnsLeft;
1176     return 0;
1177     }
1178 iliev 2012
1179 schoenebeck 2879 // if we couldn't steal a voice from the same engine channel then
1180     // steal oldest voice on the oldest key from any other engine channel
1181     // (the smaller engine channel number, the higher priority)
1182     EngineChannelBase<V, R, I>* pSelectedChannel;
1183     int iChannelIndex;
1184     VoiceIterator itSelectedVoice;
1185 iliev 2012
1186 schoenebeck 3306 #if CONFIG_DEVMODE
1187     EngineChannel* pBegin = NULL; // to detect endless loop
1188     #endif
1189    
1190 schoenebeck 2879 // select engine channel
1191     if (pLastStolenChannel) {
1192     pSelectedChannel = pLastStolenChannel;
1193     iChannelIndex = pSelectedChannel->iEngineIndexSelf;
1194     } else { // pick the engine channel followed by this engine channel
1195     iChannelIndex = (pEngineChn->iEngineIndexSelf + 1) % engineChannels.size();
1196     pSelectedChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannelIndex]);
1197     }
1198 iliev 2012
1199 schoenebeck 2879 // if we already stole in this fragment, try to proceed on same note
1200     if (this->itLastStolenVoiceGlobally) {
1201     itSelectedVoice = this->itLastStolenVoiceGlobally;
1202     do {
1203     ++itSelectedVoice;
1204     } while (itSelectedVoice && !itSelectedVoice->IsStealable()); // proceed iterating if voice was created in this fragment cycle
1205     }
1206     // did we find a 'stealable' voice?
1207     if (itSelectedVoice && itSelectedVoice->IsStealable()) {
1208     // remember which voice we stole, so we can simply proceed on next voice stealing
1209     this->itLastStolenVoiceGlobally = itSelectedVoice;
1210     // done
1211     goto stealable_voice_found;
1212     }
1213    
1214     // get (next) oldest note
1215     if (this->itLastStolenNoteGlobally) {
1216     for (NoteIterator itNote = ++this->itLastStolenNoteGlobally;
1217     itNote; ++itNote)
1218     {
1219     for (itSelectedVoice = itNote->pActiveVoices->first(); itSelectedVoice; ++itSelectedVoice) {
1220     // proceed iterating if voice was created in this audio fragment cycle
1221     if (itSelectedVoice->IsStealable()) {
1222     // remember which voice of which note we stole, so we can simply proceed on next voice stealing
1223     this->itLastStolenNoteGlobally = itNote;
1224     this->itLastStolenVoiceGlobally = itSelectedVoice;
1225     goto stealable_voice_found; // selection succeeded
1226     }
1227     }
1228 iliev 2012 }
1229 schoenebeck 2879 }
1230 iliev 2012
1231 schoenebeck 2879 #if CONFIG_DEVMODE
1232 schoenebeck 3306 pBegin = pSelectedChannel; // to detect endless loop
1233 schoenebeck 2879 #endif // CONFIG_DEVMODE
1234 iliev 2012
1235 schoenebeck 2879 while (true) { // iterate through engine channels
1236     // get (next) oldest key
1237     RTList<uint>::Iterator iuiSelectedKey = (this->iuiLastStolenKeyGlobally) ? ++this->iuiLastStolenKeyGlobally : pSelectedChannel->pActiveKeys->first();
1238     this->iuiLastStolenKeyGlobally = RTList<uint>::Iterator(); // to prevent endless loop (see line above)
1239     while (iuiSelectedKey) {
1240     MidiKey* pSelectedKey = &pSelectedChannel->pMIDIKeyInfo[*iuiSelectedKey];
1241    
1242     for (NoteIterator itNote = pSelectedKey->pActiveNotes->first(),
1243     itNotesEnd = pSelectedKey->pActiveNotes->end();
1244     itNote != itNotesEnd; ++itNote)
1245     {
1246     itSelectedVoice = itNote->pActiveVoices->first();
1247 iliev 2012 // proceed iterating if voice was created in this fragment cycle
1248     while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice;
1249     // found a "stealable" voice ?
1250     if (itSelectedVoice && itSelectedVoice->IsStealable()) {
1251 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
1252 iliev 2012 this->iuiLastStolenKeyGlobally = iuiSelectedKey;
1253 schoenebeck 2879 this->itLastStolenNoteGlobally = itNote;
1254 iliev 2012 this->itLastStolenVoiceGlobally = itSelectedVoice;
1255     this->pLastStolenChannel = pSelectedChannel;
1256     goto stealable_voice_found; // selection succeeded
1257     }
1258     }
1259 schoenebeck 2879 ++iuiSelectedKey; // get next key on current engine channel
1260 iliev 2012 }
1261 schoenebeck 2879 // get next engine channel
1262     iChannelIndex = (iChannelIndex + 1) % engineChannels.size();
1263     pSelectedChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannelIndex]);
1264 iliev 2012
1265     #if CONFIG_DEVMODE
1266 schoenebeck 2879 if (pSelectedChannel == pBegin) {
1267     dmsg(1,("FATAL ERROR: voice stealing endless loop!\n"));
1268     dmsg(1,("VoiceSpawnsLeft=%d.\n", VoiceSpawnsLeft));
1269     dmsg(1,("Exiting.\n"));
1270     exit(-1);
1271 iliev 2012 }
1272     #endif // CONFIG_DEVMODE
1273 schoenebeck 2879 }
1274 iliev 2012
1275 schoenebeck 2879 // jump point if a 'stealable' voice was found
1276     stealable_voice_found:
1277 iliev 2012
1278 schoenebeck 2879 #if CONFIG_DEVMODE
1279     if (!itSelectedVoice->IsActive()) {
1280     dmsg(1,("EngineBase: ERROR, tried to steal a voice which was not active !!!\n"));
1281 iliev 2012 return -1;
1282     }
1283 schoenebeck 2879 #endif // CONFIG_DEVMODE
1284    
1285     // now kill the selected voice
1286     itSelectedVoice->Kill(itNoteOnEvent);
1287    
1288     --VoiceSpawnsLeft;
1289    
1290     return 0; // success
1291 iliev 2012 }
1292    
1293     void HandleInstrumentChanges() {
1294     bool instrumentChanged = false;
1295     for (int i = 0; i < engineChannels.size(); i++) {
1296     EngineChannelBase<V, R, I>* pEngineChannel =
1297     static_cast<EngineChannelBase<V, R, I>*>(engineChannels[i]);
1298    
1299     // as we're going to (carefully) write some status to the
1300     // synchronized struct, we cast away the const
1301     InstrumentChangeCmd<R, I>& cmd =
1302     const_cast<InstrumentChangeCmd<R, I>&>(pEngineChannel->InstrumentChangeCommandReader.Lock());
1303    
1304     pEngineChannel->pRegionsInUse = cmd.pRegionsInUse;
1305     pEngineChannel->pRegionsInUse->clear();
1306    
1307     if (cmd.bChangeInstrument) {
1308     // change instrument
1309     dmsg(5,("Engine: instrument change command received\n"));
1310     cmd.bChangeInstrument = false;
1311     pEngineChannel->pInstrument = cmd.pInstrument;
1312 schoenebeck 2659 pEngineChannel->pScript =
1313     cmd.pScript->bHasValidScript ? cmd.pScript : NULL;
1314 iliev 2012 instrumentChanged = true;
1315    
1316     pEngineChannel->MarkAllActiveVoicesAsOrphans();
1317 schoenebeck 2611
1318     // the script's "init" event handler is only executed
1319     // once (when the script is loaded or reloaded)
1320     if (pEngineChannel->pScript && pEngineChannel->pScript->handlerInit) {
1321 schoenebeck 2972 dmsg(5,("Engine: exec handlerInit %p\n", pEngineChannel->pScript->handlerInit));
1322 schoenebeck 2611 RTList<ScriptEvent>::Iterator itScriptEvent =
1323     pEngineChannel->pScript->pEvents->allocAppend();
1324    
1325 schoenebeck 3283 itScriptEvent->cause = pEventGenerator->CreateEvent(0);
1326     itScriptEvent->cause.Type = (Event::type_t) -1; // some invalid type to avoid random event processing
1327 schoenebeck 2614 itScriptEvent->cause.pEngineChannel = pEngineChannel;
1328 schoenebeck 3283 itScriptEvent->cause.pMidiInputPort = pEngineChannel->GetMidiInputPort();
1329 schoenebeck 3293 itScriptEvent->id = 0;
1330 schoenebeck 2618 itScriptEvent->handlers[0] = pEngineChannel->pScript->handlerInit;
1331     itScriptEvent->handlers[1] = NULL;
1332 schoenebeck 2972 itScriptEvent->currentHandler = 0;
1333     itScriptEvent->executionSlices = 0;
1334     itScriptEvent->ignoreAllWaitCalls = false;
1335     itScriptEvent->handlerType = VM_EVENT_HANDLER_INIT;
1336 schoenebeck 3293 itScriptEvent->parentHandlerID = 0;
1337     itScriptEvent->childHandlerID[0] = 0;
1338     itScriptEvent->autoAbortByParent = false;
1339     itScriptEvent->forkIndex = 0;
1340 schoenebeck 2614
1341 schoenebeck 3221 VMExecStatus_t res;
1342     size_t instructionsCount = 0;
1343     const size_t maxInstructions = 200000; // aiming approx. 1 second max. (based on very roughly 5us / instruction)
1344     bool bWarningShown = false;
1345     do {
1346     res = pScriptVM->exec(
1347     pEngineChannel->pScript->parserContext, &*itScriptEvent
1348     );
1349     instructionsCount += itScriptEvent->execCtx->instructionsPerformed();
1350     if (instructionsCount > maxInstructions && !bWarningShown) {
1351     bWarningShown = true;
1352     dmsg(0,("[ScriptVM] WARNING: \"init\" event handler of instrument script executing for long time!\n"));
1353     }
1354     } while (res & VM_EXEC_SUSPENDED && !(res & VM_EXEC_ERROR));
1355 schoenebeck 2611
1356     pEngineChannel->pScript->pEvents->free(itScriptEvent);
1357     }
1358 iliev 2012 }
1359     }
1360    
1361     if (instrumentChanged) {
1362     //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
1363     ResetSuspendedRegions();
1364     }
1365     }
1366    
1367     /**
1368     * Render all 'normal' voices (that is voices which were not stolen in
1369     * this fragment) on the given engine channel.
1370     *
1371     * @param pEngineChannel - engine channel on which audio should be
1372     * rendered
1373     * @param Samples - amount of sample points to be rendered in
1374     * this audio fragment cycle
1375     */
1376     void RenderActiveVoices(EngineChannel* pEngineChannel, uint Samples) {
1377     #if !CONFIG_PROCESS_MUTED_CHANNELS
1378     if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
1379     #endif
1380    
1381     EngineChannelBase<V, R, I>* pChannel =
1382     static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1383     pChannel->RenderActiveVoices(Samples);
1384    
1385     ActiveVoiceCountTemp += pEngineChannel->GetVoiceCount();
1386     }
1387    
1388     /**
1389     * Render all stolen voices (only voices which were stolen in this
1390     * fragment) on the given engine channel. Stolen voices are rendered
1391     * after all normal voices have been rendered; this is needed to render
1392     * audio of those voices which were selected for voice stealing until
1393     * the point were the stealing (that is the take over of the voice)
1394     * actually happened.
1395     *
1396     * @param pEngineChannel - engine channel on which audio should be
1397     * rendered
1398     * @param Samples - amount of sample points to be rendered in
1399     * this audio fragment cycle
1400     */
1401     void RenderStolenVoices(uint Samples) {
1402     RTList<Event>::Iterator itVoiceStealEvent = pVoiceStealingQueue->first();
1403     RTList<Event>::Iterator end = pVoiceStealingQueue->end();
1404     for (; itVoiceStealEvent != end; ++itVoiceStealEvent) {
1405     EngineChannelBase<V, R, I>* pEngineChannel =
1406     static_cast<EngineChannelBase<V, R, I>*>(itVoiceStealEvent->pEngineChannel);;
1407     if (!pEngineChannel->pInstrument) continue; // ignore if no instrument loaded
1408 schoenebeck 2879
1409 iliev 2012 PoolVoiceIterator itNewVoice =
1410     LaunchVoice(pEngineChannel, itVoiceStealEvent, itVoiceStealEvent->Param.Note.Layer, itVoiceStealEvent->Param.Note.ReleaseTrigger, false, false);
1411     if (itNewVoice) {
1412 schoenebeck 2879 // usually there should already be a new Note object
1413     NoteIterator itNote = GetNotePool()->fromID(itVoiceStealEvent->Param.Note.ID);
1414     if (!itNote) { // should not happen, but just to be sure ...
1415 schoenebeck 3306 dmsg(2,("Engine: No Note object for stolen voice!\n"));
1416 schoenebeck 3205 const note_id_t noteID = LaunchNewNote(pEngineChannel, itVoiceStealEvent);
1417 schoenebeck 2879 if (!noteID) {
1418     dmsg(1,("Engine: Voice stealing failed; No Note object and Note pool empty!\n"));
1419     continue;
1420     }
1421     itNote = GetNotePool()->fromID(noteID);
1422     }
1423     // move voice from whereever it was, to the new note's list of active voices
1424     itNewVoice = itNewVoice.moveToEndOf(itNote->pActiveVoices);
1425     // render audio of this new voice for the first time
1426 iliev 2012 itNewVoice->Render(Samples);
1427     if (itNewVoice->IsActive()) { // still active
1428     *(pEngineChannel->pRegionsInUse->allocAppend()) = itNewVoice->GetRegion();
1429     ActiveVoiceCountTemp++;
1430     pEngineChannel->SetVoiceCount(pEngineChannel->GetVoiceCount() + 1);
1431    
1432     if (itNewVoice->PlaybackState == Voice::playback_state_disk) {
1433     if (itNewVoice->DiskStreamRef.State != Stream::state_unused) {
1434     pEngineChannel->SetDiskStreamCount(pEngineChannel->GetDiskStreamCount() + 1);
1435     }
1436     }
1437     } else { // voice reached end, is now inactive
1438     pEngineChannel->FreeVoice(itNewVoice); // remove voice from the list of active voices
1439     }
1440     }
1441     else dmsg(1,("EngineBase: ERROR, voice stealing didn't work out!\n"));
1442    
1443     // we need to clear the key's event list explicitly here in case key was never active
1444     MidiKey* pKey = &pEngineChannel->pMIDIKeyInfo[itVoiceStealEvent->Param.Note.Key];
1445     pKey->VoiceTheftsQueued--;
1446     if (!pKey->Active && !pKey->VoiceTheftsQueued) pKey->pEvents->clear();
1447     }
1448     }
1449    
1450     /**
1451     * Free all keys which have turned inactive in this audio fragment, from
1452     * the list of active keys and clear all event lists on that engine
1453     * channel.
1454     *
1455     * @param pEngineChannel - engine channel to cleanup
1456     */
1457     void PostProcess(EngineChannel* pEngineChannel) {
1458     EngineChannelBase<V, R, I>* pChannel =
1459     static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1460 schoenebeck 3306 pChannel->FreeAllInactiveKeys();
1461 iliev 2012
1462     // empty the engine channel's own event lists
1463 schoenebeck 2871 // (only events of the current audio fragment cycle)
1464     pChannel->ClearEventListsOfCurrentFragment();
1465 iliev 2012 }
1466    
1467 schoenebeck 2121 /**
1468     * Process MIDI control change events with hard coded behavior,
1469     * that is controllers whose behavior is defined independently
1470     * of the actual sampler engine type and instrument.
1471     *
1472     * @param pEngineChannel - engine channel on which the MIDI CC event was received
1473     * @param itControlChangeEvent - the actual MIDI CC event
1474     */
1475 iliev 2012 void ProcessHardcodedControllers (
1476     EngineChannel* pEngineChannel,
1477     Pool<Event>::Iterator& itControlChangeEvent
1478     ) {
1479     EngineChannelBase<V, R, I>* pChannel =
1480     static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1481    
1482     switch (itControlChangeEvent->Param.CC.Controller) {
1483     case 5: { // portamento time
1484     pChannel->PortamentoTime = (float) itControlChangeEvent->Param.CC.Value / 127.0f * (float) CONFIG_PORTAMENTO_TIME_MAX + (float) CONFIG_PORTAMENTO_TIME_MIN;
1485     break;
1486     }
1487 schoenebeck 3688 case 6: { // data entry (MSB)
1488     //dmsg(1,("DATA ENTRY MSB %d\n", itControlChangeEvent->Param.CC.Value));
1489    
1490     // look-ahead: if next MIDI event is data entry LSB,
1491     // then skip this event here for now (to avoid double
1492     // handling of what's supposed to be one RPN/NRPN event)
1493     if (isNextEventCCNr(itControlChangeEvent, 38))
1494     break;
1495    
1496 schoenebeck 3687 if (pChannel->GetMidiRpnParameter() >= 0) { // RPN parameter number was sent previously ...
1497 schoenebeck 3688 int ch = itControlChangeEvent->Param.CC.Channel;
1498     int param = pChannel->GetMidiRpnParameter();
1499     int value = itControlChangeEvent->Param.CC.Value << 7;
1500    
1501     // transform event type: CC event -> RPN event
1502     itControlChangeEvent->Type = Event::type_rpn;
1503     itControlChangeEvent->Param.RPN.Channel = ch;
1504     itControlChangeEvent->Param.RPN.Parameter = param;
1505     itControlChangeEvent->Param.RPN.Value = value;
1506    
1507 schoenebeck 3690 // if there's a RPN script handler, run it ...
1508     if (pChannel->pScript->handlerRpn) {
1509     const event_id_t eventID =
1510     pEventPool->getID(itControlChangeEvent);
1511     // run the RPN script handler
1512     ProcessEventByScript(
1513     pChannel, itControlChangeEvent,
1514     pChannel->pScript->handlerRpn
1515     );
1516     // if RPN event was dropped by script, abort
1517     // here to avoid hard coded RPN processing below
1518     if (!pEventPool->fromID(eventID)) {
1519     // to prevent other data entry messages to be misenterpreted as RPN value
1520     pChannel->ResetMidiRpnParameter();
1521     break;
1522     }
1523     }
1524    
1525     // do the actual (hard-coded) RPN value change processing
1526 schoenebeck 3688 ProcessHardcodedRpn(pEngineChannel, itControlChangeEvent);
1527    
1528     // to prevent other data entry messages to be misenterpreted as RPN value
1529 schoenebeck 3687 pChannel->ResetMidiRpnParameter();
1530     } else if (pChannel->GetMidiNrpnParameter() >= 0) { // NRPN parameter number was sent previously ...
1531 schoenebeck 3688 int ch = itControlChangeEvent->Param.CC.Channel;
1532     int param = pChannel->GetMidiNrpnParameter();
1533     int value = itControlChangeEvent->Param.CC.Value << 7;
1534    
1535     // transform event type: CC event -> NRPN event
1536     itControlChangeEvent->Type = Event::type_nrpn;
1537     itControlChangeEvent->Param.RPN.Channel = ch;
1538     itControlChangeEvent->Param.RPN.Parameter = param;
1539     itControlChangeEvent->Param.RPN.Value = value;
1540    
1541 schoenebeck 3690 // if there's a NRPN script handler, run it ...
1542     if (pChannel->pScript->handlerNrpn) {
1543     const event_id_t eventID =
1544     pEventPool->getID(itControlChangeEvent);
1545     // run the NRPN script handler
1546     ProcessEventByScript(
1547     pChannel, itControlChangeEvent,
1548     pChannel->pScript->handlerNrpn
1549     );
1550     // if NRPN event was dropped by script, abort
1551     // here to avoid hard coded NRPN processing below
1552     if (!pEventPool->fromID(eventID)) {
1553     // to prevent other data entry messages to be misenterpreted as NRPN value
1554     pChannel->ResetMidiNrpnParameter();
1555     break;
1556     }
1557     }
1558    
1559     // do the actual (hard-coded) NRPN value change processing
1560 schoenebeck 3688 ProcessHardcodedNrpn(pEngineChannel, itControlChangeEvent);
1561    
1562     // to prevent other data entry messages to be misenterpreted as NRPN value
1563 schoenebeck 3687 pChannel->ResetMidiNrpnParameter();
1564 iliev 2012 }
1565     break;
1566     }
1567     case 7: { // volume
1568     //TODO: not sample accurate yet
1569     pChannel->MidiVolume = VolumeCurve[itControlChangeEvent->Param.CC.Value];
1570     pChannel->bStatusChanged = true; // engine channel status has changed, so set notify flag
1571     break;
1572     }
1573     case 10: { // panpot
1574     //TODO: not sample accurate yet
1575     pChannel->iLastPanRequest = itControlChangeEvent->Param.CC.Value;
1576     break;
1577     }
1578 schoenebeck 3688 case 38: { // data entry (LSB)
1579     //dmsg(1,("DATA ENTRY LSB %d\n", itControlChangeEvent->Param.CC.Value));
1580     int value = 0;
1581    
1582     // look-back: if previous MIDI event was data entry MSB,
1583     // then obtain that value for the MSB value portion
1584     if (isPrevEventCCNr(itControlChangeEvent, 6))
1585     value = prevEventOf(itControlChangeEvent)->Param.CC.Value << 7;
1586    
1587     if (pChannel->GetMidiRpnParameter() >= 0) { // RPN parameter number was sent previously ...
1588     int ch = itControlChangeEvent->Param.CC.Channel;
1589     int param = pChannel->GetMidiRpnParameter();
1590     value |= itControlChangeEvent->Param.CC.Value;
1591    
1592     // transform event type: CC event -> RPN event
1593     itControlChangeEvent->Type = Event::type_rpn;
1594     itControlChangeEvent->Param.RPN.Channel = ch;
1595     itControlChangeEvent->Param.RPN.Parameter = param;
1596     itControlChangeEvent->Param.RPN.Value = value;
1597    
1598 schoenebeck 3690 // if there's a RPN script handler, run it ...
1599     if (pChannel->pScript->handlerRpn) {
1600     const event_id_t eventID =
1601     pEventPool->getID(itControlChangeEvent);
1602     // run the RPN script handler
1603     ProcessEventByScript(
1604     pChannel, itControlChangeEvent,
1605     pChannel->pScript->handlerRpn
1606     );
1607     // if RPN event was dropped by script, abort
1608     // here to avoid hard coded RPN processing below
1609     if (!pEventPool->fromID(eventID)) {
1610     // to prevent other data entry messages to be misenterpreted as RPN value
1611     pChannel->ResetMidiRpnParameter();
1612     break;
1613     }
1614     }
1615    
1616     // do the actual (hard-coded) RPN value change processing
1617 schoenebeck 3688 ProcessHardcodedRpn(pEngineChannel, itControlChangeEvent);
1618    
1619     // to prevent other data entry messages to be misenterpreted as RPN value
1620     pChannel->ResetMidiRpnParameter();
1621     } else if (pChannel->GetMidiNrpnParameter() >= 0) { // NRPN parameter number was sent previously ...
1622     int ch = itControlChangeEvent->Param.CC.Channel;
1623     int param = pChannel->GetMidiNrpnParameter();
1624     value |= itControlChangeEvent->Param.CC.Value;
1625    
1626     // transform event type: CC event -> NRPN event
1627     itControlChangeEvent->Type = Event::type_nrpn;
1628     itControlChangeEvent->Param.RPN.Channel = ch;
1629     itControlChangeEvent->Param.RPN.Parameter = param;
1630     itControlChangeEvent->Param.RPN.Value = value;
1631    
1632 schoenebeck 3690 // if there's a NRPN script handler, run it ...
1633     if (pChannel->pScript->handlerNrpn) {
1634     const event_id_t eventID =
1635     pEventPool->getID(itControlChangeEvent);
1636     // run the NRPN script handler
1637     ProcessEventByScript(
1638     pChannel, itControlChangeEvent,
1639     pChannel->pScript->handlerNrpn
1640     );
1641     // if NRPN event was dropped by script, abort
1642     // here to avoid hard coded NRPN processing below
1643     if (!pEventPool->fromID(eventID)) {
1644     // to prevent other data entry messages to be misenterpreted as NRPN value
1645     pChannel->ResetMidiNrpnParameter();
1646     break;
1647     }
1648     }
1649    
1650     // do the actual (hard-coded) NRPN value change processing
1651 schoenebeck 3688 ProcessHardcodedNrpn(pEngineChannel, itControlChangeEvent);
1652    
1653     // to prevent other data entry messages to be misenterpreted as NRPN value
1654     pChannel->ResetMidiNrpnParameter();
1655     }
1656     break;
1657     }
1658 iliev 2012 case 64: { // sustain
1659     if (itControlChangeEvent->Param.CC.Value >= 64 && !pChannel->SustainPedal) {
1660     dmsg(4,("DAMPER (RIGHT) PEDAL DOWN\n"));
1661     pChannel->SustainPedal = true;
1662     pChannel->listeners.PreProcessSustainPedalDown();
1663    
1664     #if !CONFIG_PROCESS_MUTED_CHANNELS
1665     if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
1666     pChannel->listeners.PostProcessSustainPedalDown();
1667     return;
1668     }
1669     #endif
1670    
1671     pChannel->ProcessSustainPedalDown(itControlChangeEvent);
1672     pChannel->listeners.PostProcessSustainPedalDown();
1673     }
1674     if (itControlChangeEvent->Param.CC.Value < 64 && pChannel->SustainPedal) {
1675     dmsg(4,("DAMPER (RIGHT) PEDAL UP\n"));
1676     pChannel->SustainPedal = false;
1677     pChannel->listeners.PreProcessSustainPedalUp();
1678    
1679     #if !CONFIG_PROCESS_MUTED_CHANNELS
1680     if (pChannel->GetMute()) { // skip if sampler channel is muted
1681     pChannel->listeners.PostProcessSustainPedalUp();
1682     return;
1683     }
1684     #endif
1685    
1686     pChannel->ProcessSustainPedalUp(itControlChangeEvent);
1687     pChannel->listeners.PostProcessSustainPedalUp();
1688     }
1689     break;
1690     }
1691     case 65: { // portamento on / off
1692     const bool bPortamento = itControlChangeEvent->Param.CC.Value >= 64;
1693     if (bPortamento != pChannel->PortamentoMode)
1694     KillAllVoices(pChannel, itControlChangeEvent);
1695     pChannel->PortamentoMode = bPortamento;
1696     break;
1697     }
1698     case 66: { // sostenuto
1699     if (itControlChangeEvent->Param.CC.Value >= 64 && !pChannel->SostenutoPedal) {
1700     dmsg(4,("SOSTENUTO (CENTER) PEDAL DOWN\n"));
1701     pChannel->SostenutoPedal = true;
1702     pChannel->listeners.PreProcessSostenutoPedalDown();
1703    
1704     #if !CONFIG_PROCESS_MUTED_CHANNELS
1705     if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
1706     pChannel->listeners.PostProcessSostenutoPedalDown();
1707     return;
1708     }
1709     #endif
1710    
1711     pChannel->ProcessSostenutoPedalDown();
1712     pChannel->listeners.PostProcessSostenutoPedalDown();
1713     }
1714     if (itControlChangeEvent->Param.CC.Value < 64 && pChannel->SostenutoPedal) {
1715     dmsg(4,("SOSTENUTO (CENTER) PEDAL UP\n"));
1716     pChannel->SostenutoPedal = false;
1717     pChannel->listeners.PreProcessSostenutoPedalUp();
1718    
1719     #if !CONFIG_PROCESS_MUTED_CHANNELS
1720     if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
1721     pChannel->listeners.PostProcessSostenutoPedalUp();
1722     return;
1723     }
1724     #endif
1725    
1726     pChannel->ProcessSostenutoPedalUp(itControlChangeEvent);
1727     pChannel->listeners.PostProcessSostenutoPedalUp();
1728     }
1729     break;
1730     }
1731 schoenebeck 3687 case 98: { // NRPN parameter LSB
1732 schoenebeck 2121 dmsg(4,("NRPN LSB %d\n", itControlChangeEvent->Param.CC.Value));
1733 schoenebeck 3687 pEngineChannel->SetMidiNrpnParameterLsb(itControlChangeEvent->Param.CC.Value);
1734 schoenebeck 2121 break;
1735     }
1736 schoenebeck 3687 case 99: { // NRPN parameter MSB
1737 schoenebeck 2121 dmsg(4,("NRPN MSB %d\n", itControlChangeEvent->Param.CC.Value));
1738 schoenebeck 3687 pEngineChannel->SetMidiNrpnParameterMsb(itControlChangeEvent->Param.CC.Value);
1739 schoenebeck 2121 break;
1740     }
1741 schoenebeck 3687 case 100: { // RPN parameter LSB
1742 schoenebeck 2121 dmsg(4,("RPN LSB %d\n", itControlChangeEvent->Param.CC.Value));
1743 schoenebeck 3687 pEngineChannel->SetMidiRpnParameterLsb(itControlChangeEvent->Param.CC.Value);
1744 iliev 2012 break;
1745     }
1746 schoenebeck 3687 case 101: { // RPN parameter MSB
1747 schoenebeck 2121 dmsg(4,("RPN MSB %d\n", itControlChangeEvent->Param.CC.Value));
1748 schoenebeck 3687 pEngineChannel->SetMidiRpnParameterMsb(itControlChangeEvent->Param.CC.Value);
1749 iliev 2012 break;
1750     }
1751    
1752    
1753     // Channel Mode Messages
1754    
1755     case 120: { // all sound off
1756     KillAllVoices(pEngineChannel, itControlChangeEvent);
1757     break;
1758     }
1759     case 121: { // reset all controllers
1760     pChannel->ResetControllers();
1761     break;
1762     }
1763     case 123: { // all notes off
1764     #if CONFIG_PROCESS_ALL_NOTES_OFF
1765     pChannel->ReleaseAllVoices(itControlChangeEvent);
1766     #endif // CONFIG_PROCESS_ALL_NOTES_OFF
1767     break;
1768     }
1769     case 126: { // mono mode on
1770     if (!pChannel->SoloMode)
1771     KillAllVoices(pEngineChannel, itControlChangeEvent);
1772     pChannel->SoloMode = true;
1773     break;
1774     }
1775     case 127: { // poly mode on
1776     if (pChannel->SoloMode)
1777     KillAllVoices(pEngineChannel, itControlChangeEvent);
1778     pChannel->SoloMode = false;
1779     break;
1780     }
1781     }
1782     }
1783    
1784 schoenebeck 3688 /**
1785     * Process MIDI RPN events with hard coded behavior.
1786     *
1787     * @param pEngineChannel - engine channel on which the MIDI RPN
1788     * event was received
1789     * @param itRpnEvent - the actual MIDI RPN event
1790     */
1791     void ProcessHardcodedRpn(EngineChannel* pEngineChannel,
1792     Pool<Event>::Iterator& itRpnEvent)
1793     {
1794     EngineChannelBase<V, R, I>* pChannel =
1795     static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1796    
1797     if (itRpnEvent->Param.RPN.Parameter == 2) { // coarse tuning in half tones
1798     int transpose = (int) itRpnEvent->Param.RPN.ValueMSB() - 64;
1799     // limit to +- two octaves for now
1800     transpose = RTMath::Min(transpose, 24);
1801     transpose = RTMath::Max(transpose, -24);
1802     pChannel->GlobalTranspose = transpose;
1803     // workaround, so we won't have hanging notes
1804     pChannel->ReleaseAllVoices(itRpnEvent);
1805     }
1806     }
1807    
1808     /**
1809     * Process MIDI NRPN events with hard coded behavior.
1810     *
1811     * @param pEngineChannel - engine channel on which the MIDI NRPN
1812     * event was received
1813     * @param itRpnEvent - the actual MIDI NRPN event
1814     */
1815     void ProcessHardcodedNrpn(EngineChannel* pEngineChannel,
1816     Pool<Event>::Iterator& itNrpnEvent)
1817     {
1818     EngineChannelBase<V, R, I>* pChannel =
1819     static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1820    
1821     switch (itNrpnEvent->Param.NRPN.ParameterMSB()) {
1822     case 0x1a: { // volume level of note (Roland GS NRPN)
1823     const uint note = itNrpnEvent->Param.NRPN.ParameterLSB();
1824     const uint vol = itNrpnEvent->Param.NRPN.ValueMSB();
1825     dmsg(4,("Note Volume NRPN received (note=%d,vol=%d).\n", note, vol));
1826     if (note < 128 && vol < 128)
1827     pChannel->pMIDIKeyInfo[note].Volume = VolumeCurve[vol];
1828     break;
1829     }
1830     case 0x1c: { // panpot of note (Roland GS NRPN)
1831     const uint note = itNrpnEvent->Param.NRPN.ParameterLSB();
1832     const uint pan = itNrpnEvent->Param.NRPN.ValueMSB();
1833     dmsg(4,("Note Pan NRPN received (note=%d,pan=%d).\n", note, pan));
1834     if (note < 128 && pan < 128) {
1835     pChannel->pMIDIKeyInfo[note].PanLeft = PanCurve[128 - pan];
1836     pChannel->pMIDIKeyInfo[note].PanRight = PanCurve[pan];
1837     }
1838     break;
1839     }
1840     case 0x1d: { // reverb send of note (Roland GS NRPN)
1841     const uint note = itNrpnEvent->Param.NRPN.ParameterLSB();
1842     const float reverb = float(itNrpnEvent->Param.NRPN.Value) / 16383.f;
1843     dmsg(4,("Note Reverb Send NRPN received (note=%d,send=%f).\n", note, reverb));
1844     if (note < 128)
1845     pChannel->pMIDIKeyInfo[note].ReverbSend = reverb;
1846     break;
1847     }
1848     case 0x1e: { // chorus send of note (Roland GS NRPN)
1849     const uint note = itNrpnEvent->Param.NRPN.ParameterLSB();
1850     const float chorus = float(itNrpnEvent->Param.NRPN.Value) / 16383.f;
1851     dmsg(4,("Note Chorus Send NRPN received (note=%d,send=%f).\n", note, chorus));
1852     if (note < 128)
1853     pChannel->pMIDIKeyInfo[note].ChorusSend = chorus;
1854     break;
1855     }
1856     }
1857     }
1858    
1859 iliev 2012 virtual D* CreateDiskThread() = 0;
1860    
1861     /**
1862     * Assigns and triggers a new voice for the respective MIDI key.
1863     *
1864 schoenebeck 2871 * @param pEngineChannel - engine channel on which this event occurred on
1865 iliev 2012 * @param itNoteOnEvent - key, velocity and time stamp of the event
1866     */
1867 schoenebeck 3054 virtual void ProcessNoteOn(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) OVERRIDE {
1868 iliev 2012 EngineChannelBase<V, R, I>* pChannel =
1869     static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1870    
1871 schoenebeck 2879 const int key = itNoteOnEvent->Param.Note.Key;
1872     const int vel = itNoteOnEvent->Param.Note.Velocity;
1873     if (key < 0 || key > 127) return; // ignore event, key outside allowed key range
1874 iliev 2012
1875     MidiKey* pKey = &pChannel->pMIDIKeyInfo[key];
1876    
1877 schoenebeck 2938 // There are real MIDI note-on events (Event::type_note_on) and
1878     // programmatically spawned notes (Event::type_play_note). We have
1879     // to distinguish between them, since certain processing below
1880     // must only be done on real MIDI note-on events (i.e. for
1881     // correctly updating which MIDI keys are currently pressed down).
1882     const bool isRealMIDINoteOnEvent = itNoteOnEvent->Type == Event::type_note_on;
1883    
1884     if (isRealMIDINoteOnEvent)
1885     pChannel->listeners.PreProcessNoteOn(key, vel);
1886    
1887 iliev 2012 #if !CONFIG_PROCESS_MUTED_CHANNELS
1888     if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
1889 schoenebeck 2938 if (isRealMIDINoteOnEvent)
1890     pChannel->listeners.PostProcessNoteOn(key, vel);
1891 iliev 2012 return;
1892     }
1893     #endif
1894    
1895     if (!pChannel->pInstrument) {
1896 schoenebeck 2938 if (isRealMIDINoteOnEvent)
1897     pChannel->listeners.PostProcessNoteOn(key, vel);
1898 iliev 2012 return; // ignore if no instrument loaded
1899     }
1900    
1901     // move note on event to the key's own event list
1902     RTList<Event>::Iterator itNoteOnEventOnKeyList = itNoteOnEvent.moveToEndOf(pKey->pEvents);
1903    
1904     // if Solo Mode then kill all already active voices
1905 schoenebeck 2938 if (pChannel->SoloMode && isRealMIDINoteOnEvent) {
1906 iliev 2012 Pool<uint>::Iterator itYoungestKey = pChannel->pActiveKeys->last();
1907     if (itYoungestKey) {
1908     const int iYoungestKey = *itYoungestKey;
1909     const MidiKey* pOtherKey = &pChannel->pMIDIKeyInfo[iYoungestKey];
1910     if (pOtherKey->Active) {
1911     // get final portamento position of currently active voice
1912     if (pChannel->PortamentoMode) {
1913 schoenebeck 2879 NoteIterator itNote = pOtherKey->pActiveNotes->last();
1914     if (itNote) {
1915     VoiceIterator itVoice = itNote->pActiveVoices->last();
1916     if (itVoice) itVoice->UpdatePortamentoPos(itNoteOnEventOnKeyList);
1917     }
1918 iliev 2012 }
1919     // kill all voices on the (other) key
1920 schoenebeck 2879 for (NoteIterator itNote = pOtherKey->pActiveNotes->first(); itNote; ++itNote) {
1921     VoiceIterator itVoiceToBeKilled = itNote->pActiveVoices->first();
1922     VoiceIterator end = itNote->pActiveVoices->end();
1923     for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1924     if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))
1925     itVoiceToBeKilled->Kill(itNoteOnEventOnKeyList);
1926     }
1927 iliev 2012 }
1928     }
1929     }
1930     // set this key as 'currently active solo key'
1931     pChannel->SoloKey = key;
1932     }
1933    
1934 schoenebeck 2938 if (isRealMIDINoteOnEvent) {
1935     pChannel->ProcessKeySwitchChange(key);
1936 iliev 2012
1937 schoenebeck 2938 pKey->KeyPressed = true; // the MIDI key was now pressed down
1938     pChannel->KeyDown[key] = true; // just used as built-in %KEY_DOWN script variable
1939     pKey->Velocity = itNoteOnEventOnKeyList->Param.Note.Velocity;
1940     pKey->NoteOnTime = FrameTime + itNoteOnEventOnKeyList->FragmentPos(); // will be used to calculate note length
1941     }
1942 iliev 2012
1943     // cancel release process of voices on this key if needed
1944 schoenebeck 2938 if (pKey->Active && !pChannel->SustainPedal && isRealMIDINoteOnEvent) {
1945 iliev 2012 RTList<Event>::Iterator itCancelReleaseEvent = pKey->pEvents->allocAppend();
1946     if (itCancelReleaseEvent) {
1947     *itCancelReleaseEvent = *itNoteOnEventOnKeyList; // copy event
1948 schoenebeck 2938 itCancelReleaseEvent->Type = Event::type_cancel_release_key; // transform event type
1949 iliev 2012 }
1950     else dmsg(1,("Event pool emtpy!\n"));
1951     }
1952    
1953     TriggerNewVoices(pEngineChannel, itNoteOnEventOnKeyList);
1954    
1955     // if neither a voice was spawned or postponed then remove note on event from key again
1956     if (!pKey->Active && !pKey->VoiceTheftsQueued)
1957     pKey->pEvents->free(itNoteOnEventOnKeyList);
1958    
1959 schoenebeck 2938 if (isRealMIDINoteOnEvent && (!pChannel->SoloMode || pChannel->PortamentoPos < 0.0f))
1960     pChannel->PortamentoPos = (float) key;
1961    
1962     //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?
1963 persson 2043 if (pKey->pRoundRobinIndex) {
1964     (*pKey->pRoundRobinIndex)++; // counter specific for the key or region
1965     pChannel->RoundRobinIndex++; // common counter for the channel
1966     }
1967 schoenebeck 2938
1968     if (isRealMIDINoteOnEvent)
1969     pChannel->listeners.PostProcessNoteOn(key, vel);
1970 iliev 2012 }
1971    
1972     /**
1973     * Allocate and trigger new voice(s) for the key.
1974     */
1975     virtual void TriggerNewVoices (
1976     EngineChannel* pEngineChannel,
1977     RTList<Event>::Iterator& itNoteOnEvent,
1978     bool HandleKeyGroupConflicts = true
1979     ) = 0;
1980    
1981     /**
1982     * Allocate and trigger release voice(s) for the key.
1983     */
1984     virtual void TriggerReleaseVoices (
1985     EngineChannel* pEngineChannel,
1986     RTList<Event>::Iterator& itNoteOffEvent
1987     ) = 0;
1988    
1989     /**
1990     * Releases the voices on the given key if sustain pedal is not pressed.
1991     * If sustain is pressed, the release of the note will be postponed until
1992     * sustain pedal will be released or voice turned inactive by itself (e.g.
1993     * due to completion of sample playback).
1994     *
1995 schoenebeck 2871 * @param pEngineChannel - engine channel on which this event occurred on
1996 iliev 2012 * @param itNoteOffEvent - key, velocity and time stamp of the event
1997     */
1998 schoenebeck 3054 virtual void ProcessNoteOff(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOffEvent) OVERRIDE {
1999 iliev 2012 EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
2000    
2001 schoenebeck 2879 const int iKey = itNoteOffEvent->Param.Note.Key;
2002     const int vel = itNoteOffEvent->Param.Note.Velocity;
2003     if (iKey < 0 || iKey > 127) return; // ignore event, key outside allowed key range
2004 iliev 2012
2005     MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];
2006    
2007 schoenebeck 2938 // There are real MIDI note-off events (Event::type_note_off) and
2008     // programmatically spawned notes (Event::type_stop_note). We have
2009     // to distinguish between them, since certain processing below
2010     // must only be done on real MIDI note-off events (i.e. for
2011     // correctly updating which MIDI keys are currently pressed down),
2012     // plus a stop-note event just releases voices of one particular
2013     // note, whereas a note-off event releases all voices on a
2014     // particular MIDI key instead.
2015     const bool isRealMIDINoteOffEvent = itNoteOffEvent->Type == Event::type_note_off;
2016 iliev 2012
2017 schoenebeck 2938 if (isRealMIDINoteOffEvent)
2018     pChannel->listeners.PreProcessNoteOff(iKey, vel);
2019    
2020 iliev 2012 #if !CONFIG_PROCESS_MUTED_CHANNELS
2021     if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
2022 schoenebeck 2938 if (isRealMIDINoteOffEvent)
2023     pChannel->listeners.PostProcessNoteOff(iKey, vel);
2024 iliev 2012 return;
2025     }
2026     #endif
2027    
2028 schoenebeck 2938 if (isRealMIDINoteOffEvent) {
2029     pKey->KeyPressed = false; // the MIDI key was now released
2030     pChannel->KeyDown[iKey] = false; // just used as built-in %KEY_DOWN script variable
2031     }
2032 iliev 2012
2033     // move event to the key's own event list
2034     RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);
2035    
2036 schoenebeck 2938 if (isRealMIDINoteOffEvent) {
2037     bool bShouldRelease = pKey->Active && pChannel->ShouldReleaseVoice(itNoteOffEventOnKeyList->Param.Note.Key);
2038 iliev 2012
2039 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)
2040     if (pChannel->SoloMode && pChannel->pInstrument) { //TODO: this feels like too much code just for handling solo mode :P
2041     bool bOtherKeysPressed = false;
2042     if (iKey == pChannel->SoloKey) {
2043     pChannel->SoloKey = -1;
2044     // if there's still a key pressed down, respawn a voice (group) on the highest key
2045     for (int i = 127; i > 0; i--) {
2046     MidiKey* pOtherKey = &pChannel->pMIDIKeyInfo[i];
2047     if (pOtherKey->KeyPressed) {
2048     bOtherKeysPressed = true;
2049     // make the other key the new 'currently active solo key'
2050     pChannel->SoloKey = i;
2051     // get final portamento position of currently active voice
2052     if (pChannel->PortamentoMode) {
2053     NoteIterator itNote = pKey->pActiveNotes->first();
2054     VoiceIterator itVoice = itNote->pActiveVoices->first();
2055     if (itVoice) itVoice->UpdatePortamentoPos(itNoteOffEventOnKeyList);
2056 schoenebeck 2879 }
2057 schoenebeck 2938 // create a pseudo note on event
2058     RTList<Event>::Iterator itPseudoNoteOnEvent = pOtherKey->pEvents->allocAppend();
2059     if (itPseudoNoteOnEvent) {
2060     // copy event
2061     *itPseudoNoteOnEvent = *itNoteOffEventOnKeyList;
2062     // transform event to a note on event
2063     itPseudoNoteOnEvent->Type = Event::type_note_on; //FIXME: should probably use Event::type_play_note instead (to avoid i.e. hanging notes)
2064     itPseudoNoteOnEvent->Param.Note.Key = i;
2065     itPseudoNoteOnEvent->Param.Note.Velocity = pOtherKey->Velocity;
2066     // assign a new note to this note-on event
2067 schoenebeck 3205 if (LaunchNewNote(pChannel, itPseudoNoteOnEvent)) {
2068 schoenebeck 2938 // allocate and trigger new voice(s) for the other key
2069     TriggerNewVoices(pChannel, itPseudoNoteOnEvent, false);
2070     }
2071     // if neither a voice was spawned or postponed then remove note on event from key again
2072     if (!pOtherKey->Active && !pOtherKey->VoiceTheftsQueued)
2073     pOtherKey->pEvents->free(itPseudoNoteOnEvent);
2074 iliev 2012
2075 schoenebeck 2938 } else dmsg(1,("Could not respawn voice, no free event left\n"));
2076     break; // done
2077     }
2078 iliev 2012 }
2079     }
2080 schoenebeck 2938 if (bOtherKeysPressed) {
2081     if (pKey->Active) { // kill all voices on this key
2082     bShouldRelease = false; // no need to release, as we kill it here
2083     for (NoteIterator itNote = pKey->pActiveNotes->first(); itNote; ++itNote) {
2084     VoiceIterator itVoiceToBeKilled = itNote->pActiveVoices->first();
2085     VoiceIterator end = itNote->pActiveVoices->end();
2086     for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
2087     if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))
2088     itVoiceToBeKilled->Kill(itNoteOffEventOnKeyList);
2089     }
2090 schoenebeck 2879 }
2091 iliev 2012 }
2092 schoenebeck 2938 } else pChannel->PortamentoPos = -1.0f;
2093     }
2094 iliev 2012
2095 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
2096     if (bShouldRelease) {
2097     itNoteOffEventOnKeyList->Type = Event::type_release_key; // transform event type
2098     // spawn release triggered voice(s) if needed
2099 schoenebeck 3444 if (pKey->ReleaseTrigger & release_trigger_noteoff)
2100     ProcessReleaseTrigger(pChannel, itNoteOffEventOnKeyList, pKey);
2101 schoenebeck 2938 }
2102     } else if (itNoteOffEventOnKeyList->Type == Event::type_stop_note) {
2103     // This programmatically caused event is caused by a call to
2104     // the built-in instrument script function note_off(). In
2105     // contrast to a real MIDI note-off event the stop-note
2106     // event just intends to release voices of one particular note.
2107     NoteBase* pNote = pChannel->pEngine->NoteByID( itNoteOffEventOnKeyList->Param.Note.ID );
2108     if (pNote) { // the requested note is still alive ...
2109     itNoteOffEventOnKeyList->Type = Event::type_release_note; // transform event type
2110     } else { // note is dead and gone ..
2111     pKey->pEvents->free(itNoteOffEventOnKeyList); // remove stop-note event from key again
2112     return; // prevent event to be removed a 2nd time below
2113     }
2114 iliev 2012 }
2115    
2116     // if neither a voice was spawned or postponed on this key then remove note off event from key again
2117     if (!pKey->Active && !pKey->VoiceTheftsQueued)
2118     pKey->pEvents->free(itNoteOffEventOnKeyList);
2119    
2120 schoenebeck 2938 if (isRealMIDINoteOffEvent)
2121     pChannel->listeners.PostProcessNoteOff(iKey, vel);
2122 iliev 2012 }
2123    
2124     /**
2125 schoenebeck 2927 * Called on sustain pedal up events to check and if required,
2126     * launch release trigger voices on the respective active key.
2127     *
2128     * @param pEngineChannel - engine channel on which this event occurred on
2129     * @param itEvent - release trigger event (contains note number)
2130     */
2131 schoenebeck 3444 virtual void ProcessReleaseTriggerBySustain(EngineChannel* pEngineChannel, RTList<Event>::Iterator& itEvent) OVERRIDE {
2132 schoenebeck 2927 EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
2133    
2134     const int iKey = itEvent->Param.Note.Key;
2135     if (iKey < 0 || iKey > 127) return; // ignore event, key outside allowed key range
2136    
2137     MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];
2138    
2139     ProcessReleaseTrigger(pChannel, itEvent, pKey);
2140     }
2141    
2142     /**
2143     * Called on note-off and sustain pedal up events to check and if
2144     * required, launch release trigger voices on the respective active
2145     * key.
2146     *
2147     * @param pEngineChannel - engine channel on which this event occurred on
2148     * @param itEvent - note off event / release trigger event
2149     * @param pKey - key on which the release trigger voices shall be spawned
2150     */
2151     inline void ProcessReleaseTrigger(EngineChannelBase<V, R, I>* pChannel, RTList<Event>::Iterator& itEvent, MidiKey* pKey) {
2152     // spawn release triggered voice(s) if needed
2153     if (pKey->ReleaseTrigger && pChannel->pInstrument) {
2154     // assign a new note to this release event
2155 schoenebeck 3205 if (LaunchNewNote(pChannel, itEvent)) {
2156 schoenebeck 2927 // allocate and trigger new release voice(s)
2157     TriggerReleaseVoices(pChannel, itEvent);
2158     }
2159 schoenebeck 3444 pKey->ReleaseTrigger = release_trigger_none;
2160 schoenebeck 2927 }
2161     }
2162    
2163     /**
2164 schoenebeck 3188 * Called on "kill note" events, which currently only happens on
2165     * built-in real-time instrument script function fade_out(). This
2166     * method only fulfills one task: moving the even to the Note's own
2167     * event list so that its voices can process the kill event sample
2168     * accurately.
2169     */
2170     void ProcessKillNote(EngineChannel* pEngineChannel, RTList<Event>::Iterator& itEvent) {
2171     EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
2172    
2173     NoteBase* pNote = pChannel->pEngine->NoteByID( itEvent->Param.Note.ID );
2174     if (!pNote || pNote->hostKey < 0 || pNote->hostKey >= 128) return;
2175    
2176     // move note kill event to its MIDI key
2177     MidiKey* pKey = &pChannel->pMIDIKeyInfo[pNote->hostKey];
2178     itEvent.moveToEndOf(pKey->pEvents);
2179     }
2180    
2181     /**
2182 schoenebeck 2931 * Called on note synthesis parameter change events. These are
2183     * internal events caused by calling built-in real-time instrument
2184 schoenebeck 3188 * script functions like change_vol(), change_tune(), etc.
2185 schoenebeck 2931 *
2186     * This method performs two tasks:
2187     *
2188     * - It converts the event's relative values changes (Deltas) to
2189     * the respective final new synthesis parameter value (AbsValue),
2190     * for that particular moment of the event that is.
2191     *
2192     * - It moves the individual events to the Note's own event list
2193     * (or actually to the event list of the MIDI key), so that
2194     * voices can process those events sample accurately.
2195     *
2196     * @param pEngineChannel - engine channel on which this event occurred on
2197     * @param itEvent - note synthesis parameter change event
2198     */
2199 persson 2952 virtual void ProcessNoteSynthParam(EngineChannel* pEngineChannel, RTList<Event>::Iterator& itEvent) {
2200 schoenebeck 2931 EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
2201    
2202     NoteBase* pNote = pChannel->pEngine->NoteByID( itEvent->Param.NoteSynthParam.NoteID );
2203     if (!pNote || pNote->hostKey < 0 || pNote->hostKey >= 128) return;
2204    
2205     switch (itEvent->Param.NoteSynthParam.Type) {
2206     case Event::synth_param_volume:
2207 schoenebeck 3561 pNote->apply(itEvent, &NoteBase::_Override::Volume);
2208 schoenebeck 2931 break;
2209 schoenebeck 3188 case Event::synth_param_volume_time:
2210     pNote->Override.VolumeTime = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2211     break;
2212 schoenebeck 3246 case Event::synth_param_volume_curve:
2213     itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2214     pNote->Override.VolumeCurve = (fade_curve_t) itEvent->Param.NoteSynthParam.AbsValue;
2215     break;
2216 schoenebeck 2931 case Event::synth_param_pitch:
2217 schoenebeck 3561 pNote->apply(itEvent, &NoteBase::_Override::Pitch);
2218 schoenebeck 2931 break;
2219 schoenebeck 3188 case Event::synth_param_pitch_time:
2220     pNote->Override.PitchTime = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2221     break;
2222 schoenebeck 3246 case Event::synth_param_pitch_curve:
2223     itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2224     pNote->Override.PitchCurve = (fade_curve_t) itEvent->Param.NoteSynthParam.AbsValue;
2225     break;
2226 schoenebeck 2931 case Event::synth_param_pan:
2227 schoenebeck 3561 pNote->apply(itEvent, &NoteBase::_Override::Pan);
2228 schoenebeck 2931 break;
2229 schoenebeck 3335 case Event::synth_param_pan_time:
2230     pNote->Override.PanTime = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2231     break;
2232     case Event::synth_param_pan_curve:
2233     itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2234     pNote->Override.PanCurve = (fade_curve_t) itEvent->Param.NoteSynthParam.AbsValue;
2235     break;
2236 schoenebeck 2935 case Event::synth_param_cutoff:
2237 schoenebeck 3561 pNote->apply(itEvent, &NoteBase::_Override::Cutoff);
2238 schoenebeck 2935 break;
2239     case Event::synth_param_resonance:
2240 schoenebeck 3561 pNote->apply(itEvent, &NoteBase::_Override::Resonance);
2241 schoenebeck 2935 break;
2242 schoenebeck 2953 case Event::synth_param_attack:
2243 schoenebeck 3561 pNote->apply(itEvent, &NoteBase::_Override::Attack);
2244 schoenebeck 2953 break;
2245     case Event::synth_param_decay:
2246 schoenebeck 3561 pNote->apply(itEvent, &NoteBase::_Override::Decay);
2247 schoenebeck 2953 break;
2248 schoenebeck 3316 case Event::synth_param_sustain:
2249 schoenebeck 3561 pNote->apply(itEvent, &NoteBase::_Override::Sustain);
2250 schoenebeck 3316 break;
2251 schoenebeck 2953 case Event::synth_param_release:
2252 schoenebeck 3561 pNote->apply(itEvent, &NoteBase::_Override::Release);
2253 schoenebeck 2953 break;
2254 schoenebeck 3360
2255     case Event::synth_param_cutoff_attack:
2256 schoenebeck 3561 pNote->apply(itEvent, &NoteBase::_Override::CutoffAttack);
2257 schoenebeck 3360 break;
2258     case Event::synth_param_cutoff_decay:
2259 schoenebeck 3561 pNote->apply(itEvent, &NoteBase::_Override::CutoffDecay);
2260 schoenebeck 3360 break;
2261     case Event::synth_param_cutoff_sustain:
2262 schoenebeck 3561 pNote->apply(itEvent, &NoteBase::_Override::CutoffSustain);
2263 schoenebeck 3360 break;
2264     case Event::synth_param_cutoff_release:
2265 schoenebeck 3561 pNote->apply(itEvent, &NoteBase::_Override::CutoffRelease);
2266 schoenebeck 3360 break;
2267    
2268 schoenebeck 3118 case Event::synth_param_amp_lfo_depth:
2269 schoenebeck 3561 pNote->apply(itEvent, &NoteBase::_Override::AmpLFODepth);
2270 schoenebeck 3118 break;
2271     case Event::synth_param_amp_lfo_freq:
2272 schoenebeck 3561 pNote->apply(itEvent, &NoteBase::_Override::AmpLFOFreq);
2273 schoenebeck 3118 break;
2274 schoenebeck 3360 case Event::synth_param_cutoff_lfo_depth:
2275 schoenebeck 3561 pNote->apply(itEvent, &NoteBase::_Override::CutoffLFODepth);
2276 schoenebeck 3360 break;
2277     case Event::synth_param_cutoff_lfo_freq:
2278 schoenebeck 3561 pNote->apply(itEvent, &NoteBase::_Override::CutoffLFOFreq);
2279 schoenebeck 3360 break;
2280 schoenebeck 3118 case Event::synth_param_pitch_lfo_depth:
2281 schoenebeck 3561 pNote->apply(itEvent, &NoteBase::_Override::PitchLFODepth);
2282 schoenebeck 3118 break;
2283     case Event::synth_param_pitch_lfo_freq:
2284 schoenebeck 3561 pNote->apply(itEvent, &NoteBase::_Override::PitchLFOFreq);
2285 schoenebeck 3118 break;
2286 schoenebeck 2931 }
2287    
2288     // move note parameter event to its MIDI key
2289     MidiKey* pKey = &pChannel->pMIDIKeyInfo[pNote->hostKey];
2290     itEvent.moveToEndOf(pKey->pEvents);
2291     }
2292    
2293     /**
2294 iliev 2012 * Reset all voices and disk thread and clear input event queue and all
2295     * control and status variables. This method is protected by a mutex.
2296     */
2297 schoenebeck 3054 virtual void ResetInternal() OVERRIDE {
2298 persson 2427 LockGuard lock(ResetInternalMutex);
2299 iliev 2012
2300     // make sure that the engine does not get any sysex messages
2301     // while it's reseting
2302     bool sysexDisabled = MidiInputPort::RemoveSysexListener(this);
2303     SetVoiceCount(0);
2304     ActiveVoiceCountMax = 0;
2305    
2306     // reset voice stealing parameters
2307     pVoiceStealingQueue->clear();
2308     itLastStolenVoice = VoiceIterator();
2309     itLastStolenVoiceGlobally = VoiceIterator();
2310 schoenebeck 2879 itLastStolenNote = NoteIterator();
2311     itLastStolenNoteGlobally = NoteIterator();
2312 iliev 2012 iuiLastStolenKey = RTList<uint>::Iterator();
2313     iuiLastStolenKeyGlobally = RTList<uint>::Iterator();
2314     pLastStolenChannel = NULL;
2315    
2316 schoenebeck 2879 // reset all notes
2317     pNotePool->clear();
2318     for (NoteIterator itNote = pNotePool->allocAppend(); itNote;
2319     itNote = pNotePool->allocAppend())
2320     {
2321     itNote->reset();
2322     }
2323     pNotePool->clear();
2324    
2325 iliev 2012 // reset all voices
2326 schoenebeck 2879 pVoicePool->clear();
2327 iliev 2012 for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
2328     iterVoice->Reset();
2329     }
2330     pVoicePool->clear();
2331    
2332 schoenebeck 2871 // reset all engine channels
2333     for (int i = 0; i < engineChannels.size(); i++) {
2334     AbstractEngineChannel* pEngineChannel =
2335     static_cast<AbstractEngineChannel*>(engineChannels[i]);
2336     pEngineChannel->ResetInternal(false/*don't reset engine*/);
2337     }
2338    
2339 iliev 2012 // reset disk thread
2340     if (pDiskThread) pDiskThread->Reset();
2341    
2342     // delete all input events
2343     pEventQueue->init();
2344     pSysexBuffer->init();
2345     if (sysexDisabled) MidiInputPort::AddSysexListener(this);
2346     }
2347    
2348     /**
2349     * Kills all voices on an engine channel as soon as possible. Voices
2350     * won't get into release state, their volume level will be ramped down
2351     * as fast as possible.
2352     *
2353     * @param pEngineChannel - engine channel on which all voices should be killed
2354     * @param itKillEvent - event which caused this killing of all voices
2355     */
2356 schoenebeck 3054 virtual void KillAllVoices(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itKillEvent) OVERRIDE {
2357 iliev 2012 EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
2358     int count = pChannel->KillAllVoices(itKillEvent);
2359     VoiceSpawnsLeft -= count; //FIXME: just a temporary workaround, we should check the cause in StealVoice() instead
2360     }
2361    
2362     /**
2363     * Allocates and triggers a new voice. This method will usually be
2364     * called by the ProcessNoteOn() method and by the voices itself
2365     * (e.g. to spawn further voices on the same key for layered sounds).
2366     *
2367 schoenebeck 2871 * @param pEngineChannel - engine channel on which this event occurred on
2368 iliev 2012 * @param itNoteOnEvent - key, velocity and time stamp of the event
2369     * @param iLayer - layer index for the new voice (optional - only
2370     * in case of layered sounds of course)
2371     * @param ReleaseTriggerVoice - if new voice is a release triggered voice
2372     * (optional, default = false)
2373     * @param VoiceStealing - if voice stealing should be performed
2374     * when there is no free voice
2375     * (optional, default = true)
2376     * @param HandleKeyGroupConflicts - if voices should be killed due to a
2377     * key group conflict
2378     * @returns pointer to new voice or NULL if there was no free voice or
2379     * if the voice wasn't triggered (for example when no region is
2380     * defined for the given key).
2381     */
2382     virtual PoolVoiceIterator LaunchVoice (
2383     EngineChannel* pEngineChannel,
2384     Pool<Event>::Iterator& itNoteOnEvent,
2385     int iLayer,
2386     bool ReleaseTriggerVoice,
2387     bool VoiceStealing,
2388     bool HandleKeyGroupConflicts
2389     ) = 0;
2390    
2391 schoenebeck 3054 virtual int GetMinFadeOutSamples() OVERRIDE { return MinFadeOutSamples; }
2392 iliev 2015
2393 iliev 2027 int InitNewVoice (
2394     EngineChannelBase<V, R, I>* pChannel,
2395     R* pRegion,
2396     Pool<Event>::Iterator& itNoteOnEvent,
2397     Voice::type_t VoiceType,
2398     int iLayer,
2399     int iKeyGroup,
2400     bool ReleaseTriggerVoice,
2401     bool VoiceStealing,
2402     typename Pool<V>::Iterator& itNewVoice
2403     ) {
2404     int key = itNoteOnEvent->Param.Note.Key;
2405     typename MidiKeyboardManager<V>::MidiKey* pKey = &pChannel->pMIDIKeyInfo[key];
2406     if (itNewVoice) {
2407     // launch the new voice
2408     if (itNewVoice->Trigger(pChannel, itNoteOnEvent, pChannel->Pitch, pRegion, VoiceType, iKeyGroup) < 0) {
2409     dmsg(4,("Voice not triggered\n"));
2410 schoenebeck 2879 GetVoicePool()->free(itNewVoice);
2411 iliev 2027 }
2412     else { // on success
2413     --VoiceSpawnsLeft;
2414 schoenebeck 3306
2415     // should actually be superfluous now, since this is
2416     // already done in LaunchNewNote()
2417     pChannel->markKeyAsActive(pKey);
2418    
2419 schoenebeck 3444 if (itNewVoice->Type & Voice::type_release_trigger_required)
2420     pKey->ReleaseTrigger |= itNewVoice->GetReleaseTriggerFlags(); // mark key for the need of release triggered voice(s)
2421 iliev 2027 return 0; // success
2422     }
2423     }
2424     else if (VoiceStealing) {
2425     // try to steal one voice
2426     int result = StealVoice(pChannel, itNoteOnEvent);
2427     if (!result) { // voice stolen successfully
2428     // put note-on event into voice-stealing queue, so it will be reprocessed after killed voice died
2429     RTList<Event>::Iterator itStealEvent = pVoiceStealingQueue->allocAppend();
2430     if (itStealEvent) {
2431     *itStealEvent = *itNoteOnEvent; // copy event
2432     itStealEvent->Param.Note.Layer = iLayer;
2433     itStealEvent->Param.Note.ReleaseTrigger = ReleaseTriggerVoice;
2434     pKey->VoiceTheftsQueued++;
2435     }
2436     else dmsg(1,("Voice stealing queue full!\n"));
2437     }
2438     }
2439    
2440     return -1;
2441     }
2442 schoenebeck 2448
2443     /**
2444     * Checks whether scale tuning setting has been changed since last
2445     * time this method was called, if yes, it recalculates the pitch
2446     * for all active voices.
2447     */
2448     void ProcessScaleTuningChange() {
2449     const bool changed = ScaleTuningChanged.readAndReset();
2450     if (!changed) return;
2451    
2452     for (int i = 0; i < engineChannels.size(); i++) {
2453     EngineChannelBase<V, R, I>* channel =
2454     static_cast<EngineChannelBase<V, R, I>*>(engineChannels[i]);
2455     channel->OnScaleTuningChanged();
2456     }
2457     }
2458 iliev 2027
2459 iliev 2012 private:
2460 schoenebeck 2879 Pool< Note<V> >* pNotePool;
2461     Pool<note_id_t> noteIDPool;
2462 iliev 2012 Pool<V>* pVoicePool; ///< Contains all voices that can be activated.
2463     Pool<RR*> SuspendedRegions;
2464     Mutex SuspendedRegionsMutex;
2465     Condition SuspensionChangeOngoing;
2466     RR* pPendingRegionSuspension;
2467     RR* pPendingRegionResumption;
2468     int iPendingStreamDeletions;
2469     };
2470    
2471     template <class V, class RR, class R, class D, class IM, class I>
2472     IM EngineBase<V, RR, R, D, IM, I>::instruments;
2473    
2474     } // namespace LinuxSampler
2475    
2476     #endif /* __LS_ENGINEBASE_H__ */
2477    

  ViewVC Help
Powered by ViewVC