/[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 2410 - (show annotations) (download) (as text)
Sat Feb 2 18:52:15 2013 UTC (11 years, 2 months ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 79537 byte(s)
* Several fixes in JACK audio driver:
- React on sample rate changes.
- React on buffer size changes.
- jack_port_get_buffer() was cached and called
  outside RT context.

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

  ViewVC Help
Powered by ViewVC