/[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 2448 - (show annotations) (download) (as text)
Fri May 3 14:26:32 2013 UTC (10 years, 11 months ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 80540 byte(s)
* Immediately apply scale tuning changes to active voices.
* Exposed scale tuning to C++ API (along to the already existing standard
  SysEx way).
* Bumped version to 1.0.0.svn21

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-2013 Christian Schoenebeck and Grigor Iliev *
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 * This program is distributed in the hope that it will be useful, *
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
17 * GNU General Public License for more details. *
18 * *
19 * You should have received a copy of the GNU General Public License *
20 * along with this program; if not, write to the Free Software *
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
22 * MA 02111-1307 USA *
23 ***************************************************************************/
24
25 #ifndef __LS_ENGINEBASE_H__
26 #define __LS_ENGINEBASE_H__
27
28 #include "AbstractEngine.h"
29 #include "EngineChannelBase.h"
30 #include "common/DiskThreadBase.h"
31 #include "common/MidiKeyboardManager.h"
32 #include "InstrumentManager.h"
33 #include "../common/global_private.h"
34
35
36 namespace LinuxSampler {
37
38 class AbstractEngineChannel;
39
40 template <
41 class V /* Voice */,
42 class RR /* Root Region */,
43 class R /* Region */,
44 class D /* Disk Thread */,
45 class IM /* Instrument Manager */,
46 class I /* Instrument */
47 >
48 class EngineBase: public AbstractEngine, public RegionPools<R>, public VoicePool<V> {
49
50 public:
51 typedef typename RTList<V>::Iterator VoiceIterator;
52 typedef typename Pool<V>::Iterator PoolVoiceIterator;
53 typedef typename RTList<RR*>::Iterator RootRegionIterator;
54 typedef typename MidiKeyboardManager<V>::MidiKey MidiKey;
55
56 EngineBase() : SuspendedRegions(128) {
57 pDiskThread = NULL;
58 pVoicePool = new Pool<V>(GLOBAL_MAX_VOICES);
59 pRegionPool[0] = new Pool<R*>(GLOBAL_MAX_VOICES);
60 pRegionPool[1] = new Pool<R*>(GLOBAL_MAX_VOICES);
61 pVoiceStealingQueue = new RTList<Event>(pEventPool);
62 iMaxDiskStreams = GLOBAL_MAX_STREAMS;
63
64 for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
65 iterVoice->SetEngine(this);
66 }
67 pVoicePool->clear();
68
69 ResetInternal();
70 ResetScaleTuning();
71 ResetSuspendedRegions();
72 }
73
74 virtual ~EngineBase() {
75 if (pDiskThread) {
76 dmsg(1,("Stopping disk thread..."));
77 pDiskThread->StopThread();
78 delete pDiskThread;
79 dmsg(1,("OK\n"));
80 }
81
82 if (pVoicePool) {
83 pVoicePool->clear();
84 delete pVoicePool;
85 }
86
87 if (pVoiceStealingQueue) delete pVoiceStealingQueue;
88
89 if (pRegionPool[0]) delete pRegionPool[0];
90 if (pRegionPool[1]) delete pRegionPool[1];
91 ResetSuspendedRegions();
92 }
93
94 // implementation of abstract methods derived from class 'LinuxSampler::Engine'
95
96 /**
97 * Let this engine proceed to render the given amount of sample points.
98 * The engine will iterate through all engine channels and render audio
99 * for each engine channel independently. The calculated audio data of
100 * all voices of each engine channel will be placed into the audio sum
101 * buffers of the respective audio output device, connected to the
102 * respective engine channel.
103 *
104 * @param Samples - number of sample points to be rendered
105 * @returns 0 on success
106 */
107 virtual int RenderAudio(uint Samples) OVERRIDE {
108 dmsg(8,("RenderAudio(Samples=%d)\n", Samples));
109
110 // return if engine disabled
111 if (EngineDisabled.Pop()) {
112 dmsg(5,("EngineBase: engine disabled (val=%d)\n",EngineDisabled.GetUnsafe()));
113 EngineDisabled.RttDone();
114 return 0;
115 }
116
117 // process requests for suspending / resuming regions (i.e. to avoid
118 // crashes while these regions are modified by an instrument editor)
119 ProcessSuspensionsChanges();
120
121 // update time of start and end of this audio fragment (as events' time stamps relate to this)
122 pEventGenerator->UpdateFragmentTime(Samples);
123
124 // We only allow the given maximum number of voices to be spawned
125 // in each audio fragment. All subsequent request for spawning new
126 // voices in the same audio fragment will be ignored.
127 VoiceSpawnsLeft = MaxVoices();
128
129 // get all events from the engine's global input event queue which belong to the current fragment
130 // (these are usually just SysEx messages)
131 ImportEvents(Samples);
132
133 // process engine global events (these are currently only MIDI System Exclusive messages)
134 {
135 RTList<Event>::Iterator itEvent = pGlobalEvents->first();
136 RTList<Event>::Iterator end = pGlobalEvents->end();
137 for (; itEvent != end; ++itEvent) {
138 switch (itEvent->Type) {
139 case Event::type_sysex:
140 dmsg(5,("Engine: Sysex received\n"));
141 ProcessSysex(itEvent);
142 break;
143 }
144 }
145 }
146
147 // In case scale tuning has been changed, recalculate pitch for
148 // all active voices.
149 ProcessScaleTuningChange();
150
151 // reset internal voice counter (just for statistic of active voices)
152 ActiveVoiceCountTemp = 0;
153
154 HandleInstrumentChanges();
155
156 // handle events on all engine channels
157 for (int i = 0; i < engineChannels.size(); i++) {
158 ProcessEvents(engineChannels[i], Samples);
159 }
160
161 // render all 'normal', active voices on all engine channels
162 for (int i = 0; i < engineChannels.size(); i++) {
163 RenderActiveVoices(engineChannels[i], Samples);
164 }
165
166 // now that all ordinary voices on ALL engine channels are rendered, render new stolen voices
167 RenderStolenVoices(Samples);
168
169 // handle audio routing for engine channels with FX sends
170 for (int i = 0; i < engineChannels.size(); i++) {
171 AbstractEngineChannel* pChannel = static_cast<AbstractEngineChannel*>(engineChannels[i]);
172 if (pChannel->fxSends.empty()) continue; // ignore if no FX sends
173 RouteAudio(engineChannels[i], Samples);
174 }
175
176 // handle cleanup on all engine channels for the next audio fragment
177 for (int i = 0; i < engineChannels.size(); i++) {
178 PostProcess(engineChannels[i]);
179 }
180
181
182 // empty the engine's event list for the next audio fragment
183 ClearEventLists();
184
185 // reset voice stealing for the next audio fragment
186 pVoiceStealingQueue->clear();
187
188 // just some statistics about this engine instance
189 SetVoiceCount(ActiveVoiceCountTemp);
190 if (VoiceCount() > ActiveVoiceCountMax) ActiveVoiceCountMax = VoiceCount();
191
192 // in case regions were previously suspended and we killed voices
193 // with disk streams due to that, check if those streams have finally
194 // been deleted by the disk thread
195 if (iPendingStreamDeletions) ProcessPendingStreamDeletions();
196
197 // Release the instrument change command. (This has to
198 // be done after all voices have been rendered and not
199 // in HandleInstrumentChanges, as the RegionsInUse
200 // list has been built up by the voice renderers.)
201 for (int i = 0; i < engineChannels.size(); i++) {
202 EngineChannelBase<V, R, I>* channel =
203 static_cast<EngineChannelBase<V, R, I>*>(engineChannels[i]);
204 channel->InstrumentChangeCommandReader.Unlock();
205 }
206 FrameTime += Samples;
207
208 EngineDisabled.RttDone();
209 return 0;
210 }
211
212 virtual int MaxVoices() OVERRIDE { return pVoicePool->poolSize(); }
213
214 virtual void SetMaxVoices(int iVoices) throw (Exception) OVERRIDE {
215 if (iVoices < 1)
216 throw Exception("Maximum voices for an engine cannot be set lower than 1");
217
218 SuspendAll();
219
220 // NOTE: we need to clear pRegionsInUse before deleting pDimRegionPool,
221 // otherwise memory corruption will occur if there are active voices (see bug #118)
222 for (int iChannel = 0; iChannel < engineChannels.size(); iChannel++) {
223 EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannel]);
224 pChannel->ClearRegionsInUse();
225 }
226
227 if (pRegionPool[0]) delete pRegionPool[0];
228 if (pRegionPool[1]) delete pRegionPool[1];
229
230 pRegionPool[0] = new Pool<R*>(iVoices);
231 pRegionPool[1] = new Pool<R*>(iVoices);
232
233 for (int iChannel = 0; iChannel < engineChannels.size(); iChannel++) {
234 EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannel]);
235 pChannel->ResetRegionsInUse(pRegionPool);
236 }
237
238 try {
239 pVoicePool->resizePool(iVoices);
240 } catch (...) {
241 throw Exception("FATAL: Could not resize voice pool!");
242 }
243
244 for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
245 iterVoice->SetEngine(this);
246 iterVoice->pDiskThread = this->pDiskThread;
247 }
248 pVoicePool->clear();
249
250 PostSetMaxVoices(iVoices);
251 ResumeAll();
252 }
253
254 /** Called after the new max number of voices is set and before resuming the engine. */
255 virtual void PostSetMaxVoices(int iVoices) { }
256
257 virtual uint DiskStreamCount() OVERRIDE { return (pDiskThread) ? pDiskThread->GetActiveStreamCount() : 0; }
258 virtual uint DiskStreamCountMax() OVERRIDE { return (pDiskThread) ? pDiskThread->ActiveStreamCountMax : 0; }
259 virtual int MaxDiskStreams() OVERRIDE { return iMaxDiskStreams; }
260
261 virtual void SetMaxDiskStreams(int iStreams) throw (Exception) OVERRIDE {
262 if (iStreams < 0)
263 throw Exception("Maximum disk streams for an engine cannot be set lower than 0");
264
265 SuspendAll();
266
267 iMaxDiskStreams = iStreams;
268
269 // reconnect to audio output device, because that will automatically
270 // recreate the disk thread with the required amount of streams
271 if (pAudioOutputDevice) Connect(pAudioOutputDevice);
272
273 ResumeAll();
274 }
275
276 virtual String DiskStreamBufferFillBytes() OVERRIDE { return (pDiskThread) ? pDiskThread->GetBufferFillBytes() : ""; }
277 virtual String DiskStreamBufferFillPercentage() OVERRIDE { return (pDiskThread) ? pDiskThread->GetBufferFillPercentage() : ""; }
278 virtual InstrumentManager* GetInstrumentManager() OVERRIDE { return &instruments; }
279
280 /**
281 * Connect this engine instance with the given audio output device.
282 * This method will be called when an Engine instance is created.
283 * All of the engine's data structures which are dependant to the used
284 * audio output device / driver will be (re)allocated and / or
285 * adjusted appropriately.
286 *
287 * @param pAudioOut - audio output device to connect to
288 */
289 virtual void Connect(AudioOutputDevice* pAudioOut) OVERRIDE {
290 // caution: don't ignore if connecting to the same device here,
291 // because otherwise SetMaxDiskStreams() implementation won't work anymore!
292
293 pAudioOutputDevice = pAudioOut;
294
295 ResetInternal();
296
297 // inform audio driver for the need of two channels
298 try {
299 pAudioOutputDevice->AcquireChannels(2); // default stereo
300 }
301 catch (AudioOutputException e) {
302 String msg = "Audio output device unable to provide 2 audio channels, cause: " + e.Message();
303 throw Exception(msg);
304 }
305
306 this->MaxSamplesPerCycle = pAudioOutputDevice->MaxSamplesPerCycle();
307 this->SampleRate = pAudioOutputDevice->SampleRate();
308
309 MinFadeOutSamples = int(double(SampleRate) * CONFIG_EG_MIN_RELEASE_TIME) - 1;
310 if (MaxSamplesPerCycle < MinFadeOutSamples) {
311 std::cerr << "EngineBase: WARNING, CONFIG_EG_MIN_RELEASE_TIME "
312 << "too big for current audio fragment size & sampling rate! "
313 << "May lead to click sounds if voice stealing chimes in!\n" << std::flush;
314 // force volume ramp downs at the beginning of each fragment
315 MinFadeOutSamples = MaxSamplesPerCycle;
316 // lower minimum release time
317 const float minReleaseTime = (float) MaxSamplesPerCycle / (float) SampleRate;
318 for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
319 iterVoice->CalculateFadeOutCoeff(minReleaseTime, SampleRate);
320 }
321 pVoicePool->clear();
322 }
323
324 // (re)create disk thread
325 if (this->pDiskThread) {
326 dmsg(1,("Stopping disk thread..."));
327 this->pDiskThread->StopThread();
328 delete this->pDiskThread;
329 dmsg(1,("OK\n"));
330 }
331 this->pDiskThread = CreateDiskThread();
332
333 if (!pDiskThread) {
334 dmsg(0,("EngineBase new diskthread = NULL\n"));
335 exit(EXIT_FAILURE);
336 }
337
338 for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
339 iterVoice->pDiskThread = this->pDiskThread;
340 dmsg(3,("d"));
341 }
342 pVoicePool->clear();
343
344 // (re)create event generator
345 if (pEventGenerator) delete pEventGenerator;
346 pEventGenerator = new EventGenerator(pAudioOut->SampleRate());
347
348 dmsg(1,("Starting disk thread..."));
349 pDiskThread->StartThread();
350 dmsg(1,("OK\n"));
351
352 bool printEqInfo = true;
353 for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
354 if (!iterVoice->pDiskThread) {
355 dmsg(0,("Engine -> voice::trigger: !pDiskThread\n"));
356 exit(EXIT_FAILURE);
357 }
358
359 iterVoice->CreateEq();
360
361 if(printEqInfo) {
362 iterVoice->PrintEqInfo();
363 printEqInfo = false;
364 }
365 }
366 pVoicePool->clear();
367
368 // (re)create dedicated voice audio buffers
369 //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
370 if (pDedicatedVoiceChannelLeft) delete pDedicatedVoiceChannelLeft;
371 if (pDedicatedVoiceChannelRight) delete pDedicatedVoiceChannelRight;
372 pDedicatedVoiceChannelLeft = new AudioChannel(0, MaxSamplesPerCycle);
373 pDedicatedVoiceChannelRight = new AudioChannel(1, MaxSamplesPerCycle);
374 }
375
376 // Implementattion for abstract method derived from Engine.
377 virtual void ReconnectAudioOutputDevice() OVERRIDE {
378 SuspendAll();
379 if (pAudioOutputDevice) Connect(pAudioOutputDevice);
380 ResumeAll();
381 }
382
383 /**
384 * Similar to @c Disable() but this method additionally kills all voices
385 * and disk streams and blocks until all voices and disk streams are actually
386 * killed / deleted.
387 *
388 * @e Note: only the original calling thread is able to re-enable the
389 * engine afterwards by calling @c ResumeAll() later on!
390 */
391 virtual void SuspendAll() {
392 dmsg(2,("Engine: Suspending all ...\n"));
393 // stop the engine, so we can safely modify the engine's
394 // data structures from this foreign thread
395 DisableAndLock();
396 // we could also use the respective class member variable here,
397 // but this is probably safer and cleaner
398 int iPendingStreamDeletions = 0;
399 // kill all voices on all engine channels the *die hard* way
400 for (int iChannel = 0; iChannel < engineChannels.size(); iChannel++) {
401 EngineChannelBase<V, R, I>* pEngineChannel =
402 static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannel]);
403
404 iPendingStreamDeletions += pEngineChannel->KillAllVoicesImmediately();
405 }
406 // wait until all streams were actually deleted by the disk thread
407 while (iPendingStreamDeletions) {
408 while (
409 iPendingStreamDeletions &&
410 pDiskThread->AskForDeletedStream() != Stream::INVALID_HANDLE
411 ) iPendingStreamDeletions--;
412 if (!iPendingStreamDeletions) break;
413 usleep(10000); // sleep for 10ms
414 }
415 dmsg(2,("EngineBase: Everything suspended.\n"));
416 }
417
418 /**
419 * At the moment same as calling @c Enable() directly, but this might
420 * change in future, so better call this method as counterpart to
421 * @c SuspendAll() instead of @c Enable() !
422 */
423 virtual void ResumeAll() { Enable(); }
424
425 /**
426 * Order the engine to stop rendering audio for the given region.
427 * Additionally this method will block until all voices and their disk
428 * streams associated with that region are actually killed / deleted, so
429 * one can i.e. safely modify the region with an instrument editor after
430 * returning from this method.
431 *
432 * @param pRegion - region the engine shall stop using
433 */
434 virtual void Suspend(RR* pRegion) {
435 dmsg(2,("EngineBase: Suspending Region %x ...\n",pRegion));
436 {
437 LockGuard lock(SuspendedRegionsMutex);
438 SuspensionChangeOngoing.Set(true);
439 pPendingRegionSuspension = pRegion;
440 SuspensionChangeOngoing.WaitAndUnlockIf(true);
441 }
442 dmsg(2,("EngineBase: Region %x suspended.",pRegion));
443 }
444
445 /**
446 * Orders the engine to resume playing back the given region, previously
447 * suspended with @c Suspend() .
448 *
449 * @param pRegion - region the engine shall be allowed to use again
450 */
451 virtual void Resume(RR* pRegion) {
452 dmsg(2,("EngineBase: Resuming Region %x ...\n",pRegion));
453 {
454 LockGuard lock(SuspendedRegionsMutex);
455 SuspensionChangeOngoing.Set(true);
456 pPendingRegionResumption = pRegion;
457 SuspensionChangeOngoing.WaitAndUnlockIf(true);
458 }
459 dmsg(2,("EngineBase: Region %x resumed.\n",pRegion));
460 }
461
462 virtual void ResetSuspendedRegions() {
463 SuspendedRegions.clear();
464 iPendingStreamDeletions = 0;
465 pPendingRegionSuspension = pPendingRegionResumption = NULL;
466 SuspensionChangeOngoing.Set(false);
467 }
468
469 /**
470 * Called by the engine's (audio) thread once per cycle to process requests
471 * from the outer world to suspend or resume a given @c gig::Region .
472 */
473 virtual void ProcessSuspensionsChanges() {
474 // process request for suspending one region
475 if (pPendingRegionSuspension) {
476 // kill all voices on all engine channels that use this region
477 for (int iChannel = 0; iChannel < engineChannels.size(); iChannel++) {
478 EngineChannelBase<V, R, I>* pEngineChannel =
479 static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannel]);
480 SuspensionVoiceHandler handler(pPendingRegionSuspension);
481 pEngineChannel->ProcessActiveVoices(&handler);
482 iPendingStreamDeletions += handler.PendingStreamDeletions;
483 }
484 // make sure the region is not yet on the list
485 bool bAlreadySuspended = false;
486 RootRegionIterator iter = SuspendedRegions.first();
487 RootRegionIterator end = SuspendedRegions.end();
488 for (; iter != end; ++iter) { // iterate through all suspended regions
489 if (*iter == pPendingRegionSuspension) { // found
490 bAlreadySuspended = true;
491 dmsg(1,("EngineBase: attempt to suspend an already suspended region !!!\n"));
492 break;
493 }
494 }
495 if (!bAlreadySuspended) {
496 // put the region on the list of suspended regions
497 RootRegionIterator iter = SuspendedRegions.allocAppend();
498 if (iter) {
499 *iter = pPendingRegionSuspension;
500 } else std::cerr << "EngineBase: Could not suspend Region, list is full. This is a bug!!!\n" << std::flush;
501 }
502 // free request slot for next caller (and to make sure that
503 // we're not going to process the same request in the next cycle)
504 pPendingRegionSuspension = NULL;
505 // if no disk stream deletions are pending, awaken other side, as
506 // we're done in this case
507 if (!iPendingStreamDeletions) SuspensionChangeOngoing.Set(false);
508 }
509
510 // process request for resuming one region
511 if (pPendingRegionResumption) {
512 // remove region from the list of suspended regions
513 RootRegionIterator iter = SuspendedRegions.first();
514 RootRegionIterator end = SuspendedRegions.end();
515 for (; iter != end; ++iter) { // iterate through all suspended regions
516 if (*iter == pPendingRegionResumption) { // found
517 SuspendedRegions.free(iter);
518 break; // done
519 }
520 }
521 // free request slot for next caller
522 pPendingRegionResumption = NULL;
523 // awake other side as we're done
524 SuspensionChangeOngoing.Set(false);
525 }
526 }
527
528 /**
529 * Called by the engine's (audio) thread once per cycle to check if
530 * streams of voices that were killed due to suspension request have
531 * finally really been deleted by the disk thread.
532 */
533 virtual void ProcessPendingStreamDeletions() {
534 if (!iPendingStreamDeletions) return;
535 //TODO: or shall we better store a list with stream handles instead of a scalar amount of streams to be deleted? might be safer
536 while (
537 iPendingStreamDeletions &&
538 pDiskThread->AskForDeletedStream() != Stream::INVALID_HANDLE
539 ) iPendingStreamDeletions--;
540 // just for safety ...
541 while (pDiskThread->AskForDeletedStream() != Stream::INVALID_HANDLE);
542 // now that all disk streams are deleted, awake other side as
543 // we're finally done with suspending the requested region
544 if (!iPendingStreamDeletions) SuspensionChangeOngoing.Set(false);
545 }
546
547 /**
548 * Returns @c true if the given region is currently set to be suspended
549 * from being used, @c false otherwise.
550 */
551 virtual bool RegionSuspended(RR* pRegion) {
552 if (SuspendedRegions.isEmpty()) return false;
553 //TODO: or shall we use a sorted container instead of the RTList? might be faster ... or trivial ;-)
554 RootRegionIterator iter = SuspendedRegions.first();
555 RootRegionIterator end = SuspendedRegions.end();
556 for (; iter != end; ++iter) // iterate through all suspended regions
557 if (*iter == pRegion) return true;
558 return false;
559 }
560
561 // implementation of abstract method derived from class 'LinuxSampler::RegionPools'
562 virtual Pool<R*>* GetRegionPool(int index) {
563 if (index < 0 || index > 1) throw Exception("Index out of bounds");
564 return pRegionPool[index];
565 }
566
567 // implementation of abstract method derived from class 'LinuxSampler::VoicePool'
568 virtual Pool<V>* GetVoicePool() { return pVoicePool; }
569
570 D* GetDiskThread() { return pDiskThread; }
571
572 //friend class EngineChannelBase<V, R, I>;
573
574 static IM instruments;
575
576 protected:
577 class SuspensionVoiceHandler : public MidiKeyboardManager<V>::VoiceHandler {
578 public:
579 int PendingStreamDeletions;
580 RR* pPendingRegionSuspension;
581
582 SuspensionVoiceHandler(RR* pPendingRegionSuspension) {
583 PendingStreamDeletions = 0;
584 this->pPendingRegionSuspension = pPendingRegionSuspension;
585 }
586
587 virtual bool Process(MidiKey* pMidiKey) OVERRIDE {
588 VoiceIterator itVoice = pMidiKey->pActiveVoices->first();
589 // if current key is not associated with this region, skip this key
590 if (itVoice->GetRegion()->GetParent() != pPendingRegionSuspension) return false;
591
592 return true;
593 }
594
595 virtual void Process(VoiceIterator& itVoice) OVERRIDE {
596 // request a notification from disk thread side for stream deletion
597 const Stream::Handle hStream = itVoice->KillImmediately(true);
598 if (hStream != Stream::INVALID_HANDLE) { // voice actually used a stream
599 PendingStreamDeletions++;
600 }
601 //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
602 }
603 };
604
605 Pool<R*>* pRegionPool[2]; ///< Double buffered pool, used by the engine channels to keep track of regions in use.
606 int MinFadeOutSamples; ///< The number of samples needed to make an instant fade out (e.g. for voice stealing) without leading to clicks.
607 D* pDiskThread;
608
609 int ActiveVoiceCountTemp; ///< number of currently active voices (for internal usage, will be used for incrementation)
610 VoiceIterator itLastStolenVoice; ///< Only for voice stealing: points to the last voice which was theft in current audio fragment, NULL otherwise.
611 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.
612 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.
613 VoiceIterator itLastStolenVoiceGlobally; ///< Same as itLastStolenVoice, but engine globally
614 RTList<uint>::Iterator iuiLastStolenKeyGlobally; ///< Same as iuiLastStolenKey, but engine globally
615 RTList<Event>* pVoiceStealingQueue; ///< All voice-launching events which had to be postponed due to free voice shortage.
616 Mutex ResetInternalMutex; ///< Mutex to protect the ResetInternal function for concurrent usage (e.g. by the lscp and instrument loader threads).
617 int iMaxDiskStreams;
618
619 /**
620 * Dispatch and handle all events in this audio fragment for the given
621 * engine channel.
622 *
623 * @param pEngineChannel - engine channel on which events should be
624 * processed
625 * @param Samples - amount of sample points to be processed in
626 * this audio fragment cycle
627 */
628 void ProcessEvents(EngineChannel* pEngineChannel, uint Samples) {
629 // get all events from the engine channels's input event queue which belong to the current fragment
630 // (these are the common events like NoteOn, NoteOff, ControlChange, etc.)
631 AbstractEngineChannel* pChannel = static_cast<AbstractEngineChannel*>(pEngineChannel);
632 pChannel->ImportEvents(Samples);
633
634 // process events
635 {
636 RTList<Event>::Iterator itEvent = pChannel->pEvents->first();
637 RTList<Event>::Iterator end = pChannel->pEvents->end();
638 for (; itEvent != end; ++itEvent) {
639 switch (itEvent->Type) {
640 case Event::type_note_on:
641 dmsg(5,("Engine: Note on received\n"));
642 ProcessNoteOn((EngineChannel*)itEvent->pEngineChannel, itEvent);
643 break;
644 case Event::type_note_off:
645 dmsg(5,("Engine: Note off received\n"));
646 ProcessNoteOff((EngineChannel*)itEvent->pEngineChannel, itEvent);
647 break;
648 case Event::type_control_change:
649 dmsg(5,("Engine: MIDI CC received\n"));
650 ProcessControlChange((EngineChannel*)itEvent->pEngineChannel, itEvent);
651 break;
652 case Event::type_pitchbend:
653 dmsg(5,("Engine: Pitchbend received\n"));
654 ProcessPitchbend(static_cast<AbstractEngineChannel*>(itEvent->pEngineChannel), itEvent);
655 break;
656 }
657 }
658 }
659
660 // reset voice stealing for the next engine channel (or next audio fragment)
661 itLastStolenVoice = VoiceIterator();
662 itLastStolenVoiceGlobally = VoiceIterator();
663 iuiLastStolenKey = RTList<uint>::Iterator();
664 iuiLastStolenKeyGlobally = RTList<uint>::Iterator();
665 pLastStolenChannel = NULL;
666 }
667
668 /**
669 * Will be called by LaunchVoice() method in case there are no free
670 * voices left. This method will select and kill one old voice for
671 * voice stealing and postpone the note-on event until the selected
672 * voice actually died.
673 *
674 * @param pEngineChannel - engine channel on which this event occured on
675 * @param itNoteOnEvent - key, velocity and time stamp of the event
676 * @returns 0 on success, a value < 0 if no active voice could be picked for voice stealing
677 */
678 int StealVoice(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {
679 if (VoiceSpawnsLeft <= 0) {
680 dmsg(1,("Max. voice thefts per audio fragment reached (you may raise CONFIG_MAX_VOICES).\n"));
681 return -1;
682 }
683
684 EngineChannelBase<V, R, I>* pEngineChn = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
685
686 if (!pEventPool->poolIsEmpty()) {
687
688 if(!pEngineChn->StealVoice(itNoteOnEvent, &itLastStolenVoice, &iuiLastStolenKey)) {
689 --VoiceSpawnsLeft;
690 return 0;
691 }
692
693 // if we couldn't steal a voice from the same engine channel then
694 // steal oldest voice on the oldest key from any other engine channel
695 // (the smaller engine channel number, the higher priority)
696 EngineChannelBase<V, R, I>* pSelectedChannel;
697 int iChannelIndex;
698 VoiceIterator itSelectedVoice;
699
700 // select engine channel
701 if (pLastStolenChannel) {
702 pSelectedChannel = pLastStolenChannel;
703 iChannelIndex = pSelectedChannel->iEngineIndexSelf;
704 } else { // pick the engine channel followed by this engine channel
705 iChannelIndex = (pEngineChn->iEngineIndexSelf + 1) % engineChannels.size();
706 pSelectedChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannelIndex]);
707 }
708
709 // if we already stole in this fragment, try to proceed on same key
710 if (this->itLastStolenVoiceGlobally) {
711 itSelectedVoice = this->itLastStolenVoiceGlobally;
712 do {
713 ++itSelectedVoice;
714 } while (itSelectedVoice && !itSelectedVoice->IsStealable()); // proceed iterating if voice was created in this fragment cycle
715 }
716
717 #if CONFIG_DEVMODE
718 EngineChannel* pBegin = pSelectedChannel; // to detect endless loop
719 #endif // CONFIG_DEVMODE
720
721 // did we find a 'stealable' voice?
722 if (itSelectedVoice && itSelectedVoice->IsStealable()) {
723 // remember which voice we stole, so we can simply proceed on next voice stealing
724 this->itLastStolenVoiceGlobally = itSelectedVoice;
725 } else while (true) { // iterate through engine channels
726 // get (next) oldest key
727 RTList<uint>::Iterator iuiSelectedKey = (this->iuiLastStolenKeyGlobally) ? ++this->iuiLastStolenKeyGlobally : pSelectedChannel->pActiveKeys->first();
728 this->iuiLastStolenKeyGlobally = RTList<uint>::Iterator(); // to prevent endless loop (see line above)
729 while (iuiSelectedKey) {
730 MidiKey* pSelectedKey = &pSelectedChannel->pMIDIKeyInfo[*iuiSelectedKey];
731 itSelectedVoice = pSelectedKey->pActiveVoices->first();
732 // proceed iterating if voice was created in this fragment cycle
733 while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice;
734 // found a "stealable" voice ?
735 if (itSelectedVoice && itSelectedVoice->IsStealable()) {
736 // remember which voice on which key on which engine channel we stole, so we can simply proceed on next voice stealing
737 this->iuiLastStolenKeyGlobally = iuiSelectedKey;
738 this->itLastStolenVoiceGlobally = itSelectedVoice;
739 this->pLastStolenChannel = pSelectedChannel;
740 goto stealable_voice_found; // selection succeeded
741 }
742 ++iuiSelectedKey; // get next key on current engine channel
743 }
744 // get next engine channel
745 iChannelIndex = (iChannelIndex + 1) % engineChannels.size();
746 pSelectedChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannelIndex]);
747
748 #if CONFIG_DEVMODE
749 if (pSelectedChannel == pBegin) {
750 dmsg(1,("FATAL ERROR: voice stealing endless loop!\n"));
751 dmsg(1,("VoiceSpawnsLeft=%d.\n", VoiceSpawnsLeft));
752 dmsg(1,("Exiting.\n"));
753 exit(-1);
754 }
755 #endif // CONFIG_DEVMODE
756 }
757
758 // jump point if a 'stealable' voice was found
759 stealable_voice_found:
760
761 #if CONFIG_DEVMODE
762 if (!itSelectedVoice->IsActive()) {
763 dmsg(1,("EngineBase: ERROR, tried to steal a voice which was not active !!!\n"));
764 return -1;
765 }
766 #endif // CONFIG_DEVMODE
767
768 // now kill the selected voice
769 itSelectedVoice->Kill(itNoteOnEvent);
770
771 --VoiceSpawnsLeft;
772
773 return 0; // success
774 }
775 else {
776 dmsg(1,("Event pool emtpy!\n"));
777 return -1;
778 }
779 }
780
781 void HandleInstrumentChanges() {
782 bool instrumentChanged = false;
783 for (int i = 0; i < engineChannels.size(); i++) {
784 EngineChannelBase<V, R, I>* pEngineChannel =
785 static_cast<EngineChannelBase<V, R, I>*>(engineChannels[i]);
786
787 // as we're going to (carefully) write some status to the
788 // synchronized struct, we cast away the const
789 InstrumentChangeCmd<R, I>& cmd =
790 const_cast<InstrumentChangeCmd<R, I>&>(pEngineChannel->InstrumentChangeCommandReader.Lock());
791
792 pEngineChannel->pRegionsInUse = cmd.pRegionsInUse;
793 pEngineChannel->pRegionsInUse->clear();
794
795 if (cmd.bChangeInstrument) {
796 // change instrument
797 dmsg(5,("Engine: instrument change command received\n"));
798 cmd.bChangeInstrument = false;
799 pEngineChannel->pInstrument = cmd.pInstrument;
800 instrumentChanged = true;
801
802 pEngineChannel->MarkAllActiveVoicesAsOrphans();
803 }
804 }
805
806 if (instrumentChanged) {
807 //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
808 ResetSuspendedRegions();
809 }
810 }
811
812 /**
813 * Render all 'normal' voices (that is voices which were not stolen in
814 * this fragment) on the given engine channel.
815 *
816 * @param pEngineChannel - engine channel on which audio should be
817 * rendered
818 * @param Samples - amount of sample points to be rendered in
819 * this audio fragment cycle
820 */
821 void RenderActiveVoices(EngineChannel* pEngineChannel, uint Samples) {
822 #if !CONFIG_PROCESS_MUTED_CHANNELS
823 if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
824 #endif
825
826 EngineChannelBase<V, R, I>* pChannel =
827 static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
828 pChannel->RenderActiveVoices(Samples);
829
830 ActiveVoiceCountTemp += pEngineChannel->GetVoiceCount();
831 }
832
833 /**
834 * Render all stolen voices (only voices which were stolen in this
835 * fragment) on the given engine channel. Stolen voices are rendered
836 * after all normal voices have been rendered; this is needed to render
837 * audio of those voices which were selected for voice stealing until
838 * the point were the stealing (that is the take over of the voice)
839 * actually happened.
840 *
841 * @param pEngineChannel - engine channel on which audio should be
842 * rendered
843 * @param Samples - amount of sample points to be rendered in
844 * this audio fragment cycle
845 */
846 void RenderStolenVoices(uint Samples) {
847 RTList<Event>::Iterator itVoiceStealEvent = pVoiceStealingQueue->first();
848 RTList<Event>::Iterator end = pVoiceStealingQueue->end();
849 for (; itVoiceStealEvent != end; ++itVoiceStealEvent) {
850 EngineChannelBase<V, R, I>* pEngineChannel =
851 static_cast<EngineChannelBase<V, R, I>*>(itVoiceStealEvent->pEngineChannel);;
852 if (!pEngineChannel->pInstrument) continue; // ignore if no instrument loaded
853 PoolVoiceIterator itNewVoice =
854 LaunchVoice(pEngineChannel, itVoiceStealEvent, itVoiceStealEvent->Param.Note.Layer, itVoiceStealEvent->Param.Note.ReleaseTrigger, false, false);
855 if (itNewVoice) {
856 itNewVoice->Render(Samples);
857 if (itNewVoice->IsActive()) { // still active
858 *(pEngineChannel->pRegionsInUse->allocAppend()) = itNewVoice->GetRegion();
859 ActiveVoiceCountTemp++;
860 pEngineChannel->SetVoiceCount(pEngineChannel->GetVoiceCount() + 1);
861
862 if (itNewVoice->PlaybackState == Voice::playback_state_disk) {
863 if (itNewVoice->DiskStreamRef.State != Stream::state_unused) {
864 pEngineChannel->SetDiskStreamCount(pEngineChannel->GetDiskStreamCount() + 1);
865 }
866 }
867 } else { // voice reached end, is now inactive
868 pEngineChannel->FreeVoice(itNewVoice); // remove voice from the list of active voices
869 }
870 }
871 else dmsg(1,("EngineBase: ERROR, voice stealing didn't work out!\n"));
872
873 // we need to clear the key's event list explicitly here in case key was never active
874 MidiKey* pKey = &pEngineChannel->pMIDIKeyInfo[itVoiceStealEvent->Param.Note.Key];
875 pKey->VoiceTheftsQueued--;
876 if (!pKey->Active && !pKey->VoiceTheftsQueued) pKey->pEvents->clear();
877 }
878 }
879
880 /**
881 * Free all keys which have turned inactive in this audio fragment, from
882 * the list of active keys and clear all event lists on that engine
883 * channel.
884 *
885 * @param pEngineChannel - engine channel to cleanup
886 */
887 void PostProcess(EngineChannel* pEngineChannel) {
888 EngineChannelBase<V, R, I>* pChannel =
889 static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
890 pChannel->FreeAllInactiveKyes();
891
892 // empty the engine channel's own event lists
893 pChannel->ClearEventLists();
894 }
895
896 /**
897 * Process MIDI control change events with hard coded behavior,
898 * that is controllers whose behavior is defined independently
899 * of the actual sampler engine type and instrument.
900 *
901 * @param pEngineChannel - engine channel on which the MIDI CC event was received
902 * @param itControlChangeEvent - the actual MIDI CC event
903 */
904 void ProcessHardcodedControllers (
905 EngineChannel* pEngineChannel,
906 Pool<Event>::Iterator& itControlChangeEvent
907 ) {
908 EngineChannelBase<V, R, I>* pChannel =
909 static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
910
911 switch (itControlChangeEvent->Param.CC.Controller) {
912 case 5: { // portamento time
913 pChannel->PortamentoTime = (float) itControlChangeEvent->Param.CC.Value / 127.0f * (float) CONFIG_PORTAMENTO_TIME_MAX + (float) CONFIG_PORTAMENTO_TIME_MIN;
914 break;
915 }
916 case 6: { // data entry (currently only used for RPN and NRPN controllers)
917 //dmsg(1,("DATA ENTRY %d\n", itControlChangeEvent->Param.CC.Value));
918 if (pChannel->GetMidiRpnController() >= 0) { // RPN controller number was sent previously ...
919 dmsg(4,("Guess it's an RPN ...\n"));
920 if (pChannel->GetMidiRpnController() == 2) { // coarse tuning in half tones
921 int transpose = (int) itControlChangeEvent->Param.CC.Value - 64;
922 // limit to +- two octaves for now
923 transpose = RTMath::Min(transpose, 24);
924 transpose = RTMath::Max(transpose, -24);
925 pChannel->GlobalTranspose = transpose;
926 // workaround, so we won't have hanging notes
927 pChannel->ReleaseAllVoices(itControlChangeEvent);
928 }
929 // to prevent other MIDI CC #6 messages to be misenterpreted as RPN controller data
930 pChannel->ResetMidiRpnController();
931 } else if (pChannel->GetMidiNrpnController() >= 0) { // NRPN controller number was sent previously ...
932 dmsg(4,("Guess it's an NRPN ...\n"));
933 const int NrpnCtrlMSB = pChannel->GetMidiNrpnController() >> 8;
934 const int NrpnCtrlLSB = pChannel->GetMidiNrpnController() & 0xff;
935 dmsg(4,("NRPN MSB=%d LSB=%d Data=%d\n", NrpnCtrlMSB, NrpnCtrlLSB, itControlChangeEvent->Param.CC.Value));
936 switch (NrpnCtrlMSB) {
937 case 0x1a: { // volume level of note (Roland GS NRPN)
938 const uint note = NrpnCtrlLSB;
939 const uint vol = itControlChangeEvent->Param.CC.Value;
940 dmsg(4,("Note Volume NRPN received (note=%d,vol=%d).\n", note, vol));
941 if (note < 128 && vol < 128)
942 pChannel->pMIDIKeyInfo[note].Volume = VolumeCurve[vol];
943 break;
944 }
945 case 0x1c: { // panpot of note (Roland GS NRPN)
946 const uint note = NrpnCtrlLSB;
947 const uint pan = itControlChangeEvent->Param.CC.Value;
948 dmsg(4,("Note Pan NRPN received (note=%d,pan=%d).\n", note, pan));
949 if (note < 128 && pan < 128) {
950 pChannel->pMIDIKeyInfo[note].PanLeft = PanCurve[128 - pan];
951 pChannel->pMIDIKeyInfo[note].PanRight = PanCurve[pan];
952 }
953 break;
954 }
955 case 0x1d: { // reverb send of note (Roland GS NRPN)
956 const uint note = NrpnCtrlLSB;
957 const float reverb = float(itControlChangeEvent->Param.CC.Value) / 127.0f;
958 dmsg(4,("Note Reverb Send NRPN received (note=%d,send=%d).\n", note, reverb));
959 if (note < 128)
960 pChannel->pMIDIKeyInfo[note].ReverbSend = reverb;
961 break;
962 }
963 case 0x1e: { // chorus send of note (Roland GS NRPN)
964 const uint note = NrpnCtrlLSB;
965 const float chorus = float(itControlChangeEvent->Param.CC.Value) / 127.0f;
966 dmsg(4,("Note Chorus Send NRPN received (note=%d,send=%d).\n", note, chorus));
967 if (note < 128)
968 pChannel->pMIDIKeyInfo[note].ChorusSend = chorus;
969 break;
970 }
971 }
972 // to prevent other MIDI CC #6 messages to be misenterpreted as NRPN controller data
973 pChannel->ResetMidiNrpnController();
974 }
975 break;
976 }
977 case 7: { // volume
978 //TODO: not sample accurate yet
979 pChannel->MidiVolume = VolumeCurve[itControlChangeEvent->Param.CC.Value];
980 pChannel->bStatusChanged = true; // engine channel status has changed, so set notify flag
981 break;
982 }
983 case 10: { // panpot
984 //TODO: not sample accurate yet
985 pChannel->iLastPanRequest = itControlChangeEvent->Param.CC.Value;
986 break;
987 }
988 case 64: { // sustain
989 if (itControlChangeEvent->Param.CC.Value >= 64 && !pChannel->SustainPedal) {
990 dmsg(4,("DAMPER (RIGHT) PEDAL DOWN\n"));
991 pChannel->SustainPedal = true;
992 pChannel->listeners.PreProcessSustainPedalDown();
993
994 #if !CONFIG_PROCESS_MUTED_CHANNELS
995 if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
996 pChannel->listeners.PostProcessSustainPedalDown();
997 return;
998 }
999 #endif
1000
1001 pChannel->ProcessSustainPedalDown(itControlChangeEvent);
1002 pChannel->listeners.PostProcessSustainPedalDown();
1003 }
1004 if (itControlChangeEvent->Param.CC.Value < 64 && pChannel->SustainPedal) {
1005 dmsg(4,("DAMPER (RIGHT) PEDAL UP\n"));
1006 pChannel->SustainPedal = false;
1007 pChannel->listeners.PreProcessSustainPedalUp();
1008
1009 #if !CONFIG_PROCESS_MUTED_CHANNELS
1010 if (pChannel->GetMute()) { // skip if sampler channel is muted
1011 pChannel->listeners.PostProcessSustainPedalUp();
1012 return;
1013 }
1014 #endif
1015
1016 pChannel->ProcessSustainPedalUp(itControlChangeEvent);
1017 pChannel->listeners.PostProcessSustainPedalUp();
1018 }
1019 break;
1020 }
1021 case 65: { // portamento on / off
1022 const bool bPortamento = itControlChangeEvent->Param.CC.Value >= 64;
1023 if (bPortamento != pChannel->PortamentoMode)
1024 KillAllVoices(pChannel, itControlChangeEvent);
1025 pChannel->PortamentoMode = bPortamento;
1026 break;
1027 }
1028 case 66: { // sostenuto
1029 if (itControlChangeEvent->Param.CC.Value >= 64 && !pChannel->SostenutoPedal) {
1030 dmsg(4,("SOSTENUTO (CENTER) PEDAL DOWN\n"));
1031 pChannel->SostenutoPedal = true;
1032 pChannel->listeners.PreProcessSostenutoPedalDown();
1033
1034 #if !CONFIG_PROCESS_MUTED_CHANNELS
1035 if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
1036 pChannel->listeners.PostProcessSostenutoPedalDown();
1037 return;
1038 }
1039 #endif
1040
1041 pChannel->ProcessSostenutoPedalDown();
1042 pChannel->listeners.PostProcessSostenutoPedalDown();
1043 }
1044 if (itControlChangeEvent->Param.CC.Value < 64 && pChannel->SostenutoPedal) {
1045 dmsg(4,("SOSTENUTO (CENTER) PEDAL UP\n"));
1046 pChannel->SostenutoPedal = false;
1047 pChannel->listeners.PreProcessSostenutoPedalUp();
1048
1049 #if !CONFIG_PROCESS_MUTED_CHANNELS
1050 if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
1051 pChannel->listeners.PostProcessSostenutoPedalUp();
1052 return;
1053 }
1054 #endif
1055
1056 pChannel->ProcessSostenutoPedalUp(itControlChangeEvent);
1057 pChannel->listeners.PostProcessSostenutoPedalUp();
1058 }
1059 break;
1060 }
1061 case 98: { // NRPN controller LSB
1062 dmsg(4,("NRPN LSB %d\n", itControlChangeEvent->Param.CC.Value));
1063 pEngineChannel->SetMidiNrpnControllerLsb(itControlChangeEvent->Param.CC.Value);
1064 break;
1065 }
1066 case 99: { // NRPN controller MSB
1067 dmsg(4,("NRPN MSB %d\n", itControlChangeEvent->Param.CC.Value));
1068 pEngineChannel->SetMidiNrpnControllerMsb(itControlChangeEvent->Param.CC.Value);
1069 break;
1070 }
1071 case 100: { // RPN controller LSB
1072 dmsg(4,("RPN LSB %d\n", itControlChangeEvent->Param.CC.Value));
1073 pEngineChannel->SetMidiRpnControllerLsb(itControlChangeEvent->Param.CC.Value);
1074 break;
1075 }
1076 case 101: { // RPN controller MSB
1077 dmsg(4,("RPN MSB %d\n", itControlChangeEvent->Param.CC.Value));
1078 pEngineChannel->SetMidiRpnControllerMsb(itControlChangeEvent->Param.CC.Value);
1079 break;
1080 }
1081
1082
1083 // Channel Mode Messages
1084
1085 case 120: { // all sound off
1086 KillAllVoices(pEngineChannel, itControlChangeEvent);
1087 break;
1088 }
1089 case 121: { // reset all controllers
1090 pChannel->ResetControllers();
1091 break;
1092 }
1093 case 123: { // all notes off
1094 #if CONFIG_PROCESS_ALL_NOTES_OFF
1095 pChannel->ReleaseAllVoices(itControlChangeEvent);
1096 #endif // CONFIG_PROCESS_ALL_NOTES_OFF
1097 break;
1098 }
1099 case 126: { // mono mode on
1100 if (!pChannel->SoloMode)
1101 KillAllVoices(pEngineChannel, itControlChangeEvent);
1102 pChannel->SoloMode = true;
1103 break;
1104 }
1105 case 127: { // poly mode on
1106 if (pChannel->SoloMode)
1107 KillAllVoices(pEngineChannel, itControlChangeEvent);
1108 pChannel->SoloMode = false;
1109 break;
1110 }
1111 }
1112 }
1113
1114 virtual D* CreateDiskThread() = 0;
1115
1116 /**
1117 * Assigns and triggers a new voice for the respective MIDI key.
1118 *
1119 * @param pEngineChannel - engine channel on which this event occured on
1120 * @param itNoteOnEvent - key, velocity and time stamp of the event
1121 */
1122 virtual void ProcessNoteOn(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {
1123 EngineChannelBase<V, R, I>* pChannel =
1124 static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1125
1126 //HACK: we should better add the transpose value only to the most mandatory places (like for retrieving the region and calculating the tuning), because otherwise voices will unintendedly survive when changing transpose while playing
1127 int k = itNoteOnEvent->Param.Note.Key + pChannel->GlobalTranspose;
1128 if (k < 0 || k > 127) return; //ignore keys outside the key range
1129
1130 itNoteOnEvent->Param.Note.Key += pChannel->GlobalTranspose;
1131 int vel = itNoteOnEvent->Param.Note.Velocity;
1132
1133 const int key = itNoteOnEvent->Param.Note.Key;
1134 MidiKey* pKey = &pChannel->pMIDIKeyInfo[key];
1135
1136 pChannel->listeners.PreProcessNoteOn(key, vel);
1137 #if !CONFIG_PROCESS_MUTED_CHANNELS
1138 if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
1139 pChannel->listeners.PostProcessNoteOn(key, vel);
1140 return;
1141 }
1142 #endif
1143
1144 if (!pChannel->pInstrument) {
1145 pChannel->listeners.PostProcessNoteOn(key, vel);
1146 return; // ignore if no instrument loaded
1147 }
1148
1149 // move note on event to the key's own event list
1150 RTList<Event>::Iterator itNoteOnEventOnKeyList = itNoteOnEvent.moveToEndOf(pKey->pEvents);
1151
1152 // if Solo Mode then kill all already active voices
1153 if (pChannel->SoloMode) {
1154 Pool<uint>::Iterator itYoungestKey = pChannel->pActiveKeys->last();
1155 if (itYoungestKey) {
1156 const int iYoungestKey = *itYoungestKey;
1157 const MidiKey* pOtherKey = &pChannel->pMIDIKeyInfo[iYoungestKey];
1158 if (pOtherKey->Active) {
1159 // get final portamento position of currently active voice
1160 if (pChannel->PortamentoMode) {
1161 VoiceIterator itVoice = pOtherKey->pActiveVoices->last();
1162 if (itVoice) itVoice->UpdatePortamentoPos(itNoteOnEventOnKeyList);
1163 }
1164 // kill all voices on the (other) key
1165 VoiceIterator itVoiceToBeKilled = pOtherKey->pActiveVoices->first();
1166 VoiceIterator end = pOtherKey->pActiveVoices->end();
1167 for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1168 if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))
1169 itVoiceToBeKilled->Kill(itNoteOnEventOnKeyList);
1170 }
1171 }
1172 }
1173 // set this key as 'currently active solo key'
1174 pChannel->SoloKey = key;
1175 }
1176
1177 pChannel->ProcessKeySwitchChange(key);
1178
1179 pKey->KeyPressed = true; // the MIDI key was now pressed down
1180 pKey->Velocity = itNoteOnEventOnKeyList->Param.Note.Velocity;
1181 pKey->NoteOnTime = FrameTime + itNoteOnEventOnKeyList->FragmentPos(); // will be used to calculate note length
1182
1183 // cancel release process of voices on this key if needed
1184 if (pKey->Active && !pChannel->SustainPedal) {
1185 RTList<Event>::Iterator itCancelReleaseEvent = pKey->pEvents->allocAppend();
1186 if (itCancelReleaseEvent) {
1187 *itCancelReleaseEvent = *itNoteOnEventOnKeyList; // copy event
1188 itCancelReleaseEvent->Type = Event::type_cancel_release; // transform event type
1189 }
1190 else dmsg(1,("Event pool emtpy!\n"));
1191 }
1192
1193 TriggerNewVoices(pEngineChannel, itNoteOnEventOnKeyList);
1194
1195 // if neither a voice was spawned or postponed then remove note on event from key again
1196 if (!pKey->Active && !pKey->VoiceTheftsQueued)
1197 pKey->pEvents->free(itNoteOnEventOnKeyList);
1198
1199 if (!pChannel->SoloMode || pChannel->PortamentoPos < 0.0f) pChannel->PortamentoPos = (float) key;
1200 if (pKey->pRoundRobinIndex) {
1201 (*pKey->pRoundRobinIndex)++; // counter specific for the key or region
1202 pChannel->RoundRobinIndex++; // common counter for the channel
1203 }
1204 pChannel->listeners.PostProcessNoteOn(key, vel);
1205 }
1206
1207 /**
1208 * Allocate and trigger new voice(s) for the key.
1209 */
1210 virtual void TriggerNewVoices (
1211 EngineChannel* pEngineChannel,
1212 RTList<Event>::Iterator& itNoteOnEvent,
1213 bool HandleKeyGroupConflicts = true
1214 ) = 0;
1215
1216 /**
1217 * Allocate and trigger release voice(s) for the key.
1218 */
1219 virtual void TriggerReleaseVoices (
1220 EngineChannel* pEngineChannel,
1221 RTList<Event>::Iterator& itNoteOffEvent
1222 ) = 0;
1223
1224 /**
1225 * Releases the voices on the given key if sustain pedal is not pressed.
1226 * If sustain is pressed, the release of the note will be postponed until
1227 * sustain pedal will be released or voice turned inactive by itself (e.g.
1228 * due to completion of sample playback).
1229 *
1230 * @param pEngineChannel - engine channel on which this event occured on
1231 * @param itNoteOffEvent - key, velocity and time stamp of the event
1232 */
1233 virtual void ProcessNoteOff(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOffEvent) {
1234 EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1235
1236 int k = itNoteOffEvent->Param.Note.Key + pChannel->GlobalTranspose;
1237 if (k < 0 || k > 127) return; //ignore keys outside the key range
1238
1239 //HACK: we should better add the transpose value only to the most mandatory places (like for retrieving the region and calculating the tuning), because otherwise voices will unintendedly survive when changing transpose while playing
1240 itNoteOffEvent->Param.Note.Key += pChannel->GlobalTranspose;
1241 int vel = itNoteOffEvent->Param.Note.Velocity;
1242
1243 const int iKey = itNoteOffEvent->Param.Note.Key;
1244 MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];
1245
1246 pChannel->listeners.PreProcessNoteOff(iKey, vel);
1247
1248 #if !CONFIG_PROCESS_MUTED_CHANNELS
1249 if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
1250 pChannel->listeners.PostProcessNoteOff(iKey, vel);
1251 return;
1252 }
1253 #endif
1254
1255 pKey->KeyPressed = false; // the MIDI key was now released
1256
1257 // move event to the key's own event list
1258 RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);
1259
1260 bool bShouldRelease = pKey->Active && pChannel->ShouldReleaseVoice(itNoteOffEventOnKeyList->Param.Note.Key);
1261
1262 // in case Solo Mode is enabled, kill all voices on this key and respawn a voice on the highest pressed key (if any)
1263 if (pChannel->SoloMode && pChannel->pInstrument) { //TODO: this feels like too much code just for handling solo mode :P
1264 bool bOtherKeysPressed = false;
1265 if (iKey == pChannel->SoloKey) {
1266 pChannel->SoloKey = -1;
1267 // if there's still a key pressed down, respawn a voice (group) on the highest key
1268 for (int i = 127; i > 0; i--) {
1269 MidiKey* pOtherKey = &pChannel->pMIDIKeyInfo[i];
1270 if (pOtherKey->KeyPressed) {
1271 bOtherKeysPressed = true;
1272 // make the other key the new 'currently active solo key'
1273 pChannel->SoloKey = i;
1274 // get final portamento position of currently active voice
1275 if (pChannel->PortamentoMode) {
1276 VoiceIterator itVoice = pKey->pActiveVoices->first();
1277 if (itVoice) itVoice->UpdatePortamentoPos(itNoteOffEventOnKeyList);
1278 }
1279 // create a pseudo note on event
1280 RTList<Event>::Iterator itPseudoNoteOnEvent = pOtherKey->pEvents->allocAppend();
1281 if (itPseudoNoteOnEvent) {
1282 // copy event
1283 *itPseudoNoteOnEvent = *itNoteOffEventOnKeyList;
1284 // transform event to a note on event
1285 itPseudoNoteOnEvent->Type = Event::type_note_on;
1286 itPseudoNoteOnEvent->Param.Note.Key = i;
1287 itPseudoNoteOnEvent->Param.Note.Velocity = pOtherKey->Velocity;
1288 // allocate and trigger new voice(s) for the other key
1289 TriggerNewVoices(pChannel, itPseudoNoteOnEvent, false);
1290 // if neither a voice was spawned or postponed then remove note on event from key again
1291 if (!pOtherKey->Active && !pOtherKey->VoiceTheftsQueued)
1292 pOtherKey->pEvents->free(itPseudoNoteOnEvent);
1293
1294 } else dmsg(1,("Could not respawn voice, no free event left\n"));
1295 break; // done
1296 }
1297 }
1298 }
1299 if (bOtherKeysPressed) {
1300 if (pKey->Active) { // kill all voices on this key
1301 bShouldRelease = false; // no need to release, as we kill it here
1302 VoiceIterator itVoiceToBeKilled = pKey->pActiveVoices->first();
1303 VoiceIterator end = pKey->pActiveVoices->end();
1304 for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1305 if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))
1306 itVoiceToBeKilled->Kill(itNoteOffEventOnKeyList);
1307 }
1308 }
1309 } else pChannel->PortamentoPos = -1.0f;
1310 }
1311
1312 // if no solo mode (the usual case) or if solo mode and no other key pressed, then release voices on this key if needed
1313 if (bShouldRelease) {
1314 itNoteOffEventOnKeyList->Type = Event::type_release; // transform event type
1315
1316 // spawn release triggered voice(s) if needed
1317 if (pKey->ReleaseTrigger && pChannel->pInstrument) {
1318 TriggerReleaseVoices(pChannel, itNoteOffEventOnKeyList);
1319 pKey->ReleaseTrigger = false;
1320 }
1321 }
1322
1323 // if neither a voice was spawned or postponed on this key then remove note off event from key again
1324 if (!pKey->Active && !pKey->VoiceTheftsQueued)
1325 pKey->pEvents->free(itNoteOffEventOnKeyList);
1326
1327 pChannel->listeners.PostProcessNoteOff(iKey, vel);
1328 }
1329
1330 /**
1331 * Reset all voices and disk thread and clear input event queue and all
1332 * control and status variables. This method is protected by a mutex.
1333 */
1334 virtual void ResetInternal() {
1335 LockGuard lock(ResetInternalMutex);
1336
1337 // make sure that the engine does not get any sysex messages
1338 // while it's reseting
1339 bool sysexDisabled = MidiInputPort::RemoveSysexListener(this);
1340 SetVoiceCount(0);
1341 ActiveVoiceCountMax = 0;
1342
1343 // reset voice stealing parameters
1344 pVoiceStealingQueue->clear();
1345 itLastStolenVoice = VoiceIterator();
1346 itLastStolenVoiceGlobally = VoiceIterator();
1347 iuiLastStolenKey = RTList<uint>::Iterator();
1348 iuiLastStolenKeyGlobally = RTList<uint>::Iterator();
1349 pLastStolenChannel = NULL;
1350
1351 // reset all voices
1352 for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
1353 iterVoice->Reset();
1354 }
1355 pVoicePool->clear();
1356
1357 // reset disk thread
1358 if (pDiskThread) pDiskThread->Reset();
1359
1360 // delete all input events
1361 pEventQueue->init();
1362 pSysexBuffer->init();
1363 if (sysexDisabled) MidiInputPort::AddSysexListener(this);
1364 }
1365
1366 /**
1367 * Kills all voices on an engine channel as soon as possible. Voices
1368 * won't get into release state, their volume level will be ramped down
1369 * as fast as possible.
1370 *
1371 * @param pEngineChannel - engine channel on which all voices should be killed
1372 * @param itKillEvent - event which caused this killing of all voices
1373 */
1374 virtual void KillAllVoices(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itKillEvent) {
1375 EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1376 int count = pChannel->KillAllVoices(itKillEvent);
1377 VoiceSpawnsLeft -= count; //FIXME: just a temporary workaround, we should check the cause in StealVoice() instead
1378 }
1379
1380 /**
1381 * Allocates and triggers a new voice. This method will usually be
1382 * called by the ProcessNoteOn() method and by the voices itself
1383 * (e.g. to spawn further voices on the same key for layered sounds).
1384 *
1385 * @param pEngineChannel - engine channel on which this event occured on
1386 * @param itNoteOnEvent - key, velocity and time stamp of the event
1387 * @param iLayer - layer index for the new voice (optional - only
1388 * in case of layered sounds of course)
1389 * @param ReleaseTriggerVoice - if new voice is a release triggered voice
1390 * (optional, default = false)
1391 * @param VoiceStealing - if voice stealing should be performed
1392 * when there is no free voice
1393 * (optional, default = true)
1394 * @param HandleKeyGroupConflicts - if voices should be killed due to a
1395 * key group conflict
1396 * @returns pointer to new voice or NULL if there was no free voice or
1397 * if the voice wasn't triggered (for example when no region is
1398 * defined for the given key).
1399 */
1400 virtual PoolVoiceIterator LaunchVoice (
1401 EngineChannel* pEngineChannel,
1402 Pool<Event>::Iterator& itNoteOnEvent,
1403 int iLayer,
1404 bool ReleaseTriggerVoice,
1405 bool VoiceStealing,
1406 bool HandleKeyGroupConflicts
1407 ) = 0;
1408
1409 virtual int GetMinFadeOutSamples() { return MinFadeOutSamples; }
1410
1411 int InitNewVoice (
1412 EngineChannelBase<V, R, I>* pChannel,
1413 R* pRegion,
1414 Pool<Event>::Iterator& itNoteOnEvent,
1415 Voice::type_t VoiceType,
1416 int iLayer,
1417 int iKeyGroup,
1418 bool ReleaseTriggerVoice,
1419 bool VoiceStealing,
1420 typename Pool<V>::Iterator& itNewVoice
1421 ) {
1422 int key = itNoteOnEvent->Param.Note.Key;
1423 typename MidiKeyboardManager<V>::MidiKey* pKey = &pChannel->pMIDIKeyInfo[key];
1424 if (itNewVoice) {
1425 // launch the new voice
1426 if (itNewVoice->Trigger(pChannel, itNoteOnEvent, pChannel->Pitch, pRegion, VoiceType, iKeyGroup) < 0) {
1427 dmsg(4,("Voice not triggered\n"));
1428 pKey->pActiveVoices->free(itNewVoice);
1429 }
1430 else { // on success
1431 --VoiceSpawnsLeft;
1432 if (!pKey->Active) { // mark as active key
1433 pKey->Active = true;
1434 pKey->itSelf = pChannel->pActiveKeys->allocAppend();
1435 *pKey->itSelf = itNoteOnEvent->Param.Note.Key;
1436 }
1437 if (itNewVoice->Type & Voice::type_release_trigger_required) pKey->ReleaseTrigger = true; // mark key for the need of release triggered voice(s)
1438 return 0; // success
1439 }
1440 }
1441 else if (VoiceStealing) {
1442 // try to steal one voice
1443 int result = StealVoice(pChannel, itNoteOnEvent);
1444 if (!result) { // voice stolen successfully
1445 // put note-on event into voice-stealing queue, so it will be reprocessed after killed voice died
1446 RTList<Event>::Iterator itStealEvent = pVoiceStealingQueue->allocAppend();
1447 if (itStealEvent) {
1448 *itStealEvent = *itNoteOnEvent; // copy event
1449 itStealEvent->Param.Note.Layer = iLayer;
1450 itStealEvent->Param.Note.ReleaseTrigger = ReleaseTriggerVoice;
1451 pKey->VoiceTheftsQueued++;
1452 }
1453 else dmsg(1,("Voice stealing queue full!\n"));
1454 }
1455 }
1456
1457 return -1;
1458 }
1459
1460 /**
1461 * Checks whether scale tuning setting has been changed since last
1462 * time this method was called, if yes, it recalculates the pitch
1463 * for all active voices.
1464 */
1465 void ProcessScaleTuningChange() {
1466 const bool changed = ScaleTuningChanged.readAndReset();
1467 if (!changed) return;
1468
1469 for (int i = 0; i < engineChannels.size(); i++) {
1470 EngineChannelBase<V, R, I>* channel =
1471 static_cast<EngineChannelBase<V, R, I>*>(engineChannels[i]);
1472 channel->OnScaleTuningChanged();
1473 }
1474 }
1475
1476 private:
1477 Pool<V>* pVoicePool; ///< Contains all voices that can be activated.
1478 Pool<RR*> SuspendedRegions;
1479 Mutex SuspendedRegionsMutex;
1480 Condition SuspensionChangeOngoing;
1481 RR* pPendingRegionSuspension;
1482 RR* pPendingRegionResumption;
1483 int iPendingStreamDeletions;
1484 };
1485
1486 template <class V, class RR, class R, class D, class IM, class I>
1487 IM EngineBase<V, RR, R, D, IM, I>::instruments;
1488
1489 } // namespace LinuxSampler
1490
1491 #endif /* __LS_ENGINEBASE_H__ */
1492

  ViewVC Help
Powered by ViewVC