/[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 3691 - (show annotations) (download) (as text)
Fri Jan 3 12:35:20 2020 UTC (4 years, 2 months ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 137668 byte(s)
* NKSP: Implemented built-in script function "set_rpn()".

* NKSP: Implemented built-in script function "set_nrpn()".

* Bumped version (2.1.1.svn31).

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

  ViewVC Help
Powered by ViewVC