/[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 3444 - (show annotations) (download) (as text)
Sun Dec 23 19:32:11 2018 UTC (10 months, 3 weeks ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 129684 byte(s)
* Only play release trigger samples on sustain pedal up if this behaviour
  was explicitly requested by the instrument (otherwise only on note-off).
* Bumped version (2.1.0.svn2).

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 (currently only used for RPN and NRPN controllers)
1488 //dmsg(1,("DATA ENTRY %d\n", itControlChangeEvent->Param.CC.Value));
1489 if (pChannel->GetMidiRpnController() >= 0) { // RPN controller number was sent previously ...
1490 dmsg(4,("Guess it's an RPN ...\n"));
1491 if (pChannel->GetMidiRpnController() == 2) { // coarse tuning in half tones
1492 int transpose = (int) itControlChangeEvent->Param.CC.Value - 64;
1493 // limit to +- two octaves for now
1494 transpose = RTMath::Min(transpose, 24);
1495 transpose = RTMath::Max(transpose, -24);
1496 pChannel->GlobalTranspose = transpose;
1497 // workaround, so we won't have hanging notes
1498 pChannel->ReleaseAllVoices(itControlChangeEvent);
1499 }
1500 // to prevent other MIDI CC #6 messages to be misenterpreted as RPN controller data
1501 pChannel->ResetMidiRpnController();
1502 } else if (pChannel->GetMidiNrpnController() >= 0) { // NRPN controller number was sent previously ...
1503 dmsg(4,("Guess it's an NRPN ...\n"));
1504 const int NrpnCtrlMSB = pChannel->GetMidiNrpnController() >> 8;
1505 const int NrpnCtrlLSB = pChannel->GetMidiNrpnController() & 0xff;
1506 dmsg(4,("NRPN MSB=%d LSB=%d Data=%d\n", NrpnCtrlMSB, NrpnCtrlLSB, itControlChangeEvent->Param.CC.Value));
1507 switch (NrpnCtrlMSB) {
1508 case 0x1a: { // volume level of note (Roland GS NRPN)
1509 const uint note = NrpnCtrlLSB;
1510 const uint vol = itControlChangeEvent->Param.CC.Value;
1511 dmsg(4,("Note Volume NRPN received (note=%d,vol=%d).\n", note, vol));
1512 if (note < 128 && vol < 128)
1513 pChannel->pMIDIKeyInfo[note].Volume = VolumeCurve[vol];
1514 break;
1515 }
1516 case 0x1c: { // panpot of note (Roland GS NRPN)
1517 const uint note = NrpnCtrlLSB;
1518 const uint pan = itControlChangeEvent->Param.CC.Value;
1519 dmsg(4,("Note Pan NRPN received (note=%d,pan=%d).\n", note, pan));
1520 if (note < 128 && pan < 128) {
1521 pChannel->pMIDIKeyInfo[note].PanLeft = PanCurve[128 - pan];
1522 pChannel->pMIDIKeyInfo[note].PanRight = PanCurve[pan];
1523 }
1524 break;
1525 }
1526 case 0x1d: { // reverb send of note (Roland GS NRPN)
1527 const uint note = NrpnCtrlLSB;
1528 const float reverb = float(itControlChangeEvent->Param.CC.Value) / 127.0f;
1529 dmsg(4,("Note Reverb Send NRPN received (note=%d,send=%f).\n", note, reverb));
1530 if (note < 128)
1531 pChannel->pMIDIKeyInfo[note].ReverbSend = reverb;
1532 break;
1533 }
1534 case 0x1e: { // chorus send of note (Roland GS NRPN)
1535 const uint note = NrpnCtrlLSB;
1536 const float chorus = float(itControlChangeEvent->Param.CC.Value) / 127.0f;
1537 dmsg(4,("Note Chorus Send NRPN received (note=%d,send=%f).\n", note, chorus));
1538 if (note < 128)
1539 pChannel->pMIDIKeyInfo[note].ChorusSend = chorus;
1540 break;
1541 }
1542 }
1543 // to prevent other MIDI CC #6 messages to be misenterpreted as NRPN controller data
1544 pChannel->ResetMidiNrpnController();
1545 }
1546 break;
1547 }
1548 case 7: { // volume
1549 //TODO: not sample accurate yet
1550 pChannel->MidiVolume = VolumeCurve[itControlChangeEvent->Param.CC.Value];
1551 pChannel->bStatusChanged = true; // engine channel status has changed, so set notify flag
1552 break;
1553 }
1554 case 10: { // panpot
1555 //TODO: not sample accurate yet
1556 pChannel->iLastPanRequest = itControlChangeEvent->Param.CC.Value;
1557 break;
1558 }
1559 case 64: { // sustain
1560 if (itControlChangeEvent->Param.CC.Value >= 64 && !pChannel->SustainPedal) {
1561 dmsg(4,("DAMPER (RIGHT) PEDAL DOWN\n"));
1562 pChannel->SustainPedal = true;
1563 pChannel->listeners.PreProcessSustainPedalDown();
1564
1565 #if !CONFIG_PROCESS_MUTED_CHANNELS
1566 if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
1567 pChannel->listeners.PostProcessSustainPedalDown();
1568 return;
1569 }
1570 #endif
1571
1572 pChannel->ProcessSustainPedalDown(itControlChangeEvent);
1573 pChannel->listeners.PostProcessSustainPedalDown();
1574 }
1575 if (itControlChangeEvent->Param.CC.Value < 64 && pChannel->SustainPedal) {
1576 dmsg(4,("DAMPER (RIGHT) PEDAL UP\n"));
1577 pChannel->SustainPedal = false;
1578 pChannel->listeners.PreProcessSustainPedalUp();
1579
1580 #if !CONFIG_PROCESS_MUTED_CHANNELS
1581 if (pChannel->GetMute()) { // skip if sampler channel is muted
1582 pChannel->listeners.PostProcessSustainPedalUp();
1583 return;
1584 }
1585 #endif
1586
1587 pChannel->ProcessSustainPedalUp(itControlChangeEvent);
1588 pChannel->listeners.PostProcessSustainPedalUp();
1589 }
1590 break;
1591 }
1592 case 65: { // portamento on / off
1593 const bool bPortamento = itControlChangeEvent->Param.CC.Value >= 64;
1594 if (bPortamento != pChannel->PortamentoMode)
1595 KillAllVoices(pChannel, itControlChangeEvent);
1596 pChannel->PortamentoMode = bPortamento;
1597 break;
1598 }
1599 case 66: { // sostenuto
1600 if (itControlChangeEvent->Param.CC.Value >= 64 && !pChannel->SostenutoPedal) {
1601 dmsg(4,("SOSTENUTO (CENTER) PEDAL DOWN\n"));
1602 pChannel->SostenutoPedal = true;
1603 pChannel->listeners.PreProcessSostenutoPedalDown();
1604
1605 #if !CONFIG_PROCESS_MUTED_CHANNELS
1606 if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
1607 pChannel->listeners.PostProcessSostenutoPedalDown();
1608 return;
1609 }
1610 #endif
1611
1612 pChannel->ProcessSostenutoPedalDown();
1613 pChannel->listeners.PostProcessSostenutoPedalDown();
1614 }
1615 if (itControlChangeEvent->Param.CC.Value < 64 && pChannel->SostenutoPedal) {
1616 dmsg(4,("SOSTENUTO (CENTER) PEDAL UP\n"));
1617 pChannel->SostenutoPedal = false;
1618 pChannel->listeners.PreProcessSostenutoPedalUp();
1619
1620 #if !CONFIG_PROCESS_MUTED_CHANNELS
1621 if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
1622 pChannel->listeners.PostProcessSostenutoPedalUp();
1623 return;
1624 }
1625 #endif
1626
1627 pChannel->ProcessSostenutoPedalUp(itControlChangeEvent);
1628 pChannel->listeners.PostProcessSostenutoPedalUp();
1629 }
1630 break;
1631 }
1632 case 98: { // NRPN controller LSB
1633 dmsg(4,("NRPN LSB %d\n", itControlChangeEvent->Param.CC.Value));
1634 pEngineChannel->SetMidiNrpnControllerLsb(itControlChangeEvent->Param.CC.Value);
1635 break;
1636 }
1637 case 99: { // NRPN controller MSB
1638 dmsg(4,("NRPN MSB %d\n", itControlChangeEvent->Param.CC.Value));
1639 pEngineChannel->SetMidiNrpnControllerMsb(itControlChangeEvent->Param.CC.Value);
1640 break;
1641 }
1642 case 100: { // RPN controller LSB
1643 dmsg(4,("RPN LSB %d\n", itControlChangeEvent->Param.CC.Value));
1644 pEngineChannel->SetMidiRpnControllerLsb(itControlChangeEvent->Param.CC.Value);
1645 break;
1646 }
1647 case 101: { // RPN controller MSB
1648 dmsg(4,("RPN MSB %d\n", itControlChangeEvent->Param.CC.Value));
1649 pEngineChannel->SetMidiRpnControllerMsb(itControlChangeEvent->Param.CC.Value);
1650 break;
1651 }
1652
1653
1654 // Channel Mode Messages
1655
1656 case 120: { // all sound off
1657 KillAllVoices(pEngineChannel, itControlChangeEvent);
1658 break;
1659 }
1660 case 121: { // reset all controllers
1661 pChannel->ResetControllers();
1662 break;
1663 }
1664 case 123: { // all notes off
1665 #if CONFIG_PROCESS_ALL_NOTES_OFF
1666 pChannel->ReleaseAllVoices(itControlChangeEvent);
1667 #endif // CONFIG_PROCESS_ALL_NOTES_OFF
1668 break;
1669 }
1670 case 126: { // mono mode on
1671 if (!pChannel->SoloMode)
1672 KillAllVoices(pEngineChannel, itControlChangeEvent);
1673 pChannel->SoloMode = true;
1674 break;
1675 }
1676 case 127: { // poly mode on
1677 if (pChannel->SoloMode)
1678 KillAllVoices(pEngineChannel, itControlChangeEvent);
1679 pChannel->SoloMode = false;
1680 break;
1681 }
1682 }
1683 }
1684
1685 virtual D* CreateDiskThread() = 0;
1686
1687 /**
1688 * Assigns and triggers a new voice for the respective MIDI key.
1689 *
1690 * @param pEngineChannel - engine channel on which this event occurred on
1691 * @param itNoteOnEvent - key, velocity and time stamp of the event
1692 */
1693 virtual void ProcessNoteOn(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) OVERRIDE {
1694 EngineChannelBase<V, R, I>* pChannel =
1695 static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1696
1697 const int key = itNoteOnEvent->Param.Note.Key;
1698 const int vel = itNoteOnEvent->Param.Note.Velocity;
1699 if (key < 0 || key > 127) return; // ignore event, key outside allowed key range
1700
1701 MidiKey* pKey = &pChannel->pMIDIKeyInfo[key];
1702
1703 // There are real MIDI note-on events (Event::type_note_on) and
1704 // programmatically spawned notes (Event::type_play_note). We have
1705 // to distinguish between them, since certain processing below
1706 // must only be done on real MIDI note-on events (i.e. for
1707 // correctly updating which MIDI keys are currently pressed down).
1708 const bool isRealMIDINoteOnEvent = itNoteOnEvent->Type == Event::type_note_on;
1709
1710 if (isRealMIDINoteOnEvent)
1711 pChannel->listeners.PreProcessNoteOn(key, vel);
1712
1713 #if !CONFIG_PROCESS_MUTED_CHANNELS
1714 if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
1715 if (isRealMIDINoteOnEvent)
1716 pChannel->listeners.PostProcessNoteOn(key, vel);
1717 return;
1718 }
1719 #endif
1720
1721 if (!pChannel->pInstrument) {
1722 if (isRealMIDINoteOnEvent)
1723 pChannel->listeners.PostProcessNoteOn(key, vel);
1724 return; // ignore if no instrument loaded
1725 }
1726
1727 // move note on event to the key's own event list
1728 RTList<Event>::Iterator itNoteOnEventOnKeyList = itNoteOnEvent.moveToEndOf(pKey->pEvents);
1729
1730 // if Solo Mode then kill all already active voices
1731 if (pChannel->SoloMode && isRealMIDINoteOnEvent) {
1732 Pool<uint>::Iterator itYoungestKey = pChannel->pActiveKeys->last();
1733 if (itYoungestKey) {
1734 const int iYoungestKey = *itYoungestKey;
1735 const MidiKey* pOtherKey = &pChannel->pMIDIKeyInfo[iYoungestKey];
1736 if (pOtherKey->Active) {
1737 // get final portamento position of currently active voice
1738 if (pChannel->PortamentoMode) {
1739 NoteIterator itNote = pOtherKey->pActiveNotes->last();
1740 if (itNote) {
1741 VoiceIterator itVoice = itNote->pActiveVoices->last();
1742 if (itVoice) itVoice->UpdatePortamentoPos(itNoteOnEventOnKeyList);
1743 }
1744 }
1745 // kill all voices on the (other) key
1746 for (NoteIterator itNote = pOtherKey->pActiveNotes->first(); itNote; ++itNote) {
1747 VoiceIterator itVoiceToBeKilled = itNote->pActiveVoices->first();
1748 VoiceIterator end = itNote->pActiveVoices->end();
1749 for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1750 if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))
1751 itVoiceToBeKilled->Kill(itNoteOnEventOnKeyList);
1752 }
1753 }
1754 }
1755 }
1756 // set this key as 'currently active solo key'
1757 pChannel->SoloKey = key;
1758 }
1759
1760 if (isRealMIDINoteOnEvent) {
1761 pChannel->ProcessKeySwitchChange(key);
1762
1763 pKey->KeyPressed = true; // the MIDI key was now pressed down
1764 pChannel->KeyDown[key] = true; // just used as built-in %KEY_DOWN script variable
1765 pKey->Velocity = itNoteOnEventOnKeyList->Param.Note.Velocity;
1766 pKey->NoteOnTime = FrameTime + itNoteOnEventOnKeyList->FragmentPos(); // will be used to calculate note length
1767 }
1768
1769 // cancel release process of voices on this key if needed
1770 if (pKey->Active && !pChannel->SustainPedal && isRealMIDINoteOnEvent) {
1771 RTList<Event>::Iterator itCancelReleaseEvent = pKey->pEvents->allocAppend();
1772 if (itCancelReleaseEvent) {
1773 *itCancelReleaseEvent = *itNoteOnEventOnKeyList; // copy event
1774 itCancelReleaseEvent->Type = Event::type_cancel_release_key; // transform event type
1775 }
1776 else dmsg(1,("Event pool emtpy!\n"));
1777 }
1778
1779 TriggerNewVoices(pEngineChannel, itNoteOnEventOnKeyList);
1780
1781 // if neither a voice was spawned or postponed then remove note on event from key again
1782 if (!pKey->Active && !pKey->VoiceTheftsQueued)
1783 pKey->pEvents->free(itNoteOnEventOnKeyList);
1784
1785 if (isRealMIDINoteOnEvent && (!pChannel->SoloMode || pChannel->PortamentoPos < 0.0f))
1786 pChannel->PortamentoPos = (float) key;
1787
1788 //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?
1789 if (pKey->pRoundRobinIndex) {
1790 (*pKey->pRoundRobinIndex)++; // counter specific for the key or region
1791 pChannel->RoundRobinIndex++; // common counter for the channel
1792 }
1793
1794 if (isRealMIDINoteOnEvent)
1795 pChannel->listeners.PostProcessNoteOn(key, vel);
1796 }
1797
1798 /**
1799 * Allocate and trigger new voice(s) for the key.
1800 */
1801 virtual void TriggerNewVoices (
1802 EngineChannel* pEngineChannel,
1803 RTList<Event>::Iterator& itNoteOnEvent,
1804 bool HandleKeyGroupConflicts = true
1805 ) = 0;
1806
1807 /**
1808 * Allocate and trigger release voice(s) for the key.
1809 */
1810 virtual void TriggerReleaseVoices (
1811 EngineChannel* pEngineChannel,
1812 RTList<Event>::Iterator& itNoteOffEvent
1813 ) = 0;
1814
1815 /**
1816 * Releases the voices on the given key if sustain pedal is not pressed.
1817 * If sustain is pressed, the release of the note will be postponed until
1818 * sustain pedal will be released or voice turned inactive by itself (e.g.
1819 * due to completion of sample playback).
1820 *
1821 * @param pEngineChannel - engine channel on which this event occurred on
1822 * @param itNoteOffEvent - key, velocity and time stamp of the event
1823 */
1824 virtual void ProcessNoteOff(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOffEvent) OVERRIDE {
1825 EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1826
1827 const int iKey = itNoteOffEvent->Param.Note.Key;
1828 const int vel = itNoteOffEvent->Param.Note.Velocity;
1829 if (iKey < 0 || iKey > 127) return; // ignore event, key outside allowed key range
1830
1831 MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];
1832
1833 // There are real MIDI note-off events (Event::type_note_off) and
1834 // programmatically spawned notes (Event::type_stop_note). We have
1835 // to distinguish between them, since certain processing below
1836 // must only be done on real MIDI note-off events (i.e. for
1837 // correctly updating which MIDI keys are currently pressed down),
1838 // plus a stop-note event just releases voices of one particular
1839 // note, whereas a note-off event releases all voices on a
1840 // particular MIDI key instead.
1841 const bool isRealMIDINoteOffEvent = itNoteOffEvent->Type == Event::type_note_off;
1842
1843 if (isRealMIDINoteOffEvent)
1844 pChannel->listeners.PreProcessNoteOff(iKey, vel);
1845
1846 #if !CONFIG_PROCESS_MUTED_CHANNELS
1847 if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
1848 if (isRealMIDINoteOffEvent)
1849 pChannel->listeners.PostProcessNoteOff(iKey, vel);
1850 return;
1851 }
1852 #endif
1853
1854 if (isRealMIDINoteOffEvent) {
1855 pKey->KeyPressed = false; // the MIDI key was now released
1856 pChannel->KeyDown[iKey] = false; // just used as built-in %KEY_DOWN script variable
1857 }
1858
1859 // move event to the key's own event list
1860 RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);
1861
1862 if (isRealMIDINoteOffEvent) {
1863 bool bShouldRelease = pKey->Active && pChannel->ShouldReleaseVoice(itNoteOffEventOnKeyList->Param.Note.Key);
1864
1865 // in case Solo Mode is enabled, kill all voices on this key and respawn a voice on the highest pressed key (if any)
1866 if (pChannel->SoloMode && pChannel->pInstrument) { //TODO: this feels like too much code just for handling solo mode :P
1867 bool bOtherKeysPressed = false;
1868 if (iKey == pChannel->SoloKey) {
1869 pChannel->SoloKey = -1;
1870 // if there's still a key pressed down, respawn a voice (group) on the highest key
1871 for (int i = 127; i > 0; i--) {
1872 MidiKey* pOtherKey = &pChannel->pMIDIKeyInfo[i];
1873 if (pOtherKey->KeyPressed) {
1874 bOtherKeysPressed = true;
1875 // make the other key the new 'currently active solo key'
1876 pChannel->SoloKey = i;
1877 // get final portamento position of currently active voice
1878 if (pChannel->PortamentoMode) {
1879 NoteIterator itNote = pKey->pActiveNotes->first();
1880 VoiceIterator itVoice = itNote->pActiveVoices->first();
1881 if (itVoice) itVoice->UpdatePortamentoPos(itNoteOffEventOnKeyList);
1882 }
1883 // create a pseudo note on event
1884 RTList<Event>::Iterator itPseudoNoteOnEvent = pOtherKey->pEvents->allocAppend();
1885 if (itPseudoNoteOnEvent) {
1886 // copy event
1887 *itPseudoNoteOnEvent = *itNoteOffEventOnKeyList;
1888 // transform event to a note on event
1889 itPseudoNoteOnEvent->Type = Event::type_note_on; //FIXME: should probably use Event::type_play_note instead (to avoid i.e. hanging notes)
1890 itPseudoNoteOnEvent->Param.Note.Key = i;
1891 itPseudoNoteOnEvent->Param.Note.Velocity = pOtherKey->Velocity;
1892 // assign a new note to this note-on event
1893 if (LaunchNewNote(pChannel, itPseudoNoteOnEvent)) {
1894 // allocate and trigger new voice(s) for the other key
1895 TriggerNewVoices(pChannel, itPseudoNoteOnEvent, false);
1896 }
1897 // if neither a voice was spawned or postponed then remove note on event from key again
1898 if (!pOtherKey->Active && !pOtherKey->VoiceTheftsQueued)
1899 pOtherKey->pEvents->free(itPseudoNoteOnEvent);
1900
1901 } else dmsg(1,("Could not respawn voice, no free event left\n"));
1902 break; // done
1903 }
1904 }
1905 }
1906 if (bOtherKeysPressed) {
1907 if (pKey->Active) { // kill all voices on this key
1908 bShouldRelease = false; // no need to release, as we kill it here
1909 for (NoteIterator itNote = pKey->pActiveNotes->first(); itNote; ++itNote) {
1910 VoiceIterator itVoiceToBeKilled = itNote->pActiveVoices->first();
1911 VoiceIterator end = itNote->pActiveVoices->end();
1912 for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1913 if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))
1914 itVoiceToBeKilled->Kill(itNoteOffEventOnKeyList);
1915 }
1916 }
1917 }
1918 } else pChannel->PortamentoPos = -1.0f;
1919 }
1920
1921 // if no solo mode (the usual case) or if solo mode and no other key pressed, then release voices on this key if needed
1922 if (bShouldRelease) {
1923 itNoteOffEventOnKeyList->Type = Event::type_release_key; // transform event type
1924 // spawn release triggered voice(s) if needed
1925 if (pKey->ReleaseTrigger & release_trigger_noteoff)
1926 ProcessReleaseTrigger(pChannel, itNoteOffEventOnKeyList, pKey);
1927 }
1928 } else if (itNoteOffEventOnKeyList->Type == Event::type_stop_note) {
1929 // This programmatically caused event is caused by a call to
1930 // the built-in instrument script function note_off(). In
1931 // contrast to a real MIDI note-off event the stop-note
1932 // event just intends to release voices of one particular note.
1933 NoteBase* pNote = pChannel->pEngine->NoteByID( itNoteOffEventOnKeyList->Param.Note.ID );
1934 if (pNote) { // the requested note is still alive ...
1935 itNoteOffEventOnKeyList->Type = Event::type_release_note; // transform event type
1936 } else { // note is dead and gone ..
1937 pKey->pEvents->free(itNoteOffEventOnKeyList); // remove stop-note event from key again
1938 return; // prevent event to be removed a 2nd time below
1939 }
1940 }
1941
1942 // if neither a voice was spawned or postponed on this key then remove note off event from key again
1943 if (!pKey->Active && !pKey->VoiceTheftsQueued)
1944 pKey->pEvents->free(itNoteOffEventOnKeyList);
1945
1946 if (isRealMIDINoteOffEvent)
1947 pChannel->listeners.PostProcessNoteOff(iKey, vel);
1948 }
1949
1950 /**
1951 * Called on sustain pedal up events to check and if required,
1952 * launch release trigger voices on the respective active key.
1953 *
1954 * @param pEngineChannel - engine channel on which this event occurred on
1955 * @param itEvent - release trigger event (contains note number)
1956 */
1957 virtual void ProcessReleaseTriggerBySustain(EngineChannel* pEngineChannel, RTList<Event>::Iterator& itEvent) OVERRIDE {
1958 EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1959
1960 const int iKey = itEvent->Param.Note.Key;
1961 if (iKey < 0 || iKey > 127) return; // ignore event, key outside allowed key range
1962
1963 MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];
1964
1965 ProcessReleaseTrigger(pChannel, itEvent, pKey);
1966 }
1967
1968 /**
1969 * Called on note-off and sustain pedal up events to check and if
1970 * required, launch release trigger voices on the respective active
1971 * key.
1972 *
1973 * @param pEngineChannel - engine channel on which this event occurred on
1974 * @param itEvent - note off event / release trigger event
1975 * @param pKey - key on which the release trigger voices shall be spawned
1976 */
1977 inline void ProcessReleaseTrigger(EngineChannelBase<V, R, I>* pChannel, RTList<Event>::Iterator& itEvent, MidiKey* pKey) {
1978 // spawn release triggered voice(s) if needed
1979 if (pKey->ReleaseTrigger && pChannel->pInstrument) {
1980 // assign a new note to this release event
1981 if (LaunchNewNote(pChannel, itEvent)) {
1982 // allocate and trigger new release voice(s)
1983 TriggerReleaseVoices(pChannel, itEvent);
1984 }
1985 pKey->ReleaseTrigger = release_trigger_none;
1986 }
1987 }
1988
1989 /**
1990 * Called on "kill note" events, which currently only happens on
1991 * built-in real-time instrument script function fade_out(). This
1992 * method only fulfills one task: moving the even to the Note's own
1993 * event list so that its voices can process the kill event sample
1994 * accurately.
1995 */
1996 void ProcessKillNote(EngineChannel* pEngineChannel, RTList<Event>::Iterator& itEvent) {
1997 EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1998
1999 NoteBase* pNote = pChannel->pEngine->NoteByID( itEvent->Param.Note.ID );
2000 if (!pNote || pNote->hostKey < 0 || pNote->hostKey >= 128) return;
2001
2002 // move note kill event to its MIDI key
2003 MidiKey* pKey = &pChannel->pMIDIKeyInfo[pNote->hostKey];
2004 itEvent.moveToEndOf(pKey->pEvents);
2005 }
2006
2007 /**
2008 * Called on note synthesis parameter change events. These are
2009 * internal events caused by calling built-in real-time instrument
2010 * script functions like change_vol(), change_tune(), etc.
2011 *
2012 * This method performs two tasks:
2013 *
2014 * - It converts the event's relative values changes (Deltas) to
2015 * the respective final new synthesis parameter value (AbsValue),
2016 * for that particular moment of the event that is.
2017 *
2018 * - It moves the individual events to the Note's own event list
2019 * (or actually to the event list of the MIDI key), so that
2020 * voices can process those events sample accurately.
2021 *
2022 * @param pEngineChannel - engine channel on which this event occurred on
2023 * @param itEvent - note synthesis parameter change event
2024 */
2025 virtual void ProcessNoteSynthParam(EngineChannel* pEngineChannel, RTList<Event>::Iterator& itEvent) {
2026 EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
2027
2028 NoteBase* pNote = pChannel->pEngine->NoteByID( itEvent->Param.NoteSynthParam.NoteID );
2029 if (!pNote || pNote->hostKey < 0 || pNote->hostKey >= 128) return;
2030
2031 const bool& relative = itEvent->Param.NoteSynthParam.Relative;
2032
2033 switch (itEvent->Param.NoteSynthParam.Type) {
2034 case Event::synth_param_volume:
2035 if (relative)
2036 pNote->Override.Volume *= itEvent->Param.NoteSynthParam.Delta;
2037 else
2038 pNote->Override.Volume = itEvent->Param.NoteSynthParam.Delta;
2039 itEvent->Param.NoteSynthParam.AbsValue = pNote->Override.Volume;
2040 break;
2041 case Event::synth_param_volume_time:
2042 pNote->Override.VolumeTime = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2043 break;
2044 case Event::synth_param_volume_curve:
2045 itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2046 pNote->Override.VolumeCurve = (fade_curve_t) itEvent->Param.NoteSynthParam.AbsValue;
2047 break;
2048 case Event::synth_param_pitch:
2049 if (relative)
2050 pNote->Override.Pitch *= itEvent->Param.NoteSynthParam.Delta;
2051 else
2052 pNote->Override.Pitch = itEvent->Param.NoteSynthParam.Delta;
2053 itEvent->Param.NoteSynthParam.AbsValue = pNote->Override.Pitch;
2054 break;
2055 case Event::synth_param_pitch_time:
2056 pNote->Override.PitchTime = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2057 break;
2058 case Event::synth_param_pitch_curve:
2059 itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2060 pNote->Override.PitchCurve = (fade_curve_t) itEvent->Param.NoteSynthParam.AbsValue;
2061 break;
2062 case Event::synth_param_pan:
2063 if (relative) {
2064 pNote->Override.Pan = RTMath::RelativeSummedAvg(pNote->Override.Pan, itEvent->Param.NoteSynthParam.Delta, ++pNote->Override.PanSources);
2065 } else {
2066 pNote->Override.Pan = itEvent->Param.NoteSynthParam.Delta;
2067 pNote->Override.PanSources = 1; // only relevant on subsequent change_pan() instrument script calls on same note with 'relative' argument being set
2068 }
2069 itEvent->Param.NoteSynthParam.AbsValue = pNote->Override.Pan;
2070 break;
2071 case Event::synth_param_pan_time:
2072 pNote->Override.PanTime = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2073 break;
2074 case Event::synth_param_pan_curve:
2075 itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2076 pNote->Override.PanCurve = (fade_curve_t) itEvent->Param.NoteSynthParam.AbsValue;
2077 break;
2078 case Event::synth_param_cutoff:
2079 pNote->Override.Cutoff = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2080 break;
2081 case Event::synth_param_resonance:
2082 pNote->Override.Resonance = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2083 break;
2084 case Event::synth_param_attack:
2085 pNote->Override.Attack = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2086 break;
2087 case Event::synth_param_decay:
2088 pNote->Override.Decay = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2089 break;
2090 case Event::synth_param_sustain:
2091 pNote->Override.Sustain = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2092 break;
2093 case Event::synth_param_release:
2094 pNote->Override.Release = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2095 break;
2096
2097 case Event::synth_param_cutoff_attack:
2098 pNote->Override.CutoffAttack = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2099 break;
2100 case Event::synth_param_cutoff_decay:
2101 pNote->Override.CutoffDecay = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2102 break;
2103 case Event::synth_param_cutoff_sustain:
2104 pNote->Override.CutoffSustain = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2105 break;
2106 case Event::synth_param_cutoff_release:
2107 pNote->Override.CutoffRelease = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2108 break;
2109
2110 case Event::synth_param_amp_lfo_depth:
2111 pNote->Override.AmpLFODepth = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2112 break;
2113 case Event::synth_param_amp_lfo_freq:
2114 pNote->Override.AmpLFOFreq = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2115 break;
2116 case Event::synth_param_cutoff_lfo_depth:
2117 pNote->Override.CutoffLFODepth = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2118 break;
2119 case Event::synth_param_cutoff_lfo_freq:
2120 pNote->Override.CutoffLFOFreq = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2121 break;
2122 case Event::synth_param_pitch_lfo_depth:
2123 pNote->Override.PitchLFODepth = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2124 break;
2125 case Event::synth_param_pitch_lfo_freq:
2126 pNote->Override.PitchLFOFreq = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2127 break;
2128 }
2129
2130 // move note parameter event to its MIDI key
2131 MidiKey* pKey = &pChannel->pMIDIKeyInfo[pNote->hostKey];
2132 itEvent.moveToEndOf(pKey->pEvents);
2133 }
2134
2135 /**
2136 * Reset all voices and disk thread and clear input event queue and all
2137 * control and status variables. This method is protected by a mutex.
2138 */
2139 virtual void ResetInternal() OVERRIDE {
2140 LockGuard lock(ResetInternalMutex);
2141
2142 // make sure that the engine does not get any sysex messages
2143 // while it's reseting
2144 bool sysexDisabled = MidiInputPort::RemoveSysexListener(this);
2145 SetVoiceCount(0);
2146 ActiveVoiceCountMax = 0;
2147
2148 // reset voice stealing parameters
2149 pVoiceStealingQueue->clear();
2150 itLastStolenVoice = VoiceIterator();
2151 itLastStolenVoiceGlobally = VoiceIterator();
2152 itLastStolenNote = NoteIterator();
2153 itLastStolenNoteGlobally = NoteIterator();
2154 iuiLastStolenKey = RTList<uint>::Iterator();
2155 iuiLastStolenKeyGlobally = RTList<uint>::Iterator();
2156 pLastStolenChannel = NULL;
2157
2158 // reset all notes
2159 pNotePool->clear();
2160 for (NoteIterator itNote = pNotePool->allocAppend(); itNote;
2161 itNote = pNotePool->allocAppend())
2162 {
2163 itNote->reset();
2164 }
2165 pNotePool->clear();
2166
2167 // reset all voices
2168 pVoicePool->clear();
2169 for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
2170 iterVoice->Reset();
2171 }
2172 pVoicePool->clear();
2173
2174 // reset all engine channels
2175 for (int i = 0; i < engineChannels.size(); i++) {
2176 AbstractEngineChannel* pEngineChannel =
2177 static_cast<AbstractEngineChannel*>(engineChannels[i]);
2178 pEngineChannel->ResetInternal(false/*don't reset engine*/);
2179 }
2180
2181 // reset disk thread
2182 if (pDiskThread) pDiskThread->Reset();
2183
2184 // delete all input events
2185 pEventQueue->init();
2186 pSysexBuffer->init();
2187 if (sysexDisabled) MidiInputPort::AddSysexListener(this);
2188 }
2189
2190 /**
2191 * Kills all voices on an engine channel as soon as possible. Voices
2192 * won't get into release state, their volume level will be ramped down
2193 * as fast as possible.
2194 *
2195 * @param pEngineChannel - engine channel on which all voices should be killed
2196 * @param itKillEvent - event which caused this killing of all voices
2197 */
2198 virtual void KillAllVoices(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itKillEvent) OVERRIDE {
2199 EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
2200 int count = pChannel->KillAllVoices(itKillEvent);
2201 VoiceSpawnsLeft -= count; //FIXME: just a temporary workaround, we should check the cause in StealVoice() instead
2202 }
2203
2204 /**
2205 * Allocates and triggers a new voice. This method will usually be
2206 * called by the ProcessNoteOn() method and by the voices itself
2207 * (e.g. to spawn further voices on the same key for layered sounds).
2208 *
2209 * @param pEngineChannel - engine channel on which this event occurred on
2210 * @param itNoteOnEvent - key, velocity and time stamp of the event
2211 * @param iLayer - layer index for the new voice (optional - only
2212 * in case of layered sounds of course)
2213 * @param ReleaseTriggerVoice - if new voice is a release triggered voice
2214 * (optional, default = false)
2215 * @param VoiceStealing - if voice stealing should be performed
2216 * when there is no free voice
2217 * (optional, default = true)
2218 * @param HandleKeyGroupConflicts - if voices should be killed due to a
2219 * key group conflict
2220 * @returns pointer to new voice or NULL if there was no free voice or
2221 * if the voice wasn't triggered (for example when no region is
2222 * defined for the given key).
2223 */
2224 virtual PoolVoiceIterator LaunchVoice (
2225 EngineChannel* pEngineChannel,
2226 Pool<Event>::Iterator& itNoteOnEvent,
2227 int iLayer,
2228 bool ReleaseTriggerVoice,
2229 bool VoiceStealing,
2230 bool HandleKeyGroupConflicts
2231 ) = 0;
2232
2233 virtual int GetMinFadeOutSamples() OVERRIDE { return MinFadeOutSamples; }
2234
2235 int InitNewVoice (
2236 EngineChannelBase<V, R, I>* pChannel,
2237 R* pRegion,
2238 Pool<Event>::Iterator& itNoteOnEvent,
2239 Voice::type_t VoiceType,
2240 int iLayer,
2241 int iKeyGroup,
2242 bool ReleaseTriggerVoice,
2243 bool VoiceStealing,
2244 typename Pool<V>::Iterator& itNewVoice
2245 ) {
2246 int key = itNoteOnEvent->Param.Note.Key;
2247 typename MidiKeyboardManager<V>::MidiKey* pKey = &pChannel->pMIDIKeyInfo[key];
2248 if (itNewVoice) {
2249 // launch the new voice
2250 if (itNewVoice->Trigger(pChannel, itNoteOnEvent, pChannel->Pitch, pRegion, VoiceType, iKeyGroup) < 0) {
2251 dmsg(4,("Voice not triggered\n"));
2252 GetVoicePool()->free(itNewVoice);
2253 }
2254 else { // on success
2255 --VoiceSpawnsLeft;
2256
2257 // should actually be superfluous now, since this is
2258 // already done in LaunchNewNote()
2259 pChannel->markKeyAsActive(pKey);
2260
2261 if (itNewVoice->Type & Voice::type_release_trigger_required)
2262 pKey->ReleaseTrigger |= itNewVoice->GetReleaseTriggerFlags(); // mark key for the need of release triggered voice(s)
2263 return 0; // success
2264 }
2265 }
2266 else if (VoiceStealing) {
2267 // try to steal one voice
2268 int result = StealVoice(pChannel, itNoteOnEvent);
2269 if (!result) { // voice stolen successfully
2270 // put note-on event into voice-stealing queue, so it will be reprocessed after killed voice died
2271 RTList<Event>::Iterator itStealEvent = pVoiceStealingQueue->allocAppend();
2272 if (itStealEvent) {
2273 *itStealEvent = *itNoteOnEvent; // copy event
2274 itStealEvent->Param.Note.Layer = iLayer;
2275 itStealEvent->Param.Note.ReleaseTrigger = ReleaseTriggerVoice;
2276 pKey->VoiceTheftsQueued++;
2277 }
2278 else dmsg(1,("Voice stealing queue full!\n"));
2279 }
2280 }
2281
2282 return -1;
2283 }
2284
2285 /**
2286 * Checks whether scale tuning setting has been changed since last
2287 * time this method was called, if yes, it recalculates the pitch
2288 * for all active voices.
2289 */
2290 void ProcessScaleTuningChange() {
2291 const bool changed = ScaleTuningChanged.readAndReset();
2292 if (!changed) return;
2293
2294 for (int i = 0; i < engineChannels.size(); i++) {
2295 EngineChannelBase<V, R, I>* channel =
2296 static_cast<EngineChannelBase<V, R, I>*>(engineChannels[i]);
2297 channel->OnScaleTuningChanged();
2298 }
2299 }
2300
2301 private:
2302 Pool< Note<V> >* pNotePool;
2303 Pool<note_id_t> noteIDPool;
2304 Pool<V>* pVoicePool; ///< Contains all voices that can be activated.
2305 Pool<RR*> SuspendedRegions;
2306 Mutex SuspendedRegionsMutex;
2307 Condition SuspensionChangeOngoing;
2308 RR* pPendingRegionSuspension;
2309 RR* pPendingRegionResumption;
2310 int iPendingStreamDeletions;
2311 };
2312
2313 template <class V, class RR, class R, class D, class IM, class I>
2314 IM EngineBase<V, RR, R, D, IM, I>::instruments;
2315
2316 } // namespace LinuxSampler
2317
2318 #endif /* __LS_ENGINEBASE_H__ */
2319

  ViewVC Help
Powered by ViewVC