/[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 2434 - (show annotations) (download) (as text)
Thu Mar 7 19:23:24 2013 UTC (11 years ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 79654 byte(s)
* Started to spread new C++ keyword "override" over the code base
  (keyword introduced with C++11 standard).

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

  ViewVC Help
Powered by ViewVC