/[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 3688 - (show annotations) (download) (as text)
Thu Jan 2 23:47:42 2020 UTC (4 years, 2 months ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 132572 byte(s)
Added support for MIDI CC #38 (data entry LSB):

* Combine data entry MSB and data entry LSB events' values to one 14-bit
  value, which allows higher resolution (N)RPN value handling.

* Handle now hard coded RPN events in separate method
  ProcessHardcodedRpn().

* Handle now hard coded NRPN events in separate method
  ProcessHardcodedNrpn().

* Bumped version (2.1.1.svn29).

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

  ViewVC Help
Powered by ViewVC