/[svn]/linuxsampler/trunk/src/engines/gig/Engine.cpp
ViewVC logotype

Contents of /linuxsampler/trunk/src/engines/gig/Engine.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1748 - (show annotations) (download)
Sun Jun 22 14:46:46 2008 UTC (15 years, 9 months ago) by persson
File size: 105017 byte(s)
* bugfix: notes triggered at position 0 in the audio buffer were
  sometimes wrongly killed in the same buffer, causing no sound to be
  played
* fixes for audio drivers with varying buffer sizes
* Makefile fix: JACK_CFLAGS wasn't used
* JACK driver: use jack_client_open instead of the deprecated
  jack_client_new

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 * *
8 * This program is free software; you can redistribute it and/or modify *
9 * it under the terms of the GNU General Public License as published by *
10 * the Free Software Foundation; either version 2 of the License, or *
11 * (at your option) any later version. *
12 * *
13 * This program is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU General Public License *
19 * along with this program; if not, write to the Free Software *
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
21 * MA 02111-1307 USA *
22 ***************************************************************************/
23
24 #include <sstream>
25 #include "DiskThread.h"
26 #include "Voice.h"
27 #include "EGADSR.h"
28 #include "../EngineFactory.h"
29
30 #include "Engine.h"
31
32 #include "../../common/global_private.h"
33
34 namespace LinuxSampler { namespace gig {
35
36 InstrumentResourceManager Engine::instruments;
37
38 std::map<AudioOutputDevice*,Engine*> Engine::engines;
39
40 /**
41 * Get a gig::Engine object for the given gig::EngineChannel and the
42 * given AudioOutputDevice. All engine channels which are connected to
43 * the same audio output device will use the same engine instance. This
44 * method will be called by a gig::EngineChannel whenever it's
45 * connecting to a audio output device.
46 *
47 * @param pChannel - engine channel which acquires an engine object
48 * @param pDevice - the audio output device \a pChannel is connected to
49 */
50 Engine* Engine::AcquireEngine(LinuxSampler::gig::EngineChannel* pChannel, AudioOutputDevice* pDevice) {
51 Engine* pEngine = NULL;
52 // check if there's already an engine for the given audio output device
53 if (engines.count(pDevice)) {
54 dmsg(4,("Using existing gig::Engine.\n"));
55 pEngine = engines[pDevice];
56
57 // Disable the engine while the new engine channel is
58 // added and initialized. The engine will be enabled again
59 // in EngineChannel::Connect.
60 pEngine->DisableAndLock();
61 } else { // create a new engine (and disk thread) instance for the given audio output device
62 dmsg(4,("Creating new gig::Engine.\n"));
63 pEngine = (Engine*) EngineFactory::Create("gig");
64 pEngine->Connect(pDevice);
65 engines[pDevice] = pEngine;
66 }
67 // register engine channel to the engine instance
68 pEngine->engineChannels.add(pChannel);
69 // remember index in the ArrayList
70 pChannel->iEngineIndexSelf = pEngine->engineChannels.size() - 1;
71 dmsg(4,("This gig::Engine has now %d EngineChannels.\n",pEngine->engineChannels.size()));
72 return pEngine;
73 }
74
75 /**
76 * Once an engine channel is disconnected from an audio output device,
77 * it will immediately call this method to unregister itself from the
78 * engine instance and if that engine instance is not used by any other
79 * engine channel anymore, then that engine instance will be destroyed.
80 *
81 * @param pChannel - engine channel which wants to disconnect from it's
82 * engine instance
83 * @param pDevice - audio output device \a pChannel was connected to
84 */
85 void Engine::FreeEngine(LinuxSampler::gig::EngineChannel* pChannel, AudioOutputDevice* pDevice) {
86 dmsg(4,("Disconnecting EngineChannel from gig::Engine.\n"));
87 Engine* pEngine = engines[pDevice];
88 // unregister EngineChannel from the Engine instance
89 pEngine->engineChannels.remove(pChannel);
90 // if the used Engine instance is not used anymore, then destroy it
91 if (pEngine->engineChannels.empty()) {
92 pDevice->Disconnect(pEngine);
93 engines.erase(pDevice);
94 delete pEngine;
95 dmsg(4,("Destroying gig::Engine.\n"));
96 }
97 else dmsg(4,("This gig::Engine has now %d EngineChannels.\n",pEngine->engineChannels.size()));
98 }
99
100 /**
101 * Constructor
102 */
103 Engine::Engine() : SuspendedRegions(128) {
104 pAudioOutputDevice = NULL;
105 pDiskThread = NULL;
106 pEventGenerator = NULL;
107 pSysexBuffer = new RingBuffer<uint8_t,false>(CONFIG_SYSEX_BUFFER_SIZE, 0);
108 pEventQueue = new RingBuffer<Event,false>(CONFIG_MAX_EVENTS_PER_FRAGMENT, 0);
109 pEventPool = new Pool<Event>(CONFIG_MAX_EVENTS_PER_FRAGMENT);
110 pVoicePool = new Pool<Voice>(CONFIG_MAX_VOICES);
111 pDimRegionPool[0] = new Pool< ::gig::DimensionRegion*>(CONFIG_MAX_VOICES);
112 pDimRegionPool[1] = new Pool< ::gig::DimensionRegion*>(CONFIG_MAX_VOICES);
113 pVoiceStealingQueue = new RTList<Event>(pEventPool);
114 pGlobalEvents = new RTList<Event>(pEventPool);
115
116 for (RTList<Voice>::Iterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
117 iterVoice->SetEngine(this);
118 }
119 pVoicePool->clear();
120
121 ResetInternal();
122 ResetScaleTuning();
123 ResetSuspendedRegions();
124 }
125
126 /**
127 * Destructor
128 */
129 Engine::~Engine() {
130 MidiInputPort::RemoveSysexListener(this);
131 if (pDiskThread) {
132 dmsg(1,("Stopping disk thread..."));
133 pDiskThread->StopThread();
134 delete pDiskThread;
135 dmsg(1,("OK\n"));
136 }
137 if (pEventQueue) delete pEventQueue;
138 if (pEventPool) delete pEventPool;
139 if (pVoicePool) {
140 pVoicePool->clear();
141 delete pVoicePool;
142 }
143 if (pEventGenerator) delete pEventGenerator;
144 if (pVoiceStealingQueue) delete pVoiceStealingQueue;
145 if (pSysexBuffer) delete pSysexBuffer;
146 if (pGlobalEvents) delete pGlobalEvents;
147 if (pDimRegionPool[0]) delete pDimRegionPool[0];
148 if (pDimRegionPool[1]) delete pDimRegionPool[1];
149 ResetSuspendedRegions();
150 Unregister();
151 }
152
153 void Engine::Enable() {
154 dmsg(3,("gig::Engine: enabling\n"));
155 EngineDisabled.PushAndUnlock(false, 2); // set condition object 'EngineDisabled' to false (wait max. 2s)
156 dmsg(3,("gig::Engine: enabled (val=%d)\n", EngineDisabled.GetUnsafe()));
157 }
158
159 /**
160 * Temporarily stop the engine to not do anything. The engine will just be
161 * frozen during that time, that means after enabling it again it will
162 * continue where it was, with all its voices and playback state it had at
163 * the point of disabling. Notice that the engine's (audio) thread will
164 * continue to run, it just remains in an inactive loop during that time.
165 *
166 * If you need to be sure that all voices and disk streams are killed as
167 * well, use @c SuspendAll() instead.
168 *
169 * @see Enable(), SuspendAll()
170 */
171 void Engine::Disable() {
172 dmsg(3,("gig::Engine: disabling\n"));
173 bool* pWasDisabled = EngineDisabled.PushAndUnlock(true, 2); // wait max. 2s
174 if (!pWasDisabled) dmsg(3,("gig::Engine warning: Timeout waiting to disable engine.\n"));
175 }
176
177 void Engine::DisableAndLock() {
178 dmsg(3,("gig::Engine: disabling\n"));
179 bool* pWasDisabled = EngineDisabled.Push(true, 2); // wait max. 2s
180 if (!pWasDisabled) dmsg(3,("gig::Engine warning: Timeout waiting to disable engine.\n"));
181 }
182
183 /**
184 * Similar to @c Disable() but this method additionally kills all voices
185 * and disk streams and blocks until all voices and disk streams are actually
186 * killed / deleted.
187 *
188 * @e Note: only the original calling thread is able to re-enable the
189 * engine afterwards by calling @c ResumeAll() later on!
190 */
191 void Engine::SuspendAll() {
192 dmsg(2,("gig::Engine: Suspending all ...\n"));
193 // stop the engine, so we can safely modify the engine's
194 // data structures from this foreign thread
195 DisableAndLock();
196 // we could also use the respective class member variable here,
197 // but this is probably safer and cleaner
198 int iPendingStreamDeletions = 0;
199 // kill all voices on all engine channels the *die hard* way
200 for (int iChannel = 0; iChannel < engineChannels.size(); iChannel++) {
201 EngineChannel* pEngineChannel = engineChannels[iChannel];
202 RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
203 RTList<uint>::Iterator end = pEngineChannel->pActiveKeys->end();
204 for (; iuiKey != end; ++iuiKey) { // iterate through all active keys
205 midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];
206 RTList<Voice>::Iterator itVoice = pKey->pActiveVoices->first();
207 RTList<Voice>::Iterator itVoicesEnd = pKey->pActiveVoices->end();
208 for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
209 // request a notification from disk thread side for stream deletion
210 const Stream::Handle hStream = itVoice->KillImmediately(true);
211 if (hStream != Stream::INVALID_HANDLE) { // voice actually used a stream
212 iPendingStreamDeletions++;
213 }
214 }
215 }
216 }
217 // wait until all streams were actually deleted by the disk thread
218 while (iPendingStreamDeletions) {
219 while (
220 iPendingStreamDeletions &&
221 pDiskThread->AskForDeletedStream() != Stream::INVALID_HANDLE
222 ) iPendingStreamDeletions--;
223 if (!iPendingStreamDeletions) break;
224 usleep(10000); // sleep for 10ms
225 }
226 dmsg(2,("gig::Engine: Everything suspended.\n"));
227 }
228
229 /**
230 * At the moment same as calling @c Enable() directly, but this might
231 * change in future, so better call this method as counterpart to
232 * @c SuspendAll() instead of @c Enable() !
233 */
234 void Engine::ResumeAll() {
235 Enable();
236 }
237
238 /**
239 * Order the engine to stop rendering audio for the given region.
240 * Additionally this method will block until all voices and their disk
241 * streams associated with that region are actually killed / deleted, so
242 * one can i.e. safely modify the region with an instrument editor after
243 * returning from this method.
244 *
245 * @param pRegion - region the engine shall stop using
246 */
247 void Engine::Suspend(::gig::Region* pRegion) {
248 dmsg(2,("gig::Engine: Suspending Region %x ...\n",pRegion));
249 SuspendedRegionsMutex.Lock();
250 SuspensionChangeOngoing.Set(true);
251 pPendingRegionSuspension = pRegion;
252 SuspensionChangeOngoing.WaitAndUnlockIf(true);
253 SuspendedRegionsMutex.Unlock();
254 dmsg(2,("gig::Engine: Region %x suspended.",pRegion));
255 }
256
257 /**
258 * Orders the engine to resume playing back the given region, previously
259 * suspended with @c Suspend() .
260 *
261 * @param pRegion - region the engine shall be allowed to use again
262 */
263 void Engine::Resume(::gig::Region* pRegion) {
264 dmsg(2,("gig::Engine: Resuming Region %x ...\n",pRegion));
265 SuspendedRegionsMutex.Lock();
266 SuspensionChangeOngoing.Set(true);
267 pPendingRegionResumption = pRegion;
268 SuspensionChangeOngoing.WaitAndUnlockIf(true);
269 SuspendedRegionsMutex.Unlock();
270 dmsg(2,("gig::Engine: Region %x resumed.\n",pRegion));
271 }
272
273 /**
274 * Reset all voices and disk thread and clear input event queue and all
275 * control and status variables.
276 */
277 void Engine::Reset() {
278 DisableAndLock();
279 ResetInternal();
280 ResetScaleTuning();
281 Enable();
282 }
283
284 /**
285 * Reset all voices and disk thread and clear input event queue and all
286 * control and status variables. This method is protected by a mutex.
287 */
288 void Engine::ResetInternal() {
289 ResetInternalMutex.Lock();
290
291 // make sure that the engine does not get any sysex messages
292 // while it's reseting
293 bool sysexDisabled = MidiInputPort::RemoveSysexListener(this);
294 ActiveVoiceCount = 0;
295 ActiveVoiceCountMax = 0;
296
297 // reset voice stealing parameters
298 pVoiceStealingQueue->clear();
299 itLastStolenVoice = RTList<Voice>::Iterator();
300 itLastStolenVoiceGlobally = RTList<Voice>::Iterator();
301 iuiLastStolenKey = RTList<uint>::Iterator();
302 iuiLastStolenKeyGlobally = RTList<uint>::Iterator();
303 pLastStolenChannel = NULL;
304
305 // reset all voices
306 for (RTList<Voice>::Iterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
307 iterVoice->Reset();
308 }
309 pVoicePool->clear();
310
311 // reset disk thread
312 if (pDiskThread) pDiskThread->Reset();
313
314 // delete all input events
315 pEventQueue->init();
316 pSysexBuffer->init();
317 if (sysexDisabled) MidiInputPort::AddSysexListener(this);
318 ResetInternalMutex.Unlock();
319 }
320
321 /**
322 * Reset to normal, chromatic scale (means equal tempered).
323 */
324 void Engine::ResetScaleTuning() {
325 memset(&ScaleTuning[0], 0x00, 12);
326 }
327
328 void Engine::ResetSuspendedRegions() {
329 SuspendedRegions.clear();
330 iPendingStreamDeletions = 0;
331 pPendingRegionSuspension = pPendingRegionResumption = NULL;
332 SuspensionChangeOngoing.Set(false);
333 }
334
335 /**
336 * Connect this engine instance with the given audio output device.
337 * This method will be called when an Engine instance is created.
338 * All of the engine's data structures which are dependant to the used
339 * audio output device / driver will be (re)allocated and / or
340 * adjusted appropriately.
341 *
342 * @param pAudioOut - audio output device to connect to
343 */
344 void Engine::Connect(AudioOutputDevice* pAudioOut) {
345 pAudioOutputDevice = pAudioOut;
346
347 ResetInternal();
348
349 // inform audio driver for the need of two channels
350 try {
351 pAudioOutputDevice->AcquireChannels(2); // gig engine only stereo
352 }
353 catch (AudioOutputException e) {
354 String msg = "Audio output device unable to provide 2 audio channels, cause: " + e.Message();
355 throw Exception(msg);
356 }
357
358 this->MaxSamplesPerCycle = pAudioOutputDevice->MaxSamplesPerCycle();
359 this->SampleRate = pAudioOutputDevice->SampleRate();
360
361 MinFadeOutSamples = int(double(SampleRate) * CONFIG_EG_MIN_RELEASE_TIME) - 1;
362 if (MaxSamplesPerCycle < MinFadeOutSamples) {
363 std::cerr << "gig::Engine: WARNING, CONFIG_EG_MIN_RELEASE_TIME "
364 << "too big for current audio fragment size & sampling rate! "
365 << "May lead to click sounds if voice stealing chimes in!\n" << std::flush;
366 // force volume ramp downs at the beginning of each fragment
367 MinFadeOutSamples = MaxSamplesPerCycle;
368 // lower minimum release time
369 const float minReleaseTime = (float) MaxSamplesPerCycle / (float) SampleRate;
370 for (RTList<Voice>::Iterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
371 iterVoice->EG1.CalculateFadeOutCoeff(minReleaseTime, SampleRate);
372 }
373 pVoicePool->clear();
374 }
375
376 // (re)create disk thread
377 if (this->pDiskThread) {
378 dmsg(1,("Stopping disk thread..."));
379 this->pDiskThread->StopThread();
380 delete this->pDiskThread;
381 dmsg(1,("OK\n"));
382 }
383 this->pDiskThread = new DiskThread(((pAudioOut->MaxSamplesPerCycle() << CONFIG_MAX_PITCH) << 1) + 6, //FIXME: assuming stereo
384 &instruments);
385 if (!pDiskThread) {
386 dmsg(0,("gig::Engine new diskthread = NULL\n"));
387 exit(EXIT_FAILURE);
388 }
389
390 for (RTList<Voice>::Iterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
391 iterVoice->pDiskThread = this->pDiskThread;
392 dmsg(3,("d"));
393 }
394 pVoicePool->clear();
395
396 // (re)create event generator
397 if (pEventGenerator) delete pEventGenerator;
398 pEventGenerator = new EventGenerator(pAudioOut->SampleRate());
399
400 dmsg(1,("Starting disk thread..."));
401 pDiskThread->StartThread();
402 dmsg(1,("OK\n"));
403
404 for (RTList<Voice>::Iterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
405 if (!iterVoice->pDiskThread) {
406 dmsg(0,("Engine -> voice::trigger: !pDiskThread\n"));
407 exit(EXIT_FAILURE);
408 }
409 }
410 }
411
412 /**
413 * Called by the engine's (audio) thread once per cycle to process requests
414 * from the outer world to suspend or resume a given @c gig::Region .
415 */
416 void Engine::ProcessSuspensionsChanges() {
417 // process request for suspending one region
418 if (pPendingRegionSuspension) {
419 // kill all voices on all engine channels that use this region
420 for (int iChannel = 0; iChannel < engineChannels.size(); iChannel++) {
421 EngineChannel* pEngineChannel = engineChannels[iChannel];
422 RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
423 RTList<uint>::Iterator end = pEngineChannel->pActiveKeys->end();
424 for (; iuiKey != end; ++iuiKey) { // iterate through all active keys
425 midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];
426 RTList<Voice>::Iterator itVoice = pKey->pActiveVoices->first();
427 // if current key is not associated with this region, skip this key
428 if (itVoice->pDimRgn->GetParent() != pPendingRegionSuspension) continue;
429 RTList<Voice>::Iterator itVoicesEnd = pKey->pActiveVoices->end();
430 for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
431 // request a notification from disk thread side for stream deletion
432 const Stream::Handle hStream = itVoice->KillImmediately(true);
433 if (hStream != Stream::INVALID_HANDLE) { // voice actually used a stream
434 iPendingStreamDeletions++;
435 }
436 }
437 }
438 }
439 // make sure the region is not yet on the list
440 bool bAlreadySuspended = false;
441 RTList< ::gig::Region*>::Iterator iter = SuspendedRegions.first();
442 RTList< ::gig::Region*>::Iterator end = SuspendedRegions.end();
443 for (; iter != end; ++iter) { // iterate through all suspended regions
444 if (*iter == pPendingRegionSuspension) { // found
445 bAlreadySuspended = true;
446 dmsg(1,("gig::Engine: attempt to suspend an already suspended region !!!\n"));
447 break;
448 }
449 }
450 if (!bAlreadySuspended) {
451 // put the region on the list of suspended regions
452 RTList< ::gig::Region*>::Iterator iter = SuspendedRegions.allocAppend();
453 if (iter) {
454 *iter = pPendingRegionSuspension;
455 } else std::cerr << "gig::Engine: Could not suspend Region, list is full. This is a bug!!!\n" << std::flush;
456 }
457 // free request slot for next caller (and to make sure that
458 // we're not going to process the same request in the next cycle)
459 pPendingRegionSuspension = NULL;
460 // if no disk stream deletions are pending, awaken other side, as
461 // we're done in this case
462 if (!iPendingStreamDeletions) SuspensionChangeOngoing.Set(false);
463 }
464
465 // process request for resuming one region
466 if (pPendingRegionResumption) {
467 // remove region from the list of suspended regions
468 RTList< ::gig::Region*>::Iterator iter = SuspendedRegions.first();
469 RTList< ::gig::Region*>::Iterator end = SuspendedRegions.end();
470 for (; iter != end; ++iter) { // iterate through all suspended regions
471 if (*iter == pPendingRegionResumption) { // found
472 SuspendedRegions.free(iter);
473 break; // done
474 }
475 }
476 // free request slot for next caller
477 pPendingRegionResumption = NULL;
478 // awake other side as we're done
479 SuspensionChangeOngoing.Set(false);
480 }
481 }
482
483 /**
484 * Called by the engine's (audio) thread once per cycle to check if
485 * streams of voices that were killed due to suspension request have
486 * finally really been deleted by the disk thread.
487 */
488 void Engine::ProcessPendingStreamDeletions() {
489 if (!iPendingStreamDeletions) return;
490 //TODO: or shall we better store a list with stream handles instead of a scalar amount of streams to be deleted? might be safer
491 while (
492 iPendingStreamDeletions &&
493 pDiskThread->AskForDeletedStream() != Stream::INVALID_HANDLE
494 ) iPendingStreamDeletions--;
495 // just for safety ...
496 while (pDiskThread->AskForDeletedStream() != Stream::INVALID_HANDLE);
497 // now that all disk streams are deleted, awake other side as
498 // we're finally done with suspending the requested region
499 if (!iPendingStreamDeletions) SuspensionChangeOngoing.Set(false);
500 }
501
502 /**
503 * Returns @c true if the given region is currently set to be suspended
504 * from being used, @c false otherwise.
505 */
506 bool Engine::RegionSuspended(::gig::Region* pRegion) {
507 if (SuspendedRegions.isEmpty()) return false;
508 //TODO: or shall we use a sorted container instead of the RTList? might be faster ... or trivial ;-)
509 RTList< ::gig::Region*>::Iterator iter = SuspendedRegions.first();
510 RTList< ::gig::Region*>::Iterator end = SuspendedRegions.end();
511 for (; iter != end; ++iter) // iterate through all suspended regions
512 if (*iter == pRegion) return true;
513 return false;
514 }
515
516 /**
517 * Clear all engine global event lists.
518 */
519 void Engine::ClearEventLists() {
520 pGlobalEvents->clear();
521 }
522
523 /**
524 * Copy all events from the engine's global input queue buffer to the
525 * engine's internal event list. This will be done at the beginning of
526 * each audio cycle (that is each RenderAudio() call) to distinguish
527 * all global events which have to be processed in the current audio
528 * cycle. These events are usually just SysEx messages. Every
529 * EngineChannel has it's own input event queue buffer and event list
530 * to handle common events like NoteOn, NoteOff and ControlChange
531 * events.
532 *
533 * @param Samples - number of sample points to be processed in the
534 * current audio cycle
535 */
536 void Engine::ImportEvents(uint Samples) {
537 RingBuffer<Event,false>::NonVolatileReader eventQueueReader = pEventQueue->get_non_volatile_reader();
538 Event* pEvent;
539 while (true) {
540 // get next event from input event queue
541 if (!(pEvent = eventQueueReader.pop())) break;
542 // if younger event reached, ignore that and all subsequent ones for now
543 if (pEvent->FragmentPos() >= Samples) {
544 eventQueueReader--;
545 dmsg(2,("Younger Event, pos=%d ,Samples=%d!\n",pEvent->FragmentPos(),Samples));
546 pEvent->ResetFragmentPos();
547 break;
548 }
549 // copy event to internal event list
550 if (pGlobalEvents->poolIsEmpty()) {
551 dmsg(1,("Event pool emtpy!\n"));
552 break;
553 }
554 *pGlobalEvents->allocAppend() = *pEvent;
555 }
556 eventQueueReader.free(); // free all copied events from input queue
557 }
558
559 /**
560 * Let this engine proceed to render the given amount of sample points.
561 * The engine will iterate through all engine channels and render audio
562 * for each engine channel independently. The calculated audio data of
563 * all voices of each engine channel will be placed into the audio sum
564 * buffers of the respective audio output device, connected to the
565 * respective engine channel.
566 *
567 * @param Samples - number of sample points to be rendered
568 * @returns 0 on success
569 */
570 int Engine::RenderAudio(uint Samples) {
571 dmsg(8,("RenderAudio(Samples=%d)\n", Samples));
572
573 // return if engine disabled
574 if (EngineDisabled.Pop()) {
575 dmsg(5,("gig::Engine: engine disabled (val=%d)\n",EngineDisabled.GetUnsafe()));
576 return 0;
577 }
578
579 // process requests for suspending / resuming regions (i.e. to avoid
580 // crashes while these regions are modified by an instrument editor)
581 ProcessSuspensionsChanges();
582
583 // update time of start and end of this audio fragment (as events' time stamps relate to this)
584 pEventGenerator->UpdateFragmentTime(Samples);
585
586 // We only allow a maximum of CONFIG_MAX_VOICES voices to be spawned
587 // in each audio fragment. All subsequent request for spawning new
588 // voices in the same audio fragment will be ignored.
589 VoiceSpawnsLeft = CONFIG_MAX_VOICES;
590
591 // get all events from the engine's global input event queue which belong to the current fragment
592 // (these are usually just SysEx messages)
593 ImportEvents(Samples);
594
595 // process engine global events (these are currently only MIDI System Exclusive messages)
596 {
597 RTList<Event>::Iterator itEvent = pGlobalEvents->first();
598 RTList<Event>::Iterator end = pGlobalEvents->end();
599 for (; itEvent != end; ++itEvent) {
600 switch (itEvent->Type) {
601 case Event::type_sysex:
602 dmsg(5,("Engine: Sysex received\n"));
603 ProcessSysex(itEvent);
604 break;
605 }
606 }
607 }
608
609 // reset internal voice counter (just for statistic of active voices)
610 ActiveVoiceCountTemp = 0;
611
612 // handle instrument change commands
613 bool instrumentChanged = false;
614 for (int i = 0; i < engineChannels.size(); i++) {
615 EngineChannel* pEngineChannel = engineChannels[i];
616
617 // as we're going to (carefully) write some status to the
618 // synchronized struct, we cast away the const
619 EngineChannel::instrument_change_command_t& cmd =
620 const_cast<EngineChannel::instrument_change_command_t&>(pEngineChannel->InstrumentChangeCommandReader.Lock());
621
622 pEngineChannel->pDimRegionsInUse = cmd.pDimRegionsInUse;
623 pEngineChannel->pDimRegionsInUse->clear();
624
625 if (cmd.bChangeInstrument) {
626 // change instrument
627 dmsg(5,("Engine: instrument change command received\n"));
628 cmd.bChangeInstrument = false;
629 pEngineChannel->pInstrument = cmd.pInstrument;
630 instrumentChanged = true;
631
632 // Iterate through all active voices and mark them as
633 // "orphans", which means that the dimension regions
634 // and samples they use should be released to the
635 // instrument resource manager when the voices die.
636 int i = 0;
637 RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
638 RTList<uint>::Iterator end = pEngineChannel->pActiveKeys->end();
639 while (iuiKey != end) { // iterate through all active keys
640 midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];
641 ++iuiKey;
642
643 RTList<Voice>::Iterator itVoice = pKey->pActiveVoices->first();
644 RTList<Voice>::Iterator itVoicesEnd = pKey->pActiveVoices->end();
645 for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
646 itVoice->Orphan = true;
647 }
648 }
649 }
650 }
651 if (instrumentChanged) {
652 //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
653 ResetSuspendedRegions();
654 }
655
656 // handle events on all engine channels
657 for (int i = 0; i < engineChannels.size(); i++) {
658 ProcessEvents(engineChannels[i], Samples);
659 }
660
661 // render all 'normal', active voices on all engine channels
662 for (int i = 0; i < engineChannels.size(); i++) {
663 RenderActiveVoices(engineChannels[i], Samples);
664 }
665
666 // now that all ordinary voices on ALL engine channels are rendered, render new stolen voices
667 RenderStolenVoices(Samples);
668
669 // handle audio routing for engine channels with FX sends
670 for (int i = 0; i < engineChannels.size(); i++) {
671 if (engineChannels[i]->fxSends.empty()) continue; // ignore if no FX sends
672 RouteAudio(engineChannels[i], Samples);
673 }
674
675 // handle cleanup on all engine channels for the next audio fragment
676 for (int i = 0; i < engineChannels.size(); i++) {
677 PostProcess(engineChannels[i]);
678 }
679
680
681 // empty the engine's event list for the next audio fragment
682 ClearEventLists();
683
684 // reset voice stealing for the next audio fragment
685 pVoiceStealingQueue->clear();
686
687 // just some statistics about this engine instance
688 ActiveVoiceCount = ActiveVoiceCountTemp;
689 if (ActiveVoiceCount > ActiveVoiceCountMax) ActiveVoiceCountMax = ActiveVoiceCount;
690
691 // in case regions were previously suspended and we killed voices
692 // with disk streams due to that, check if those streams have finally
693 // been deleted by the disk thread
694 if (iPendingStreamDeletions) ProcessPendingStreamDeletions();
695
696 for (int i = 0; i < engineChannels.size(); i++) {
697 engineChannels[i]->InstrumentChangeCommandReader.Unlock();
698 }
699 FrameTime += Samples;
700
701 return 0;
702 }
703
704 /**
705 * Dispatch and handle all events in this audio fragment for the given
706 * engine channel.
707 *
708 * @param pEngineChannel - engine channel on which events should be
709 * processed
710 * @param Samples - amount of sample points to be processed in
711 * this audio fragment cycle
712 */
713 void Engine::ProcessEvents(EngineChannel* pEngineChannel, uint Samples) {
714 // get all events from the engine channels's input event queue which belong to the current fragment
715 // (these are the common events like NoteOn, NoteOff, ControlChange, etc.)
716 pEngineChannel->ImportEvents(Samples);
717
718 // process events
719 {
720 RTList<Event>::Iterator itEvent = pEngineChannel->pEvents->first();
721 RTList<Event>::Iterator end = pEngineChannel->pEvents->end();
722 for (; itEvent != end; ++itEvent) {
723 switch (itEvent->Type) {
724 case Event::type_note_on:
725 dmsg(5,("Engine: Note on received\n"));
726 ProcessNoteOn((EngineChannel*)itEvent->pEngineChannel, itEvent);
727 break;
728 case Event::type_note_off:
729 dmsg(5,("Engine: Note off received\n"));
730 ProcessNoteOff((EngineChannel*)itEvent->pEngineChannel, itEvent);
731 break;
732 case Event::type_control_change:
733 dmsg(5,("Engine: MIDI CC received\n"));
734 ProcessControlChange((EngineChannel*)itEvent->pEngineChannel, itEvent);
735 break;
736 case Event::type_pitchbend:
737 dmsg(5,("Engine: Pitchbend received\n"));
738 ProcessPitchbend((EngineChannel*)itEvent->pEngineChannel, itEvent);
739 break;
740 }
741 }
742 }
743
744 // reset voice stealing for the next engine channel (or next audio fragment)
745 itLastStolenVoice = RTList<Voice>::Iterator();
746 itLastStolenVoiceGlobally = RTList<Voice>::Iterator();
747 iuiLastStolenKey = RTList<uint>::Iterator();
748 iuiLastStolenKeyGlobally = RTList<uint>::Iterator();
749 pLastStolenChannel = NULL;
750 }
751
752 /**
753 * Render all 'normal' voices (that is voices which were not stolen in
754 * this fragment) on the given engine channel.
755 *
756 * @param pEngineChannel - engine channel on which audio should be
757 * rendered
758 * @param Samples - amount of sample points to be rendered in
759 * this audio fragment cycle
760 */
761 void Engine::RenderActiveVoices(EngineChannel* pEngineChannel, uint Samples) {
762 #if !CONFIG_PROCESS_MUTED_CHANNELS
763 if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
764 #endif
765
766 uint voiceCount = 0;
767 uint streamCount = 0;
768 RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
769 RTList<uint>::Iterator end = pEngineChannel->pActiveKeys->end();
770 while (iuiKey != end) { // iterate through all active keys
771 midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];
772 ++iuiKey;
773
774 RTList<Voice>::Iterator itVoice = pKey->pActiveVoices->first();
775 RTList<Voice>::Iterator itVoicesEnd = pKey->pActiveVoices->end();
776 for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
777 // now render current voice
778 itVoice->Render(Samples);
779 if (itVoice->IsActive()) { // still active
780 if (!itVoice->Orphan) {
781 *(pEngineChannel->pDimRegionsInUse->allocAppend()) = itVoice->pDimRgn;
782 }
783 ActiveVoiceCountTemp++;
784 voiceCount++;
785
786 if (itVoice->PlaybackState == Voice::playback_state_disk) {
787 if ((itVoice->DiskStreamRef).State == Stream::state_active) streamCount++;
788 }
789 } else { // voice reached end, is now inactive
790 FreeVoice(pEngineChannel, itVoice); // remove voice from the list of active voices
791 }
792 }
793 }
794
795 pEngineChannel->SetVoiceCount(voiceCount);
796 pEngineChannel->SetDiskStreamCount(streamCount);
797 }
798
799 /**
800 * Render all stolen voices (only voices which were stolen in this
801 * fragment) on the given engine channel. Stolen voices are rendered
802 * after all normal voices have been rendered; this is needed to render
803 * audio of those voices which were selected for voice stealing until
804 * the point were the stealing (that is the take over of the voice)
805 * actually happened.
806 *
807 * @param pEngineChannel - engine channel on which audio should be
808 * rendered
809 * @param Samples - amount of sample points to be rendered in
810 * this audio fragment cycle
811 */
812 void Engine::RenderStolenVoices(uint Samples) {
813 RTList<Event>::Iterator itVoiceStealEvent = pVoiceStealingQueue->first();
814 RTList<Event>::Iterator end = pVoiceStealingQueue->end();
815 for (; itVoiceStealEvent != end; ++itVoiceStealEvent) {
816 EngineChannel* pEngineChannel = (EngineChannel*) itVoiceStealEvent->pEngineChannel;
817 if (!pEngineChannel->pInstrument) continue; // ignore if no instrument loaded
818 Pool<Voice>::Iterator itNewVoice =
819 LaunchVoice(pEngineChannel, itVoiceStealEvent, itVoiceStealEvent->Param.Note.Layer, itVoiceStealEvent->Param.Note.ReleaseTrigger, false, false);
820 if (itNewVoice) {
821 itNewVoice->Render(Samples);
822 if (itNewVoice->IsActive()) { // still active
823 *(pEngineChannel->pDimRegionsInUse->allocAppend()) = itNewVoice->pDimRgn;
824 ActiveVoiceCountTemp++;
825 pEngineChannel->SetVoiceCount(pEngineChannel->GetVoiceCount() + 1);
826
827 if (itNewVoice->PlaybackState == Voice::playback_state_disk) {
828 if (itNewVoice->DiskStreamRef.State == Stream::state_active) {
829 pEngineChannel->SetDiskStreamCount(pEngineChannel->GetDiskStreamCount() + 1);
830 }
831 }
832 } else { // voice reached end, is now inactive
833 FreeVoice(pEngineChannel, itNewVoice); // remove voice from the list of active voices
834 }
835 }
836 else dmsg(1,("gig::Engine: ERROR, voice stealing didn't work out!\n"));
837
838 // we need to clear the key's event list explicitly here in case key was never active
839 midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[itVoiceStealEvent->Param.Note.Key];
840 pKey->VoiceTheftsQueued--;
841 if (!pKey->Active && !pKey->VoiceTheftsQueued) pKey->pEvents->clear();
842 }
843 }
844
845 /**
846 * Will be called in case the respective engine channel sports FX send
847 * channels. In this particular case, engine channel local buffers are
848 * used to render and mix all voices to. This method is responsible for
849 * copying the audio data from those local buffers to the master audio
850 * output channels as well as to the FX send audio output channels with
851 * their respective FX send levels.
852 *
853 * @param pEngineChannel - engine channel from which audio should be
854 * routed
855 * @param Samples - amount of sample points to be routed in
856 * this audio fragment cycle
857 */
858 void Engine::RouteAudio(EngineChannel* pEngineChannel, uint Samples) {
859 // route dry signal
860 {
861 AudioChannel* pDstL = pAudioOutputDevice->Channel(pEngineChannel->AudioDeviceChannelLeft);
862 AudioChannel* pDstR = pAudioOutputDevice->Channel(pEngineChannel->AudioDeviceChannelRight);
863 pEngineChannel->pChannelLeft->MixTo(pDstL, Samples);
864 pEngineChannel->pChannelRight->MixTo(pDstR, Samples);
865 }
866 // route FX send signal
867 {
868 for (int iFxSend = 0; iFxSend < pEngineChannel->GetFxSendCount(); iFxSend++) {
869 FxSend* pFxSend = pEngineChannel->GetFxSend(iFxSend);
870 for (int iChan = 0; iChan < 2; ++iChan) {
871 AudioChannel* pSource =
872 (iChan)
873 ? pEngineChannel->pChannelRight
874 : pEngineChannel->pChannelLeft;
875 const int iDstChan = pFxSend->DestinationChannel(iChan);
876 if (iDstChan < 0) {
877 dmsg(1,("Engine::RouteAudio() Error: invalid FX send (%s) destination channel (%d->%d)", ((iChan) ? "R" : "L"), iChan, iDstChan));
878 goto channel_cleanup;
879 }
880 AudioChannel* pDstChan = NULL;
881 if (pFxSend->DestinationMasterEffectChain() >= 0) { // fx send routed to an internal master effect
882 EffectChain* pEffectChain =
883 pAudioOutputDevice->MasterEffectChain(
884 pFxSend->DestinationMasterEffectChain()
885 );
886 if (!pEffectChain) {
887 dmsg(1,("Engine::RouteAudio() Error: invalid FX send (%s) destination effect chain %d", ((iChan) ? "R" : "L"), pFxSend->DestinationMasterEffectChain()));
888 goto channel_cleanup;
889 }
890 Effect* pEffect =
891 pEffectChain->GetEffect(
892 pFxSend->DestinationMasterEffect()
893 );
894 if (!pEffect) {
895 dmsg(1,("Engine::RouteAudio() Error: invalid FX send (%s) destination effect %d of effect chain %d", ((iChan) ? "R" : "L"), pFxSend->DestinationMasterEffect(), pFxSend->DestinationMasterEffectChain()));
896 goto channel_cleanup;
897 }
898 pDstChan = pEffect->InputChannel(iDstChan);
899 } else { // FX send routed directly to an audio output channel
900 pDstChan = pAudioOutputDevice->Channel(iDstChan);
901 }
902 if (!pDstChan) {
903 dmsg(1,("Engine::RouteAudio() Error: invalid FX send (%s) destination channel (%d->%d)", ((iChan) ? "R" : "L"), iChan, iDstChan));
904 goto channel_cleanup;
905 }
906 pSource->MixTo(pDstChan, Samples, pFxSend->Level());
907 }
908 }
909 }
910 channel_cleanup:
911 // reset buffers with silence (zero out) for the next audio cycle
912 pEngineChannel->pChannelLeft->Clear();
913 pEngineChannel->pChannelRight->Clear();
914 }
915
916 /**
917 * Free all keys which have turned inactive in this audio fragment, from
918 * the list of active keys and clear all event lists on that engine
919 * channel.
920 *
921 * @param pEngineChannel - engine channel to cleanup
922 */
923 void Engine::PostProcess(EngineChannel* pEngineChannel) {
924 // free all keys which have no active voices left
925 {
926 RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
927 RTList<uint>::Iterator end = pEngineChannel->pActiveKeys->end();
928 while (iuiKey != end) { // iterate through all active keys
929 midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];
930 ++iuiKey;
931 if (pKey->pActiveVoices->isEmpty()) FreeKey(pEngineChannel, pKey);
932 #if CONFIG_DEVMODE
933 else { // just a sanity check for debugging
934 RTList<Voice>::Iterator itVoice = pKey->pActiveVoices->first();
935 RTList<Voice>::Iterator itVoicesEnd = pKey->pActiveVoices->end();
936 for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
937 if (itVoice->itKillEvent) {
938 dmsg(1,("gig::Engine: ERROR, killed voice survived !!!\n"));
939 }
940 }
941 }
942 #endif // CONFIG_DEVMODE
943 }
944 }
945
946 // empty the engine channel's own event lists
947 pEngineChannel->ClearEventLists();
948 }
949
950 /**
951 * Will be called by the MIDI input device whenever a MIDI system
952 * exclusive message has arrived.
953 *
954 * @param pData - pointer to sysex data
955 * @param Size - lenght of sysex data (in bytes)
956 */
957 void Engine::SendSysex(void* pData, uint Size) {
958 Event event = pEventGenerator->CreateEvent();
959 event.Type = Event::type_sysex;
960 event.Param.Sysex.Size = Size;
961 event.pEngineChannel = NULL; // as Engine global event
962 if (pEventQueue->write_space() > 0) {
963 if (pSysexBuffer->write_space() >= Size) {
964 // copy sysex data to input buffer
965 uint toWrite = Size;
966 uint8_t* pPos = (uint8_t*) pData;
967 while (toWrite) {
968 const uint writeNow = RTMath::Min(toWrite, pSysexBuffer->write_space_to_end());
969 pSysexBuffer->write(pPos, writeNow);
970 toWrite -= writeNow;
971 pPos += writeNow;
972
973 }
974 // finally place sysex event into input event queue
975 pEventQueue->push(&event);
976 }
977 else dmsg(1,("Engine: Sysex message too large (%d byte) for input buffer (%d byte)!",Size,CONFIG_SYSEX_BUFFER_SIZE));
978 }
979 else dmsg(1,("Engine: Input event queue full!"));
980 }
981
982 /**
983 * Assigns and triggers a new voice for the respective MIDI key.
984 *
985 * @param pEngineChannel - engine channel on which this event occured on
986 * @param itNoteOnEvent - key, velocity and time stamp of the event
987 */
988 void Engine::ProcessNoteOn(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {
989 #if !CONFIG_PROCESS_MUTED_CHANNELS
990 if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
991 #endif
992
993 if (!pEngineChannel->pInstrument) return; // ignore if no instrument loaded
994
995 //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
996 itNoteOnEvent->Param.Note.Key += pEngineChannel->GlobalTranspose;
997
998 const int key = itNoteOnEvent->Param.Note.Key;
999 midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[key];
1000
1001 // move note on event to the key's own event list
1002 RTList<Event>::Iterator itNoteOnEventOnKeyList = itNoteOnEvent.moveToEndOf(pKey->pEvents);
1003
1004 // if Solo Mode then kill all already active voices
1005 if (pEngineChannel->SoloMode) {
1006 Pool<uint>::Iterator itYoungestKey = pEngineChannel->pActiveKeys->last();
1007 if (itYoungestKey) {
1008 const int iYoungestKey = *itYoungestKey;
1009 const midi_key_info_t* pOtherKey = &pEngineChannel->pMIDIKeyInfo[iYoungestKey];
1010 if (pOtherKey->Active) {
1011 // get final portamento position of currently active voice
1012 if (pEngineChannel->PortamentoMode) {
1013 RTList<Voice>::Iterator itVoice = pOtherKey->pActiveVoices->last();
1014 if (itVoice) itVoice->UpdatePortamentoPos(itNoteOnEventOnKeyList);
1015 }
1016 // kill all voices on the (other) key
1017 RTList<Voice>::Iterator itVoiceToBeKilled = pOtherKey->pActiveVoices->first();
1018 RTList<Voice>::Iterator end = pOtherKey->pActiveVoices->end();
1019 for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1020 if (itVoiceToBeKilled->Type != Voice::type_release_trigger)
1021 itVoiceToBeKilled->Kill(itNoteOnEventOnKeyList);
1022 }
1023 }
1024 }
1025 // set this key as 'currently active solo key'
1026 pEngineChannel->SoloKey = key;
1027 }
1028
1029 // Change key dimension value if key is in keyswitching area
1030 {
1031 const ::gig::Instrument* pInstrument = pEngineChannel->pInstrument;
1032 if (key >= pInstrument->DimensionKeyRange.low && key <= pInstrument->DimensionKeyRange.high)
1033 pEngineChannel->CurrentKeyDimension = float(key - pInstrument->DimensionKeyRange.low) /
1034 (pInstrument->DimensionKeyRange.high - pInstrument->DimensionKeyRange.low + 1);
1035 }
1036
1037 pKey->KeyPressed = true; // the MIDI key was now pressed down
1038 pKey->Velocity = itNoteOnEventOnKeyList->Param.Note.Velocity;
1039 pKey->NoteOnTime = FrameTime + itNoteOnEventOnKeyList->FragmentPos(); // will be used to calculate note length
1040
1041 // cancel release process of voices on this key if needed
1042 if (pKey->Active && !pEngineChannel->SustainPedal) {
1043 RTList<Event>::Iterator itCancelReleaseEvent = pKey->pEvents->allocAppend();
1044 if (itCancelReleaseEvent) {
1045 *itCancelReleaseEvent = *itNoteOnEventOnKeyList; // copy event
1046 itCancelReleaseEvent->Type = Event::type_cancel_release; // transform event type
1047 }
1048 else dmsg(1,("Event pool emtpy!\n"));
1049 }
1050
1051 // allocate and trigger new voice(s) for the key
1052 {
1053 // first, get total amount of required voices (dependant on amount of layers)
1054 ::gig::Region* pRegion = pEngineChannel->pInstrument->GetRegion(itNoteOnEventOnKeyList->Param.Note.Key);
1055 if (pRegion && !RegionSuspended(pRegion)) {
1056 int voicesRequired = pRegion->Layers;
1057 // now launch the required amount of voices
1058 for (int i = 0; i < voicesRequired; i++)
1059 LaunchVoice(pEngineChannel, itNoteOnEventOnKeyList, i, false, true, true);
1060 }
1061 }
1062
1063 // if neither a voice was spawned or postponed then remove note on event from key again
1064 if (!pKey->Active && !pKey->VoiceTheftsQueued)
1065 pKey->pEvents->free(itNoteOnEventOnKeyList);
1066
1067 if (!pEngineChannel->SoloMode || pEngineChannel->PortamentoPos < 0.0f) pEngineChannel->PortamentoPos = (float) key;
1068 pKey->RoundRobinIndex++;
1069 }
1070
1071 /**
1072 * Releases the voices on the given key if sustain pedal is not pressed.
1073 * If sustain is pressed, the release of the note will be postponed until
1074 * sustain pedal will be released or voice turned inactive by itself (e.g.
1075 * due to completion of sample playback).
1076 *
1077 * @param pEngineChannel - engine channel on which this event occured on
1078 * @param itNoteOffEvent - key, velocity and time stamp of the event
1079 */
1080 void Engine::ProcessNoteOff(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOffEvent) {
1081 #if !CONFIG_PROCESS_MUTED_CHANNELS
1082 if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
1083 #endif
1084
1085 //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
1086 itNoteOffEvent->Param.Note.Key += pEngineChannel->GlobalTranspose;
1087
1088 const int iKey = itNoteOffEvent->Param.Note.Key;
1089 midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[iKey];
1090 pKey->KeyPressed = false; // the MIDI key was now released
1091
1092 // move event to the key's own event list
1093 RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);
1094
1095 bool bShouldRelease = pKey->Active && ShouldReleaseVoice(pEngineChannel, itNoteOffEventOnKeyList->Param.Note.Key);
1096
1097 // in case Solo Mode is enabled, kill all voices on this key and respawn a voice on the highest pressed key (if any)
1098 if (pEngineChannel->SoloMode && pEngineChannel->pInstrument) { //TODO: this feels like too much code just for handling solo mode :P
1099 bool bOtherKeysPressed = false;
1100 if (iKey == pEngineChannel->SoloKey) {
1101 pEngineChannel->SoloKey = -1;
1102 // if there's still a key pressed down, respawn a voice (group) on the highest key
1103 for (int i = 127; i > 0; i--) {
1104 midi_key_info_t* pOtherKey = &pEngineChannel->pMIDIKeyInfo[i];
1105 if (pOtherKey->KeyPressed) {
1106 bOtherKeysPressed = true;
1107 // make the other key the new 'currently active solo key'
1108 pEngineChannel->SoloKey = i;
1109 // get final portamento position of currently active voice
1110 if (pEngineChannel->PortamentoMode) {
1111 RTList<Voice>::Iterator itVoice = pKey->pActiveVoices->first();
1112 if (itVoice) itVoice->UpdatePortamentoPos(itNoteOffEventOnKeyList);
1113 }
1114 // create a pseudo note on event
1115 RTList<Event>::Iterator itPseudoNoteOnEvent = pOtherKey->pEvents->allocAppend();
1116 if (itPseudoNoteOnEvent) {
1117 // copy event
1118 *itPseudoNoteOnEvent = *itNoteOffEventOnKeyList;
1119 // transform event to a note on event
1120 itPseudoNoteOnEvent->Type = Event::type_note_on;
1121 itPseudoNoteOnEvent->Param.Note.Key = i;
1122 itPseudoNoteOnEvent->Param.Note.Velocity = pOtherKey->Velocity;
1123 // allocate and trigger new voice(s) for the other key
1124 {
1125 // first, get total amount of required voices (dependant on amount of layers)
1126 ::gig::Region* pRegion = pEngineChannel->pInstrument->GetRegion(i);
1127 if (pRegion) {
1128 int voicesRequired = pRegion->Layers;
1129 // now launch the required amount of voices
1130 for (int iLayer = 0; iLayer < voicesRequired; iLayer++)
1131 LaunchVoice(pEngineChannel, itPseudoNoteOnEvent, iLayer, false, true, false);
1132 }
1133 }
1134 // if neither a voice was spawned or postponed then remove note on event from key again
1135 if (!pOtherKey->Active && !pOtherKey->VoiceTheftsQueued)
1136 pOtherKey->pEvents->free(itPseudoNoteOnEvent);
1137
1138 } else dmsg(1,("Could not respawn voice, no free event left\n"));
1139 break; // done
1140 }
1141 }
1142 }
1143 if (bOtherKeysPressed) {
1144 if (pKey->Active) { // kill all voices on this key
1145 bShouldRelease = false; // no need to release, as we kill it here
1146 RTList<Voice>::Iterator itVoiceToBeKilled = pKey->pActiveVoices->first();
1147 RTList<Voice>::Iterator end = pKey->pActiveVoices->end();
1148 for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1149 if (itVoiceToBeKilled->Type != Voice::type_release_trigger)
1150 itVoiceToBeKilled->Kill(itNoteOffEventOnKeyList);
1151 }
1152 }
1153 } else pEngineChannel->PortamentoPos = -1.0f;
1154 }
1155
1156 // if no solo mode (the usual case) or if solo mode and no other key pressed, then release voices on this key if needed
1157 if (bShouldRelease) {
1158 itNoteOffEventOnKeyList->Type = Event::type_release; // transform event type
1159
1160 // spawn release triggered voice(s) if needed
1161 if (pKey->ReleaseTrigger && pEngineChannel->pInstrument) {
1162 // first, get total amount of required voices (dependant on amount of layers)
1163 ::gig::Region* pRegion = pEngineChannel->pInstrument->GetRegion(itNoteOffEventOnKeyList->Param.Note.Key);
1164 if (pRegion) {
1165 int voicesRequired = pRegion->Layers;
1166
1167 // MIDI note-on velocity is used instead of note-off velocity
1168 itNoteOffEventOnKeyList->Param.Note.Velocity = pKey->Velocity;
1169
1170 // now launch the required amount of voices
1171 for (int i = 0; i < voicesRequired; i++)
1172 LaunchVoice(pEngineChannel, itNoteOffEventOnKeyList, i, true, false, false); //FIXME: for the moment we don't perform voice stealing for release triggered samples
1173 }
1174 pKey->ReleaseTrigger = false;
1175 }
1176 }
1177
1178 // if neither a voice was spawned or postponed on this key then remove note off event from key again
1179 if (!pKey->Active && !pKey->VoiceTheftsQueued)
1180 pKey->pEvents->free(itNoteOffEventOnKeyList);
1181 }
1182
1183 /**
1184 * Moves pitchbend event from the general (input) event list to the engine
1185 * channel's event list. It will actually processed later by the
1186 * respective voice.
1187 *
1188 * @param pEngineChannel - engine channel on which this event occured on
1189 * @param itPitchbendEvent - absolute pitch value and time stamp of the event
1190 */
1191 void Engine::ProcessPitchbend(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itPitchbendEvent) {
1192 pEngineChannel->Pitch = itPitchbendEvent->Param.Pitch.Pitch; // store current pitch value
1193 }
1194
1195 /**
1196 * Allocates and triggers a new voice. This method will usually be
1197 * called by the ProcessNoteOn() method and by the voices itself
1198 * (e.g. to spawn further voices on the same key for layered sounds).
1199 *
1200 * @param pEngineChannel - engine channel on which this event occured on
1201 * @param itNoteOnEvent - key, velocity and time stamp of the event
1202 * @param iLayer - layer index for the new voice (optional - only
1203 * in case of layered sounds of course)
1204 * @param ReleaseTriggerVoice - if new voice is a release triggered voice
1205 * (optional, default = false)
1206 * @param VoiceStealing - if voice stealing should be performed
1207 * when there is no free voice
1208 * (optional, default = true)
1209 * @param HandleKeyGroupConflicts - if voices should be killed due to a
1210 * key group conflict
1211 * @returns pointer to new voice or NULL if there was no free voice or
1212 * if the voice wasn't triggered (for example when no region is
1213 * defined for the given key).
1214 */
1215 Pool<Voice>::Iterator Engine::LaunchVoice(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent, int iLayer, bool ReleaseTriggerVoice, bool VoiceStealing, bool HandleKeyGroupConflicts) {
1216 int MIDIKey = itNoteOnEvent->Param.Note.Key;
1217 midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[MIDIKey];
1218 ::gig::Region* pRegion = pEngineChannel->pInstrument->GetRegion(MIDIKey);
1219
1220 // if nothing defined for this key
1221 if (!pRegion) return Pool<Voice>::Iterator(); // nothing to do
1222
1223 // only mark the first voice of a layered voice (group) to be in a
1224 // key group, so the layered voices won't kill each other
1225 int iKeyGroup = (iLayer == 0 && !ReleaseTriggerVoice) ? pRegion->KeyGroup : 0;
1226
1227 // handle key group (a.k.a. exclusive group) conflicts
1228 if (HandleKeyGroupConflicts) {
1229 if (iKeyGroup) { // if this voice / key belongs to a key group
1230 uint** ppKeyGroup = &pEngineChannel->ActiveKeyGroups[iKeyGroup];
1231 if (*ppKeyGroup) { // if there's already an active key in that key group
1232 midi_key_info_t* pOtherKey = &pEngineChannel->pMIDIKeyInfo[**ppKeyGroup];
1233 // kill all voices on the (other) key
1234 RTList<Voice>::Iterator itVoiceToBeKilled = pOtherKey->pActiveVoices->first();
1235 RTList<Voice>::Iterator end = pOtherKey->pActiveVoices->end();
1236 for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1237 if (itVoiceToBeKilled->Type != Voice::type_release_trigger) {
1238 itVoiceToBeKilled->Kill(itNoteOnEvent);
1239 --VoiceSpawnsLeft; //FIXME: just a hack, we should better check in StealVoice() if the voice was killed due to key conflict
1240 }
1241 }
1242 }
1243 }
1244 }
1245
1246 Voice::type_t VoiceType = Voice::type_normal;
1247
1248 // get current dimension values to select the right dimension region
1249 //TODO: for stolen voices this dimension region selection block is processed twice, this should be changed
1250 //FIXME: controller values for selecting the dimension region here are currently not sample accurate
1251 uint DimValues[8] = { 0 };
1252 for (int i = pRegion->Dimensions - 1; i >= 0; i--) {
1253 switch (pRegion->pDimensionDefinitions[i].dimension) {
1254 case ::gig::dimension_samplechannel:
1255 DimValues[i] = 0; //TODO: we currently ignore this dimension
1256 break;
1257 case ::gig::dimension_layer:
1258 DimValues[i] = iLayer;
1259 break;
1260 case ::gig::dimension_velocity:
1261 DimValues[i] = itNoteOnEvent->Param.Note.Velocity;
1262 break;
1263 case ::gig::dimension_channelaftertouch:
1264 DimValues[i] = pEngineChannel->ControllerTable[128];
1265 break;
1266 case ::gig::dimension_releasetrigger:
1267 VoiceType = (ReleaseTriggerVoice) ? Voice::type_release_trigger : (!iLayer) ? Voice::type_release_trigger_required : Voice::type_normal;
1268 DimValues[i] = (uint) ReleaseTriggerVoice;
1269 break;
1270 case ::gig::dimension_keyboard:
1271 DimValues[i] = (uint) (pEngineChannel->CurrentKeyDimension * pRegion->pDimensionDefinitions[i].zones);
1272 break;
1273 case ::gig::dimension_roundrobin:
1274 DimValues[i] = (uint) pEngineChannel->pMIDIKeyInfo[MIDIKey].RoundRobinIndex; // incremented for each note on
1275 break;
1276 case ::gig::dimension_random:
1277 RandomSeed = RandomSeed * 1103515245 + 12345; // classic pseudo random number generator
1278 DimValues[i] = (uint) RandomSeed >> (32 - pRegion->pDimensionDefinitions[i].bits); // highest bits are most random
1279 break;
1280 case ::gig::dimension_modwheel:
1281 DimValues[i] = pEngineChannel->ControllerTable[1];
1282 break;
1283 case ::gig::dimension_breath:
1284 DimValues[i] = pEngineChannel->ControllerTable[2];
1285 break;
1286 case ::gig::dimension_foot:
1287 DimValues[i] = pEngineChannel->ControllerTable[4];
1288 break;
1289 case ::gig::dimension_portamentotime:
1290 DimValues[i] = pEngineChannel->ControllerTable[5];
1291 break;
1292 case ::gig::dimension_effect1:
1293 DimValues[i] = pEngineChannel->ControllerTable[12];
1294 break;
1295 case ::gig::dimension_effect2:
1296 DimValues[i] = pEngineChannel->ControllerTable[13];
1297 break;
1298 case ::gig::dimension_genpurpose1:
1299 DimValues[i] = pEngineChannel->ControllerTable[16];
1300 break;
1301 case ::gig::dimension_genpurpose2:
1302 DimValues[i] = pEngineChannel->ControllerTable[17];
1303 break;
1304 case ::gig::dimension_genpurpose3:
1305 DimValues[i] = pEngineChannel->ControllerTable[18];
1306 break;
1307 case ::gig::dimension_genpurpose4:
1308 DimValues[i] = pEngineChannel->ControllerTable[19];
1309 break;
1310 case ::gig::dimension_sustainpedal:
1311 DimValues[i] = pEngineChannel->ControllerTable[64];
1312 break;
1313 case ::gig::dimension_portamento:
1314 DimValues[i] = pEngineChannel->ControllerTable[65];
1315 break;
1316 case ::gig::dimension_sostenutopedal:
1317 DimValues[i] = pEngineChannel->ControllerTable[66];
1318 break;
1319 case ::gig::dimension_softpedal:
1320 DimValues[i] = pEngineChannel->ControllerTable[67];
1321 break;
1322 case ::gig::dimension_genpurpose5:
1323 DimValues[i] = pEngineChannel->ControllerTable[80];
1324 break;
1325 case ::gig::dimension_genpurpose6:
1326 DimValues[i] = pEngineChannel->ControllerTable[81];
1327 break;
1328 case ::gig::dimension_genpurpose7:
1329 DimValues[i] = pEngineChannel->ControllerTable[82];
1330 break;
1331 case ::gig::dimension_genpurpose8:
1332 DimValues[i] = pEngineChannel->ControllerTable[83];
1333 break;
1334 case ::gig::dimension_effect1depth:
1335 DimValues[i] = pEngineChannel->ControllerTable[91];
1336 break;
1337 case ::gig::dimension_effect2depth:
1338 DimValues[i] = pEngineChannel->ControllerTable[92];
1339 break;
1340 case ::gig::dimension_effect3depth:
1341 DimValues[i] = pEngineChannel->ControllerTable[93];
1342 break;
1343 case ::gig::dimension_effect4depth:
1344 DimValues[i] = pEngineChannel->ControllerTable[94];
1345 break;
1346 case ::gig::dimension_effect5depth:
1347 DimValues[i] = pEngineChannel->ControllerTable[95];
1348 break;
1349 case ::gig::dimension_none:
1350 std::cerr << "gig::Engine::LaunchVoice() Error: dimension=none\n" << std::flush;
1351 break;
1352 default:
1353 std::cerr << "gig::Engine::LaunchVoice() Error: Unknown dimension\n" << std::flush;
1354 }
1355 }
1356
1357 // return if this is a release triggered voice and there is no
1358 // releasetrigger dimension (could happen if an instrument
1359 // change has occured between note on and off)
1360 if (ReleaseTriggerVoice && VoiceType != Voice::type_release_trigger) return Pool<Voice>::Iterator();
1361
1362 ::gig::DimensionRegion* pDimRgn = pRegion->GetDimensionRegionByValue(DimValues);
1363
1364 // no need to continue if sample is silent
1365 if (!pDimRgn->pSample || !pDimRgn->pSample->SamplesTotal) return Pool<Voice>::Iterator();
1366
1367 // allocate a new voice for the key
1368 Pool<Voice>::Iterator itNewVoice = pKey->pActiveVoices->allocAppend();
1369 if (itNewVoice) {
1370 // launch the new voice
1371 if (itNewVoice->Trigger(pEngineChannel, itNoteOnEvent, pEngineChannel->Pitch, pDimRgn, VoiceType, iKeyGroup) < 0) {
1372 dmsg(4,("Voice not triggered\n"));
1373 pKey->pActiveVoices->free(itNewVoice);
1374 }
1375 else { // on success
1376 --VoiceSpawnsLeft;
1377 if (!pKey->Active) { // mark as active key
1378 pKey->Active = true;
1379 pKey->itSelf = pEngineChannel->pActiveKeys->allocAppend();
1380 *pKey->itSelf = itNoteOnEvent->Param.Note.Key;
1381 }
1382 if (itNewVoice->KeyGroup) {
1383 uint** ppKeyGroup = &pEngineChannel->ActiveKeyGroups[itNewVoice->KeyGroup];
1384 *ppKeyGroup = &*pKey->itSelf; // put key as the (new) active key to its key group
1385 }
1386 if (itNewVoice->Type == Voice::type_release_trigger_required) pKey->ReleaseTrigger = true; // mark key for the need of release triggered voice(s)
1387 return itNewVoice; // success
1388 }
1389 }
1390 else if (VoiceStealing) {
1391 // try to steal one voice
1392 int result = StealVoice(pEngineChannel, itNoteOnEvent);
1393 if (!result) { // voice stolen successfully
1394 // put note-on event into voice-stealing queue, so it will be reprocessed after killed voice died
1395 RTList<Event>::Iterator itStealEvent = pVoiceStealingQueue->allocAppend();
1396 if (itStealEvent) {
1397 *itStealEvent = *itNoteOnEvent; // copy event
1398 itStealEvent->Param.Note.Layer = iLayer;
1399 itStealEvent->Param.Note.ReleaseTrigger = ReleaseTriggerVoice;
1400 pKey->VoiceTheftsQueued++;
1401 }
1402 else dmsg(1,("Voice stealing queue full!\n"));
1403 }
1404 }
1405
1406 return Pool<Voice>::Iterator(); // no free voice or error
1407 }
1408
1409 /**
1410 * Will be called by LaunchVoice() method in case there are no free
1411 * voices left. This method will select and kill one old voice for
1412 * voice stealing and postpone the note-on event until the selected
1413 * voice actually died.
1414 *
1415 * @param pEngineChannel - engine channel on which this event occured on
1416 * @param itNoteOnEvent - key, velocity and time stamp of the event
1417 * @returns 0 on success, a value < 0 if no active voice could be picked for voice stealing
1418 */
1419 int Engine::StealVoice(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {
1420 if (VoiceSpawnsLeft <= 0) {
1421 dmsg(1,("Max. voice thefts per audio fragment reached (you may raise CONFIG_MAX_VOICES).\n"));
1422 return -1;
1423 }
1424 if (!pEventPool->poolIsEmpty()) {
1425
1426 RTList<Voice>::Iterator itSelectedVoice;
1427
1428 // Select one voice for voice stealing
1429 switch (CONFIG_VOICE_STEAL_ALGO) {
1430
1431 // try to pick the oldest voice on the key where the new
1432 // voice should be spawned, if there is no voice on that
1433 // key, or no voice left to kill, then procceed with
1434 // 'oldestkey' algorithm
1435 case voice_steal_algo_oldestvoiceonkey: {
1436 midi_key_info_t* pSelectedKey = &pEngineChannel->pMIDIKeyInfo[itNoteOnEvent->Param.Note.Key];
1437 itSelectedVoice = pSelectedKey->pActiveVoices->first();
1438 // proceed iterating if voice was created in this fragment cycle
1439 while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice;
1440 // if we haven't found a voice then proceed with algorithm 'oldestkey'
1441 if (itSelectedVoice && itSelectedVoice->IsStealable()) break;
1442 } // no break - intentional !
1443
1444 // try to pick the oldest voice on the oldest active key
1445 // from the same engine channel
1446 // (caution: must stay after 'oldestvoiceonkey' algorithm !)
1447 case voice_steal_algo_oldestkey: {
1448 // if we already stole in this fragment, try to proceed on same key
1449 if (this->itLastStolenVoice) {
1450 itSelectedVoice = this->itLastStolenVoice;
1451 do {
1452 ++itSelectedVoice;
1453 } while (itSelectedVoice && !itSelectedVoice->IsStealable()); // proceed iterating if voice was created in this fragment cycle
1454 // found a "stealable" voice ?
1455 if (itSelectedVoice && itSelectedVoice->IsStealable()) {
1456 // remember which voice we stole, so we can simply proceed on next voice stealing
1457 this->itLastStolenVoice = itSelectedVoice;
1458 break; // selection succeeded
1459 }
1460 }
1461 // get (next) oldest key
1462 RTList<uint>::Iterator iuiSelectedKey = (this->iuiLastStolenKey) ? ++this->iuiLastStolenKey : pEngineChannel->pActiveKeys->first();
1463 while (iuiSelectedKey) {
1464 midi_key_info_t* pSelectedKey = &pEngineChannel->pMIDIKeyInfo[*iuiSelectedKey];
1465 itSelectedVoice = pSelectedKey->pActiveVoices->first();
1466 // proceed iterating if voice was created in this fragment cycle
1467 while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice;
1468 // found a "stealable" voice ?
1469 if (itSelectedVoice && itSelectedVoice->IsStealable()) {
1470 // remember which voice on which key we stole, so we can simply proceed on next voice stealing
1471 this->iuiLastStolenKey = iuiSelectedKey;
1472 this->itLastStolenVoice = itSelectedVoice;
1473 break; // selection succeeded
1474 }
1475 ++iuiSelectedKey; // get next oldest key
1476 }
1477 break;
1478 }
1479
1480 // don't steal anything
1481 case voice_steal_algo_none:
1482 default: {
1483 dmsg(1,("No free voice (voice stealing disabled)!\n"));
1484 return -1;
1485 }
1486 }
1487
1488 // if we couldn't steal a voice from the same engine channel then
1489 // steal oldest voice on the oldest key from any other engine channel
1490 // (the smaller engine channel number, the higher priority)
1491 if (!itSelectedVoice || !itSelectedVoice->IsStealable()) {
1492 EngineChannel* pSelectedChannel;
1493 int iChannelIndex;
1494 // select engine channel
1495 if (pLastStolenChannel) {
1496 pSelectedChannel = pLastStolenChannel;
1497 iChannelIndex = pSelectedChannel->iEngineIndexSelf;
1498 } else { // pick the engine channel followed by this engine channel
1499 iChannelIndex = (pEngineChannel->iEngineIndexSelf + 1) % engineChannels.size();
1500 pSelectedChannel = engineChannels[iChannelIndex];
1501 }
1502
1503 // if we already stole in this fragment, try to proceed on same key
1504 if (this->itLastStolenVoiceGlobally) {
1505 itSelectedVoice = this->itLastStolenVoiceGlobally;
1506 do {
1507 ++itSelectedVoice;
1508 } while (itSelectedVoice && !itSelectedVoice->IsStealable()); // proceed iterating if voice was created in this fragment cycle
1509 }
1510
1511 #if CONFIG_DEVMODE
1512 EngineChannel* pBegin = pSelectedChannel; // to detect endless loop
1513 #endif // CONFIG_DEVMODE
1514
1515 // did we find a 'stealable' voice?
1516 if (itSelectedVoice && itSelectedVoice->IsStealable()) {
1517 // remember which voice we stole, so we can simply proceed on next voice stealing
1518 this->itLastStolenVoiceGlobally = itSelectedVoice;
1519 } else while (true) { // iterate through engine channels
1520 // get (next) oldest key
1521 RTList<uint>::Iterator iuiSelectedKey = (this->iuiLastStolenKeyGlobally) ? ++this->iuiLastStolenKeyGlobally : pSelectedChannel->pActiveKeys->first();
1522 this->iuiLastStolenKeyGlobally = RTList<uint>::Iterator(); // to prevent endless loop (see line above)
1523 while (iuiSelectedKey) {
1524 midi_key_info_t* pSelectedKey = &pSelectedChannel->pMIDIKeyInfo[*iuiSelectedKey];
1525 itSelectedVoice = pSelectedKey->pActiveVoices->first();
1526 // proceed iterating if voice was created in this fragment cycle
1527 while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice;
1528 // found a "stealable" voice ?
1529 if (itSelectedVoice && itSelectedVoice->IsStealable()) {
1530 // remember which voice on which key on which engine channel we stole, so we can simply proceed on next voice stealing
1531 this->iuiLastStolenKeyGlobally = iuiSelectedKey;
1532 this->itLastStolenVoiceGlobally = itSelectedVoice;
1533 this->pLastStolenChannel = pSelectedChannel;
1534 goto stealable_voice_found; // selection succeeded
1535 }
1536 ++iuiSelectedKey; // get next key on current engine channel
1537 }
1538 // get next engine channel
1539 iChannelIndex = (iChannelIndex + 1) % engineChannels.size();
1540 pSelectedChannel = engineChannels[iChannelIndex];
1541
1542 #if CONFIG_DEVMODE
1543 if (pSelectedChannel == pBegin) {
1544 dmsg(1,("FATAL ERROR: voice stealing endless loop!\n"));
1545 dmsg(1,("VoiceSpawnsLeft=%d.\n", VoiceSpawnsLeft));
1546 dmsg(1,("Exiting.\n"));
1547 exit(-1);
1548 }
1549 #endif // CONFIG_DEVMODE
1550 }
1551 }
1552
1553 // jump point if a 'stealable' voice was found
1554 stealable_voice_found:
1555
1556 #if CONFIG_DEVMODE
1557 if (!itSelectedVoice->IsActive()) {
1558 dmsg(1,("gig::Engine: ERROR, tried to steal a voice which was not active !!!\n"));
1559 return -1;
1560 }
1561 #endif // CONFIG_DEVMODE
1562
1563 // now kill the selected voice
1564 itSelectedVoice->Kill(itNoteOnEvent);
1565
1566 --VoiceSpawnsLeft;
1567
1568 return 0; // success
1569 }
1570 else {
1571 dmsg(1,("Event pool emtpy!\n"));
1572 return -1;
1573 }
1574 }
1575
1576 /**
1577 * Removes the given voice from the MIDI key's list of active voices.
1578 * This method will be called when a voice went inactive, e.g. because
1579 * it finished to playback its sample, finished its release stage or
1580 * just was killed.
1581 *
1582 * @param pEngineChannel - engine channel on which this event occured on
1583 * @param itVoice - points to the voice to be freed
1584 */
1585 void Engine::FreeVoice(EngineChannel* pEngineChannel, Pool<Voice>::Iterator& itVoice) {
1586 if (itVoice) {
1587 midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[itVoice->MIDIKey];
1588
1589 uint keygroup = itVoice->KeyGroup;
1590
1591 // if the sample and dimension region belong to an
1592 // instrument that is unloaded, tell the disk thread to
1593 // release them
1594 if (itVoice->Orphan) {
1595 pDiskThread->OrderDeletionOfDimreg(itVoice->pDimRgn);
1596 }
1597
1598 // free the voice object
1599 pVoicePool->free(itVoice);
1600
1601 // if no other voices left and member of a key group, remove from key group
1602 if (pKey->pActiveVoices->isEmpty() && keygroup) {
1603 uint** ppKeyGroup = &pEngineChannel->ActiveKeyGroups[keygroup];
1604 if (*ppKeyGroup == &*pKey->itSelf) *ppKeyGroup = NULL; // remove key from key group
1605 }
1606 }
1607 else std::cerr << "Couldn't release voice! (!itVoice)\n" << std::flush;
1608 }
1609
1610 /**
1611 * Called when there's no more voice left on a key, this call will
1612 * update the key info respectively.
1613 *
1614 * @param pEngineChannel - engine channel on which this event occured on
1615 * @param pKey - key which is now inactive
1616 */
1617 void Engine::FreeKey(EngineChannel* pEngineChannel, midi_key_info_t* pKey) {
1618 if (pKey->pActiveVoices->isEmpty()) {
1619 pKey->Active = false;
1620 pEngineChannel->pActiveKeys->free(pKey->itSelf); // remove key from list of active keys
1621 pKey->itSelf = RTList<uint>::Iterator();
1622 pKey->ReleaseTrigger = false;
1623 pKey->pEvents->clear();
1624 dmsg(3,("Key has no more voices now\n"));
1625 }
1626 else dmsg(1,("gig::Engine: Oops, tried to free a key which contains voices.\n"));
1627 }
1628
1629 /**
1630 * Reacts on supported control change commands (e.g. pitch bend wheel,
1631 * modulation wheel, aftertouch).
1632 *
1633 * @param pEngineChannel - engine channel on which this event occured on
1634 * @param itControlChangeEvent - controller, value and time stamp of the event
1635 */
1636 void Engine::ProcessControlChange(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itControlChangeEvent) {
1637 dmsg(4,("Engine::ContinuousController cc=%d v=%d\n", itControlChangeEvent->Param.CC.Controller, itControlChangeEvent->Param.CC.Value));
1638
1639 // handle the "control triggered" MIDI rule: a control change
1640 // event can trigger a new note on or note off event
1641 if (pEngineChannel->pInstrument) {
1642
1643 ::gig::MidiRule* rule;
1644 for (int i = 0 ; (rule = pEngineChannel->pInstrument->GetMidiRule(i)) ; i++) {
1645
1646 if (::gig::MidiRuleCtrlTrigger* ctrlTrigger =
1647 dynamic_cast< ::gig::MidiRuleCtrlTrigger*>(rule)) {
1648 if (itControlChangeEvent->Param.CC.Controller ==
1649 ctrlTrigger->ControllerNumber) {
1650
1651 uint8_t oldCCValue = pEngineChannel->ControllerTable[
1652 itControlChangeEvent->Param.CC.Controller];
1653 uint8_t newCCValue = itControlChangeEvent->Param.CC.Value;
1654
1655 for (int i = 0 ; i < ctrlTrigger->Triggers ; i++) {
1656 ::gig::MidiRuleCtrlTrigger::trigger_t* pTrigger =
1657 &ctrlTrigger->pTriggers[i];
1658
1659 // check if the controller has passed the
1660 // trigger point in the right direction
1661 if ((pTrigger->Descending &&
1662 oldCCValue > pTrigger->TriggerPoint &&
1663 newCCValue <= pTrigger->TriggerPoint) ||
1664 (!pTrigger->Descending &&
1665 oldCCValue < pTrigger->TriggerPoint &&
1666 newCCValue >= pTrigger->TriggerPoint)) {
1667
1668 RTList<Event>::Iterator itNewEvent = pGlobalEvents->allocAppend();
1669 if (itNewEvent) {
1670 *itNewEvent = *itControlChangeEvent;
1671 itNewEvent->Param.Note.Key = pTrigger->Key;
1672
1673 if (pTrigger->NoteOff || pTrigger->Velocity == 0) {
1674 itNewEvent->Type = Event::type_note_off;
1675 itNewEvent->Param.Note.Velocity = 100;
1676
1677 ProcessNoteOff(pEngineChannel, itNewEvent);
1678 } else {
1679 itNewEvent->Type = Event::type_note_on;
1680 //TODO: if Velocity is 255, the triggered velocity should
1681 // depend on how fast the controller is moving
1682 itNewEvent->Param.Note.Velocity =
1683 pTrigger->Velocity == 255 ? 100 :
1684 pTrigger->Velocity;
1685
1686 ProcessNoteOn(pEngineChannel, itNewEvent);
1687 }
1688 }
1689 else dmsg(1,("Event pool emtpy!\n"));
1690 }
1691 }
1692 }
1693 }
1694 }
1695 }
1696
1697 // update controller value in the engine channel's controller table
1698 pEngineChannel->ControllerTable[itControlChangeEvent->Param.CC.Controller] = itControlChangeEvent->Param.CC.Value;
1699
1700 // handle hard coded MIDI controllers
1701 switch (itControlChangeEvent->Param.CC.Controller) {
1702 case 5: { // portamento time
1703 pEngineChannel->PortamentoTime = (float) itControlChangeEvent->Param.CC.Value / 127.0f * (float) CONFIG_PORTAMENTO_TIME_MAX + (float) CONFIG_PORTAMENTO_TIME_MIN;
1704 break;
1705 }
1706 case 6: { // data entry (currently only used for RPN controllers)
1707 if (pEngineChannel->GetMidiRpnController() == 2) { // coarse tuning in half tones
1708 int transpose = (int) itControlChangeEvent->Param.CC.Value - 64;
1709 // limit to +- two octaves for now
1710 transpose = RTMath::Min(transpose, 24);
1711 transpose = RTMath::Max(transpose, -24);
1712 pEngineChannel->GlobalTranspose = transpose;
1713 // workaround, so we won't have hanging notes
1714 ReleaseAllVoices(pEngineChannel, itControlChangeEvent);
1715 }
1716 // to avoid other MIDI CC #6 messages to be misenterpreted as RPN controller data
1717 pEngineChannel->ResetMidiRpnController();
1718 break;
1719 }
1720 case 7: { // volume
1721 //TODO: not sample accurate yet
1722 pEngineChannel->MidiVolume = VolumeCurve[itControlChangeEvent->Param.CC.Value];
1723 pEngineChannel->bStatusChanged = true; // engine channel status has changed, so set notify flag
1724 break;
1725 }
1726 case 10: { // panpot
1727 //TODO: not sample accurate yet
1728 pEngineChannel->GlobalPanLeft = PanCurve[128 - itControlChangeEvent->Param.CC.Value];
1729 pEngineChannel->GlobalPanRight = PanCurve[itControlChangeEvent->Param.CC.Value];
1730 pEngineChannel->iLastPanRequest = itControlChangeEvent->Param.CC.Value;
1731 break;
1732 }
1733 case 64: { // sustain
1734 if (itControlChangeEvent->Param.CC.Value >= 64 && !pEngineChannel->SustainPedal) {
1735 dmsg(4,("DAMPER (RIGHT) PEDAL DOWN\n"));
1736 pEngineChannel->SustainPedal = true;
1737
1738 #if !CONFIG_PROCESS_MUTED_CHANNELS
1739 if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
1740 #endif
1741
1742 // cancel release process of voices if necessary
1743 RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
1744 for (; iuiKey; ++iuiKey) {
1745 midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];
1746 if (!pKey->KeyPressed) {
1747 RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend();
1748 if (itNewEvent) {
1749 *itNewEvent = *itControlChangeEvent; // copy event to the key's own event list
1750 itNewEvent->Type = Event::type_cancel_release; // transform event type
1751 }
1752 else dmsg(1,("Event pool emtpy!\n"));
1753 }
1754 }
1755 }
1756 if (itControlChangeEvent->Param.CC.Value < 64 && pEngineChannel->SustainPedal) {
1757 dmsg(4,("DAMPER (RIGHT) PEDAL UP\n"));
1758 pEngineChannel->SustainPedal = false;
1759
1760 #if !CONFIG_PROCESS_MUTED_CHANNELS
1761 if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
1762 #endif
1763
1764 // release voices if their respective key is not pressed
1765 RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
1766 for (; iuiKey; ++iuiKey) {
1767 midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];
1768 if (!pKey->KeyPressed && ShouldReleaseVoice(pEngineChannel, *iuiKey)) {
1769 RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend();
1770 if (itNewEvent) {
1771 *itNewEvent = *itControlChangeEvent; // copy event to the key's own event list
1772 itNewEvent->Type = Event::type_release; // transform event type
1773 }
1774 else dmsg(1,("Event pool emtpy!\n"));
1775 }
1776 }
1777 }
1778 break;
1779 }
1780 case 65: { // portamento on / off
1781 const bool bPortamento = itControlChangeEvent->Param.CC.Value >= 64;
1782 if (bPortamento != pEngineChannel->PortamentoMode)
1783 KillAllVoices(pEngineChannel, itControlChangeEvent);
1784 pEngineChannel->PortamentoMode = bPortamento;
1785 break;
1786 }
1787 case 66: { // sostenuto
1788 if (itControlChangeEvent->Param.CC.Value >= 64 && !pEngineChannel->SostenutoPedal) {
1789 dmsg(4,("SOSTENUTO (CENTER) PEDAL DOWN\n"));
1790 pEngineChannel->SostenutoPedal = true;
1791
1792 #if !CONFIG_PROCESS_MUTED_CHANNELS
1793 if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
1794 #endif
1795
1796 SostenutoKeyCount = 0;
1797 // Remeber the pressed keys
1798 RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
1799 for (; iuiKey; ++iuiKey) {
1800 midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];
1801 if (pKey->KeyPressed && SostenutoKeyCount < 128) SostenutoKeys[SostenutoKeyCount++] = *iuiKey;
1802 }
1803 }
1804 if (itControlChangeEvent->Param.CC.Value < 64 && pEngineChannel->SostenutoPedal) {
1805 dmsg(4,("SOSTENUTO (CENTER) PEDAL UP\n"));
1806 pEngineChannel->SostenutoPedal = false;
1807
1808 #if !CONFIG_PROCESS_MUTED_CHANNELS
1809 if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
1810 #endif
1811
1812 // release voices if the damper pedal is up and their respective key is not pressed
1813 for (int i = 0; i < SostenutoKeyCount; i++) {
1814 midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[SostenutoKeys[i]];
1815 if (!pKey->KeyPressed && !pEngineChannel->SustainPedal) {
1816 RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend();
1817 if (itNewEvent) {
1818 *itNewEvent = *itControlChangeEvent; // copy event to the key's own event list
1819 itNewEvent->Type = Event::type_release; // transform event type
1820 }
1821 else dmsg(1,("Event pool emtpy!\n"));
1822 }
1823 }
1824 }
1825 break;
1826 }
1827 case 100: { // RPN controller LSB
1828 pEngineChannel->SetMidiRpnControllerLsb(itControlChangeEvent->Param.CC.Value);
1829 break;
1830 }
1831 case 101: { // RPN controller MSB
1832 pEngineChannel->SetMidiRpnControllerMsb(itControlChangeEvent->Param.CC.Value);
1833 break;
1834 }
1835
1836
1837 // Channel Mode Messages
1838
1839 case 120: { // all sound off
1840 KillAllVoices(pEngineChannel, itControlChangeEvent);
1841 break;
1842 }
1843 case 121: { // reset all controllers
1844 pEngineChannel->ResetControllers();
1845 break;
1846 }
1847 case 123: { // all notes off
1848 #if CONFIG_PROCESS_ALL_NOTES_OFF
1849 ReleaseAllVoices(pEngineChannel, itControlChangeEvent);
1850 #endif // CONFIG_PROCESS_ALL_NOTES_OFF
1851 break;
1852 }
1853 case 126: { // mono mode on
1854 if (!pEngineChannel->SoloMode)
1855 KillAllVoices(pEngineChannel, itControlChangeEvent);
1856 pEngineChannel->SoloMode = true;
1857 break;
1858 }
1859 case 127: { // poly mode on
1860 if (pEngineChannel->SoloMode)
1861 KillAllVoices(pEngineChannel, itControlChangeEvent);
1862 pEngineChannel->SoloMode = false;
1863 break;
1864 }
1865 }
1866
1867 // handle FX send controllers
1868 if (!pEngineChannel->fxSends.empty()) {
1869 for (int iFxSend = 0; iFxSend < pEngineChannel->GetFxSendCount(); iFxSend++) {
1870 FxSend* pFxSend = pEngineChannel->GetFxSend(iFxSend);
1871 if (pFxSend->MidiController() == itControlChangeEvent->Param.CC.Controller) {
1872 pFxSend->SetLevel(itControlChangeEvent->Param.CC.Value);
1873 pFxSend->SetInfoChanged(true);
1874 }
1875 }
1876 }
1877 }
1878
1879 /**
1880 * Reacts on MIDI system exclusive messages.
1881 *
1882 * @param itSysexEvent - sysex data size and time stamp of the sysex event
1883 */
1884 void Engine::ProcessSysex(Pool<Event>::Iterator& itSysexEvent) {
1885 RingBuffer<uint8_t,false>::NonVolatileReader reader = pSysexBuffer->get_non_volatile_reader();
1886
1887 uint8_t exclusive_status, id;
1888 if (!reader.pop(&exclusive_status)) goto free_sysex_data;
1889 if (!reader.pop(&id)) goto free_sysex_data;
1890 if (exclusive_status != 0xF0) goto free_sysex_data;
1891
1892 switch (id) {
1893 case 0x7f: { // (Realtime) Universal Sysex (GM Standard)
1894 uint8_t sysex_channel, sub_id1, sub_id2, val_msb, val_lsb;;
1895 if (!reader.pop(&sysex_channel)) goto free_sysex_data;
1896 if (!reader.pop(&sub_id1)) goto free_sysex_data;
1897 if (!reader.pop(&sub_id2)) goto free_sysex_data;
1898 if (!reader.pop(&val_lsb)) goto free_sysex_data;
1899 if (!reader.pop(&val_msb)) goto free_sysex_data;
1900 //TODO: for now we simply ignore the sysex channel, seldom used anyway
1901 switch (sub_id1) {
1902 case 0x04: // Device Control
1903 switch (sub_id2) {
1904 case 0x01: // Master Volume
1905 GLOBAL_VOLUME =
1906 double((uint(val_msb)<<7) | uint(val_lsb)) / 16383.0;
1907 break;
1908 }
1909 break;
1910 }
1911 break;
1912 }
1913 case 0x41: { // Roland
1914 dmsg(3,("Roland Sysex\n"));
1915 uint8_t device_id, model_id, cmd_id;
1916 if (!reader.pop(&device_id)) goto free_sysex_data;
1917 if (!reader.pop(&model_id)) goto free_sysex_data;
1918 if (!reader.pop(&cmd_id)) goto free_sysex_data;
1919 if (model_id != 0x42 /*GS*/) goto free_sysex_data;
1920 if (cmd_id != 0x12 /*DT1*/) goto free_sysex_data;
1921
1922 // command address
1923 uint8_t addr[3]; // 2 byte addr MSB, followed by 1 byte addr LSB)
1924 const RingBuffer<uint8_t,false>::NonVolatileReader checksum_reader = reader; // so we can calculate the check sum later
1925 if (reader.read(&addr[0], 3) != 3) goto free_sysex_data;
1926 if (addr[0] == 0x40 && addr[1] == 0x00) { // System Parameters
1927 dmsg(3,("\tSystem Parameter\n"));
1928 }
1929 else if (addr[0] == 0x40 && addr[1] == 0x01) { // Common Parameters
1930 dmsg(3,("\tCommon Parameter\n"));
1931 }
1932 else if (addr[0] == 0x40 && (addr[1] & 0xf0) == 0x10) { // Part Parameters (1)
1933 dmsg(3,("\tPart Parameter\n"));
1934 switch (addr[2]) {
1935 case 0x40: { // scale tuning
1936 dmsg(3,("\t\tScale Tuning\n"));
1937 uint8_t scale_tunes[12]; // detuning of all 12 semitones of an octave
1938 if (reader.read(&scale_tunes[0], 12) != 12) goto free_sysex_data;
1939 uint8_t checksum;
1940 if (!reader.pop(&checksum)) goto free_sysex_data;
1941 #if CONFIG_ASSERT_GS_SYSEX_CHECKSUM
1942 if (GSCheckSum(checksum_reader, 12)) goto free_sysex_data;
1943 #endif // CONFIG_ASSERT_GS_SYSEX_CHECKSUM
1944 for (int i = 0; i < 12; i++) scale_tunes[i] -= 64;
1945 AdjustScale((int8_t*) scale_tunes);
1946 dmsg(3,("\t\t\tNew scale applied.\n"));
1947 break;
1948 }
1949 }
1950 }
1951 else if (addr[0] == 0x40 && (addr[1] & 0xf0) == 0x20) { // Part Parameters (2)
1952 }
1953 else if (addr[0] == 0x41) { // Drum Setup Parameters
1954 }
1955 break;
1956 }
1957 }
1958
1959 free_sysex_data: // finally free sysex data
1960 pSysexBuffer->increment_read_ptr(itSysexEvent->Param.Sysex.Size);
1961 }
1962
1963 /**
1964 * Calculates the Roland GS sysex check sum.
1965 *
1966 * @param AddrReader - reader which currently points to the first GS
1967 * command address byte of the GS sysex message in
1968 * question
1969 * @param DataSize - size of the GS message data (in bytes)
1970 */
1971 uint8_t Engine::GSCheckSum(const RingBuffer<uint8_t,false>::NonVolatileReader AddrReader, uint DataSize) {
1972 RingBuffer<uint8_t,false>::NonVolatileReader reader = AddrReader;
1973 uint bytes = 3 /*addr*/ + DataSize;
1974 uint8_t addr_and_data[bytes];
1975 reader.read(&addr_and_data[0], bytes);
1976 uint8_t sum = 0;
1977 for (uint i = 0; i < bytes; i++) sum += addr_and_data[i];
1978 return 128 - sum % 128;
1979 }
1980
1981 /**
1982 * Allows to tune each of the twelve semitones of an octave.
1983 *
1984 * @param ScaleTunes - detuning of all twelve semitones (in cents)
1985 */
1986 void Engine::AdjustScale(int8_t ScaleTunes[12]) {
1987 memcpy(&this->ScaleTuning[0], &ScaleTunes[0], 12); //TODO: currently not sample accurate
1988 }
1989
1990 /**
1991 * Releases all voices on an engine channel. All voices will go into
1992 * the release stage and thus it might take some time (e.g. dependant to
1993 * their envelope release time) until they actually die.
1994 *
1995 * @param pEngineChannel - engine channel on which all voices should be released
1996 * @param itReleaseEvent - event which caused this releasing of all voices
1997 */
1998 void Engine::ReleaseAllVoices(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itReleaseEvent) {
1999 RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
2000 while (iuiKey) {
2001 midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];
2002 ++iuiKey;
2003 // append a 'release' event to the key's own event list
2004 RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend();
2005 if (itNewEvent) {
2006 *itNewEvent = *itReleaseEvent; // copy original event (to the key's event list)
2007 itNewEvent->Type = Event::type_release; // transform event type
2008 }
2009 else dmsg(1,("Event pool emtpy!\n"));
2010 }
2011 }
2012
2013 /**
2014 * Kills all voices on an engine channel as soon as possible. Voices
2015 * won't get into release state, their volume level will be ramped down
2016 * as fast as possible.
2017 *
2018 * @param pEngineChannel - engine channel on which all voices should be killed
2019 * @param itKillEvent - event which caused this killing of all voices
2020 */
2021 void Engine::KillAllVoices(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itKillEvent) {
2022 RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
2023 RTList<uint>::Iterator end = pEngineChannel->pActiveKeys->end();
2024 while (iuiKey != end) { // iterate through all active keys
2025 midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];
2026 ++iuiKey;
2027 RTList<Voice>::Iterator itVoice = pKey->pActiveVoices->first();
2028 RTList<Voice>::Iterator itVoicesEnd = pKey->pActiveVoices->end();
2029 for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
2030 itVoice->Kill(itKillEvent);
2031 --VoiceSpawnsLeft; //FIXME: just a temporary workaround, we should check the cause in StealVoice() instead
2032 }
2033 }
2034 }
2035
2036 /**
2037 * Determines whether the specified voice should be released.
2038 *
2039 * @param pEngineChannel - The engine channel on which the voice should be checked
2040 * @param Key - The key number
2041 * @returns true if the specified should be released, false otherwise.
2042 */
2043 bool Engine::ShouldReleaseVoice(EngineChannel* pEngineChannel, int Key) {
2044 if (pEngineChannel->SustainPedal) return false;
2045
2046 if (pEngineChannel->SostenutoPedal) {
2047 for (int i = 0; i < SostenutoKeyCount; i++)
2048 if (Key == SostenutoKeys[i]) return false;
2049 }
2050
2051 return true;
2052 }
2053
2054 uint Engine::VoiceCount() {
2055 return ActiveVoiceCount;
2056 }
2057
2058 uint Engine::VoiceCountMax() {
2059 return ActiveVoiceCountMax;
2060 }
2061
2062 bool Engine::DiskStreamSupported() {
2063 return true;
2064 }
2065
2066 uint Engine::DiskStreamCount() {
2067 return (pDiskThread) ? pDiskThread->ActiveStreamCount : 0;
2068 }
2069
2070 uint Engine::DiskStreamCountMax() {
2071 return (pDiskThread) ? pDiskThread->ActiveStreamCountMax : 0;
2072 }
2073
2074 String Engine::DiskStreamBufferFillBytes() {
2075 return pDiskThread->GetBufferFillBytes();
2076 }
2077
2078 String Engine::DiskStreamBufferFillPercentage() {
2079 return pDiskThread->GetBufferFillPercentage();
2080 }
2081
2082 String Engine::EngineName() {
2083 return LS_GIG_ENGINE_NAME;
2084 }
2085
2086 String Engine::Description() {
2087 return "Gigasampler Format Engine";
2088 }
2089
2090 String Engine::Version() {
2091 String s = "$Revision: 1.93 $";
2092 return s.substr(11, s.size() - 13); // cut dollar signs, spaces and CVS macro keyword
2093 }
2094
2095 InstrumentManager* Engine::GetInstrumentManager() {
2096 return &instruments;
2097 }
2098
2099 // static constant initializers
2100 const Engine::FloatTable Engine::VolumeCurve(InitVolumeCurve());
2101 const Engine::FloatTable Engine::PanCurve(InitPanCurve());
2102 const Engine::FloatTable Engine::CrossfadeCurve(InitCrossfadeCurve());
2103
2104 float* Engine::InitVolumeCurve() {
2105 // line-segment approximation
2106 const float segments[] = {
2107 0, 0, 2, 0.0046, 16, 0.016, 31, 0.051, 45, 0.115, 54.5, 0.2,
2108 64.5, 0.39, 74, 0.74, 92, 1.03, 114, 1.94, 119.2, 2.2, 127, 2.2
2109 };
2110 return InitCurve(segments);
2111 }
2112
2113 float* Engine::InitPanCurve() {
2114 // line-segment approximation
2115 const float segments[] = {
2116 0, 0, 1, 0,
2117 2, 0.05, 31.5, 0.7, 51, 0.851, 74.5, 1.12,
2118 127, 1.41, 128, 1.41
2119 };
2120 return InitCurve(segments, 129);
2121 }
2122
2123 float* Engine::InitCrossfadeCurve() {
2124 // line-segment approximation
2125 const float segments[] = {
2126 0, 0, 1, 0.03, 10, 0.1, 51, 0.58, 127, 1
2127 };
2128 return InitCurve(segments);
2129 }
2130
2131 float* Engine::InitCurve(const float* segments, int size) {
2132 float* y = new float[size];
2133 for (int x = 0 ; x < size ; x++) {
2134 if (x > segments[2]) segments += 2;
2135 y[x] = segments[1] + (x - segments[0]) *
2136 (segments[3] - segments[1]) / (segments[2] - segments[0]);
2137 }
2138 return y;
2139 }
2140
2141 }} // namespace LinuxSampler::gig

  ViewVC Help
Powered by ViewVC