/[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 2121 - (show annotations) (download) (as text)
Tue Sep 14 17:09:08 2010 UTC (13 years, 6 months ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 78697 byte(s)
* implemented Roland GS NRPN 1ArrH which allows to set volume per note
* implemented Roland GS NRPN 1CrrH which allows to set pan per note
* implemented Roland GS NRPN 1DrrH which allows to set reverb send per
  note (in this implementation of the sampler its simply hard routed to
  the 1st effect send of the sampler channel, no matter what the actual
  effect type is)
* implemented Roland GS NRPN 1ErrH which allows to set chorus send per
  note (in this implementation of the sampler its simply hard routed to
  the 2nd effect send of the sampler channel, no matter what the actual
  effect type is)
* bumped version to 1.0.0cvs4

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

  ViewVC Help
Powered by ViewVC