/[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 2244 - (show annotations) (download) (as text)
Thu Aug 18 11:32:33 2011 UTC (12 years, 7 months ago) by iliev
File MIME type: text/x-c++hdr
File size: 79187 byte(s)
* sfz engine: use common pool of CC objects to minimize RAM usage

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

  ViewVC Help
Powered by ViewVC