/[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 2879 - (show annotations) (download) (as text)
Tue Apr 19 14:07:53 2016 UTC (8 years ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 108931 byte(s)
* All engines: Active voices are now internally grouped to "Note" objects,
  instead of being directly assigned to a keyboard key. This allows more
  fine graded processing of voices, which is i.e. required for certain
  instrument script features.
* Built-in script function "play_note()": Added support for passing
  special value -1 for "duration-us" argument, which will cause the
  triggered note to be released once the original note was released.
* Bumped version (2.0.0.svn3).

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

  ViewVC Help
Powered by ViewVC