/[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 3293 - (show annotations) (download) (as text)
Tue Jun 27 22:19:19 2017 UTC (6 years, 9 months ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 126456 byte(s)
* NKSP: Added built-in script function "fork()".
* NKSP: Added built-in array variable %NKSP_CALLBACK_CHILD_ID[].
* NKSP: Added built-in variable $NKSP_CALLBACK_PARENT_ID.
* NKSP: Fixed potential crash when accessing dynamic built-in
  array variables.
* Bumped version (2.0.0.svn65).

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

  ViewVC Help
Powered by ViewVC