/[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 3697 - (show annotations) (download) (as text)
Sat Jan 4 12:09:45 2020 UTC (4 years, 3 months ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 138320 byte(s)
Implemented support for compressed RPN/NRPN message sequences:

* Allow processing MIDI data entry messages without having to be
  preceded strictly always by RPN/NRPN parameter selection messages
  prior to each value change (i.e. data entry CC).

* Bumped version (2.1.1.svn33).

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

  ViewVC Help
Powered by ViewVC