/[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 2382 - (show annotations) (download) (as text)
Sun Dec 2 16:30:42 2012 UTC (11 years, 3 months ago) by persson
File MIME type: text/x-c++hdr
File size: 79258 byte(s)
* all engines: add pan CC value to instrument pan parameter before
  applying panning, instead of using two separate pan functions in
  series (#182)
* sfz parser: allow -200 to 200 for pan_oncc opcode (#182)
* gig engine: handle special case when pan parameter in gig file has
  max or min value
* CoreMIDI: fixed memory deallocation error

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

  ViewVC Help
Powered by ViewVC