/[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 1700 - (show annotations) (download)
Sun Feb 17 12:40:59 2008 UTC (16 years, 2 months ago) by persson
File size: 102666 byte(s)
* added partial support for the "Controller Triggered" MIDI rule,
  enough for piano gigs with pedal noise samples

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 master 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 // left channel
872 const int iDstL = pFxSend->DestinationChannel(0);
873 if (iDstL < 0) {
874 dmsg(1,("Engine::RouteAudio() Error: invalid FX send (L) destination channel"));
875 } else {
876 AudioChannel* pDstL = pAudioOutputDevice->Channel(iDstL);
877 if (!pDstL) {
878 dmsg(1,("Engine::RouteAudio() Error: invalid FX send (L) destination channel"));
879 } else pEngineChannel->pChannelLeft->MixTo(pDstL, Samples, pFxSend->Level());
880 }
881 // right channel
882 const int iDstR = pFxSend->DestinationChannel(1);
883 if (iDstR < 0) {
884 dmsg(1,("Engine::RouteAudio() Error: invalid FX send (R) destination channel"));
885 } else {
886 AudioChannel* pDstR = pAudioOutputDevice->Channel(iDstR);
887 if (!pDstR) {
888 dmsg(1,("Engine::RouteAudio() Error: invalid FX send (R) destination channel"));
889 } else pEngineChannel->pChannelRight->MixTo(pDstR, Samples, pFxSend->Level());
890 }
891 }
892 }
893 // reset buffers with silence (zero out) for the next audio cycle
894 pEngineChannel->pChannelLeft->Clear();
895 pEngineChannel->pChannelRight->Clear();
896 }
897
898 /**
899 * Free all keys which have turned inactive in this audio fragment, from
900 * the list of active keys and clear all event lists on that engine
901 * channel.
902 *
903 * @param pEngineChannel - engine channel to cleanup
904 */
905 void Engine::PostProcess(EngineChannel* pEngineChannel) {
906 // free all keys which have no active voices left
907 {
908 RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
909 RTList<uint>::Iterator end = pEngineChannel->pActiveKeys->end();
910 while (iuiKey != end) { // iterate through all active keys
911 midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];
912 ++iuiKey;
913 if (pKey->pActiveVoices->isEmpty()) FreeKey(pEngineChannel, pKey);
914 #if CONFIG_DEVMODE
915 else { // just a sanity check for debugging
916 RTList<Voice>::Iterator itVoice = pKey->pActiveVoices->first();
917 RTList<Voice>::Iterator itVoicesEnd = pKey->pActiveVoices->end();
918 for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
919 if (itVoice->itKillEvent) {
920 dmsg(1,("gig::Engine: ERROR, killed voice survived !!!\n"));
921 }
922 }
923 }
924 #endif // CONFIG_DEVMODE
925 }
926 }
927
928 // empty the engine channel's own event lists
929 pEngineChannel->ClearEventLists();
930 }
931
932 /**
933 * Will be called by the MIDI input device whenever a MIDI system
934 * exclusive message has arrived.
935 *
936 * @param pData - pointer to sysex data
937 * @param Size - lenght of sysex data (in bytes)
938 */
939 void Engine::SendSysex(void* pData, uint Size) {
940 Event event = pEventGenerator->CreateEvent();
941 event.Type = Event::type_sysex;
942 event.Param.Sysex.Size = Size;
943 event.pEngineChannel = NULL; // as Engine global event
944 if (pEventQueue->write_space() > 0) {
945 if (pSysexBuffer->write_space() >= Size) {
946 // copy sysex data to input buffer
947 uint toWrite = Size;
948 uint8_t* pPos = (uint8_t*) pData;
949 while (toWrite) {
950 const uint writeNow = RTMath::Min(toWrite, pSysexBuffer->write_space_to_end());
951 pSysexBuffer->write(pPos, writeNow);
952 toWrite -= writeNow;
953 pPos += writeNow;
954
955 }
956 // finally place sysex event into input event queue
957 pEventQueue->push(&event);
958 }
959 else dmsg(1,("Engine: Sysex message too large (%d byte) for input buffer (%d byte)!",Size,CONFIG_SYSEX_BUFFER_SIZE));
960 }
961 else dmsg(1,("Engine: Input event queue full!"));
962 }
963
964 /**
965 * Assigns and triggers a new voice for the respective MIDI key.
966 *
967 * @param pEngineChannel - engine channel on which this event occured on
968 * @param itNoteOnEvent - key, velocity and time stamp of the event
969 */
970 void Engine::ProcessNoteOn(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {
971 #if !CONFIG_PROCESS_MUTED_CHANNELS
972 if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
973 #endif
974
975 if (!pEngineChannel->pInstrument) return; // ignore if no instrument loaded
976
977 //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
978 itNoteOnEvent->Param.Note.Key += pEngineChannel->GlobalTranspose;
979
980 const int key = itNoteOnEvent->Param.Note.Key;
981 midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[key];
982
983 // move note on event to the key's own event list
984 RTList<Event>::Iterator itNoteOnEventOnKeyList = itNoteOnEvent.moveToEndOf(pKey->pEvents);
985
986 // if Solo Mode then kill all already active voices
987 if (pEngineChannel->SoloMode) {
988 Pool<uint>::Iterator itYoungestKey = pEngineChannel->pActiveKeys->last();
989 if (itYoungestKey) {
990 const int iYoungestKey = *itYoungestKey;
991 const midi_key_info_t* pOtherKey = &pEngineChannel->pMIDIKeyInfo[iYoungestKey];
992 if (pOtherKey->Active) {
993 // get final portamento position of currently active voice
994 if (pEngineChannel->PortamentoMode) {
995 RTList<Voice>::Iterator itVoice = pOtherKey->pActiveVoices->last();
996 if (itVoice) itVoice->UpdatePortamentoPos(itNoteOnEventOnKeyList);
997 }
998 // kill all voices on the (other) key
999 RTList<Voice>::Iterator itVoiceToBeKilled = pOtherKey->pActiveVoices->first();
1000 RTList<Voice>::Iterator end = pOtherKey->pActiveVoices->end();
1001 for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1002 if (itVoiceToBeKilled->Type != Voice::type_release_trigger)
1003 itVoiceToBeKilled->Kill(itNoteOnEventOnKeyList);
1004 }
1005 }
1006 }
1007 // set this key as 'currently active solo key'
1008 pEngineChannel->SoloKey = key;
1009 }
1010
1011 // Change key dimension value if key is in keyswitching area
1012 {
1013 const ::gig::Instrument* pInstrument = pEngineChannel->pInstrument;
1014 if (key >= pInstrument->DimensionKeyRange.low && key <= pInstrument->DimensionKeyRange.high)
1015 pEngineChannel->CurrentKeyDimension = float(key - pInstrument->DimensionKeyRange.low) /
1016 (pInstrument->DimensionKeyRange.high - pInstrument->DimensionKeyRange.low + 1);
1017 }
1018
1019 pKey->KeyPressed = true; // the MIDI key was now pressed down
1020 pKey->Velocity = itNoteOnEventOnKeyList->Param.Note.Velocity;
1021 pKey->NoteOnTime = FrameTime + itNoteOnEventOnKeyList->FragmentPos(); // will be used to calculate note length
1022
1023 // cancel release process of voices on this key if needed
1024 if (pKey->Active && !pEngineChannel->SustainPedal) {
1025 RTList<Event>::Iterator itCancelReleaseEvent = pKey->pEvents->allocAppend();
1026 if (itCancelReleaseEvent) {
1027 *itCancelReleaseEvent = *itNoteOnEventOnKeyList; // copy event
1028 itCancelReleaseEvent->Type = Event::type_cancel_release; // transform event type
1029 }
1030 else dmsg(1,("Event pool emtpy!\n"));
1031 }
1032
1033 // allocate and trigger new voice(s) for the key
1034 {
1035 // first, get total amount of required voices (dependant on amount of layers)
1036 ::gig::Region* pRegion = pEngineChannel->pInstrument->GetRegion(itNoteOnEventOnKeyList->Param.Note.Key);
1037 if (pRegion && !RegionSuspended(pRegion)) {
1038 int voicesRequired = pRegion->Layers;
1039 // now launch the required amount of voices
1040 for (int i = 0; i < voicesRequired; i++)
1041 LaunchVoice(pEngineChannel, itNoteOnEventOnKeyList, i, false, true, true);
1042 }
1043 }
1044
1045 // if neither a voice was spawned or postponed then remove note on event from key again
1046 if (!pKey->Active && !pKey->VoiceTheftsQueued)
1047 pKey->pEvents->free(itNoteOnEventOnKeyList);
1048
1049 if (!pEngineChannel->SoloMode || pEngineChannel->PortamentoPos < 0.0f) pEngineChannel->PortamentoPos = (float) key;
1050 pKey->RoundRobinIndex++;
1051 }
1052
1053 /**
1054 * Releases the voices on the given key if sustain pedal is not pressed.
1055 * If sustain is pressed, the release of the note will be postponed until
1056 * sustain pedal will be released or voice turned inactive by itself (e.g.
1057 * due to completion of sample playback).
1058 *
1059 * @param pEngineChannel - engine channel on which this event occured on
1060 * @param itNoteOffEvent - key, velocity and time stamp of the event
1061 */
1062 void Engine::ProcessNoteOff(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOffEvent) {
1063 #if !CONFIG_PROCESS_MUTED_CHANNELS
1064 if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
1065 #endif
1066
1067 //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
1068 itNoteOffEvent->Param.Note.Key += pEngineChannel->GlobalTranspose;
1069
1070 const int iKey = itNoteOffEvent->Param.Note.Key;
1071 midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[iKey];
1072 pKey->KeyPressed = false; // the MIDI key was now released
1073
1074 // move event to the key's own event list
1075 RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);
1076
1077 bool bShouldRelease = pKey->Active && ShouldReleaseVoice(pEngineChannel, itNoteOffEventOnKeyList->Param.Note.Key);
1078
1079 // in case Solo Mode is enabled, kill all voices on this key and respawn a voice on the highest pressed key (if any)
1080 if (pEngineChannel->SoloMode && pEngineChannel->pInstrument) { //TODO: this feels like too much code just for handling solo mode :P
1081 bool bOtherKeysPressed = false;
1082 if (iKey == pEngineChannel->SoloKey) {
1083 pEngineChannel->SoloKey = -1;
1084 // if there's still a key pressed down, respawn a voice (group) on the highest key
1085 for (int i = 127; i > 0; i--) {
1086 midi_key_info_t* pOtherKey = &pEngineChannel->pMIDIKeyInfo[i];
1087 if (pOtherKey->KeyPressed) {
1088 bOtherKeysPressed = true;
1089 // make the other key the new 'currently active solo key'
1090 pEngineChannel->SoloKey = i;
1091 // get final portamento position of currently active voice
1092 if (pEngineChannel->PortamentoMode) {
1093 RTList<Voice>::Iterator itVoice = pKey->pActiveVoices->first();
1094 if (itVoice) itVoice->UpdatePortamentoPos(itNoteOffEventOnKeyList);
1095 }
1096 // create a pseudo note on event
1097 RTList<Event>::Iterator itPseudoNoteOnEvent = pOtherKey->pEvents->allocAppend();
1098 if (itPseudoNoteOnEvent) {
1099 // copy event
1100 *itPseudoNoteOnEvent = *itNoteOffEventOnKeyList;
1101 // transform event to a note on event
1102 itPseudoNoteOnEvent->Type = Event::type_note_on;
1103 itPseudoNoteOnEvent->Param.Note.Key = i;
1104 itPseudoNoteOnEvent->Param.Note.Velocity = pOtherKey->Velocity;
1105 // allocate and trigger new voice(s) for the other key
1106 {
1107 // first, get total amount of required voices (dependant on amount of layers)
1108 ::gig::Region* pRegion = pEngineChannel->pInstrument->GetRegion(i);
1109 if (pRegion) {
1110 int voicesRequired = pRegion->Layers;
1111 // now launch the required amount of voices
1112 for (int iLayer = 0; iLayer < voicesRequired; iLayer++)
1113 LaunchVoice(pEngineChannel, itPseudoNoteOnEvent, iLayer, false, true, false);
1114 }
1115 }
1116 // if neither a voice was spawned or postponed then remove note on event from key again
1117 if (!pOtherKey->Active && !pOtherKey->VoiceTheftsQueued)
1118 pOtherKey->pEvents->free(itPseudoNoteOnEvent);
1119
1120 } else dmsg(1,("Could not respawn voice, no free event left\n"));
1121 break; // done
1122 }
1123 }
1124 }
1125 if (bOtherKeysPressed) {
1126 if (pKey->Active) { // kill all voices on this key
1127 bShouldRelease = false; // no need to release, as we kill it here
1128 RTList<Voice>::Iterator itVoiceToBeKilled = pKey->pActiveVoices->first();
1129 RTList<Voice>::Iterator end = pKey->pActiveVoices->end();
1130 for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1131 if (itVoiceToBeKilled->Type != Voice::type_release_trigger)
1132 itVoiceToBeKilled->Kill(itNoteOffEventOnKeyList);
1133 }
1134 }
1135 } else pEngineChannel->PortamentoPos = -1.0f;
1136 }
1137
1138 // if no solo mode (the usual case) or if solo mode and no other key pressed, then release voices on this key if needed
1139 if (bShouldRelease) {
1140 itNoteOffEventOnKeyList->Type = Event::type_release; // transform event type
1141
1142 // spawn release triggered voice(s) if needed
1143 if (pKey->ReleaseTrigger && pEngineChannel->pInstrument) {
1144 // first, get total amount of required voices (dependant on amount of layers)
1145 ::gig::Region* pRegion = pEngineChannel->pInstrument->GetRegion(itNoteOffEventOnKeyList->Param.Note.Key);
1146 if (pRegion) {
1147 int voicesRequired = pRegion->Layers;
1148
1149 // MIDI note-on velocity is used instead of note-off velocity
1150 itNoteOffEventOnKeyList->Param.Note.Velocity = pKey->Velocity;
1151
1152 // now launch the required amount of voices
1153 for (int i = 0; i < voicesRequired; i++)
1154 LaunchVoice(pEngineChannel, itNoteOffEventOnKeyList, i, true, false, false); //FIXME: for the moment we don't perform voice stealing for release triggered samples
1155 }
1156 pKey->ReleaseTrigger = false;
1157 }
1158 }
1159
1160 // if neither a voice was spawned or postponed on this key then remove note off event from key again
1161 if (!pKey->Active && !pKey->VoiceTheftsQueued)
1162 pKey->pEvents->free(itNoteOffEventOnKeyList);
1163 }
1164
1165 /**
1166 * Moves pitchbend event from the general (input) event list to the engine
1167 * channel's event list. It will actually processed later by the
1168 * respective voice.
1169 *
1170 * @param pEngineChannel - engine channel on which this event occured on
1171 * @param itPitchbendEvent - absolute pitch value and time stamp of the event
1172 */
1173 void Engine::ProcessPitchbend(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itPitchbendEvent) {
1174 pEngineChannel->Pitch = itPitchbendEvent->Param.Pitch.Pitch; // store current pitch value
1175 }
1176
1177 /**
1178 * Allocates and triggers a new voice. This method will usually be
1179 * called by the ProcessNoteOn() method and by the voices itself
1180 * (e.g. to spawn further voices on the same key for layered sounds).
1181 *
1182 * @param pEngineChannel - engine channel on which this event occured on
1183 * @param itNoteOnEvent - key, velocity and time stamp of the event
1184 * @param iLayer - layer index for the new voice (optional - only
1185 * in case of layered sounds of course)
1186 * @param ReleaseTriggerVoice - if new voice is a release triggered voice
1187 * (optional, default = false)
1188 * @param VoiceStealing - if voice stealing should be performed
1189 * when there is no free voice
1190 * (optional, default = true)
1191 * @param HandleKeyGroupConflicts - if voices should be killed due to a
1192 * key group conflict
1193 * @returns pointer to new voice or NULL if there was no free voice or
1194 * if the voice wasn't triggered (for example when no region is
1195 * defined for the given key).
1196 */
1197 Pool<Voice>::Iterator Engine::LaunchVoice(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent, int iLayer, bool ReleaseTriggerVoice, bool VoiceStealing, bool HandleKeyGroupConflicts) {
1198 int MIDIKey = itNoteOnEvent->Param.Note.Key;
1199 midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[MIDIKey];
1200 ::gig::Region* pRegion = pEngineChannel->pInstrument->GetRegion(MIDIKey);
1201
1202 // if nothing defined for this key
1203 if (!pRegion) return Pool<Voice>::Iterator(); // nothing to do
1204
1205 // only mark the first voice of a layered voice (group) to be in a
1206 // key group, so the layered voices won't kill each other
1207 int iKeyGroup = (iLayer == 0 && !ReleaseTriggerVoice) ? pRegion->KeyGroup : 0;
1208
1209 // handle key group (a.k.a. exclusive group) conflicts
1210 if (HandleKeyGroupConflicts) {
1211 if (iKeyGroup) { // if this voice / key belongs to a key group
1212 uint** ppKeyGroup = &pEngineChannel->ActiveKeyGroups[iKeyGroup];
1213 if (*ppKeyGroup) { // if there's already an active key in that key group
1214 midi_key_info_t* pOtherKey = &pEngineChannel->pMIDIKeyInfo[**ppKeyGroup];
1215 // kill all voices on the (other) key
1216 RTList<Voice>::Iterator itVoiceToBeKilled = pOtherKey->pActiveVoices->first();
1217 RTList<Voice>::Iterator end = pOtherKey->pActiveVoices->end();
1218 for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1219 if (itVoiceToBeKilled->Type != Voice::type_release_trigger) {
1220 itVoiceToBeKilled->Kill(itNoteOnEvent);
1221 --VoiceSpawnsLeft; //FIXME: just a hack, we should better check in StealVoice() if the voice was killed due to key conflict
1222 }
1223 }
1224 }
1225 }
1226 }
1227
1228 Voice::type_t VoiceType = Voice::type_normal;
1229
1230 // get current dimension values to select the right dimension region
1231 //TODO: for stolen voices this dimension region selection block is processed twice, this should be changed
1232 //FIXME: controller values for selecting the dimension region here are currently not sample accurate
1233 uint DimValues[8] = { 0 };
1234 for (int i = pRegion->Dimensions - 1; i >= 0; i--) {
1235 switch (pRegion->pDimensionDefinitions[i].dimension) {
1236 case ::gig::dimension_samplechannel:
1237 DimValues[i] = 0; //TODO: we currently ignore this dimension
1238 break;
1239 case ::gig::dimension_layer:
1240 DimValues[i] = iLayer;
1241 break;
1242 case ::gig::dimension_velocity:
1243 DimValues[i] = itNoteOnEvent->Param.Note.Velocity;
1244 break;
1245 case ::gig::dimension_channelaftertouch:
1246 DimValues[i] = pEngineChannel->ControllerTable[128];
1247 break;
1248 case ::gig::dimension_releasetrigger:
1249 VoiceType = (ReleaseTriggerVoice) ? Voice::type_release_trigger : (!iLayer) ? Voice::type_release_trigger_required : Voice::type_normal;
1250 DimValues[i] = (uint) ReleaseTriggerVoice;
1251 break;
1252 case ::gig::dimension_keyboard:
1253 DimValues[i] = (uint) (pEngineChannel->CurrentKeyDimension * pRegion->pDimensionDefinitions[i].zones);
1254 break;
1255 case ::gig::dimension_roundrobin:
1256 DimValues[i] = (uint) pEngineChannel->pMIDIKeyInfo[MIDIKey].RoundRobinIndex; // incremented for each note on
1257 break;
1258 case ::gig::dimension_random:
1259 RandomSeed = RandomSeed * 1103515245 + 12345; // classic pseudo random number generator
1260 DimValues[i] = (uint) RandomSeed >> (32 - pRegion->pDimensionDefinitions[i].bits); // highest bits are most random
1261 break;
1262 case ::gig::dimension_modwheel:
1263 DimValues[i] = pEngineChannel->ControllerTable[1];
1264 break;
1265 case ::gig::dimension_breath:
1266 DimValues[i] = pEngineChannel->ControllerTable[2];
1267 break;
1268 case ::gig::dimension_foot:
1269 DimValues[i] = pEngineChannel->ControllerTable[4];
1270 break;
1271 case ::gig::dimension_portamentotime:
1272 DimValues[i] = pEngineChannel->ControllerTable[5];
1273 break;
1274 case ::gig::dimension_effect1:
1275 DimValues[i] = pEngineChannel->ControllerTable[12];
1276 break;
1277 case ::gig::dimension_effect2:
1278 DimValues[i] = pEngineChannel->ControllerTable[13];
1279 break;
1280 case ::gig::dimension_genpurpose1:
1281 DimValues[i] = pEngineChannel->ControllerTable[16];
1282 break;
1283 case ::gig::dimension_genpurpose2:
1284 DimValues[i] = pEngineChannel->ControllerTable[17];
1285 break;
1286 case ::gig::dimension_genpurpose3:
1287 DimValues[i] = pEngineChannel->ControllerTable[18];
1288 break;
1289 case ::gig::dimension_genpurpose4:
1290 DimValues[i] = pEngineChannel->ControllerTable[19];
1291 break;
1292 case ::gig::dimension_sustainpedal:
1293 DimValues[i] = pEngineChannel->ControllerTable[64];
1294 break;
1295 case ::gig::dimension_portamento:
1296 DimValues[i] = pEngineChannel->ControllerTable[65];
1297 break;
1298 case ::gig::dimension_sostenutopedal:
1299 DimValues[i] = pEngineChannel->ControllerTable[66];
1300 break;
1301 case ::gig::dimension_softpedal:
1302 DimValues[i] = pEngineChannel->ControllerTable[67];
1303 break;
1304 case ::gig::dimension_genpurpose5:
1305 DimValues[i] = pEngineChannel->ControllerTable[80];
1306 break;
1307 case ::gig::dimension_genpurpose6:
1308 DimValues[i] = pEngineChannel->ControllerTable[81];
1309 break;
1310 case ::gig::dimension_genpurpose7:
1311 DimValues[i] = pEngineChannel->ControllerTable[82];
1312 break;
1313 case ::gig::dimension_genpurpose8:
1314 DimValues[i] = pEngineChannel->ControllerTable[83];
1315 break;
1316 case ::gig::dimension_effect1depth:
1317 DimValues[i] = pEngineChannel->ControllerTable[91];
1318 break;
1319 case ::gig::dimension_effect2depth:
1320 DimValues[i] = pEngineChannel->ControllerTable[92];
1321 break;
1322 case ::gig::dimension_effect3depth:
1323 DimValues[i] = pEngineChannel->ControllerTable[93];
1324 break;
1325 case ::gig::dimension_effect4depth:
1326 DimValues[i] = pEngineChannel->ControllerTable[94];
1327 break;
1328 case ::gig::dimension_effect5depth:
1329 DimValues[i] = pEngineChannel->ControllerTable[95];
1330 break;
1331 case ::gig::dimension_none:
1332 std::cerr << "gig::Engine::LaunchVoice() Error: dimension=none\n" << std::flush;
1333 break;
1334 default:
1335 std::cerr << "gig::Engine::LaunchVoice() Error: Unknown dimension\n" << std::flush;
1336 }
1337 }
1338
1339 // return if this is a release triggered voice and there is no
1340 // releasetrigger dimension (could happen if an instrument
1341 // change has occured between note on and off)
1342 if (ReleaseTriggerVoice && VoiceType != Voice::type_release_trigger) return Pool<Voice>::Iterator();
1343
1344 ::gig::DimensionRegion* pDimRgn = pRegion->GetDimensionRegionByValue(DimValues);
1345
1346 // no need to continue if sample is silent
1347 if (!pDimRgn->pSample || !pDimRgn->pSample->SamplesTotal) return Pool<Voice>::Iterator();
1348
1349 // allocate a new voice for the key
1350 Pool<Voice>::Iterator itNewVoice = pKey->pActiveVoices->allocAppend();
1351 if (itNewVoice) {
1352 // launch the new voice
1353 if (itNewVoice->Trigger(pEngineChannel, itNoteOnEvent, pEngineChannel->Pitch, pDimRgn, VoiceType, iKeyGroup) < 0) {
1354 dmsg(4,("Voice not triggered\n"));
1355 pKey->pActiveVoices->free(itNewVoice);
1356 }
1357 else { // on success
1358 --VoiceSpawnsLeft;
1359 if (!pKey->Active) { // mark as active key
1360 pKey->Active = true;
1361 pKey->itSelf = pEngineChannel->pActiveKeys->allocAppend();
1362 *pKey->itSelf = itNoteOnEvent->Param.Note.Key;
1363 }
1364 if (itNewVoice->KeyGroup) {
1365 uint** ppKeyGroup = &pEngineChannel->ActiveKeyGroups[itNewVoice->KeyGroup];
1366 *ppKeyGroup = &*pKey->itSelf; // put key as the (new) active key to its key group
1367 }
1368 if (itNewVoice->Type == Voice::type_release_trigger_required) pKey->ReleaseTrigger = true; // mark key for the need of release triggered voice(s)
1369 return itNewVoice; // success
1370 }
1371 }
1372 else if (VoiceStealing) {
1373 // try to steal one voice
1374 int result = StealVoice(pEngineChannel, itNoteOnEvent);
1375 if (!result) { // voice stolen successfully
1376 // put note-on event into voice-stealing queue, so it will be reprocessed after killed voice died
1377 RTList<Event>::Iterator itStealEvent = pVoiceStealingQueue->allocAppend();
1378 if (itStealEvent) {
1379 *itStealEvent = *itNoteOnEvent; // copy event
1380 itStealEvent->Param.Note.Layer = iLayer;
1381 itStealEvent->Param.Note.ReleaseTrigger = ReleaseTriggerVoice;
1382 pKey->VoiceTheftsQueued++;
1383 }
1384 else dmsg(1,("Voice stealing queue full!\n"));
1385 }
1386 }
1387
1388 return Pool<Voice>::Iterator(); // no free voice or error
1389 }
1390
1391 /**
1392 * Will be called by LaunchVoice() method in case there are no free
1393 * voices left. This method will select and kill one old voice for
1394 * voice stealing and postpone the note-on event until the selected
1395 * voice actually died.
1396 *
1397 * @param pEngineChannel - engine channel on which this event occured on
1398 * @param itNoteOnEvent - key, velocity and time stamp of the event
1399 * @returns 0 on success, a value < 0 if no active voice could be picked for voice stealing
1400 */
1401 int Engine::StealVoice(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {
1402 if (VoiceSpawnsLeft <= 0) {
1403 dmsg(1,("Max. voice thefts per audio fragment reached (you may raise CONFIG_MAX_VOICES).\n"));
1404 return -1;
1405 }
1406 if (!pEventPool->poolIsEmpty()) {
1407
1408 RTList<Voice>::Iterator itSelectedVoice;
1409
1410 // Select one voice for voice stealing
1411 switch (CONFIG_VOICE_STEAL_ALGO) {
1412
1413 // try to pick the oldest voice on the key where the new
1414 // voice should be spawned, if there is no voice on that
1415 // key, or no voice left to kill, then procceed with
1416 // 'oldestkey' algorithm
1417 case voice_steal_algo_oldestvoiceonkey: {
1418 midi_key_info_t* pSelectedKey = &pEngineChannel->pMIDIKeyInfo[itNoteOnEvent->Param.Note.Key];
1419 itSelectedVoice = pSelectedKey->pActiveVoices->first();
1420 // proceed iterating if voice was created in this fragment cycle
1421 while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice;
1422 // if we haven't found a voice then proceed with algorithm 'oldestkey'
1423 if (itSelectedVoice && itSelectedVoice->IsStealable()) break;
1424 } // no break - intentional !
1425
1426 // try to pick the oldest voice on the oldest active key
1427 // from the same engine channel
1428 // (caution: must stay after 'oldestvoiceonkey' algorithm !)
1429 case voice_steal_algo_oldestkey: {
1430 // if we already stole in this fragment, try to proceed on same key
1431 if (this->itLastStolenVoice) {
1432 itSelectedVoice = this->itLastStolenVoice;
1433 do {
1434 ++itSelectedVoice;
1435 } while (itSelectedVoice && !itSelectedVoice->IsStealable()); // proceed iterating if voice was created in this fragment cycle
1436 // found a "stealable" voice ?
1437 if (itSelectedVoice && itSelectedVoice->IsStealable()) {
1438 // remember which voice we stole, so we can simply proceed on next voice stealing
1439 this->itLastStolenVoice = itSelectedVoice;
1440 break; // selection succeeded
1441 }
1442 }
1443 // get (next) oldest key
1444 RTList<uint>::Iterator iuiSelectedKey = (this->iuiLastStolenKey) ? ++this->iuiLastStolenKey : pEngineChannel->pActiveKeys->first();
1445 while (iuiSelectedKey) {
1446 midi_key_info_t* pSelectedKey = &pEngineChannel->pMIDIKeyInfo[*iuiSelectedKey];
1447 itSelectedVoice = pSelectedKey->pActiveVoices->first();
1448 // proceed iterating if voice was created in this fragment cycle
1449 while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice;
1450 // found a "stealable" voice ?
1451 if (itSelectedVoice && itSelectedVoice->IsStealable()) {
1452 // remember which voice on which key we stole, so we can simply proceed on next voice stealing
1453 this->iuiLastStolenKey = iuiSelectedKey;
1454 this->itLastStolenVoice = itSelectedVoice;
1455 break; // selection succeeded
1456 }
1457 ++iuiSelectedKey; // get next oldest key
1458 }
1459 break;
1460 }
1461
1462 // don't steal anything
1463 case voice_steal_algo_none:
1464 default: {
1465 dmsg(1,("No free voice (voice stealing disabled)!\n"));
1466 return -1;
1467 }
1468 }
1469
1470 // if we couldn't steal a voice from the same engine channel then
1471 // steal oldest voice on the oldest key from any other engine channel
1472 // (the smaller engine channel number, the higher priority)
1473 if (!itSelectedVoice || !itSelectedVoice->IsStealable()) {
1474 EngineChannel* pSelectedChannel;
1475 int iChannelIndex;
1476 // select engine channel
1477 if (pLastStolenChannel) {
1478 pSelectedChannel = pLastStolenChannel;
1479 iChannelIndex = pSelectedChannel->iEngineIndexSelf;
1480 } else { // pick the engine channel followed by this engine channel
1481 iChannelIndex = (pEngineChannel->iEngineIndexSelf + 1) % engineChannels.size();
1482 pSelectedChannel = engineChannels[iChannelIndex];
1483 }
1484
1485 // if we already stole in this fragment, try to proceed on same key
1486 if (this->itLastStolenVoiceGlobally) {
1487 itSelectedVoice = this->itLastStolenVoiceGlobally;
1488 do {
1489 ++itSelectedVoice;
1490 } while (itSelectedVoice && !itSelectedVoice->IsStealable()); // proceed iterating if voice was created in this fragment cycle
1491 }
1492
1493 #if CONFIG_DEVMODE
1494 EngineChannel* pBegin = pSelectedChannel; // to detect endless loop
1495 #endif // CONFIG_DEVMODE
1496
1497 // did we find a 'stealable' voice?
1498 if (itSelectedVoice && itSelectedVoice->IsStealable()) {
1499 // remember which voice we stole, so we can simply proceed on next voice stealing
1500 this->itLastStolenVoiceGlobally = itSelectedVoice;
1501 } else while (true) { // iterate through engine channels
1502 // get (next) oldest key
1503 RTList<uint>::Iterator iuiSelectedKey = (this->iuiLastStolenKeyGlobally) ? ++this->iuiLastStolenKeyGlobally : pSelectedChannel->pActiveKeys->first();
1504 this->iuiLastStolenKeyGlobally = RTList<uint>::Iterator(); // to prevent endless loop (see line above)
1505 while (iuiSelectedKey) {
1506 midi_key_info_t* pSelectedKey = &pSelectedChannel->pMIDIKeyInfo[*iuiSelectedKey];
1507 itSelectedVoice = pSelectedKey->pActiveVoices->first();
1508 // proceed iterating if voice was created in this fragment cycle
1509 while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice;
1510 // found a "stealable" voice ?
1511 if (itSelectedVoice && itSelectedVoice->IsStealable()) {
1512 // remember which voice on which key on which engine channel we stole, so we can simply proceed on next voice stealing
1513 this->iuiLastStolenKeyGlobally = iuiSelectedKey;
1514 this->itLastStolenVoiceGlobally = itSelectedVoice;
1515 this->pLastStolenChannel = pSelectedChannel;
1516 goto stealable_voice_found; // selection succeeded
1517 }
1518 ++iuiSelectedKey; // get next key on current engine channel
1519 }
1520 // get next engine channel
1521 iChannelIndex = (iChannelIndex + 1) % engineChannels.size();
1522 pSelectedChannel = engineChannels[iChannelIndex];
1523
1524 #if CONFIG_DEVMODE
1525 if (pSelectedChannel == pBegin) {
1526 dmsg(1,("FATAL ERROR: voice stealing endless loop!\n"));
1527 dmsg(1,("VoiceSpawnsLeft=%d.\n", VoiceSpawnsLeft));
1528 dmsg(1,("Exiting.\n"));
1529 exit(-1);
1530 }
1531 #endif // CONFIG_DEVMODE
1532 }
1533 }
1534
1535 // jump point if a 'stealable' voice was found
1536 stealable_voice_found:
1537
1538 #if CONFIG_DEVMODE
1539 if (!itSelectedVoice->IsActive()) {
1540 dmsg(1,("gig::Engine: ERROR, tried to steal a voice which was not active !!!\n"));
1541 return -1;
1542 }
1543 #endif // CONFIG_DEVMODE
1544
1545 // now kill the selected voice
1546 itSelectedVoice->Kill(itNoteOnEvent);
1547
1548 --VoiceSpawnsLeft;
1549
1550 return 0; // success
1551 }
1552 else {
1553 dmsg(1,("Event pool emtpy!\n"));
1554 return -1;
1555 }
1556 }
1557
1558 /**
1559 * Removes the given voice from the MIDI key's list of active voices.
1560 * This method will be called when a voice went inactive, e.g. because
1561 * it finished to playback its sample, finished its release stage or
1562 * just was killed.
1563 *
1564 * @param pEngineChannel - engine channel on which this event occured on
1565 * @param itVoice - points to the voice to be freed
1566 */
1567 void Engine::FreeVoice(EngineChannel* pEngineChannel, Pool<Voice>::Iterator& itVoice) {
1568 if (itVoice) {
1569 midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[itVoice->MIDIKey];
1570
1571 uint keygroup = itVoice->KeyGroup;
1572
1573 // if the sample and dimension region belong to an
1574 // instrument that is unloaded, tell the disk thread to
1575 // release them
1576 if (itVoice->Orphan) {
1577 pDiskThread->OrderDeletionOfDimreg(itVoice->pDimRgn);
1578 }
1579
1580 // free the voice object
1581 pVoicePool->free(itVoice);
1582
1583 // if no other voices left and member of a key group, remove from key group
1584 if (pKey->pActiveVoices->isEmpty() && keygroup) {
1585 uint** ppKeyGroup = &pEngineChannel->ActiveKeyGroups[keygroup];
1586 if (*ppKeyGroup == &*pKey->itSelf) *ppKeyGroup = NULL; // remove key from key group
1587 }
1588 }
1589 else std::cerr << "Couldn't release voice! (!itVoice)\n" << std::flush;
1590 }
1591
1592 /**
1593 * Called when there's no more voice left on a key, this call will
1594 * update the key info respectively.
1595 *
1596 * @param pEngineChannel - engine channel on which this event occured on
1597 * @param pKey - key which is now inactive
1598 */
1599 void Engine::FreeKey(EngineChannel* pEngineChannel, midi_key_info_t* pKey) {
1600 if (pKey->pActiveVoices->isEmpty()) {
1601 pKey->Active = false;
1602 pEngineChannel->pActiveKeys->free(pKey->itSelf); // remove key from list of active keys
1603 pKey->itSelf = RTList<uint>::Iterator();
1604 pKey->ReleaseTrigger = false;
1605 pKey->pEvents->clear();
1606 dmsg(3,("Key has no more voices now\n"));
1607 }
1608 else dmsg(1,("gig::Engine: Oops, tried to free a key which contains voices.\n"));
1609 }
1610
1611 /**
1612 * Reacts on supported control change commands (e.g. pitch bend wheel,
1613 * modulation wheel, aftertouch).
1614 *
1615 * @param pEngineChannel - engine channel on which this event occured on
1616 * @param itControlChangeEvent - controller, value and time stamp of the event
1617 */
1618 void Engine::ProcessControlChange(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itControlChangeEvent) {
1619 dmsg(4,("Engine::ContinuousController cc=%d v=%d\n", itControlChangeEvent->Param.CC.Controller, itControlChangeEvent->Param.CC.Value));
1620
1621 // handle the "control triggered" MIDI rule: a control change
1622 // event can trigger a new note on or note off event
1623 if (pEngineChannel->pInstrument) {
1624
1625 ::gig::MidiRule* rule;
1626 for (int i = 0 ; (rule = pEngineChannel->pInstrument->GetMidiRule(i)) ; i++) {
1627
1628 if (::gig::MidiRuleCtrlTrigger* ctrlTrigger =
1629 dynamic_cast< ::gig::MidiRuleCtrlTrigger*>(rule)) {
1630 if (itControlChangeEvent->Param.CC.Controller ==
1631 ctrlTrigger->ControllerNumber) {
1632
1633 uint8_t oldCCValue = pEngineChannel->ControllerTable[
1634 itControlChangeEvent->Param.CC.Controller];
1635 uint8_t newCCValue = itControlChangeEvent->Param.CC.Value;
1636
1637 for (int i = 0 ; i < ctrlTrigger->Triggers ; i++) {
1638 ::gig::MidiRuleCtrlTrigger::trigger_t* pTrigger =
1639 &ctrlTrigger->pTriggers[i];
1640
1641 // check if the controller has passed the
1642 // trigger point in the right direction
1643 if ((pTrigger->Descending &&
1644 oldCCValue > pTrigger->TriggerPoint &&
1645 newCCValue <= pTrigger->TriggerPoint) ||
1646 (!pTrigger->Descending &&
1647 oldCCValue < pTrigger->TriggerPoint &&
1648 newCCValue >= pTrigger->TriggerPoint)) {
1649
1650 RTList<Event>::Iterator itNewEvent = pGlobalEvents->allocAppend();
1651 if (itNewEvent) {
1652 *itNewEvent = *itControlChangeEvent;
1653 itNewEvent->Param.Note.Key = pTrigger->Key;
1654
1655 if (pTrigger->NoteOff || pTrigger->Velocity == 0) {
1656 itNewEvent->Type = Event::type_note_off;
1657 itNewEvent->Param.Note.Velocity = 100;
1658
1659 ProcessNoteOff(pEngineChannel, itNewEvent);
1660 } else {
1661 itNewEvent->Type = Event::type_note_on;
1662 //TODO: if Velocity is 255, the triggered velocity should
1663 // depend on how fast the controller is moving
1664 itNewEvent->Param.Note.Velocity =
1665 pTrigger->Velocity == 255 ? 100 :
1666 pTrigger->Velocity;
1667
1668 ProcessNoteOn(pEngineChannel, itNewEvent);
1669 }
1670 }
1671 else dmsg(1,("Event pool emtpy!\n"));
1672 }
1673 }
1674 }
1675 }
1676 }
1677 }
1678
1679 // update controller value in the engine channel's controller table
1680 pEngineChannel->ControllerTable[itControlChangeEvent->Param.CC.Controller] = itControlChangeEvent->Param.CC.Value;
1681
1682 // handle hard coded MIDI controllers
1683 switch (itControlChangeEvent->Param.CC.Controller) {
1684 case 5: { // portamento time
1685 pEngineChannel->PortamentoTime = (float) itControlChangeEvent->Param.CC.Value / 127.0f * (float) CONFIG_PORTAMENTO_TIME_MAX + (float) CONFIG_PORTAMENTO_TIME_MIN;
1686 break;
1687 }
1688 case 6: { // data entry (currently only used for RPN controllers)
1689 if (pEngineChannel->GetMidiRpnController() == 2) { // coarse tuning in half tones
1690 int transpose = (int) itControlChangeEvent->Param.CC.Value - 64;
1691 // limit to +- two octaves for now
1692 transpose = RTMath::Min(transpose, 24);
1693 transpose = RTMath::Max(transpose, -24);
1694 pEngineChannel->GlobalTranspose = transpose;
1695 // workaround, so we won't have hanging notes
1696 ReleaseAllVoices(pEngineChannel, itControlChangeEvent);
1697 }
1698 // to avoid other MIDI CC #6 messages to be misenterpreted as RPN controller data
1699 pEngineChannel->ResetMidiRpnController();
1700 break;
1701 }
1702 case 7: { // volume
1703 //TODO: not sample accurate yet
1704 pEngineChannel->MidiVolume = VolumeCurve[itControlChangeEvent->Param.CC.Value];
1705 pEngineChannel->bStatusChanged = true; // engine channel status has changed, so set notify flag
1706 break;
1707 }
1708 case 10: { // panpot
1709 //TODO: not sample accurate yet
1710 pEngineChannel->GlobalPanLeft = PanCurve[128 - itControlChangeEvent->Param.CC.Value];
1711 pEngineChannel->GlobalPanRight = PanCurve[itControlChangeEvent->Param.CC.Value];
1712 break;
1713 }
1714 case 64: { // sustain
1715 if (itControlChangeEvent->Param.CC.Value >= 64 && !pEngineChannel->SustainPedal) {
1716 dmsg(4,("DAMPER (RIGHT) PEDAL DOWN\n"));
1717 pEngineChannel->SustainPedal = true;
1718
1719 #if !CONFIG_PROCESS_MUTED_CHANNELS
1720 if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
1721 #endif
1722
1723 // cancel release process of voices if necessary
1724 RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
1725 for (; iuiKey; ++iuiKey) {
1726 midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];
1727 if (!pKey->KeyPressed) {
1728 RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend();
1729 if (itNewEvent) {
1730 *itNewEvent = *itControlChangeEvent; // copy event to the key's own event list
1731 itNewEvent->Type = Event::type_cancel_release; // transform event type
1732 }
1733 else dmsg(1,("Event pool emtpy!\n"));
1734 }
1735 }
1736 }
1737 if (itControlChangeEvent->Param.CC.Value < 64 && pEngineChannel->SustainPedal) {
1738 dmsg(4,("DAMPER (RIGHT) PEDAL UP\n"));
1739 pEngineChannel->SustainPedal = false;
1740
1741 #if !CONFIG_PROCESS_MUTED_CHANNELS
1742 if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
1743 #endif
1744
1745 // release voices if their respective key is not pressed
1746 RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
1747 for (; iuiKey; ++iuiKey) {
1748 midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];
1749 if (!pKey->KeyPressed && ShouldReleaseVoice(pEngineChannel, *iuiKey)) {
1750 RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend();
1751 if (itNewEvent) {
1752 *itNewEvent = *itControlChangeEvent; // copy event to the key's own event list
1753 itNewEvent->Type = Event::type_release; // transform event type
1754 }
1755 else dmsg(1,("Event pool emtpy!\n"));
1756 }
1757 }
1758 }
1759 break;
1760 }
1761 case 65: { // portamento on / off
1762 const bool bPortamento = itControlChangeEvent->Param.CC.Value >= 64;
1763 if (bPortamento != pEngineChannel->PortamentoMode)
1764 KillAllVoices(pEngineChannel, itControlChangeEvent);
1765 pEngineChannel->PortamentoMode = bPortamento;
1766 break;
1767 }
1768 case 66: { // sostenuto
1769 if (itControlChangeEvent->Param.CC.Value >= 64 && !pEngineChannel->SostenutoPedal) {
1770 dmsg(4,("SOSTENUTO (CENTER) PEDAL DOWN\n"));
1771 pEngineChannel->SostenutoPedal = true;
1772
1773 #if !CONFIG_PROCESS_MUTED_CHANNELS
1774 if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
1775 #endif
1776
1777 SostenutoKeyCount = 0;
1778 // Remeber the pressed keys
1779 RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
1780 for (; iuiKey; ++iuiKey) {
1781 midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];
1782 if (pKey->KeyPressed && SostenutoKeyCount < 128) SostenutoKeys[SostenutoKeyCount++] = *iuiKey;
1783 }
1784 }
1785 if (itControlChangeEvent->Param.CC.Value < 64 && pEngineChannel->SostenutoPedal) {
1786 dmsg(4,("SOSTENUTO (CENTER) PEDAL UP\n"));
1787 pEngineChannel->SostenutoPedal = false;
1788
1789 #if !CONFIG_PROCESS_MUTED_CHANNELS
1790 if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
1791 #endif
1792
1793 // release voices if the damper pedal is up and their respective key is not pressed
1794 for (int i = 0; i < SostenutoKeyCount; i++) {
1795 midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[SostenutoKeys[i]];
1796 if (!pKey->KeyPressed && !pEngineChannel->SustainPedal) {
1797 RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend();
1798 if (itNewEvent) {
1799 *itNewEvent = *itControlChangeEvent; // copy event to the key's own event list
1800 itNewEvent->Type = Event::type_release; // transform event type
1801 }
1802 else dmsg(1,("Event pool emtpy!\n"));
1803 }
1804 }
1805 }
1806 break;
1807 }
1808 case 100: { // RPN controller LSB
1809 pEngineChannel->SetMidiRpnControllerLsb(itControlChangeEvent->Param.CC.Value);
1810 break;
1811 }
1812 case 101: { // RPN controller MSB
1813 pEngineChannel->SetMidiRpnControllerMsb(itControlChangeEvent->Param.CC.Value);
1814 break;
1815 }
1816
1817
1818 // Channel Mode Messages
1819
1820 case 120: { // all sound off
1821 KillAllVoices(pEngineChannel, itControlChangeEvent);
1822 break;
1823 }
1824 case 121: { // reset all controllers
1825 pEngineChannel->ResetControllers();
1826 break;
1827 }
1828 case 123: { // all notes off
1829 #if CONFIG_PROCESS_ALL_NOTES_OFF
1830 ReleaseAllVoices(pEngineChannel, itControlChangeEvent);
1831 #endif // CONFIG_PROCESS_ALL_NOTES_OFF
1832 break;
1833 }
1834 case 126: { // mono mode on
1835 if (!pEngineChannel->SoloMode)
1836 KillAllVoices(pEngineChannel, itControlChangeEvent);
1837 pEngineChannel->SoloMode = true;
1838 break;
1839 }
1840 case 127: { // poly mode on
1841 if (pEngineChannel->SoloMode)
1842 KillAllVoices(pEngineChannel, itControlChangeEvent);
1843 pEngineChannel->SoloMode = false;
1844 break;
1845 }
1846 }
1847
1848 // handle FX send controllers
1849 if (!pEngineChannel->fxSends.empty()) {
1850 for (int iFxSend = 0; iFxSend < pEngineChannel->GetFxSendCount(); iFxSend++) {
1851 FxSend* pFxSend = pEngineChannel->GetFxSend(iFxSend);
1852 if (pFxSend->MidiController() == itControlChangeEvent->Param.CC.Controller)
1853 pFxSend->SetLevel(itControlChangeEvent->Param.CC.Value);
1854 pFxSend->SetInfoChanged(true);
1855 }
1856 }
1857 }
1858
1859 /**
1860 * Reacts on MIDI system exclusive messages.
1861 *
1862 * @param itSysexEvent - sysex data size and time stamp of the sysex event
1863 */
1864 void Engine::ProcessSysex(Pool<Event>::Iterator& itSysexEvent) {
1865 RingBuffer<uint8_t,false>::NonVolatileReader reader = pSysexBuffer->get_non_volatile_reader();
1866
1867 uint8_t exclusive_status, id;
1868 if (!reader.pop(&exclusive_status)) goto free_sysex_data;
1869 if (!reader.pop(&id)) goto free_sysex_data;
1870 if (exclusive_status != 0xF0) goto free_sysex_data;
1871
1872 switch (id) {
1873 case 0x41: { // Roland
1874 dmsg(3,("Roland Sysex\n"));
1875 uint8_t device_id, model_id, cmd_id;
1876 if (!reader.pop(&device_id)) goto free_sysex_data;
1877 if (!reader.pop(&model_id)) goto free_sysex_data;
1878 if (!reader.pop(&cmd_id)) goto free_sysex_data;
1879 if (model_id != 0x42 /*GS*/) goto free_sysex_data;
1880 if (cmd_id != 0x12 /*DT1*/) goto free_sysex_data;
1881
1882 // command address
1883 uint8_t addr[3]; // 2 byte addr MSB, followed by 1 byte addr LSB)
1884 const RingBuffer<uint8_t,false>::NonVolatileReader checksum_reader = reader; // so we can calculate the check sum later
1885 if (reader.read(&addr[0], 3) != 3) goto free_sysex_data;
1886 if (addr[0] == 0x40 && addr[1] == 0x00) { // System Parameters
1887 dmsg(3,("\tSystem Parameter\n"));
1888 }
1889 else if (addr[0] == 0x40 && addr[1] == 0x01) { // Common Parameters
1890 dmsg(3,("\tCommon Parameter\n"));
1891 }
1892 else if (addr[0] == 0x40 && (addr[1] & 0xf0) == 0x10) { // Part Parameters (1)
1893 dmsg(3,("\tPart Parameter\n"));
1894 switch (addr[2]) {
1895 case 0x40: { // scale tuning
1896 dmsg(3,("\t\tScale Tuning\n"));
1897 uint8_t scale_tunes[12]; // detuning of all 12 semitones of an octave
1898 if (reader.read(&scale_tunes[0], 12) != 12) goto free_sysex_data;
1899 uint8_t checksum;
1900 if (!reader.pop(&checksum)) goto free_sysex_data;
1901 #if CONFIG_ASSERT_GS_SYSEX_CHECKSUM
1902 if (GSCheckSum(checksum_reader, 12)) goto free_sysex_data;
1903 #endif // CONFIG_ASSERT_GS_SYSEX_CHECKSUM
1904 for (int i = 0; i < 12; i++) scale_tunes[i] -= 64;
1905 AdjustScale((int8_t*) scale_tunes);
1906 dmsg(3,("\t\t\tNew scale applied.\n"));
1907 break;
1908 }
1909 }
1910 }
1911 else if (addr[0] == 0x40 && (addr[1] & 0xf0) == 0x20) { // Part Parameters (2)
1912 }
1913 else if (addr[0] == 0x41) { // Drum Setup Parameters
1914 }
1915 break;
1916 }
1917 }
1918
1919 free_sysex_data: // finally free sysex data
1920 pSysexBuffer->increment_read_ptr(itSysexEvent->Param.Sysex.Size);
1921 }
1922
1923 /**
1924 * Calculates the Roland GS sysex check sum.
1925 *
1926 * @param AddrReader - reader which currently points to the first GS
1927 * command address byte of the GS sysex message in
1928 * question
1929 * @param DataSize - size of the GS message data (in bytes)
1930 */
1931 uint8_t Engine::GSCheckSum(const RingBuffer<uint8_t,false>::NonVolatileReader AddrReader, uint DataSize) {
1932 RingBuffer<uint8_t,false>::NonVolatileReader reader = AddrReader;
1933 uint bytes = 3 /*addr*/ + DataSize;
1934 uint8_t addr_and_data[bytes];
1935 reader.read(&addr_and_data[0], bytes);
1936 uint8_t sum = 0;
1937 for (uint i = 0; i < bytes; i++) sum += addr_and_data[i];
1938 return 128 - sum % 128;
1939 }
1940
1941 /**
1942 * Allows to tune each of the twelve semitones of an octave.
1943 *
1944 * @param ScaleTunes - detuning of all twelve semitones (in cents)
1945 */
1946 void Engine::AdjustScale(int8_t ScaleTunes[12]) {
1947 memcpy(&this->ScaleTuning[0], &ScaleTunes[0], 12); //TODO: currently not sample accurate
1948 }
1949
1950 /**
1951 * Releases all voices on an engine channel. All voices will go into
1952 * the release stage and thus it might take some time (e.g. dependant to
1953 * their envelope release time) until they actually die.
1954 *
1955 * @param pEngineChannel - engine channel on which all voices should be released
1956 * @param itReleaseEvent - event which caused this releasing of all voices
1957 */
1958 void Engine::ReleaseAllVoices(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itReleaseEvent) {
1959 RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
1960 while (iuiKey) {
1961 midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];
1962 ++iuiKey;
1963 // append a 'release' event to the key's own event list
1964 RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend();
1965 if (itNewEvent) {
1966 *itNewEvent = *itReleaseEvent; // copy original event (to the key's event list)
1967 itNewEvent->Type = Event::type_release; // transform event type
1968 }
1969 else dmsg(1,("Event pool emtpy!\n"));
1970 }
1971 }
1972
1973 /**
1974 * Kills all voices on an engine channel as soon as possible. Voices
1975 * won't get into release state, their volume level will be ramped down
1976 * as fast as possible.
1977 *
1978 * @param pEngineChannel - engine channel on which all voices should be killed
1979 * @param itKillEvent - event which caused this killing of all voices
1980 */
1981 void Engine::KillAllVoices(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itKillEvent) {
1982 RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
1983 RTList<uint>::Iterator end = pEngineChannel->pActiveKeys->end();
1984 while (iuiKey != end) { // iterate through all active keys
1985 midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];
1986 ++iuiKey;
1987 RTList<Voice>::Iterator itVoice = pKey->pActiveVoices->first();
1988 RTList<Voice>::Iterator itVoicesEnd = pKey->pActiveVoices->end();
1989 for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
1990 itVoice->Kill(itKillEvent);
1991 --VoiceSpawnsLeft; //FIXME: just a temporary workaround, we should check the cause in StealVoice() instead
1992 }
1993 }
1994 }
1995
1996 /**
1997 * Determines whether the specified voice should be released.
1998 *
1999 * @param pEngineChannel - The engine channel on which the voice should be checked
2000 * @param Key - The key number
2001 * @returns true if the specified should be released, false otherwise.
2002 */
2003 bool Engine::ShouldReleaseVoice(EngineChannel* pEngineChannel, int Key) {
2004 if (pEngineChannel->SustainPedal) return false;
2005
2006 if (pEngineChannel->SostenutoPedal) {
2007 for (int i = 0; i < SostenutoKeyCount; i++)
2008 if (Key == SostenutoKeys[i]) return false;
2009 }
2010
2011 return true;
2012 }
2013
2014 uint Engine::VoiceCount() {
2015 return ActiveVoiceCount;
2016 }
2017
2018 uint Engine::VoiceCountMax() {
2019 return ActiveVoiceCountMax;
2020 }
2021
2022 bool Engine::DiskStreamSupported() {
2023 return true;
2024 }
2025
2026 uint Engine::DiskStreamCount() {
2027 return (pDiskThread) ? pDiskThread->ActiveStreamCount : 0;
2028 }
2029
2030 uint Engine::DiskStreamCountMax() {
2031 return (pDiskThread) ? pDiskThread->ActiveStreamCountMax : 0;
2032 }
2033
2034 String Engine::DiskStreamBufferFillBytes() {
2035 return pDiskThread->GetBufferFillBytes();
2036 }
2037
2038 String Engine::DiskStreamBufferFillPercentage() {
2039 return pDiskThread->GetBufferFillPercentage();
2040 }
2041
2042 String Engine::EngineName() {
2043 return LS_GIG_ENGINE_NAME;
2044 }
2045
2046 String Engine::Description() {
2047 return "Gigasampler Format Engine";
2048 }
2049
2050 String Engine::Version() {
2051 String s = "$Revision: 1.88 $";
2052 return s.substr(11, s.size() - 13); // cut dollar signs, spaces and CVS macro keyword
2053 }
2054
2055 InstrumentManager* Engine::GetInstrumentManager() {
2056 return &instruments;
2057 }
2058
2059 // static constant initializers
2060 const Engine::FloatTable Engine::VolumeCurve(InitVolumeCurve());
2061 const Engine::FloatTable Engine::PanCurve(InitPanCurve());
2062 const Engine::FloatTable Engine::CrossfadeCurve(InitCrossfadeCurve());
2063
2064 float* Engine::InitVolumeCurve() {
2065 // line-segment approximation
2066 const float segments[] = {
2067 0, 0, 2, 0.0046, 16, 0.016, 31, 0.051, 45, 0.115, 54.5, 0.2,
2068 64.5, 0.39, 74, 0.74, 92, 1.03, 114, 1.94, 119.2, 2.2, 127, 2.2
2069 };
2070 return InitCurve(segments);
2071 }
2072
2073 float* Engine::InitPanCurve() {
2074 // line-segment approximation
2075 const float segments[] = {
2076 0, 0, 1, 0,
2077 2, 0.05, 31.5, 0.7, 51, 0.851, 74.5, 1.12,
2078 127, 1.41, 128, 1.41
2079 };
2080 return InitCurve(segments, 129);
2081 }
2082
2083 float* Engine::InitCrossfadeCurve() {
2084 // line-segment approximation
2085 const float segments[] = {
2086 0, 0, 1, 0.03, 10, 0.1, 51, 0.58, 127, 1
2087 };
2088 return InitCurve(segments);
2089 }
2090
2091 float* Engine::InitCurve(const float* segments, int size) {
2092 float* y = new float[size];
2093 for (int x = 0 ; x < size ; x++) {
2094 if (x > segments[2]) segments += 2;
2095 y[x] = segments[1] + (x - segments[0]) *
2096 (segments[3] - segments[1]) / (segments[2] - segments[0]);
2097 }
2098 return y;
2099 }
2100
2101 }} // namespace LinuxSampler::gig

  ViewVC Help
Powered by ViewVC