/[svn]/linuxsampler/trunk/src/engines/EngineBase.h
ViewVC logotype

Contents of /linuxsampler/trunk/src/engines/EngineBase.h

Parent Directory Parent Directory | Revision Log Revision Log


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

* Bumped version (2.1.1.svn64).

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

  ViewVC Help
Powered by ViewVC