/[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 2043 - (show annotations) (download) (as text)
Sat Jan 9 09:37:01 2010 UTC (14 years, 2 months ago) by persson
File MIME type: text/x-c++hdr
File size: 73400 byte(s)
* gig engine: implemented the "round robin keyboard" dimension
* gig engine: fixed round robin and random dimensions for cases when
  number of dimension zones is not a power of two
* gig engine: made round robin use a counter for each region instead
  of each key
* fixed building with libgig installed in a non-standard directory

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

  ViewVC Help
Powered by ViewVC