/[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 3207 - (show annotations) (download) (as text)
Thu May 25 10:53:45 2017 UTC (6 years, 10 months ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 124250 byte(s)
* NKSP: Fixed polyphonic variables not being reset to zero
  after usage.
* Bumped version (2.0.0.svn48).

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

  ViewVC Help
Powered by ViewVC