/[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 2972 - (show annotations) (download) (as text)
Fri Jul 22 14:37:34 2016 UTC (7 years, 8 months ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 120139 byte(s)
* NKSP Fix: "init" event handler was not always executed when a script
  was loaded.
* NKSP built-in wait() script function: abort script execution if
  a negative or zero wait time was passed as argument (since this is
  a common indication of a bug either of the script or even of the
  engine, which could lead to RT instability or even worse).
* Bumped version (2.0.0.svn24).

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

  ViewVC Help
Powered by ViewVC