/[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 1723 - (show annotations) (download)
Sun Apr 20 08:53:39 2008 UTC (12 years, 1 month ago) by schoenebeck
File size: 104041 byte(s)
* allow pan control of engine channels on C++ API level
* export denormals-are-zero mode feature to C++ API

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

  ViewVC Help
Powered by ViewVC