/[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 2938 - (show annotations) (download) (as text)
Mon Jul 11 17:10:40 2016 UTC (7 years, 8 months ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 118835 byte(s)
* Fixed behavior of built-in instrument script functions play_note()
  and note_off(), which must be distinguished engine internally
  from "real" MIDI note on/off events in order to avoid
  misbehaviors like hanging notes.
* Bumped version (2.0.0.svn13).

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

  ViewVC Help
Powered by ViewVC