/[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 2012 - (show annotations) (download) (as text)
Fri Oct 23 17:53:17 2009 UTC (14 years, 5 months ago) by iliev
File MIME type: text/x-c++hdr
File size: 70370 byte(s)
* Refactoring: moved the independent code from
  the Gigasampler format engine to base classes
* SFZ format engine: experimental code (not usable yet)
* SoundFont format engine: experimental code (not usable yet)
* Fixed crash which may occur when MIDI key + transpose is out of range

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 VoiceSpawnsLeft; ///< We only allow CONFIG_MAX_VOICES voices to be spawned per audio fragment, we use this variable to ensure this limit.
568 int ActiveVoiceCountTemp; ///< number of currently active voices (for internal usage, will be used for incrementation)
569 VoiceIterator itLastStolenVoice; ///< Only for voice stealing: points to the last voice which was theft in current audio fragment, NULL otherwise.
570 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.
571 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.
572 VoiceIterator itLastStolenVoiceGlobally; ///< Same as itLastStolenVoice, but engine globally
573 RTList<uint>::Iterator iuiLastStolenKeyGlobally; ///< Same as iuiLastStolenKey, but engine globally
574 RTList<Event>* pVoiceStealingQueue; ///< All voice-launching events which had to be postponed due to free voice shortage.
575 Mutex ResetInternalMutex; ///< Mutex to protect the ResetInternal function for concurrent usage (e.g. by the lscp and instrument loader threads).
576 int iMaxDiskStreams;
577
578 /**
579 * Dispatch and handle all events in this audio fragment for the given
580 * engine channel.
581 *
582 * @param pEngineChannel - engine channel on which events should be
583 * processed
584 * @param Samples - amount of sample points to be processed in
585 * this audio fragment cycle
586 */
587 void ProcessEvents(EngineChannel* pEngineChannel, uint Samples) {
588 // get all events from the engine channels's input event queue which belong to the current fragment
589 // (these are the common events like NoteOn, NoteOff, ControlChange, etc.)
590 AbstractEngineChannel* pChannel = static_cast<AbstractEngineChannel*>(pEngineChannel);
591 pChannel->ImportEvents(Samples);
592
593 // process events
594 {
595 RTList<Event>::Iterator itEvent = pChannel->pEvents->first();
596 RTList<Event>::Iterator end = pChannel->pEvents->end();
597 for (; itEvent != end; ++itEvent) {
598 switch (itEvent->Type) {
599 case Event::type_note_on:
600 dmsg(5,("Engine: Note on received\n"));
601 ProcessNoteOn((EngineChannel*)itEvent->pEngineChannel, itEvent);
602 break;
603 case Event::type_note_off:
604 dmsg(5,("Engine: Note off received\n"));
605 ProcessNoteOff((EngineChannel*)itEvent->pEngineChannel, itEvent);
606 break;
607 case Event::type_control_change:
608 dmsg(5,("Engine: MIDI CC received\n"));
609 ProcessControlChange((EngineChannel*)itEvent->pEngineChannel, itEvent);
610 break;
611 case Event::type_pitchbend:
612 dmsg(5,("Engine: Pitchbend received\n"));
613 ProcessPitchbend(static_cast<AbstractEngineChannel*>(itEvent->pEngineChannel), itEvent);
614 break;
615 }
616 }
617 }
618
619 // reset voice stealing for the next engine channel (or next audio fragment)
620 itLastStolenVoice = VoiceIterator();
621 itLastStolenVoiceGlobally = VoiceIterator();
622 iuiLastStolenKey = RTList<uint>::Iterator();
623 iuiLastStolenKeyGlobally = RTList<uint>::Iterator();
624 pLastStolenChannel = NULL;
625 }
626
627 /**
628 * Will be called by LaunchVoice() method in case there are no free
629 * voices left. This method will select and kill one old voice for
630 * voice stealing and postpone the note-on event until the selected
631 * voice actually died.
632 *
633 * @param pEngineChannel - engine channel on which this event occured on
634 * @param itNoteOnEvent - key, velocity and time stamp of the event
635 * @returns 0 on success, a value < 0 if no active voice could be picked for voice stealing
636 */
637 int StealVoice(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {
638 if (VoiceSpawnsLeft <= 0) {
639 dmsg(1,("Max. voice thefts per audio fragment reached (you may raise CONFIG_MAX_VOICES).\n"));
640 return -1;
641 }
642
643 EngineChannelBase<V, R, I>* pEngineChn = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
644
645 if (!pEventPool->poolIsEmpty()) {
646
647 if(!pEngineChn->StealVoice(itNoteOnEvent, &itLastStolenVoice, &iuiLastStolenKey)) {
648 --VoiceSpawnsLeft;
649 return 0;
650 }
651
652 // if we couldn't steal a voice from the same engine channel then
653 // steal oldest voice on the oldest key from any other engine channel
654 // (the smaller engine channel number, the higher priority)
655 EngineChannelBase<V, R, I>* pSelectedChannel;
656 int iChannelIndex;
657 VoiceIterator itSelectedVoice;
658
659 // select engine channel
660 if (pLastStolenChannel) {
661 pSelectedChannel = pLastStolenChannel;
662 iChannelIndex = pSelectedChannel->iEngineIndexSelf;
663 } else { // pick the engine channel followed by this engine channel
664 iChannelIndex = (pEngineChn->iEngineIndexSelf + 1) % engineChannels.size();
665 pSelectedChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannelIndex]);
666 }
667
668 // if we already stole in this fragment, try to proceed on same key
669 if (this->itLastStolenVoiceGlobally) {
670 itSelectedVoice = this->itLastStolenVoiceGlobally;
671 do {
672 ++itSelectedVoice;
673 } while (itSelectedVoice && !itSelectedVoice->IsStealable()); // proceed iterating if voice was created in this fragment cycle
674 }
675
676 #if CONFIG_DEVMODE
677 EngineChannel* pBegin = pSelectedChannel; // to detect endless loop
678 #endif // CONFIG_DEVMODE
679
680 // did we find a 'stealable' voice?
681 if (itSelectedVoice && itSelectedVoice->IsStealable()) {
682 // remember which voice we stole, so we can simply proceed on next voice stealing
683 this->itLastStolenVoiceGlobally = itSelectedVoice;
684 } else while (true) { // iterate through engine channels
685 // get (next) oldest key
686 RTList<uint>::Iterator iuiSelectedKey = (this->iuiLastStolenKeyGlobally) ? ++this->iuiLastStolenKeyGlobally : pSelectedChannel->pActiveKeys->first();
687 this->iuiLastStolenKeyGlobally = RTList<uint>::Iterator(); // to prevent endless loop (see line above)
688 while (iuiSelectedKey) {
689 MidiKey* pSelectedKey = &pSelectedChannel->pMIDIKeyInfo[*iuiSelectedKey];
690 itSelectedVoice = pSelectedKey->pActiveVoices->first();
691 // proceed iterating if voice was created in this fragment cycle
692 while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice;
693 // found a "stealable" voice ?
694 if (itSelectedVoice && itSelectedVoice->IsStealable()) {
695 // remember which voice on which key on which engine channel we stole, so we can simply proceed on next voice stealing
696 this->iuiLastStolenKeyGlobally = iuiSelectedKey;
697 this->itLastStolenVoiceGlobally = itSelectedVoice;
698 this->pLastStolenChannel = pSelectedChannel;
699 goto stealable_voice_found; // selection succeeded
700 }
701 ++iuiSelectedKey; // get next key on current engine channel
702 }
703 // get next engine channel
704 iChannelIndex = (iChannelIndex + 1) % engineChannels.size();
705 pSelectedChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannelIndex]);
706
707 #if CONFIG_DEVMODE
708 if (pSelectedChannel == pBegin) {
709 dmsg(1,("FATAL ERROR: voice stealing endless loop!\n"));
710 dmsg(1,("VoiceSpawnsLeft=%d.\n", VoiceSpawnsLeft));
711 dmsg(1,("Exiting.\n"));
712 exit(-1);
713 }
714 #endif // CONFIG_DEVMODE
715 }
716
717 // jump point if a 'stealable' voice was found
718 stealable_voice_found:
719
720 #if CONFIG_DEVMODE
721 if (!itSelectedVoice->IsActive()) {
722 dmsg(1,("EngineBase: ERROR, tried to steal a voice which was not active !!!\n"));
723 return -1;
724 }
725 #endif // CONFIG_DEVMODE
726
727 // now kill the selected voice
728 itSelectedVoice->Kill(itNoteOnEvent);
729
730 --VoiceSpawnsLeft;
731
732 return 0; // success
733 }
734 else {
735 dmsg(1,("Event pool emtpy!\n"));
736 return -1;
737 }
738 }
739
740 void HandleInstrumentChanges() {
741 bool instrumentChanged = false;
742 for (int i = 0; i < engineChannels.size(); i++) {
743 EngineChannelBase<V, R, I>* pEngineChannel =
744 static_cast<EngineChannelBase<V, R, I>*>(engineChannels[i]);
745
746 // as we're going to (carefully) write some status to the
747 // synchronized struct, we cast away the const
748 InstrumentChangeCmd<R, I>& cmd =
749 const_cast<InstrumentChangeCmd<R, I>&>(pEngineChannel->InstrumentChangeCommandReader.Lock());
750
751 pEngineChannel->pRegionsInUse = cmd.pRegionsInUse;
752 pEngineChannel->pRegionsInUse->clear();
753
754 if (cmd.bChangeInstrument) {
755 // change instrument
756 dmsg(5,("Engine: instrument change command received\n"));
757 cmd.bChangeInstrument = false;
758 pEngineChannel->pInstrument = cmd.pInstrument;
759 instrumentChanged = true;
760
761 pEngineChannel->MarkAllActiveVoicesAsOrphans();
762 }
763 }
764
765 if (instrumentChanged) {
766 //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
767 ResetSuspendedRegions();
768 }
769
770 for (int i = 0; i < engineChannels.size(); i++) {
771 EngineChannelBase<V, R, I>* channel =
772 static_cast<EngineChannelBase<V, R, I>*>(engineChannels[i]);
773 channel->InstrumentChangeCommandReader.Unlock();
774 }
775 }
776
777 /**
778 * Render all 'normal' voices (that is voices which were not stolen in
779 * this fragment) on the given engine channel.
780 *
781 * @param pEngineChannel - engine channel on which audio should be
782 * rendered
783 * @param Samples - amount of sample points to be rendered in
784 * this audio fragment cycle
785 */
786 void RenderActiveVoices(EngineChannel* pEngineChannel, uint Samples) {
787 #if !CONFIG_PROCESS_MUTED_CHANNELS
788 if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
789 #endif
790
791 EngineChannelBase<V, R, I>* pChannel =
792 static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
793 pChannel->RenderActiveVoices(Samples);
794
795 ActiveVoiceCountTemp += pEngineChannel->GetVoiceCount();
796 }
797
798 /**
799 * Render all stolen voices (only voices which were stolen in this
800 * fragment) on the given engine channel. Stolen voices are rendered
801 * after all normal voices have been rendered; this is needed to render
802 * audio of those voices which were selected for voice stealing until
803 * the point were the stealing (that is the take over of the voice)
804 * actually happened.
805 *
806 * @param pEngineChannel - engine channel on which audio should be
807 * rendered
808 * @param Samples - amount of sample points to be rendered in
809 * this audio fragment cycle
810 */
811 void RenderStolenVoices(uint Samples) {
812 RTList<Event>::Iterator itVoiceStealEvent = pVoiceStealingQueue->first();
813 RTList<Event>::Iterator end = pVoiceStealingQueue->end();
814 for (; itVoiceStealEvent != end; ++itVoiceStealEvent) {
815 EngineChannelBase<V, R, I>* pEngineChannel =
816 static_cast<EngineChannelBase<V, R, I>*>(itVoiceStealEvent->pEngineChannel);;
817 if (!pEngineChannel->pInstrument) continue; // ignore if no instrument loaded
818 PoolVoiceIterator itNewVoice =
819 LaunchVoice(pEngineChannel, itVoiceStealEvent, itVoiceStealEvent->Param.Note.Layer, itVoiceStealEvent->Param.Note.ReleaseTrigger, false, false);
820 if (itNewVoice) {
821 itNewVoice->Render(Samples);
822 if (itNewVoice->IsActive()) { // still active
823 *(pEngineChannel->pRegionsInUse->allocAppend()) = itNewVoice->GetRegion();
824 ActiveVoiceCountTemp++;
825 pEngineChannel->SetVoiceCount(pEngineChannel->GetVoiceCount() + 1);
826
827 if (itNewVoice->PlaybackState == Voice::playback_state_disk) {
828 if (itNewVoice->DiskStreamRef.State != Stream::state_unused) {
829 pEngineChannel->SetDiskStreamCount(pEngineChannel->GetDiskStreamCount() + 1);
830 }
831 }
832 } else { // voice reached end, is now inactive
833 pEngineChannel->FreeVoice(itNewVoice); // remove voice from the list of active voices
834 }
835 }
836 else dmsg(1,("EngineBase: ERROR, voice stealing didn't work out!\n"));
837
838 // we need to clear the key's event list explicitly here in case key was never active
839 MidiKey* pKey = &pEngineChannel->pMIDIKeyInfo[itVoiceStealEvent->Param.Note.Key];
840 pKey->VoiceTheftsQueued--;
841 if (!pKey->Active && !pKey->VoiceTheftsQueued) pKey->pEvents->clear();
842 }
843 }
844
845 /**
846 * Free all keys which have turned inactive in this audio fragment, from
847 * the list of active keys and clear all event lists on that engine
848 * channel.
849 *
850 * @param pEngineChannel - engine channel to cleanup
851 */
852 void PostProcess(EngineChannel* pEngineChannel) {
853 EngineChannelBase<V, R, I>* pChannel =
854 static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
855 pChannel->FreeAllInactiveKyes();
856
857 // empty the engine channel's own event lists
858 pChannel->ClearEventLists();
859 }
860
861 void ProcessHardcodedControllers (
862 EngineChannel* pEngineChannel,
863 Pool<Event>::Iterator& itControlChangeEvent
864 ) {
865 EngineChannelBase<V, R, I>* pChannel =
866 static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
867
868 switch (itControlChangeEvent->Param.CC.Controller) {
869 case 5: { // portamento time
870 pChannel->PortamentoTime = (float) itControlChangeEvent->Param.CC.Value / 127.0f * (float) CONFIG_PORTAMENTO_TIME_MAX + (float) CONFIG_PORTAMENTO_TIME_MIN;
871 break;
872 }
873 case 6: { // data entry (currently only used for RPN controllers)
874 if (pChannel->GetMidiRpnController() == 2) { // coarse tuning in half tones
875 int transpose = (int) itControlChangeEvent->Param.CC.Value - 64;
876 // limit to +- two octaves for now
877 transpose = RTMath::Min(transpose, 24);
878 transpose = RTMath::Max(transpose, -24);
879 pChannel->GlobalTranspose = transpose;
880 // workaround, so we won't have hanging notes
881 pChannel->ReleaseAllVoices(itControlChangeEvent);
882 }
883 // to avoid other MIDI CC #6 messages to be misenterpreted as RPN controller data
884 pChannel->ResetMidiRpnController();
885 break;
886 }
887 case 7: { // volume
888 //TODO: not sample accurate yet
889 pChannel->MidiVolume = VolumeCurve[itControlChangeEvent->Param.CC.Value];
890 pChannel->bStatusChanged = true; // engine channel status has changed, so set notify flag
891 break;
892 }
893 case 10: { // panpot
894 //TODO: not sample accurate yet
895 pChannel->GlobalPanLeft = PanCurve[128 - itControlChangeEvent->Param.CC.Value];
896 pChannel->GlobalPanRight = PanCurve[itControlChangeEvent->Param.CC.Value];
897 pChannel->iLastPanRequest = itControlChangeEvent->Param.CC.Value;
898 break;
899 }
900 case 64: { // sustain
901 if (itControlChangeEvent->Param.CC.Value >= 64 && !pChannel->SustainPedal) {
902 dmsg(4,("DAMPER (RIGHT) PEDAL DOWN\n"));
903 pChannel->SustainPedal = true;
904 pChannel->listeners.PreProcessSustainPedalDown();
905
906 #if !CONFIG_PROCESS_MUTED_CHANNELS
907 if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
908 pChannel->listeners.PostProcessSustainPedalDown();
909 return;
910 }
911 #endif
912
913 pChannel->ProcessSustainPedalDown(itControlChangeEvent);
914 pChannel->listeners.PostProcessSustainPedalDown();
915 }
916 if (itControlChangeEvent->Param.CC.Value < 64 && pChannel->SustainPedal) {
917 dmsg(4,("DAMPER (RIGHT) PEDAL UP\n"));
918 pChannel->SustainPedal = false;
919 pChannel->listeners.PreProcessSustainPedalUp();
920
921 #if !CONFIG_PROCESS_MUTED_CHANNELS
922 if (pChannel->GetMute()) { // skip if sampler channel is muted
923 pChannel->listeners.PostProcessSustainPedalUp();
924 return;
925 }
926 #endif
927
928 pChannel->ProcessSustainPedalUp(itControlChangeEvent);
929 pChannel->listeners.PostProcessSustainPedalUp();
930 }
931 break;
932 }
933 case 65: { // portamento on / off
934 const bool bPortamento = itControlChangeEvent->Param.CC.Value >= 64;
935 if (bPortamento != pChannel->PortamentoMode)
936 KillAllVoices(pChannel, itControlChangeEvent);
937 pChannel->PortamentoMode = bPortamento;
938 break;
939 }
940 case 66: { // sostenuto
941 if (itControlChangeEvent->Param.CC.Value >= 64 && !pChannel->SostenutoPedal) {
942 dmsg(4,("SOSTENUTO (CENTER) PEDAL DOWN\n"));
943 pChannel->SostenutoPedal = true;
944 pChannel->listeners.PreProcessSostenutoPedalDown();
945
946 #if !CONFIG_PROCESS_MUTED_CHANNELS
947 if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
948 pChannel->listeners.PostProcessSostenutoPedalDown();
949 return;
950 }
951 #endif
952
953 pChannel->ProcessSostenutoPedalDown();
954 pChannel->listeners.PostProcessSostenutoPedalDown();
955 }
956 if (itControlChangeEvent->Param.CC.Value < 64 && pChannel->SostenutoPedal) {
957 dmsg(4,("SOSTENUTO (CENTER) PEDAL UP\n"));
958 pChannel->SostenutoPedal = false;
959 pChannel->listeners.PreProcessSostenutoPedalUp();
960
961 #if !CONFIG_PROCESS_MUTED_CHANNELS
962 if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
963 pChannel->listeners.PostProcessSostenutoPedalUp();
964 return;
965 }
966 #endif
967
968 pChannel->ProcessSostenutoPedalUp(itControlChangeEvent);
969 pChannel->listeners.PostProcessSostenutoPedalUp();
970 }
971 break;
972 }
973 case 100: { // RPN controller LSB
974 pEngineChannel->SetMidiRpnControllerLsb(itControlChangeEvent->Param.CC.Value);
975 break;
976 }
977 case 101: { // RPN controller MSB
978 pEngineChannel->SetMidiRpnControllerMsb(itControlChangeEvent->Param.CC.Value);
979 break;
980 }
981
982
983 // Channel Mode Messages
984
985 case 120: { // all sound off
986 KillAllVoices(pEngineChannel, itControlChangeEvent);
987 break;
988 }
989 case 121: { // reset all controllers
990 pChannel->ResetControllers();
991 break;
992 }
993 case 123: { // all notes off
994 #if CONFIG_PROCESS_ALL_NOTES_OFF
995 pChannel->ReleaseAllVoices(itControlChangeEvent);
996 #endif // CONFIG_PROCESS_ALL_NOTES_OFF
997 break;
998 }
999 case 126: { // mono mode on
1000 if (!pChannel->SoloMode)
1001 KillAllVoices(pEngineChannel, itControlChangeEvent);
1002 pChannel->SoloMode = true;
1003 break;
1004 }
1005 case 127: { // poly mode on
1006 if (pChannel->SoloMode)
1007 KillAllVoices(pEngineChannel, itControlChangeEvent);
1008 pChannel->SoloMode = false;
1009 break;
1010 }
1011 }
1012 }
1013
1014 virtual D* CreateDiskThread() = 0;
1015
1016 /**
1017 * Assigns and triggers a new voice for the respective MIDI key.
1018 *
1019 * @param pEngineChannel - engine channel on which this event occured on
1020 * @param itNoteOnEvent - key, velocity and time stamp of the event
1021 */
1022 virtual void ProcessNoteOn(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {
1023 EngineChannelBase<V, R, I>* pChannel =
1024 static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1025
1026 //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
1027 int k = itNoteOnEvent->Param.Note.Key + pChannel->GlobalTranspose;
1028 if (k < 0 || k > 127) return; //ignore keys outside the key range
1029
1030 itNoteOnEvent->Param.Note.Key += pChannel->GlobalTranspose;
1031 int vel = itNoteOnEvent->Param.Note.Velocity;
1032
1033 const int key = itNoteOnEvent->Param.Note.Key;
1034 MidiKey* pKey = &pChannel->pMIDIKeyInfo[key];
1035
1036 pChannel->listeners.PreProcessNoteOn(key, vel);
1037 #if !CONFIG_PROCESS_MUTED_CHANNELS
1038 if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
1039 pChannel->listeners.PostProcessNoteOn(key, vel);
1040 return;
1041 }
1042 #endif
1043
1044 if (!pChannel->pInstrument) {
1045 pChannel->listeners.PostProcessNoteOn(key, vel);
1046 return; // ignore if no instrument loaded
1047 }
1048
1049 // move note on event to the key's own event list
1050 RTList<Event>::Iterator itNoteOnEventOnKeyList = itNoteOnEvent.moveToEndOf(pKey->pEvents);
1051
1052 // if Solo Mode then kill all already active voices
1053 if (pChannel->SoloMode) {
1054 Pool<uint>::Iterator itYoungestKey = pChannel->pActiveKeys->last();
1055 if (itYoungestKey) {
1056 const int iYoungestKey = *itYoungestKey;
1057 const MidiKey* pOtherKey = &pChannel->pMIDIKeyInfo[iYoungestKey];
1058 if (pOtherKey->Active) {
1059 // get final portamento position of currently active voice
1060 if (pChannel->PortamentoMode) {
1061 VoiceIterator itVoice = pOtherKey->pActiveVoices->last();
1062 if (itVoice) itVoice->UpdatePortamentoPos(itNoteOnEventOnKeyList);
1063 }
1064 // kill all voices on the (other) key
1065 VoiceIterator itVoiceToBeKilled = pOtherKey->pActiveVoices->first();
1066 VoiceIterator end = pOtherKey->pActiveVoices->end();
1067 for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1068 if (itVoiceToBeKilled->Type != Voice::type_release_trigger)
1069 itVoiceToBeKilled->Kill(itNoteOnEventOnKeyList);
1070 }
1071 }
1072 }
1073 // set this key as 'currently active solo key'
1074 pChannel->SoloKey = key;
1075 }
1076
1077 pChannel->ProcessKeySwitchChange(key);
1078
1079 pKey->KeyPressed = true; // the MIDI key was now pressed down
1080 pKey->Velocity = itNoteOnEventOnKeyList->Param.Note.Velocity;
1081 pKey->NoteOnTime = FrameTime + itNoteOnEventOnKeyList->FragmentPos(); // will be used to calculate note length
1082
1083 // cancel release process of voices on this key if needed
1084 if (pKey->Active && !pChannel->SustainPedal) {
1085 RTList<Event>::Iterator itCancelReleaseEvent = pKey->pEvents->allocAppend();
1086 if (itCancelReleaseEvent) {
1087 *itCancelReleaseEvent = *itNoteOnEventOnKeyList; // copy event
1088 itCancelReleaseEvent->Type = Event::type_cancel_release; // transform event type
1089 }
1090 else dmsg(1,("Event pool emtpy!\n"));
1091 }
1092
1093 TriggerNewVoices(pEngineChannel, itNoteOnEventOnKeyList);
1094
1095 // if neither a voice was spawned or postponed then remove note on event from key again
1096 if (!pKey->Active && !pKey->VoiceTheftsQueued)
1097 pKey->pEvents->free(itNoteOnEventOnKeyList);
1098
1099 if (!pChannel->SoloMode || pChannel->PortamentoPos < 0.0f) pChannel->PortamentoPos = (float) key;
1100 pKey->RoundRobinIndex++;
1101 pChannel->listeners.PostProcessNoteOn(key, vel);
1102 }
1103
1104 /**
1105 * Allocate and trigger new voice(s) for the key.
1106 */
1107 virtual void TriggerNewVoices (
1108 EngineChannel* pEngineChannel,
1109 RTList<Event>::Iterator& itNoteOnEvent,
1110 bool HandleKeyGroupConflicts = true
1111 ) = 0;
1112
1113 /**
1114 * Allocate and trigger release voice(s) for the key.
1115 */
1116 virtual void TriggerReleaseVoices (
1117 EngineChannel* pEngineChannel,
1118 RTList<Event>::Iterator& itNoteOffEvent
1119 ) = 0;
1120
1121 /**
1122 * Releases the voices on the given key if sustain pedal is not pressed.
1123 * If sustain is pressed, the release of the note will be postponed until
1124 * sustain pedal will be released or voice turned inactive by itself (e.g.
1125 * due to completion of sample playback).
1126 *
1127 * @param pEngineChannel - engine channel on which this event occured on
1128 * @param itNoteOffEvent - key, velocity and time stamp of the event
1129 */
1130 virtual void ProcessNoteOff(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOffEvent) {
1131 EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1132
1133 int k = itNoteOffEvent->Param.Note.Key + pChannel->GlobalTranspose;
1134 if (k < 0 || k > 127) return; //ignore keys outside the key range
1135
1136 //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
1137 itNoteOffEvent->Param.Note.Key += pChannel->GlobalTranspose;
1138 int vel = itNoteOffEvent->Param.Note.Velocity;
1139
1140 const int iKey = itNoteOffEvent->Param.Note.Key;
1141 MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];
1142
1143 pChannel->listeners.PreProcessNoteOff(iKey, vel);
1144
1145 #if !CONFIG_PROCESS_MUTED_CHANNELS
1146 if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
1147 pChannel->listeners.PostProcessNoteOff(iKey, vel);
1148 return;
1149 }
1150 #endif
1151
1152 pKey->KeyPressed = false; // the MIDI key was now released
1153
1154 // move event to the key's own event list
1155 RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);
1156
1157 bool bShouldRelease = pKey->Active && pChannel->ShouldReleaseVoice(itNoteOffEventOnKeyList->Param.Note.Key);
1158
1159 // in case Solo Mode is enabled, kill all voices on this key and respawn a voice on the highest pressed key (if any)
1160 if (pChannel->SoloMode && pChannel->pInstrument) { //TODO: this feels like too much code just for handling solo mode :P
1161 bool bOtherKeysPressed = false;
1162 if (iKey == pChannel->SoloKey) {
1163 pChannel->SoloKey = -1;
1164 // if there's still a key pressed down, respawn a voice (group) on the highest key
1165 for (int i = 127; i > 0; i--) {
1166 MidiKey* pOtherKey = &pChannel->pMIDIKeyInfo[i];
1167 if (pOtherKey->KeyPressed) {
1168 bOtherKeysPressed = true;
1169 // make the other key the new 'currently active solo key'
1170 pChannel->SoloKey = i;
1171 // get final portamento position of currently active voice
1172 if (pChannel->PortamentoMode) {
1173 VoiceIterator itVoice = pKey->pActiveVoices->first();
1174 if (itVoice) itVoice->UpdatePortamentoPos(itNoteOffEventOnKeyList);
1175 }
1176 // create a pseudo note on event
1177 RTList<Event>::Iterator itPseudoNoteOnEvent = pOtherKey->pEvents->allocAppend();
1178 if (itPseudoNoteOnEvent) {
1179 // copy event
1180 *itPseudoNoteOnEvent = *itNoteOffEventOnKeyList;
1181 // transform event to a note on event
1182 itPseudoNoteOnEvent->Type = Event::type_note_on;
1183 itPseudoNoteOnEvent->Param.Note.Key = i;
1184 itPseudoNoteOnEvent->Param.Note.Velocity = pOtherKey->Velocity;
1185 // allocate and trigger new voice(s) for the other key
1186 TriggerNewVoices(pChannel, itPseudoNoteOnEvent, false);
1187 // if neither a voice was spawned or postponed then remove note on event from key again
1188 if (!pOtherKey->Active && !pOtherKey->VoiceTheftsQueued)
1189 pOtherKey->pEvents->free(itPseudoNoteOnEvent);
1190
1191 } else dmsg(1,("Could not respawn voice, no free event left\n"));
1192 break; // done
1193 }
1194 }
1195 }
1196 if (bOtherKeysPressed) {
1197 if (pKey->Active) { // kill all voices on this key
1198 bShouldRelease = false; // no need to release, as we kill it here
1199 VoiceIterator itVoiceToBeKilled = pKey->pActiveVoices->first();
1200 VoiceIterator end = pKey->pActiveVoices->end();
1201 for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1202 if (itVoiceToBeKilled->Type != Voice::type_release_trigger)
1203 itVoiceToBeKilled->Kill(itNoteOffEventOnKeyList);
1204 }
1205 }
1206 } else pChannel->PortamentoPos = -1.0f;
1207 }
1208
1209 // if no solo mode (the usual case) or if solo mode and no other key pressed, then release voices on this key if needed
1210 if (bShouldRelease) {
1211 itNoteOffEventOnKeyList->Type = Event::type_release; // transform event type
1212
1213 // spawn release triggered voice(s) if needed
1214 if (pKey->ReleaseTrigger && pChannel->pInstrument) {
1215 TriggerReleaseVoices(pChannel, itNoteOffEventOnKeyList);
1216 pKey->ReleaseTrigger = false;
1217 }
1218 }
1219
1220 // if neither a voice was spawned or postponed on this key then remove note off event from key again
1221 if (!pKey->Active && !pKey->VoiceTheftsQueued)
1222 pKey->pEvents->free(itNoteOffEventOnKeyList);
1223
1224 pChannel->listeners.PostProcessNoteOff(iKey, vel);
1225 }
1226
1227 /**
1228 * Reset all voices and disk thread and clear input event queue and all
1229 * control and status variables. This method is protected by a mutex.
1230 */
1231 virtual void ResetInternal() {
1232 ResetInternalMutex.Lock();
1233
1234 // make sure that the engine does not get any sysex messages
1235 // while it's reseting
1236 bool sysexDisabled = MidiInputPort::RemoveSysexListener(this);
1237 SetVoiceCount(0);
1238 ActiveVoiceCountMax = 0;
1239
1240 // reset voice stealing parameters
1241 pVoiceStealingQueue->clear();
1242 itLastStolenVoice = VoiceIterator();
1243 itLastStolenVoiceGlobally = VoiceIterator();
1244 iuiLastStolenKey = RTList<uint>::Iterator();
1245 iuiLastStolenKeyGlobally = RTList<uint>::Iterator();
1246 pLastStolenChannel = NULL;
1247
1248 // reset all voices
1249 for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
1250 iterVoice->Reset();
1251 }
1252 pVoicePool->clear();
1253
1254 // reset disk thread
1255 if (pDiskThread) pDiskThread->Reset();
1256
1257 // delete all input events
1258 pEventQueue->init();
1259 pSysexBuffer->init();
1260 if (sysexDisabled) MidiInputPort::AddSysexListener(this);
1261 ResetInternalMutex.Unlock();
1262 }
1263
1264 /**
1265 * Kills all voices on an engine channel as soon as possible. Voices
1266 * won't get into release state, their volume level will be ramped down
1267 * as fast as possible.
1268 *
1269 * @param pEngineChannel - engine channel on which all voices should be killed
1270 * @param itKillEvent - event which caused this killing of all voices
1271 */
1272 virtual void KillAllVoices(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itKillEvent) {
1273 EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1274 int count = pChannel->KillAllVoices(itKillEvent);
1275 VoiceSpawnsLeft -= count; //FIXME: just a temporary workaround, we should check the cause in StealVoice() instead
1276 }
1277
1278 /**
1279 * Allocates and triggers a new voice. This method will usually be
1280 * called by the ProcessNoteOn() method and by the voices itself
1281 * (e.g. to spawn further voices on the same key for layered sounds).
1282 *
1283 * @param pEngineChannel - engine channel on which this event occured on
1284 * @param itNoteOnEvent - key, velocity and time stamp of the event
1285 * @param iLayer - layer index for the new voice (optional - only
1286 * in case of layered sounds of course)
1287 * @param ReleaseTriggerVoice - if new voice is a release triggered voice
1288 * (optional, default = false)
1289 * @param VoiceStealing - if voice stealing should be performed
1290 * when there is no free voice
1291 * (optional, default = true)
1292 * @param HandleKeyGroupConflicts - if voices should be killed due to a
1293 * key group conflict
1294 * @returns pointer to new voice or NULL if there was no free voice or
1295 * if the voice wasn't triggered (for example when no region is
1296 * defined for the given key).
1297 */
1298 virtual PoolVoiceIterator LaunchVoice (
1299 EngineChannel* pEngineChannel,
1300 Pool<Event>::Iterator& itNoteOnEvent,
1301 int iLayer,
1302 bool ReleaseTriggerVoice,
1303 bool VoiceStealing,
1304 bool HandleKeyGroupConflicts
1305 ) = 0;
1306
1307 private:
1308 Pool<V>* pVoicePool; ///< Contains all voices that can be activated.
1309 Pool<RR*> SuspendedRegions;
1310 Mutex SuspendedRegionsMutex;
1311 Condition SuspensionChangeOngoing;
1312 RR* pPendingRegionSuspension;
1313 RR* pPendingRegionResumption;
1314 int iPendingStreamDeletions;
1315 };
1316
1317 template <class V, class RR, class R, class D, class IM, class I>
1318 IM EngineBase<V, RR, R, D, IM, I>::instruments;
1319
1320 } // namespace LinuxSampler
1321
1322 #endif /* __LS_ENGINEBASE_H__ */
1323

  ViewVC Help
Powered by ViewVC