/[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 3188 - (hide annotations) (download) (as text)
Fri May 19 14:23:12 2017 UTC (6 years, 11 months ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 123726 byte(s)
* NKSP: Implemented built-in script function "change_vol_time()".
* NKSP: Implemented built-in script function "change_tune_time()".
* NKSP: Implemented built-in script function "fade_in()".
* NKSP: Implemented built-in script function "fade_out()".
* NKSP: Fixed acceptance of wrong data type of parameters passed to
  built-in script functions "change_vol()", "change_tune()",
  "change_pan()", "change_cutoff()", "change_reso()",
  "change_attack()", "change_decay()", "change_release()",
  "change_amp_lfo_depth()", "change_amp_lfo_freq()",
  "change_pitch_lfo_depth()" and "change_pitch_lfo_freq()".
* Bumped version (2.0.0.svn45).

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

  ViewVC Help
Powered by ViewVC