/[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 2296 - (show annotations) (download) (as text)
Thu Dec 8 20:03:47 2011 UTC (12 years, 3 months ago) by iliev
File MIME type: text/x-c++hdr
File size: 79339 byte(s)
* fixed crash when trying to create an effect instance with controls
  which min and/or max values depend on the sample rate
* experimental support for per voice equalization (work in progress)
* sfz engine: implemented opcodes eq1_freq, eq2_freq, eq3_freq,
  eq1_freqccN, eq2_freqccN, eq3_freqccN, eq1_bw, eq2_bw, eq3_bw,
  eq1_bwccN, eq2_bwccN, eq3_bwccN, eq1_gain, eq2_gain, eq3_gain,
  eq1_gainccN, eq2_gainccN, eq3_gainccN

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

  ViewVC Help
Powered by ViewVC