/[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 2027 - (show annotations) (download) (as text)
Tue Nov 3 19:27:42 2009 UTC (14 years, 4 months ago) by iliev
File MIME type: text/x-c++hdr
File size: 73203 byte(s)
* sfz engine: support for exclusive groups
* sf2 engine: support for exclusive groups
* sf2 engine: manage presets only
* sf2 engine: preset regions are now taken into account

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 pKey->RoundRobinIndex++;
1100 pChannel->listeners.PostProcessNoteOn(key, vel);
1101 }
1102
1103 /**
1104 * Allocate and trigger new voice(s) for the key.
1105 */
1106 virtual void TriggerNewVoices (
1107 EngineChannel* pEngineChannel,
1108 RTList<Event>::Iterator& itNoteOnEvent,
1109 bool HandleKeyGroupConflicts = true
1110 ) = 0;
1111
1112 /**
1113 * Allocate and trigger release voice(s) for the key.
1114 */
1115 virtual void TriggerReleaseVoices (
1116 EngineChannel* pEngineChannel,
1117 RTList<Event>::Iterator& itNoteOffEvent
1118 ) = 0;
1119
1120 /**
1121 * Releases the voices on the given key if sustain pedal is not pressed.
1122 * If sustain is pressed, the release of the note will be postponed until
1123 * sustain pedal will be released or voice turned inactive by itself (e.g.
1124 * due to completion of sample playback).
1125 *
1126 * @param pEngineChannel - engine channel on which this event occured on
1127 * @param itNoteOffEvent - key, velocity and time stamp of the event
1128 */
1129 virtual void ProcessNoteOff(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOffEvent) {
1130 EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1131
1132 int k = itNoteOffEvent->Param.Note.Key + pChannel->GlobalTranspose;
1133 if (k < 0 || k > 127) return; //ignore keys outside the key range
1134
1135 //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
1136 itNoteOffEvent->Param.Note.Key += pChannel->GlobalTranspose;
1137 int vel = itNoteOffEvent->Param.Note.Velocity;
1138
1139 const int iKey = itNoteOffEvent->Param.Note.Key;
1140 MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];
1141
1142 pChannel->listeners.PreProcessNoteOff(iKey, vel);
1143
1144 #if !CONFIG_PROCESS_MUTED_CHANNELS
1145 if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
1146 pChannel->listeners.PostProcessNoteOff(iKey, vel);
1147 return;
1148 }
1149 #endif
1150
1151 pKey->KeyPressed = false; // the MIDI key was now released
1152
1153 // move event to the key's own event list
1154 RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);
1155
1156 bool bShouldRelease = pKey->Active && pChannel->ShouldReleaseVoice(itNoteOffEventOnKeyList->Param.Note.Key);
1157
1158 // in case Solo Mode is enabled, kill all voices on this key and respawn a voice on the highest pressed key (if any)
1159 if (pChannel->SoloMode && pChannel->pInstrument) { //TODO: this feels like too much code just for handling solo mode :P
1160 bool bOtherKeysPressed = false;
1161 if (iKey == pChannel->SoloKey) {
1162 pChannel->SoloKey = -1;
1163 // if there's still a key pressed down, respawn a voice (group) on the highest key
1164 for (int i = 127; i > 0; i--) {
1165 MidiKey* pOtherKey = &pChannel->pMIDIKeyInfo[i];
1166 if (pOtherKey->KeyPressed) {
1167 bOtherKeysPressed = true;
1168 // make the other key the new 'currently active solo key'
1169 pChannel->SoloKey = i;
1170 // get final portamento position of currently active voice
1171 if (pChannel->PortamentoMode) {
1172 VoiceIterator itVoice = pKey->pActiveVoices->first();
1173 if (itVoice) itVoice->UpdatePortamentoPos(itNoteOffEventOnKeyList);
1174 }
1175 // create a pseudo note on event
1176 RTList<Event>::Iterator itPseudoNoteOnEvent = pOtherKey->pEvents->allocAppend();
1177 if (itPseudoNoteOnEvent) {
1178 // copy event
1179 *itPseudoNoteOnEvent = *itNoteOffEventOnKeyList;
1180 // transform event to a note on event
1181 itPseudoNoteOnEvent->Type = Event::type_note_on;
1182 itPseudoNoteOnEvent->Param.Note.Key = i;
1183 itPseudoNoteOnEvent->Param.Note.Velocity = pOtherKey->Velocity;
1184 // allocate and trigger new voice(s) for the other key
1185 TriggerNewVoices(pChannel, itPseudoNoteOnEvent, false);
1186 // if neither a voice was spawned or postponed then remove note on event from key again
1187 if (!pOtherKey->Active && !pOtherKey->VoiceTheftsQueued)
1188 pOtherKey->pEvents->free(itPseudoNoteOnEvent);
1189
1190 } else dmsg(1,("Could not respawn voice, no free event left\n"));
1191 break; // done
1192 }
1193 }
1194 }
1195 if (bOtherKeysPressed) {
1196 if (pKey->Active) { // kill all voices on this key
1197 bShouldRelease = false; // no need to release, as we kill it here
1198 VoiceIterator itVoiceToBeKilled = pKey->pActiveVoices->first();
1199 VoiceIterator end = pKey->pActiveVoices->end();
1200 for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1201 if (itVoiceToBeKilled->Type != Voice::type_release_trigger)
1202 itVoiceToBeKilled->Kill(itNoteOffEventOnKeyList);
1203 }
1204 }
1205 } else pChannel->PortamentoPos = -1.0f;
1206 }
1207
1208 // if no solo mode (the usual case) or if solo mode and no other key pressed, then release voices on this key if needed
1209 if (bShouldRelease) {
1210 itNoteOffEventOnKeyList->Type = Event::type_release; // transform event type
1211
1212 // spawn release triggered voice(s) if needed
1213 if (pKey->ReleaseTrigger && pChannel->pInstrument) {
1214 TriggerReleaseVoices(pChannel, itNoteOffEventOnKeyList);
1215 pKey->ReleaseTrigger = false;
1216 }
1217 }
1218
1219 // if neither a voice was spawned or postponed on this key then remove note off event from key again
1220 if (!pKey->Active && !pKey->VoiceTheftsQueued)
1221 pKey->pEvents->free(itNoteOffEventOnKeyList);
1222
1223 pChannel->listeners.PostProcessNoteOff(iKey, vel);
1224 }
1225
1226 /**
1227 * Reset all voices and disk thread and clear input event queue and all
1228 * control and status variables. This method is protected by a mutex.
1229 */
1230 virtual void ResetInternal() {
1231 ResetInternalMutex.Lock();
1232
1233 // make sure that the engine does not get any sysex messages
1234 // while it's reseting
1235 bool sysexDisabled = MidiInputPort::RemoveSysexListener(this);
1236 SetVoiceCount(0);
1237 ActiveVoiceCountMax = 0;
1238
1239 // reset voice stealing parameters
1240 pVoiceStealingQueue->clear();
1241 itLastStolenVoice = VoiceIterator();
1242 itLastStolenVoiceGlobally = VoiceIterator();
1243 iuiLastStolenKey = RTList<uint>::Iterator();
1244 iuiLastStolenKeyGlobally = RTList<uint>::Iterator();
1245 pLastStolenChannel = NULL;
1246
1247 // reset all voices
1248 for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
1249 iterVoice->Reset();
1250 }
1251 pVoicePool->clear();
1252
1253 // reset disk thread
1254 if (pDiskThread) pDiskThread->Reset();
1255
1256 // delete all input events
1257 pEventQueue->init();
1258 pSysexBuffer->init();
1259 if (sysexDisabled) MidiInputPort::AddSysexListener(this);
1260 ResetInternalMutex.Unlock();
1261 }
1262
1263 /**
1264 * Kills all voices on an engine channel as soon as possible. Voices
1265 * won't get into release state, their volume level will be ramped down
1266 * as fast as possible.
1267 *
1268 * @param pEngineChannel - engine channel on which all voices should be killed
1269 * @param itKillEvent - event which caused this killing of all voices
1270 */
1271 virtual void KillAllVoices(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itKillEvent) {
1272 EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1273 int count = pChannel->KillAllVoices(itKillEvent);
1274 VoiceSpawnsLeft -= count; //FIXME: just a temporary workaround, we should check the cause in StealVoice() instead
1275 }
1276
1277 /**
1278 * Allocates and triggers a new voice. This method will usually be
1279 * called by the ProcessNoteOn() method and by the voices itself
1280 * (e.g. to spawn further voices on the same key for layered sounds).
1281 *
1282 * @param pEngineChannel - engine channel on which this event occured on
1283 * @param itNoteOnEvent - key, velocity and time stamp of the event
1284 * @param iLayer - layer index for the new voice (optional - only
1285 * in case of layered sounds of course)
1286 * @param ReleaseTriggerVoice - if new voice is a release triggered voice
1287 * (optional, default = false)
1288 * @param VoiceStealing - if voice stealing should be performed
1289 * when there is no free voice
1290 * (optional, default = true)
1291 * @param HandleKeyGroupConflicts - if voices should be killed due to a
1292 * key group conflict
1293 * @returns pointer to new voice or NULL if there was no free voice or
1294 * if the voice wasn't triggered (for example when no region is
1295 * defined for the given key).
1296 */
1297 virtual PoolVoiceIterator LaunchVoice (
1298 EngineChannel* pEngineChannel,
1299 Pool<Event>::Iterator& itNoteOnEvent,
1300 int iLayer,
1301 bool ReleaseTriggerVoice,
1302 bool VoiceStealing,
1303 bool HandleKeyGroupConflicts
1304 ) = 0;
1305
1306 virtual int GetMinFadeOutSamples() { return MinFadeOutSamples; }
1307
1308 int InitNewVoice (
1309 EngineChannelBase<V, R, I>* pChannel,
1310 R* pRegion,
1311 Pool<Event>::Iterator& itNoteOnEvent,
1312 Voice::type_t VoiceType,
1313 int iLayer,
1314 int iKeyGroup,
1315 bool ReleaseTriggerVoice,
1316 bool VoiceStealing,
1317 typename Pool<V>::Iterator& itNewVoice
1318 ) {
1319 int key = itNoteOnEvent->Param.Note.Key;
1320 typename MidiKeyboardManager<V>::MidiKey* pKey = &pChannel->pMIDIKeyInfo[key];
1321 if (itNewVoice) {
1322 // launch the new voice
1323 if (itNewVoice->Trigger(pChannel, itNoteOnEvent, pChannel->Pitch, pRegion, VoiceType, iKeyGroup) < 0) {
1324 dmsg(4,("Voice not triggered\n"));
1325 pKey->pActiveVoices->free(itNewVoice);
1326 }
1327 else { // on success
1328 --VoiceSpawnsLeft;
1329 if (!pKey->Active) { // mark as active key
1330 pKey->Active = true;
1331 pKey->itSelf = pChannel->pActiveKeys->allocAppend();
1332 *pKey->itSelf = itNoteOnEvent->Param.Note.Key;
1333 }
1334 if (itNewVoice->KeyGroup) {
1335 uint** ppKeyGroup = &pChannel->ActiveKeyGroups[itNewVoice->KeyGroup];
1336 *ppKeyGroup = &*pKey->itSelf; // put key as the (new) active key to its key group
1337 }
1338 if (itNewVoice->Type == Voice::type_release_trigger_required) pKey->ReleaseTrigger = true; // mark key for the need of release triggered voice(s)
1339 return 0; // success
1340 }
1341 }
1342 else if (VoiceStealing) {
1343 // try to steal one voice
1344 int result = StealVoice(pChannel, itNoteOnEvent);
1345 if (!result) { // voice stolen successfully
1346 // put note-on event into voice-stealing queue, so it will be reprocessed after killed voice died
1347 RTList<Event>::Iterator itStealEvent = pVoiceStealingQueue->allocAppend();
1348 if (itStealEvent) {
1349 *itStealEvent = *itNoteOnEvent; // copy event
1350 itStealEvent->Param.Note.Layer = iLayer;
1351 itStealEvent->Param.Note.ReleaseTrigger = ReleaseTriggerVoice;
1352 pKey->VoiceTheftsQueued++;
1353 }
1354 else dmsg(1,("Voice stealing queue full!\n"));
1355 }
1356 }
1357
1358 return -1;
1359 }
1360
1361 private:
1362 Pool<V>* pVoicePool; ///< Contains all voices that can be activated.
1363 Pool<RR*> SuspendedRegions;
1364 Mutex SuspendedRegionsMutex;
1365 Condition SuspensionChangeOngoing;
1366 RR* pPendingRegionSuspension;
1367 RR* pPendingRegionResumption;
1368 int iPendingStreamDeletions;
1369 };
1370
1371 template <class V, class RR, class R, class D, class IM, class I>
1372 IM EngineBase<V, RR, R, D, IM, I>::instruments;
1373
1374 } // namespace LinuxSampler
1375
1376 #endif /* __LS_ENGINEBASE_H__ */
1377

  ViewVC Help
Powered by ViewVC