/[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 3188 - (show annotations) (download) (as text)
Fri May 19 14:23:12 2017 UTC (6 years, 11 months ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 123726 byte(s)
* NKSP: Implemented built-in script function "change_vol_time()".
* NKSP: Implemented built-in script function "change_tune_time()".
* NKSP: Implemented built-in script function "fade_in()".
* NKSP: Implemented built-in script function "fade_out()".
* NKSP: Fixed acceptance of wrong data type of parameters passed to
  built-in script functions "change_vol()", "change_tune()",
  "change_pan()", "change_cutoff()", "change_reso()",
  "change_attack()", "change_decay()", "change_release()",
  "change_amp_lfo_depth()", "change_amp_lfo_freq()",
  "change_pitch_lfo_depth()" and "change_pitch_lfo_freq()".
* Bumped version (2.0.0.svn45).

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

  ViewVC Help
Powered by ViewVC