/[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 3034 - (show annotations) (download) (as text)
Mon Oct 31 00:05:00 2016 UTC (7 years, 4 months ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 121065 byte(s)
* Fixed a bunch of minor issues (mostly compiler warnings).
* Bumped version (2.0.0.svn31).

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

  ViewVC Help
Powered by ViewVC