/[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 3205 - (show annotations) (download) (as text)
Wed May 24 20:05:38 2017 UTC (6 years, 10 months ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 123969 byte(s)
* Fixed invalid (note-on) event ID being assigned to new Note
  objects.
* Fixed a bunch of scheduler time related bugs.
* Bumped version (2.0.0.svn47).

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

  ViewVC Help
Powered by ViewVC