/[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 2162 - (show annotations) (download) (as text)
Tue Feb 8 18:22:50 2011 UTC (13 years, 2 months ago) by persson
File MIME type: text/x-c++hdr
File size: 78972 byte(s)
* bugfix: playing a note while changing the instrument could cause a
  crash, or give "Handing back unknown region" error messages

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

  ViewVC Help
Powered by ViewVC