/[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 3221 - (show annotations) (download) (as text)
Fri May 26 18:30:42 2017 UTC (6 years, 10 months ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 125094 byte(s)
* NKSP Fix: Never suspend "init" event handlers.
* NKSP: Implemented built-in script function "array_equal()".
* NKSP: Implemented built-in script function "search()".
* NKSP: Implemented built-in script function "sort()".
* Bumped version (2.0.0.svn52).

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;
1308 size_t instructionsCount = 0;
1309 const size_t maxInstructions = 200000; // aiming approx. 1 second max. (based on very roughly 5us / instruction)
1310 bool bWarningShown = false;
1311 do {
1312 res = pScriptVM->exec(
1313 pEngineChannel->pScript->parserContext, &*itScriptEvent
1314 );
1315 instructionsCount += itScriptEvent->execCtx->instructionsPerformed();
1316 if (instructionsCount > maxInstructions && !bWarningShown) {
1317 bWarningShown = true;
1318 dmsg(0,("[ScriptVM] WARNING: \"init\" event handler of instrument script executing for long time!\n"));
1319 }
1320 } while (res & VM_EXEC_SUSPENDED && !(res & VM_EXEC_ERROR));
1321
1322 pEngineChannel->pScript->pEvents->free(itScriptEvent);
1323 }
1324 }
1325 }
1326
1327 if (instrumentChanged) {
1328 //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
1329 ResetSuspendedRegions();
1330 }
1331 }
1332
1333 /**
1334 * Render all 'normal' voices (that is voices which were not stolen in
1335 * this fragment) on the given engine channel.
1336 *
1337 * @param pEngineChannel - engine channel on which audio should be
1338 * rendered
1339 * @param Samples - amount of sample points to be rendered in
1340 * this audio fragment cycle
1341 */
1342 void RenderActiveVoices(EngineChannel* pEngineChannel, uint Samples) {
1343 #if !CONFIG_PROCESS_MUTED_CHANNELS
1344 if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
1345 #endif
1346
1347 EngineChannelBase<V, R, I>* pChannel =
1348 static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1349 pChannel->RenderActiveVoices(Samples);
1350
1351 ActiveVoiceCountTemp += pEngineChannel->GetVoiceCount();
1352 }
1353
1354 /**
1355 * Render all stolen voices (only voices which were stolen in this
1356 * fragment) on the given engine channel. Stolen voices are rendered
1357 * after all normal voices have been rendered; this is needed to render
1358 * audio of those voices which were selected for voice stealing until
1359 * the point were the stealing (that is the take over of the voice)
1360 * actually happened.
1361 *
1362 * @param pEngineChannel - engine channel on which audio should be
1363 * rendered
1364 * @param Samples - amount of sample points to be rendered in
1365 * this audio fragment cycle
1366 */
1367 void RenderStolenVoices(uint Samples) {
1368 RTList<Event>::Iterator itVoiceStealEvent = pVoiceStealingQueue->first();
1369 RTList<Event>::Iterator end = pVoiceStealingQueue->end();
1370 for (; itVoiceStealEvent != end; ++itVoiceStealEvent) {
1371 EngineChannelBase<V, R, I>* pEngineChannel =
1372 static_cast<EngineChannelBase<V, R, I>*>(itVoiceStealEvent->pEngineChannel);;
1373 if (!pEngineChannel->pInstrument) continue; // ignore if no instrument loaded
1374
1375 PoolVoiceIterator itNewVoice =
1376 LaunchVoice(pEngineChannel, itVoiceStealEvent, itVoiceStealEvent->Param.Note.Layer, itVoiceStealEvent->Param.Note.ReleaseTrigger, false, false);
1377 if (itNewVoice) {
1378 // usually there should already be a new Note object
1379 NoteIterator itNote = GetNotePool()->fromID(itVoiceStealEvent->Param.Note.ID);
1380 if (!itNote) { // should not happen, but just to be sure ...
1381 const note_id_t noteID = LaunchNewNote(pEngineChannel, itVoiceStealEvent);
1382 if (!noteID) {
1383 dmsg(1,("Engine: Voice stealing failed; No Note object and Note pool empty!\n"));
1384 continue;
1385 }
1386 itNote = GetNotePool()->fromID(noteID);
1387 }
1388 // move voice from whereever it was, to the new note's list of active voices
1389 itNewVoice = itNewVoice.moveToEndOf(itNote->pActiveVoices);
1390 // render audio of this new voice for the first time
1391 itNewVoice->Render(Samples);
1392 if (itNewVoice->IsActive()) { // still active
1393 *(pEngineChannel->pRegionsInUse->allocAppend()) = itNewVoice->GetRegion();
1394 ActiveVoiceCountTemp++;
1395 pEngineChannel->SetVoiceCount(pEngineChannel->GetVoiceCount() + 1);
1396
1397 if (itNewVoice->PlaybackState == Voice::playback_state_disk) {
1398 if (itNewVoice->DiskStreamRef.State != Stream::state_unused) {
1399 pEngineChannel->SetDiskStreamCount(pEngineChannel->GetDiskStreamCount() + 1);
1400 }
1401 }
1402 } else { // voice reached end, is now inactive
1403 pEngineChannel->FreeVoice(itNewVoice); // remove voice from the list of active voices
1404 }
1405 }
1406 else dmsg(1,("EngineBase: ERROR, voice stealing didn't work out!\n"));
1407
1408 // we need to clear the key's event list explicitly here in case key was never active
1409 MidiKey* pKey = &pEngineChannel->pMIDIKeyInfo[itVoiceStealEvent->Param.Note.Key];
1410 pKey->VoiceTheftsQueued--;
1411 if (!pKey->Active && !pKey->VoiceTheftsQueued) pKey->pEvents->clear();
1412 }
1413 }
1414
1415 /**
1416 * Free all keys which have turned inactive in this audio fragment, from
1417 * the list of active keys and clear all event lists on that engine
1418 * channel.
1419 *
1420 * @param pEngineChannel - engine channel to cleanup
1421 */
1422 void PostProcess(EngineChannel* pEngineChannel) {
1423 EngineChannelBase<V, R, I>* pChannel =
1424 static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1425 pChannel->FreeAllInactiveKyes();
1426
1427 // empty the engine channel's own event lists
1428 // (only events of the current audio fragment cycle)
1429 pChannel->ClearEventListsOfCurrentFragment();
1430 }
1431
1432 /**
1433 * Process MIDI control change events with hard coded behavior,
1434 * that is controllers whose behavior is defined independently
1435 * of the actual sampler engine type and instrument.
1436 *
1437 * @param pEngineChannel - engine channel on which the MIDI CC event was received
1438 * @param itControlChangeEvent - the actual MIDI CC event
1439 */
1440 void ProcessHardcodedControllers (
1441 EngineChannel* pEngineChannel,
1442 Pool<Event>::Iterator& itControlChangeEvent
1443 ) {
1444 EngineChannelBase<V, R, I>* pChannel =
1445 static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1446
1447 switch (itControlChangeEvent->Param.CC.Controller) {
1448 case 5: { // portamento time
1449 pChannel->PortamentoTime = (float) itControlChangeEvent->Param.CC.Value / 127.0f * (float) CONFIG_PORTAMENTO_TIME_MAX + (float) CONFIG_PORTAMENTO_TIME_MIN;
1450 break;
1451 }
1452 case 6: { // data entry (currently only used for RPN and NRPN controllers)
1453 //dmsg(1,("DATA ENTRY %d\n", itControlChangeEvent->Param.CC.Value));
1454 if (pChannel->GetMidiRpnController() >= 0) { // RPN controller number was sent previously ...
1455 dmsg(4,("Guess it's an RPN ...\n"));
1456 if (pChannel->GetMidiRpnController() == 2) { // coarse tuning in half tones
1457 int transpose = (int) itControlChangeEvent->Param.CC.Value - 64;
1458 // limit to +- two octaves for now
1459 transpose = RTMath::Min(transpose, 24);
1460 transpose = RTMath::Max(transpose, -24);
1461 pChannel->GlobalTranspose = transpose;
1462 // workaround, so we won't have hanging notes
1463 pChannel->ReleaseAllVoices(itControlChangeEvent);
1464 }
1465 // to prevent other MIDI CC #6 messages to be misenterpreted as RPN controller data
1466 pChannel->ResetMidiRpnController();
1467 } else if (pChannel->GetMidiNrpnController() >= 0) { // NRPN controller number was sent previously ...
1468 dmsg(4,("Guess it's an NRPN ...\n"));
1469 const int NrpnCtrlMSB = pChannel->GetMidiNrpnController() >> 8;
1470 const int NrpnCtrlLSB = pChannel->GetMidiNrpnController() & 0xff;
1471 dmsg(4,("NRPN MSB=%d LSB=%d Data=%d\n", NrpnCtrlMSB, NrpnCtrlLSB, itControlChangeEvent->Param.CC.Value));
1472 switch (NrpnCtrlMSB) {
1473 case 0x1a: { // volume level of note (Roland GS NRPN)
1474 const uint note = NrpnCtrlLSB;
1475 const uint vol = itControlChangeEvent->Param.CC.Value;
1476 dmsg(4,("Note Volume NRPN received (note=%d,vol=%d).\n", note, vol));
1477 if (note < 128 && vol < 128)
1478 pChannel->pMIDIKeyInfo[note].Volume = VolumeCurve[vol];
1479 break;
1480 }
1481 case 0x1c: { // panpot of note (Roland GS NRPN)
1482 const uint note = NrpnCtrlLSB;
1483 const uint pan = itControlChangeEvent->Param.CC.Value;
1484 dmsg(4,("Note Pan NRPN received (note=%d,pan=%d).\n", note, pan));
1485 if (note < 128 && pan < 128) {
1486 pChannel->pMIDIKeyInfo[note].PanLeft = PanCurve[128 - pan];
1487 pChannel->pMIDIKeyInfo[note].PanRight = PanCurve[pan];
1488 }
1489 break;
1490 }
1491 case 0x1d: { // reverb send of note (Roland GS NRPN)
1492 const uint note = NrpnCtrlLSB;
1493 const float reverb = float(itControlChangeEvent->Param.CC.Value) / 127.0f;
1494 dmsg(4,("Note Reverb Send NRPN received (note=%d,send=%f).\n", note, reverb));
1495 if (note < 128)
1496 pChannel->pMIDIKeyInfo[note].ReverbSend = reverb;
1497 break;
1498 }
1499 case 0x1e: { // chorus send of note (Roland GS NRPN)
1500 const uint note = NrpnCtrlLSB;
1501 const float chorus = float(itControlChangeEvent->Param.CC.Value) / 127.0f;
1502 dmsg(4,("Note Chorus Send NRPN received (note=%d,send=%f).\n", note, chorus));
1503 if (note < 128)
1504 pChannel->pMIDIKeyInfo[note].ChorusSend = chorus;
1505 break;
1506 }
1507 }
1508 // to prevent other MIDI CC #6 messages to be misenterpreted as NRPN controller data
1509 pChannel->ResetMidiNrpnController();
1510 }
1511 break;
1512 }
1513 case 7: { // volume
1514 //TODO: not sample accurate yet
1515 pChannel->MidiVolume = VolumeCurve[itControlChangeEvent->Param.CC.Value];
1516 pChannel->bStatusChanged = true; // engine channel status has changed, so set notify flag
1517 break;
1518 }
1519 case 10: { // panpot
1520 //TODO: not sample accurate yet
1521 pChannel->iLastPanRequest = itControlChangeEvent->Param.CC.Value;
1522 break;
1523 }
1524 case 64: { // sustain
1525 if (itControlChangeEvent->Param.CC.Value >= 64 && !pChannel->SustainPedal) {
1526 dmsg(4,("DAMPER (RIGHT) PEDAL DOWN\n"));
1527 pChannel->SustainPedal = true;
1528 pChannel->listeners.PreProcessSustainPedalDown();
1529
1530 #if !CONFIG_PROCESS_MUTED_CHANNELS
1531 if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
1532 pChannel->listeners.PostProcessSustainPedalDown();
1533 return;
1534 }
1535 #endif
1536
1537 pChannel->ProcessSustainPedalDown(itControlChangeEvent);
1538 pChannel->listeners.PostProcessSustainPedalDown();
1539 }
1540 if (itControlChangeEvent->Param.CC.Value < 64 && pChannel->SustainPedal) {
1541 dmsg(4,("DAMPER (RIGHT) PEDAL UP\n"));
1542 pChannel->SustainPedal = false;
1543 pChannel->listeners.PreProcessSustainPedalUp();
1544
1545 #if !CONFIG_PROCESS_MUTED_CHANNELS
1546 if (pChannel->GetMute()) { // skip if sampler channel is muted
1547 pChannel->listeners.PostProcessSustainPedalUp();
1548 return;
1549 }
1550 #endif
1551
1552 pChannel->ProcessSustainPedalUp(itControlChangeEvent);
1553 pChannel->listeners.PostProcessSustainPedalUp();
1554 }
1555 break;
1556 }
1557 case 65: { // portamento on / off
1558 const bool bPortamento = itControlChangeEvent->Param.CC.Value >= 64;
1559 if (bPortamento != pChannel->PortamentoMode)
1560 KillAllVoices(pChannel, itControlChangeEvent);
1561 pChannel->PortamentoMode = bPortamento;
1562 break;
1563 }
1564 case 66: { // sostenuto
1565 if (itControlChangeEvent->Param.CC.Value >= 64 && !pChannel->SostenutoPedal) {
1566 dmsg(4,("SOSTENUTO (CENTER) PEDAL DOWN\n"));
1567 pChannel->SostenutoPedal = true;
1568 pChannel->listeners.PreProcessSostenutoPedalDown();
1569
1570 #if !CONFIG_PROCESS_MUTED_CHANNELS
1571 if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
1572 pChannel->listeners.PostProcessSostenutoPedalDown();
1573 return;
1574 }
1575 #endif
1576
1577 pChannel->ProcessSostenutoPedalDown();
1578 pChannel->listeners.PostProcessSostenutoPedalDown();
1579 }
1580 if (itControlChangeEvent->Param.CC.Value < 64 && pChannel->SostenutoPedal) {
1581 dmsg(4,("SOSTENUTO (CENTER) PEDAL UP\n"));
1582 pChannel->SostenutoPedal = false;
1583 pChannel->listeners.PreProcessSostenutoPedalUp();
1584
1585 #if !CONFIG_PROCESS_MUTED_CHANNELS
1586 if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
1587 pChannel->listeners.PostProcessSostenutoPedalUp();
1588 return;
1589 }
1590 #endif
1591
1592 pChannel->ProcessSostenutoPedalUp(itControlChangeEvent);
1593 pChannel->listeners.PostProcessSostenutoPedalUp();
1594 }
1595 break;
1596 }
1597 case 98: { // NRPN controller LSB
1598 dmsg(4,("NRPN LSB %d\n", itControlChangeEvent->Param.CC.Value));
1599 pEngineChannel->SetMidiNrpnControllerLsb(itControlChangeEvent->Param.CC.Value);
1600 break;
1601 }
1602 case 99: { // NRPN controller MSB
1603 dmsg(4,("NRPN MSB %d\n", itControlChangeEvent->Param.CC.Value));
1604 pEngineChannel->SetMidiNrpnControllerMsb(itControlChangeEvent->Param.CC.Value);
1605 break;
1606 }
1607 case 100: { // RPN controller LSB
1608 dmsg(4,("RPN LSB %d\n", itControlChangeEvent->Param.CC.Value));
1609 pEngineChannel->SetMidiRpnControllerLsb(itControlChangeEvent->Param.CC.Value);
1610 break;
1611 }
1612 case 101: { // RPN controller MSB
1613 dmsg(4,("RPN MSB %d\n", itControlChangeEvent->Param.CC.Value));
1614 pEngineChannel->SetMidiRpnControllerMsb(itControlChangeEvent->Param.CC.Value);
1615 break;
1616 }
1617
1618
1619 // Channel Mode Messages
1620
1621 case 120: { // all sound off
1622 KillAllVoices(pEngineChannel, itControlChangeEvent);
1623 break;
1624 }
1625 case 121: { // reset all controllers
1626 pChannel->ResetControllers();
1627 break;
1628 }
1629 case 123: { // all notes off
1630 #if CONFIG_PROCESS_ALL_NOTES_OFF
1631 pChannel->ReleaseAllVoices(itControlChangeEvent);
1632 #endif // CONFIG_PROCESS_ALL_NOTES_OFF
1633 break;
1634 }
1635 case 126: { // mono mode on
1636 if (!pChannel->SoloMode)
1637 KillAllVoices(pEngineChannel, itControlChangeEvent);
1638 pChannel->SoloMode = true;
1639 break;
1640 }
1641 case 127: { // poly mode on
1642 if (pChannel->SoloMode)
1643 KillAllVoices(pEngineChannel, itControlChangeEvent);
1644 pChannel->SoloMode = false;
1645 break;
1646 }
1647 }
1648 }
1649
1650 virtual D* CreateDiskThread() = 0;
1651
1652 /**
1653 * Assigns and triggers a new voice for the respective MIDI key.
1654 *
1655 * @param pEngineChannel - engine channel on which this event occurred on
1656 * @param itNoteOnEvent - key, velocity and time stamp of the event
1657 */
1658 virtual void ProcessNoteOn(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) OVERRIDE {
1659 EngineChannelBase<V, R, I>* pChannel =
1660 static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1661
1662 const int key = itNoteOnEvent->Param.Note.Key;
1663 const int vel = itNoteOnEvent->Param.Note.Velocity;
1664 if (key < 0 || key > 127) return; // ignore event, key outside allowed key range
1665
1666 MidiKey* pKey = &pChannel->pMIDIKeyInfo[key];
1667
1668 // There are real MIDI note-on events (Event::type_note_on) and
1669 // programmatically spawned notes (Event::type_play_note). We have
1670 // to distinguish between them, since certain processing below
1671 // must only be done on real MIDI note-on events (i.e. for
1672 // correctly updating which MIDI keys are currently pressed down).
1673 const bool isRealMIDINoteOnEvent = itNoteOnEvent->Type == Event::type_note_on;
1674
1675 if (isRealMIDINoteOnEvent)
1676 pChannel->listeners.PreProcessNoteOn(key, vel);
1677
1678 #if !CONFIG_PROCESS_MUTED_CHANNELS
1679 if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
1680 if (isRealMIDINoteOnEvent)
1681 pChannel->listeners.PostProcessNoteOn(key, vel);
1682 return;
1683 }
1684 #endif
1685
1686 if (!pChannel->pInstrument) {
1687 if (isRealMIDINoteOnEvent)
1688 pChannel->listeners.PostProcessNoteOn(key, vel);
1689 return; // ignore if no instrument loaded
1690 }
1691
1692 // move note on event to the key's own event list
1693 RTList<Event>::Iterator itNoteOnEventOnKeyList = itNoteOnEvent.moveToEndOf(pKey->pEvents);
1694
1695 // if Solo Mode then kill all already active voices
1696 if (pChannel->SoloMode && isRealMIDINoteOnEvent) {
1697 Pool<uint>::Iterator itYoungestKey = pChannel->pActiveKeys->last();
1698 if (itYoungestKey) {
1699 const int iYoungestKey = *itYoungestKey;
1700 const MidiKey* pOtherKey = &pChannel->pMIDIKeyInfo[iYoungestKey];
1701 if (pOtherKey->Active) {
1702 // get final portamento position of currently active voice
1703 if (pChannel->PortamentoMode) {
1704 NoteIterator itNote = pOtherKey->pActiveNotes->last();
1705 if (itNote) {
1706 VoiceIterator itVoice = itNote->pActiveVoices->last();
1707 if (itVoice) itVoice->UpdatePortamentoPos(itNoteOnEventOnKeyList);
1708 }
1709 }
1710 // kill all voices on the (other) key
1711 for (NoteIterator itNote = pOtherKey->pActiveNotes->first(); itNote; ++itNote) {
1712 VoiceIterator itVoiceToBeKilled = itNote->pActiveVoices->first();
1713 VoiceIterator end = itNote->pActiveVoices->end();
1714 for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1715 if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))
1716 itVoiceToBeKilled->Kill(itNoteOnEventOnKeyList);
1717 }
1718 }
1719 }
1720 }
1721 // set this key as 'currently active solo key'
1722 pChannel->SoloKey = key;
1723 }
1724
1725 if (isRealMIDINoteOnEvent) {
1726 pChannel->ProcessKeySwitchChange(key);
1727
1728 pKey->KeyPressed = true; // the MIDI key was now pressed down
1729 pChannel->KeyDown[key] = true; // just used as built-in %KEY_DOWN script variable
1730 pKey->Velocity = itNoteOnEventOnKeyList->Param.Note.Velocity;
1731 pKey->NoteOnTime = FrameTime + itNoteOnEventOnKeyList->FragmentPos(); // will be used to calculate note length
1732 }
1733
1734 // cancel release process of voices on this key if needed
1735 if (pKey->Active && !pChannel->SustainPedal && isRealMIDINoteOnEvent) {
1736 RTList<Event>::Iterator itCancelReleaseEvent = pKey->pEvents->allocAppend();
1737 if (itCancelReleaseEvent) {
1738 *itCancelReleaseEvent = *itNoteOnEventOnKeyList; // copy event
1739 itCancelReleaseEvent->Type = Event::type_cancel_release_key; // transform event type
1740 }
1741 else dmsg(1,("Event pool emtpy!\n"));
1742 }
1743
1744 TriggerNewVoices(pEngineChannel, itNoteOnEventOnKeyList);
1745
1746 // if neither a voice was spawned or postponed then remove note on event from key again
1747 if (!pKey->Active && !pKey->VoiceTheftsQueued)
1748 pKey->pEvents->free(itNoteOnEventOnKeyList);
1749
1750 if (isRealMIDINoteOnEvent && (!pChannel->SoloMode || pChannel->PortamentoPos < 0.0f))
1751 pChannel->PortamentoPos = (float) key;
1752
1753 //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?
1754 if (pKey->pRoundRobinIndex) {
1755 (*pKey->pRoundRobinIndex)++; // counter specific for the key or region
1756 pChannel->RoundRobinIndex++; // common counter for the channel
1757 }
1758
1759 if (isRealMIDINoteOnEvent)
1760 pChannel->listeners.PostProcessNoteOn(key, vel);
1761 }
1762
1763 /**
1764 * Allocate and trigger new voice(s) for the key.
1765 */
1766 virtual void TriggerNewVoices (
1767 EngineChannel* pEngineChannel,
1768 RTList<Event>::Iterator& itNoteOnEvent,
1769 bool HandleKeyGroupConflicts = true
1770 ) = 0;
1771
1772 /**
1773 * Allocate and trigger release voice(s) for the key.
1774 */
1775 virtual void TriggerReleaseVoices (
1776 EngineChannel* pEngineChannel,
1777 RTList<Event>::Iterator& itNoteOffEvent
1778 ) = 0;
1779
1780 /**
1781 * Releases the voices on the given key if sustain pedal is not pressed.
1782 * If sustain is pressed, the release of the note will be postponed until
1783 * sustain pedal will be released or voice turned inactive by itself (e.g.
1784 * due to completion of sample playback).
1785 *
1786 * @param pEngineChannel - engine channel on which this event occurred on
1787 * @param itNoteOffEvent - key, velocity and time stamp of the event
1788 */
1789 virtual void ProcessNoteOff(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOffEvent) OVERRIDE {
1790 EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1791
1792 const int iKey = itNoteOffEvent->Param.Note.Key;
1793 const int vel = itNoteOffEvent->Param.Note.Velocity;
1794 if (iKey < 0 || iKey > 127) return; // ignore event, key outside allowed key range
1795
1796 MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];
1797
1798 // There are real MIDI note-off events (Event::type_note_off) and
1799 // programmatically spawned notes (Event::type_stop_note). We have
1800 // to distinguish between them, since certain processing below
1801 // must only be done on real MIDI note-off events (i.e. for
1802 // correctly updating which MIDI keys are currently pressed down),
1803 // plus a stop-note event just releases voices of one particular
1804 // note, whereas a note-off event releases all voices on a
1805 // particular MIDI key instead.
1806 const bool isRealMIDINoteOffEvent = itNoteOffEvent->Type == Event::type_note_off;
1807
1808 if (isRealMIDINoteOffEvent)
1809 pChannel->listeners.PreProcessNoteOff(iKey, vel);
1810
1811 #if !CONFIG_PROCESS_MUTED_CHANNELS
1812 if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
1813 if (isRealMIDINoteOffEvent)
1814 pChannel->listeners.PostProcessNoteOff(iKey, vel);
1815 return;
1816 }
1817 #endif
1818
1819 if (isRealMIDINoteOffEvent) {
1820 pKey->KeyPressed = false; // the MIDI key was now released
1821 pChannel->KeyDown[iKey] = false; // just used as built-in %KEY_DOWN script variable
1822 }
1823
1824 // move event to the key's own event list
1825 RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);
1826
1827 if (isRealMIDINoteOffEvent) {
1828 bool bShouldRelease = pKey->Active && pChannel->ShouldReleaseVoice(itNoteOffEventOnKeyList->Param.Note.Key);
1829
1830 // in case Solo Mode is enabled, kill all voices on this key and respawn a voice on the highest pressed key (if any)
1831 if (pChannel->SoloMode && pChannel->pInstrument) { //TODO: this feels like too much code just for handling solo mode :P
1832 bool bOtherKeysPressed = false;
1833 if (iKey == pChannel->SoloKey) {
1834 pChannel->SoloKey = -1;
1835 // if there's still a key pressed down, respawn a voice (group) on the highest key
1836 for (int i = 127; i > 0; i--) {
1837 MidiKey* pOtherKey = &pChannel->pMIDIKeyInfo[i];
1838 if (pOtherKey->KeyPressed) {
1839 bOtherKeysPressed = true;
1840 // make the other key the new 'currently active solo key'
1841 pChannel->SoloKey = i;
1842 // get final portamento position of currently active voice
1843 if (pChannel->PortamentoMode) {
1844 NoteIterator itNote = pKey->pActiveNotes->first();
1845 VoiceIterator itVoice = itNote->pActiveVoices->first();
1846 if (itVoice) itVoice->UpdatePortamentoPos(itNoteOffEventOnKeyList);
1847 }
1848 // create a pseudo note on event
1849 RTList<Event>::Iterator itPseudoNoteOnEvent = pOtherKey->pEvents->allocAppend();
1850 if (itPseudoNoteOnEvent) {
1851 // copy event
1852 *itPseudoNoteOnEvent = *itNoteOffEventOnKeyList;
1853 // transform event to a note on event
1854 itPseudoNoteOnEvent->Type = Event::type_note_on; //FIXME: should probably use Event::type_play_note instead (to avoid i.e. hanging notes)
1855 itPseudoNoteOnEvent->Param.Note.Key = i;
1856 itPseudoNoteOnEvent->Param.Note.Velocity = pOtherKey->Velocity;
1857 // assign a new note to this note-on event
1858 if (LaunchNewNote(pChannel, itPseudoNoteOnEvent)) {
1859 // allocate and trigger new voice(s) for the other key
1860 TriggerNewVoices(pChannel, itPseudoNoteOnEvent, false);
1861 }
1862 // if neither a voice was spawned or postponed then remove note on event from key again
1863 if (!pOtherKey->Active && !pOtherKey->VoiceTheftsQueued)
1864 pOtherKey->pEvents->free(itPseudoNoteOnEvent);
1865
1866 } else dmsg(1,("Could not respawn voice, no free event left\n"));
1867 break; // done
1868 }
1869 }
1870 }
1871 if (bOtherKeysPressed) {
1872 if (pKey->Active) { // kill all voices on this key
1873 bShouldRelease = false; // no need to release, as we kill it here
1874 for (NoteIterator itNote = pKey->pActiveNotes->first(); itNote; ++itNote) {
1875 VoiceIterator itVoiceToBeKilled = itNote->pActiveVoices->first();
1876 VoiceIterator end = itNote->pActiveVoices->end();
1877 for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1878 if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))
1879 itVoiceToBeKilled->Kill(itNoteOffEventOnKeyList);
1880 }
1881 }
1882 }
1883 } else pChannel->PortamentoPos = -1.0f;
1884 }
1885
1886 // if no solo mode (the usual case) or if solo mode and no other key pressed, then release voices on this key if needed
1887 if (bShouldRelease) {
1888 itNoteOffEventOnKeyList->Type = Event::type_release_key; // transform event type
1889 // spawn release triggered voice(s) if needed
1890 ProcessReleaseTrigger(pChannel, itNoteOffEventOnKeyList, pKey);
1891 }
1892 } else if (itNoteOffEventOnKeyList->Type == Event::type_stop_note) {
1893 // This programmatically caused event is caused by a call to
1894 // the built-in instrument script function note_off(). In
1895 // contrast to a real MIDI note-off event the stop-note
1896 // event just intends to release voices of one particular note.
1897 NoteBase* pNote = pChannel->pEngine->NoteByID( itNoteOffEventOnKeyList->Param.Note.ID );
1898 if (pNote) { // the requested note is still alive ...
1899 itNoteOffEventOnKeyList->Type = Event::type_release_note; // transform event type
1900 } else { // note is dead and gone ..
1901 pKey->pEvents->free(itNoteOffEventOnKeyList); // remove stop-note event from key again
1902 return; // prevent event to be removed a 2nd time below
1903 }
1904 }
1905
1906 // if neither a voice was spawned or postponed on this key then remove note off event from key again
1907 if (!pKey->Active && !pKey->VoiceTheftsQueued)
1908 pKey->pEvents->free(itNoteOffEventOnKeyList);
1909
1910 if (isRealMIDINoteOffEvent)
1911 pChannel->listeners.PostProcessNoteOff(iKey, vel);
1912 }
1913
1914 /**
1915 * Called on sustain pedal up events to check and if required,
1916 * launch release trigger voices on the respective active key.
1917 *
1918 * @param pEngineChannel - engine channel on which this event occurred on
1919 * @param itEvent - release trigger event (contains note number)
1920 */
1921 virtual void ProcessReleaseTrigger(EngineChannel* pEngineChannel, RTList<Event>::Iterator& itEvent) OVERRIDE {
1922 EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1923
1924 const int iKey = itEvent->Param.Note.Key;
1925 if (iKey < 0 || iKey > 127) return; // ignore event, key outside allowed key range
1926
1927 MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];
1928
1929 ProcessReleaseTrigger(pChannel, itEvent, pKey);
1930 }
1931
1932 /**
1933 * Called on note-off and sustain pedal up events to check and if
1934 * required, launch release trigger voices on the respective active
1935 * key.
1936 *
1937 * @param pEngineChannel - engine channel on which this event occurred on
1938 * @param itEvent - note off event / release trigger event
1939 * @param pKey - key on which the release trigger voices shall be spawned
1940 */
1941 inline void ProcessReleaseTrigger(EngineChannelBase<V, R, I>* pChannel, RTList<Event>::Iterator& itEvent, MidiKey* pKey) {
1942 // spawn release triggered voice(s) if needed
1943 if (pKey->ReleaseTrigger && pChannel->pInstrument) {
1944 // assign a new note to this release event
1945 if (LaunchNewNote(pChannel, itEvent)) {
1946 // allocate and trigger new release voice(s)
1947 TriggerReleaseVoices(pChannel, itEvent);
1948 }
1949 pKey->ReleaseTrigger = false;
1950 }
1951 }
1952
1953 /**
1954 * Called on "kill note" events, which currently only happens on
1955 * built-in real-time instrument script function fade_out(). This
1956 * method only fulfills one task: moving the even to the Note's own
1957 * event list so that its voices can process the kill event sample
1958 * accurately.
1959 */
1960 void ProcessKillNote(EngineChannel* pEngineChannel, RTList<Event>::Iterator& itEvent) {
1961 EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1962
1963 NoteBase* pNote = pChannel->pEngine->NoteByID( itEvent->Param.Note.ID );
1964 if (!pNote || pNote->hostKey < 0 || pNote->hostKey >= 128) return;
1965
1966 // move note kill event to its MIDI key
1967 MidiKey* pKey = &pChannel->pMIDIKeyInfo[pNote->hostKey];
1968 itEvent.moveToEndOf(pKey->pEvents);
1969 }
1970
1971 /**
1972 * Called on note synthesis parameter change events. These are
1973 * internal events caused by calling built-in real-time instrument
1974 * script functions like change_vol(), change_tune(), etc.
1975 *
1976 * This method performs two tasks:
1977 *
1978 * - It converts the event's relative values changes (Deltas) to
1979 * the respective final new synthesis parameter value (AbsValue),
1980 * for that particular moment of the event that is.
1981 *
1982 * - It moves the individual events to the Note's own event list
1983 * (or actually to the event list of the MIDI key), so that
1984 * voices can process those events sample accurately.
1985 *
1986 * @param pEngineChannel - engine channel on which this event occurred on
1987 * @param itEvent - note synthesis parameter change event
1988 */
1989 virtual void ProcessNoteSynthParam(EngineChannel* pEngineChannel, RTList<Event>::Iterator& itEvent) {
1990 EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1991
1992 NoteBase* pNote = pChannel->pEngine->NoteByID( itEvent->Param.NoteSynthParam.NoteID );
1993 if (!pNote || pNote->hostKey < 0 || pNote->hostKey >= 128) return;
1994
1995 const bool& relative = itEvent->Param.NoteSynthParam.Relative;
1996
1997 switch (itEvent->Param.NoteSynthParam.Type) {
1998 case Event::synth_param_volume:
1999 if (relative)
2000 pNote->Override.Volume *= itEvent->Param.NoteSynthParam.Delta;
2001 else
2002 pNote->Override.Volume = itEvent->Param.NoteSynthParam.Delta;
2003 itEvent->Param.NoteSynthParam.AbsValue = pNote->Override.Volume;
2004 break;
2005 case Event::synth_param_volume_time:
2006 pNote->Override.VolumeTime = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2007 break;
2008 case Event::synth_param_pitch:
2009 if (relative)
2010 pNote->Override.Pitch *= itEvent->Param.NoteSynthParam.Delta;
2011 else
2012 pNote->Override.Pitch = itEvent->Param.NoteSynthParam.Delta;
2013 itEvent->Param.NoteSynthParam.AbsValue = pNote->Override.Pitch;
2014 break;
2015 case Event::synth_param_pitch_time:
2016 pNote->Override.PitchTime = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2017 break;
2018 case Event::synth_param_pan:
2019 if (relative) {
2020 pNote->Override.Pan = RTMath::RelativeSummedAvg(pNote->Override.Pan, itEvent->Param.NoteSynthParam.Delta, ++pNote->Override.PanSources);
2021 } else {
2022 pNote->Override.Pan = itEvent->Param.NoteSynthParam.Delta;
2023 pNote->Override.PanSources = 1; // only relevant on subsequent change_pan() instrument script calls on same note with 'relative' argument being set
2024 }
2025 itEvent->Param.NoteSynthParam.AbsValue = pNote->Override.Pan;
2026 break;
2027 case Event::synth_param_cutoff:
2028 pNote->Override.Cutoff = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2029 break;
2030 case Event::synth_param_resonance:
2031 pNote->Override.Resonance = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2032 break;
2033 case Event::synth_param_attack:
2034 pNote->Override.Attack = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2035 break;
2036 case Event::synth_param_decay:
2037 pNote->Override.Decay = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2038 break;
2039 case Event::synth_param_release:
2040 pNote->Override.Release = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2041 break;
2042 case Event::synth_param_amp_lfo_depth:
2043 pNote->Override.AmpLFODepth = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2044 break;
2045 case Event::synth_param_amp_lfo_freq:
2046 pNote->Override.AmpLFOFreq = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2047 break;
2048 case Event::synth_param_pitch_lfo_depth:
2049 pNote->Override.PitchLFODepth = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2050 break;
2051 case Event::synth_param_pitch_lfo_freq:
2052 pNote->Override.PitchLFOFreq = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2053 break;
2054 }
2055
2056 // move note parameter event to its MIDI key
2057 MidiKey* pKey = &pChannel->pMIDIKeyInfo[pNote->hostKey];
2058 itEvent.moveToEndOf(pKey->pEvents);
2059 }
2060
2061 /**
2062 * Reset all voices and disk thread and clear input event queue and all
2063 * control and status variables. This method is protected by a mutex.
2064 */
2065 virtual void ResetInternal() OVERRIDE {
2066 LockGuard lock(ResetInternalMutex);
2067
2068 // make sure that the engine does not get any sysex messages
2069 // while it's reseting
2070 bool sysexDisabled = MidiInputPort::RemoveSysexListener(this);
2071 SetVoiceCount(0);
2072 ActiveVoiceCountMax = 0;
2073
2074 // reset voice stealing parameters
2075 pVoiceStealingQueue->clear();
2076 itLastStolenVoice = VoiceIterator();
2077 itLastStolenVoiceGlobally = VoiceIterator();
2078 itLastStolenNote = NoteIterator();
2079 itLastStolenNoteGlobally = NoteIterator();
2080 iuiLastStolenKey = RTList<uint>::Iterator();
2081 iuiLastStolenKeyGlobally = RTList<uint>::Iterator();
2082 pLastStolenChannel = NULL;
2083
2084 // reset all notes
2085 pNotePool->clear();
2086 for (NoteIterator itNote = pNotePool->allocAppend(); itNote;
2087 itNote = pNotePool->allocAppend())
2088 {
2089 itNote->reset();
2090 }
2091 pNotePool->clear();
2092
2093 // reset all voices
2094 pVoicePool->clear();
2095 for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
2096 iterVoice->Reset();
2097 }
2098 pVoicePool->clear();
2099
2100 // reset all engine channels
2101 for (int i = 0; i < engineChannels.size(); i++) {
2102 AbstractEngineChannel* pEngineChannel =
2103 static_cast<AbstractEngineChannel*>(engineChannels[i]);
2104 pEngineChannel->ResetInternal(false/*don't reset engine*/);
2105 }
2106
2107 // reset disk thread
2108 if (pDiskThread) pDiskThread->Reset();
2109
2110 // delete all input events
2111 pEventQueue->init();
2112 pSysexBuffer->init();
2113 if (sysexDisabled) MidiInputPort::AddSysexListener(this);
2114 }
2115
2116 /**
2117 * Kills all voices on an engine channel as soon as possible. Voices
2118 * won't get into release state, their volume level will be ramped down
2119 * as fast as possible.
2120 *
2121 * @param pEngineChannel - engine channel on which all voices should be killed
2122 * @param itKillEvent - event which caused this killing of all voices
2123 */
2124 virtual void KillAllVoices(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itKillEvent) OVERRIDE {
2125 EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
2126 int count = pChannel->KillAllVoices(itKillEvent);
2127 VoiceSpawnsLeft -= count; //FIXME: just a temporary workaround, we should check the cause in StealVoice() instead
2128 }
2129
2130 /**
2131 * Allocates and triggers a new voice. This method will usually be
2132 * called by the ProcessNoteOn() method and by the voices itself
2133 * (e.g. to spawn further voices on the same key for layered sounds).
2134 *
2135 * @param pEngineChannel - engine channel on which this event occurred on
2136 * @param itNoteOnEvent - key, velocity and time stamp of the event
2137 * @param iLayer - layer index for the new voice (optional - only
2138 * in case of layered sounds of course)
2139 * @param ReleaseTriggerVoice - if new voice is a release triggered voice
2140 * (optional, default = false)
2141 * @param VoiceStealing - if voice stealing should be performed
2142 * when there is no free voice
2143 * (optional, default = true)
2144 * @param HandleKeyGroupConflicts - if voices should be killed due to a
2145 * key group conflict
2146 * @returns pointer to new voice or NULL if there was no free voice or
2147 * if the voice wasn't triggered (for example when no region is
2148 * defined for the given key).
2149 */
2150 virtual PoolVoiceIterator LaunchVoice (
2151 EngineChannel* pEngineChannel,
2152 Pool<Event>::Iterator& itNoteOnEvent,
2153 int iLayer,
2154 bool ReleaseTriggerVoice,
2155 bool VoiceStealing,
2156 bool HandleKeyGroupConflicts
2157 ) = 0;
2158
2159 virtual int GetMinFadeOutSamples() OVERRIDE { return MinFadeOutSamples; }
2160
2161 int InitNewVoice (
2162 EngineChannelBase<V, R, I>* pChannel,
2163 R* pRegion,
2164 Pool<Event>::Iterator& itNoteOnEvent,
2165 Voice::type_t VoiceType,
2166 int iLayer,
2167 int iKeyGroup,
2168 bool ReleaseTriggerVoice,
2169 bool VoiceStealing,
2170 typename Pool<V>::Iterator& itNewVoice
2171 ) {
2172 int key = itNoteOnEvent->Param.Note.Key;
2173 typename MidiKeyboardManager<V>::MidiKey* pKey = &pChannel->pMIDIKeyInfo[key];
2174 if (itNewVoice) {
2175 // launch the new voice
2176 if (itNewVoice->Trigger(pChannel, itNoteOnEvent, pChannel->Pitch, pRegion, VoiceType, iKeyGroup) < 0) {
2177 dmsg(4,("Voice not triggered\n"));
2178 GetVoicePool()->free(itNewVoice);
2179 }
2180 else { // on success
2181 --VoiceSpawnsLeft;
2182 if (!pKey->Active) { // mark as active key
2183 pKey->Active = true;
2184 pKey->itSelf = pChannel->pActiveKeys->allocAppend();
2185 *pKey->itSelf = itNoteOnEvent->Param.Note.Key;
2186 }
2187 if (itNewVoice->Type & Voice::type_release_trigger_required) pKey->ReleaseTrigger = true; // mark key for the need of release triggered voice(s)
2188 return 0; // success
2189 }
2190 }
2191 else if (VoiceStealing) {
2192 // try to steal one voice
2193 int result = StealVoice(pChannel, itNoteOnEvent);
2194 if (!result) { // voice stolen successfully
2195 // put note-on event into voice-stealing queue, so it will be reprocessed after killed voice died
2196 RTList<Event>::Iterator itStealEvent = pVoiceStealingQueue->allocAppend();
2197 if (itStealEvent) {
2198 *itStealEvent = *itNoteOnEvent; // copy event
2199 itStealEvent->Param.Note.Layer = iLayer;
2200 itStealEvent->Param.Note.ReleaseTrigger = ReleaseTriggerVoice;
2201 pKey->VoiceTheftsQueued++;
2202 }
2203 else dmsg(1,("Voice stealing queue full!\n"));
2204 }
2205 }
2206
2207 return -1;
2208 }
2209
2210 /**
2211 * Checks whether scale tuning setting has been changed since last
2212 * time this method was called, if yes, it recalculates the pitch
2213 * for all active voices.
2214 */
2215 void ProcessScaleTuningChange() {
2216 const bool changed = ScaleTuningChanged.readAndReset();
2217 if (!changed) return;
2218
2219 for (int i = 0; i < engineChannels.size(); i++) {
2220 EngineChannelBase<V, R, I>* channel =
2221 static_cast<EngineChannelBase<V, R, I>*>(engineChannels[i]);
2222 channel->OnScaleTuningChanged();
2223 }
2224 }
2225
2226 private:
2227 Pool< Note<V> >* pNotePool;
2228 Pool<note_id_t> noteIDPool;
2229 Pool<V>* pVoicePool; ///< Contains all voices that can be activated.
2230 Pool<RR*> SuspendedRegions;
2231 Mutex SuspendedRegionsMutex;
2232 Condition SuspensionChangeOngoing;
2233 RR* pPendingRegionSuspension;
2234 RR* pPendingRegionResumption;
2235 int iPendingStreamDeletions;
2236 };
2237
2238 template <class V, class RR, class R, class D, class IM, class I>
2239 IM EngineBase<V, RR, R, D, IM, I>::instruments;
2240
2241 } // namespace LinuxSampler
2242
2243 #endif /* __LS_ENGINEBASE_H__ */
2244

  ViewVC Help
Powered by ViewVC