/[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 3854 - (show annotations) (download) (as text)
Mon Feb 1 17:37:52 2021 UTC (3 years, 2 months ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 151840 byte(s)
* Fixed crash on certain MIDI RPN and NRPN messages that occurred if no
  real-time instrument script was loaded.

* Bumped version (2.1.1.svn71).

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

  ViewVC Help
Powered by ViewVC