/[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 2427 - (show annotations) (download) (as text)
Sat Mar 2 07:03:04 2013 UTC (11 years, 1 month ago) by persson
File MIME type: text/x-c++hdr
File size: 79527 byte(s)
* code refactoring: added a lock guard class for exception safe mutex
  handling and used it everywhere appropriate

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

  ViewVC Help
Powered by ViewVC