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

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

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

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

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

* Bumped version (2.1.1.svn30).

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

  ViewVC Help
Powered by ViewVC