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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 738 - (hide annotations) (download)
Tue Aug 16 17:14:25 2005 UTC (18 years, 8 months ago) by schoenebeck
File size: 67028 byte(s)
* extensive synthesis optimization: reimplementation of EGs and LFO(s),
  removed synthesis parameter prerendering and the synthesis parameter
  matrix in general, splitting each audio fragment into subfragments now
  where each subfragment uses constant synthesis parameters
  (everything's still very buggy ATM)

1 schoenebeck 53 /***************************************************************************
2     * *
3     * LinuxSampler - modular, streaming capable sampler *
4     * *
5 schoenebeck 56 * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6 schoenebeck 411 * Copyright (C) 2005 Christian Schoenebeck *
7 schoenebeck 53 * *
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 schoenebeck 285 #include "EGADSR.h"
28 schoenebeck 420 #include "../EngineFactory.h"
29 schoenebeck 53
30     #include "Engine.h"
31    
32     namespace LinuxSampler { namespace gig {
33    
34 schoenebeck 411 InstrumentResourceManager Engine::instruments;
35 schoenebeck 53
36 schoenebeck 411 std::map<AudioOutputDevice*,Engine*> Engine::engines;
37    
38 schoenebeck 412 /**
39     * Get a gig::Engine object for the given gig::EngineChannel and the
40     * given AudioOutputDevice. All engine channels which are connected to
41     * the same audio output device will use the same engine instance. This
42     * method will be called by a gig::EngineChannel whenever it's
43     * connecting to a audio output device.
44     *
45     * @param pChannel - engine channel which acquires an engine object
46     * @param pDevice - the audio output device \a pChannel is connected to
47     */
48 schoenebeck 411 Engine* Engine::AcquireEngine(LinuxSampler::gig::EngineChannel* pChannel, AudioOutputDevice* pDevice) {
49 schoenebeck 412 Engine* pEngine = NULL;
50     // check if there's already an engine for the given audio output device
51 schoenebeck 411 if (engines.count(pDevice)) {
52 schoenebeck 412 dmsg(4,("Using existing gig::Engine.\n"));
53 persson 438 pEngine = engines[pDevice];
54 schoenebeck 412 } else { // create a new engine (and disk thread) instance for the given audio output device
55     dmsg(4,("Creating new gig::Engine.\n"));
56 schoenebeck 420 pEngine = (Engine*) EngineFactory::Create("gig");
57 schoenebeck 411 pEngine->Connect(pDevice);
58 persson 438 engines[pDevice] = pEngine;
59 schoenebeck 411 }
60 schoenebeck 412 // register engine channel to the engine instance
61 schoenebeck 460 pEngine->engineChannels.add(pChannel);
62     // remember index in the ArrayList
63     pChannel->iEngineIndexSelf = pEngine->engineChannels.size() - 1;
64 schoenebeck 412 dmsg(4,("This gig::Engine has now %d EngineChannels.\n",pEngine->engineChannels.size()));
65 schoenebeck 411 return pEngine;
66     }
67    
68 schoenebeck 412 /**
69     * Once an engine channel is disconnected from an audio output device,
70     * it wil immediately call this method to unregister itself from the
71     * engine instance and if that engine instance is not used by any other
72     * engine channel anymore, then that engine instance will be destroyed.
73     *
74     * @param pChannel - engine channel which wants to disconnect from it's
75     * engine instance
76     * @param pDevice - audio output device \a pChannel was connected to
77     */
78 schoenebeck 411 void Engine::FreeEngine(LinuxSampler::gig::EngineChannel* pChannel, AudioOutputDevice* pDevice) {
79 schoenebeck 412 dmsg(4,("Disconnecting EngineChannel from gig::Engine.\n"));
80 schoenebeck 411 Engine* pEngine = engines[pDevice];
81 schoenebeck 412 // unregister EngineChannel from the Engine instance
82     pEngine->engineChannels.remove(pChannel);
83     // if the used Engine instance is not used anymore, then destroy it
84     if (pEngine->engineChannels.empty()) {
85     pDevice->Disconnect(pEngine);
86     engines.erase(pDevice);
87     delete pEngine;
88     dmsg(4,("Destroying gig::Engine.\n"));
89     }
90     else dmsg(4,("This gig::Engine has now %d EngineChannels.\n",pEngine->engineChannels.size()));
91 schoenebeck 411 }
92    
93 schoenebeck 473 /**
94     * Constructor
95     */
96 schoenebeck 53 Engine::Engine() {
97     pAudioOutputDevice = NULL;
98     pDiskThread = NULL;
99     pEventGenerator = NULL;
100 schoenebeck 554 pSysexBuffer = new RingBuffer<uint8_t>(CONFIG_SYSEX_BUFFER_SIZE, 0);
101     pEventQueue = new RingBuffer<Event>(CONFIG_MAX_EVENTS_PER_FRAGMENT, 0);
102     pEventPool = new Pool<Event>(CONFIG_MAX_EVENTS_PER_FRAGMENT);
103     pVoicePool = new Pool<Voice>(CONFIG_MAX_VOICES);
104 schoenebeck 271 pVoiceStealingQueue = new RTList<Event>(pEventPool);
105 schoenebeck 460 pGlobalEvents = new RTList<Event>(pEventPool);
106 schoenebeck 271 for (RTList<Voice>::Iterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
107     iterVoice->SetEngine(this);
108 schoenebeck 53 }
109     pVoicePool->clear();
110    
111     ResetInternal();
112 schoenebeck 659 ResetScaleTuning();
113 schoenebeck 53 }
114    
115 schoenebeck 473 /**
116     * Destructor
117     */
118 schoenebeck 53 Engine::~Engine() {
119     if (pDiskThread) {
120 senkov 329 dmsg(1,("Stopping disk thread..."));
121 schoenebeck 53 pDiskThread->StopThread();
122     delete pDiskThread;
123 senkov 329 dmsg(1,("OK\n"));
124 schoenebeck 53 }
125     if (pEventQueue) delete pEventQueue;
126     if (pEventPool) delete pEventPool;
127 schoenebeck 411 if (pVoicePool) {
128     pVoicePool->clear();
129     delete pVoicePool;
130     }
131 schoenebeck 53 if (pEventGenerator) delete pEventGenerator;
132 schoenebeck 250 if (pVoiceStealingQueue) delete pVoiceStealingQueue;
133 schoenebeck 411 if (pSysexBuffer) delete pSysexBuffer;
134 schoenebeck 420 EngineFactory::Destroy(this);
135 schoenebeck 53 }
136    
137     void Engine::Enable() {
138     dmsg(3,("gig::Engine: enabling\n"));
139     EngineDisabled.PushAndUnlock(false, 2); // set condition object 'EngineDisabled' to false (wait max. 2s)
140 schoenebeck 64 dmsg(3,("gig::Engine: enabled (val=%d)\n", EngineDisabled.GetUnsafe()));
141 schoenebeck 53 }
142    
143     void Engine::Disable() {
144     dmsg(3,("gig::Engine: disabling\n"));
145     bool* pWasDisabled = EngineDisabled.PushAndUnlock(true, 2); // wait max. 2s
146     if (!pWasDisabled) dmsg(3,("gig::Engine warning: Timeout waiting to disable engine.\n"));
147     }
148    
149     void Engine::DisableAndLock() {
150     dmsg(3,("gig::Engine: disabling\n"));
151     bool* pWasDisabled = EngineDisabled.Push(true, 2); // wait max. 2s
152     if (!pWasDisabled) dmsg(3,("gig::Engine warning: Timeout waiting to disable engine.\n"));
153     }
154    
155     /**
156     * Reset all voices and disk thread and clear input event queue and all
157     * control and status variables.
158     */
159     void Engine::Reset() {
160     DisableAndLock();
161     ResetInternal();
162 schoenebeck 659 ResetScaleTuning();
163 schoenebeck 53 Enable();
164     }
165    
166     /**
167     * Reset all voices and disk thread and clear input event queue and all
168     * control and status variables. This method is not thread safe!
169     */
170     void Engine::ResetInternal() {
171     ActiveVoiceCount = 0;
172     ActiveVoiceCountMax = 0;
173    
174 schoenebeck 250 // reset voice stealing parameters
175     pVoiceStealingQueue->clear();
176 schoenebeck 649 itLastStolenVoice = RTList<Voice>::Iterator();
177     itLastStolenVoiceGlobally = RTList<Voice>::Iterator();
178     iuiLastStolenKey = RTList<uint>::Iterator();
179     iuiLastStolenKeyGlobally = RTList<uint>::Iterator();
180     pLastStolenChannel = NULL;
181 schoenebeck 250
182 schoenebeck 53 // reset all voices
183 schoenebeck 271 for (RTList<Voice>::Iterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
184     iterVoice->Reset();
185 schoenebeck 53 }
186     pVoicePool->clear();
187    
188     // reset disk thread
189     if (pDiskThread) pDiskThread->Reset();
190    
191     // delete all input events
192     pEventQueue->init();
193 persson 438 }
194 schoenebeck 53
195 schoenebeck 473 /**
196 schoenebeck 659 * Reset to normal, chromatic scale (means equal tempered).
197     */
198     void Engine::ResetScaleTuning() {
199     memset(&ScaleTuning[0], 0x00, 12);
200     }
201    
202     /**
203 schoenebeck 473 * Connect this engine instance with the given audio output device.
204     * This method will be called when an Engine instance is created.
205     * All of the engine's data structures which are dependant to the used
206     * audio output device / driver will be (re)allocated and / or
207     * adjusted appropriately.
208     *
209     * @param pAudioOut - audio output device to connect to
210     */
211 schoenebeck 53 void Engine::Connect(AudioOutputDevice* pAudioOut) {
212     pAudioOutputDevice = pAudioOut;
213    
214     ResetInternal();
215    
216     // inform audio driver for the need of two channels
217     try {
218     pAudioOutputDevice->AcquireChannels(2); // gig engine only stereo
219     }
220     catch (AudioOutputException e) {
221     String msg = "Audio output device unable to provide 2 audio channels, cause: " + e.Message();
222     throw LinuxSamplerException(msg);
223     }
224 persson 438
225 schoenebeck 460 this->MaxSamplesPerCycle = pAudioOutputDevice->MaxSamplesPerCycle();
226     this->SampleRate = pAudioOutputDevice->SampleRate();
227 schoenebeck 225
228 schoenebeck 285 // FIXME: audio drivers with varying fragment sizes might be a problem here
229 schoenebeck 554 MaxFadeOutPos = MaxSamplesPerCycle - int(double(SampleRate) * CONFIG_EG_MIN_RELEASE_TIME) - 1;
230 schoenebeck 688 if (MaxFadeOutPos < 0) {
231     std::cerr << "gig::Engine: WARNING, CONFIG_EG_MIN_RELEASE_TIME "
232     << "too big for current audio fragment size & sampling rate! "
233 schoenebeck 690 << "May lead to click sounds if voice stealing chimes in!\n" << std::flush;
234 schoenebeck 688 // force volume ramp downs at the beginning of each fragment
235     MaxFadeOutPos = 0;
236     // lower minimum release time
237     const float minReleaseTime = (float) MaxSamplesPerCycle / (float) SampleRate;
238     for (RTList<Voice>::Iterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
239 schoenebeck 738 iterVoice->EG1.CalculateFadeOutCoeff(minReleaseTime, SampleRate);
240 schoenebeck 688 }
241     pVoicePool->clear();
242     }
243 schoenebeck 285
244 schoenebeck 53 // (re)create disk thread
245     if (this->pDiskThread) {
246 senkov 329 dmsg(1,("Stopping disk thread..."));
247 schoenebeck 53 this->pDiskThread->StopThread();
248     delete this->pDiskThread;
249 senkov 329 dmsg(1,("OK\n"));
250 schoenebeck 53 }
251 schoenebeck 554 this->pDiskThread = new DiskThread(((pAudioOut->MaxSamplesPerCycle() << CONFIG_MAX_PITCH) << 1) + 6); //FIXME: assuming stereo
252 schoenebeck 53 if (!pDiskThread) {
253     dmsg(0,("gig::Engine new diskthread = NULL\n"));
254     exit(EXIT_FAILURE);
255     }
256    
257 schoenebeck 271 for (RTList<Voice>::Iterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
258     iterVoice->pDiskThread = this->pDiskThread;
259 schoenebeck 53 dmsg(3,("d"));
260     }
261     pVoicePool->clear();
262    
263     // (re)create event generator
264     if (pEventGenerator) delete pEventGenerator;
265     pEventGenerator = new EventGenerator(pAudioOut->SampleRate());
266    
267     dmsg(1,("Starting disk thread..."));
268     pDiskThread->StartThread();
269     dmsg(1,("OK\n"));
270    
271 schoenebeck 271 for (RTList<Voice>::Iterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
272     if (!iterVoice->pDiskThread) {
273 schoenebeck 53 dmsg(0,("Engine -> voice::trigger: !pDiskThread\n"));
274     exit(EXIT_FAILURE);
275     }
276     }
277     }
278    
279 schoenebeck 473 /**
280     * Clear all engine global event lists.
281     */
282 schoenebeck 412 void Engine::ClearEventLists() {
283 schoenebeck 460 pGlobalEvents->clear();
284 schoenebeck 412 }
285    
286 schoenebeck 53 /**
287 schoenebeck 460 * Copy all events from the engine's global input queue buffer to the
288     * engine's internal event list. This will be done at the beginning of
289     * each audio cycle (that is each RenderAudio() call) to distinguish
290     * all global events which have to be processed in the current audio
291     * cycle. These events are usually just SysEx messages. Every
292     * EngineChannel has it's own input event queue buffer and event list
293     * to handle common events like NoteOn, NoteOff and ControlChange
294     * events.
295 schoenebeck 412 *
296 schoenebeck 460 * @param Samples - number of sample points to be processed in the
297     * current audio cycle
298 schoenebeck 412 */
299 schoenebeck 460 void Engine::ImportEvents(uint Samples) {
300 schoenebeck 412 RingBuffer<Event>::NonVolatileReader eventQueueReader = pEventQueue->get_non_volatile_reader();
301     Event* pEvent;
302     while (true) {
303     // get next event from input event queue
304     if (!(pEvent = eventQueueReader.pop())) break;
305     // if younger event reached, ignore that and all subsequent ones for now
306     if (pEvent->FragmentPos() >= Samples) {
307     eventQueueReader--;
308     dmsg(2,("Younger Event, pos=%d ,Samples=%d!\n",pEvent->FragmentPos(),Samples));
309     pEvent->ResetFragmentPos();
310     break;
311     }
312     // copy event to internal event list
313 schoenebeck 460 if (pGlobalEvents->poolIsEmpty()) {
314 schoenebeck 412 dmsg(1,("Event pool emtpy!\n"));
315     break;
316     }
317 schoenebeck 460 *pGlobalEvents->allocAppend() = *pEvent;
318 schoenebeck 412 }
319     eventQueueReader.free(); // free all copied events from input queue
320 persson 438 }
321 schoenebeck 412
322     /**
323 schoenebeck 53 * Let this engine proceed to render the given amount of sample points. The
324     * calculated audio data of all voices of this engine will be placed into
325     * the engine's audio sum buffer which has to be copied and eventually be
326     * converted to the appropriate value range by the audio output class (e.g.
327     * AlsaIO or JackIO) right after.
328     *
329     * @param Samples - number of sample points to be rendered
330     * @returns 0 on success
331     */
332 schoenebeck 412 int Engine::RenderAudio(uint Samples) {
333 schoenebeck 53 dmsg(5,("RenderAudio(Samples=%d)\n", Samples));
334    
335 schoenebeck 412 // return if engine disabled
336 schoenebeck 53 if (EngineDisabled.Pop()) {
337     dmsg(5,("gig::Engine: engine disabled (val=%d)\n",EngineDisabled.GetUnsafe()));
338     return 0;
339     }
340    
341 schoenebeck 293 // update time of start and end of this audio fragment (as events' time stamps relate to this)
342     pEventGenerator->UpdateFragmentTime(Samples);
343    
344 schoenebeck 663 // We only allow a maximum of CONFIG_MAX_VOICES voices to be spawned
345     // in each audio fragment. All subsequent request for spawning new
346     // voices in the same audio fragment will be ignored.
347     VoiceSpawnsLeft = CONFIG_MAX_VOICES;
348    
349 schoenebeck 412 // get all events from the engine's global input event queue which belong to the current fragment
350     // (these are usually just SysEx messages)
351 schoenebeck 460 ImportEvents(Samples);
352 schoenebeck 412
353     // process engine global events (these are currently only MIDI System Exclusive messages)
354     {
355 schoenebeck 460 RTList<Event>::Iterator itEvent = pGlobalEvents->first();
356     RTList<Event>::Iterator end = pGlobalEvents->end();
357 schoenebeck 412 for (; itEvent != end; ++itEvent) {
358     switch (itEvent->Type) {
359     case Event::type_sysex:
360     dmsg(5,("Engine: Sysex received\n"));
361     ProcessSysex(itEvent);
362     break;
363     }
364     }
365 schoenebeck 53 }
366 schoenebeck 412
367     // reset internal voice counter (just for statistic of active voices)
368     ActiveVoiceCountTemp = 0;
369    
370 schoenebeck 466 // handle events on all engine channels
371 schoenebeck 460 for (int i = 0; i < engineChannels.size(); i++) {
372     if (!engineChannels[i]->pInstrument) continue; // ignore if no instrument loaded
373     ProcessEvents(engineChannels[i], Samples);
374 schoenebeck 466 }
375    
376     // render all 'normal', active voices on all engine channels
377     for (int i = 0; i < engineChannels.size(); i++) {
378     if (!engineChannels[i]->pInstrument) continue; // ignore if no instrument loaded
379 schoenebeck 460 RenderActiveVoices(engineChannels[i], Samples);
380 schoenebeck 412 }
381    
382 schoenebeck 460 // now that all ordinary voices on ALL engine channels are rendered, render new stolen voices
383     RenderStolenVoices(Samples);
384    
385     // handle cleanup on all engine channels for the next audio fragment
386     for (int i = 0; i < engineChannels.size(); i++) {
387     if (!engineChannels[i]->pInstrument) continue; // ignore if no instrument loaded
388     PostProcess(engineChannels[i]);
389     }
390    
391    
392     // empty the engine's event list for the next audio fragment
393     ClearEventLists();
394    
395     // reset voice stealing for the next audio fragment
396     pVoiceStealingQueue->clear();
397    
398 schoenebeck 412 // just some statistics about this engine instance
399     ActiveVoiceCount = ActiveVoiceCountTemp;
400     if (ActiveVoiceCount > ActiveVoiceCountMax) ActiveVoiceCountMax = ActiveVoiceCount;
401    
402 persson 630 FrameTime += Samples;
403    
404 schoenebeck 412 return 0;
405     }
406    
407 schoenebeck 473 /**
408     * Dispatch and handle all events in this audio fragment for the given
409     * engine channel.
410     *
411     * @param pEngineChannel - engine channel on which events should be
412     * processed
413     * @param Samples - amount of sample points to be processed in
414     * this audio fragment cycle
415     */
416 schoenebeck 460 void Engine::ProcessEvents(EngineChannel* pEngineChannel, uint Samples) {
417 schoenebeck 412 // get all events from the engine channels's input event queue which belong to the current fragment
418     // (these are the common events like NoteOn, NoteOff, ControlChange, etc.)
419 schoenebeck 460 pEngineChannel->ImportEvents(Samples);
420 schoenebeck 53
421     // process events
422 schoenebeck 271 {
423 schoenebeck 460 RTList<Event>::Iterator itEvent = pEngineChannel->pEvents->first();
424     RTList<Event>::Iterator end = pEngineChannel->pEvents->end();
425 schoenebeck 271 for (; itEvent != end; ++itEvent) {
426     switch (itEvent->Type) {
427     case Event::type_note_on:
428     dmsg(5,("Engine: Note on received\n"));
429 schoenebeck 412 ProcessNoteOn((EngineChannel*)itEvent->pEngineChannel, itEvent);
430 schoenebeck 271 break;
431     case Event::type_note_off:
432     dmsg(5,("Engine: Note off received\n"));
433 schoenebeck 412 ProcessNoteOff((EngineChannel*)itEvent->pEngineChannel, itEvent);
434 schoenebeck 271 break;
435     case Event::type_control_change:
436     dmsg(5,("Engine: MIDI CC received\n"));
437 schoenebeck 412 ProcessControlChange((EngineChannel*)itEvent->pEngineChannel, itEvent);
438 schoenebeck 271 break;
439     case Event::type_pitchbend:
440     dmsg(5,("Engine: Pitchbend received\n"));
441 schoenebeck 412 ProcessPitchbend((EngineChannel*)itEvent->pEngineChannel, itEvent);
442 schoenebeck 271 break;
443     }
444 schoenebeck 53 }
445     }
446 schoenebeck 649
447     // reset voice stealing for the next engine channel (or next audio fragment)
448     itLastStolenVoice = RTList<Voice>::Iterator();
449     itLastStolenVoiceGlobally = RTList<Voice>::Iterator();
450     iuiLastStolenKey = RTList<uint>::Iterator();
451     iuiLastStolenKeyGlobally = RTList<uint>::Iterator();
452     pLastStolenChannel = NULL;
453 schoenebeck 460 }
454 schoenebeck 53
455 schoenebeck 473 /**
456     * Render all 'normal' voices (that is voices which were not stolen in
457     * this fragment) on the given engine channel.
458     *
459     * @param pEngineChannel - engine channel on which audio should be
460     * rendered
461     * @param Samples - amount of sample points to be rendered in
462     * this audio fragment cycle
463     */
464 schoenebeck 460 void Engine::RenderActiveVoices(EngineChannel* pEngineChannel, uint Samples) {
465 iliev 716 #if !CONFIG_PROCESS_MUTED_CHANNELS
466 schoenebeck 705 if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
467 iliev 716 #endif
468 schoenebeck 705
469 schoenebeck 460 RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
470     RTList<uint>::Iterator end = pEngineChannel->pActiveKeys->end();
471     while (iuiKey != end) { // iterate through all active keys
472     midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];
473     ++iuiKey;
474 schoenebeck 53
475 schoenebeck 460 RTList<Voice>::Iterator itVoice = pKey->pActiveVoices->first();
476     RTList<Voice>::Iterator itVoicesEnd = pKey->pActiveVoices->end();
477     for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
478     // now render current voice
479     itVoice->Render(Samples);
480     if (itVoice->IsActive()) ActiveVoiceCountTemp++; // still active
481     else { // voice reached end, is now inactive
482     FreeVoice(pEngineChannel, itVoice); // remove voice from the list of active voices
483 schoenebeck 53 }
484     }
485     }
486 schoenebeck 460 }
487 schoenebeck 53
488 schoenebeck 473 /**
489     * Render all stolen voices (only voices which were stolen in this
490     * fragment) on the given engine channel. Stolen voices are rendered
491     * after all normal voices have been rendered; this is needed to render
492     * audio of those voices which were selected for voice stealing until
493     * the point were the stealing (that is the take over of the voice)
494     * actually happened.
495     *
496     * @param pEngineChannel - engine channel on which audio should be
497     * rendered
498     * @param Samples - amount of sample points to be rendered in
499     * this audio fragment cycle
500     */
501 schoenebeck 460 void Engine::RenderStolenVoices(uint Samples) {
502     RTList<Event>::Iterator itVoiceStealEvent = pVoiceStealingQueue->first();
503     RTList<Event>::Iterator end = pVoiceStealingQueue->end();
504     for (; itVoiceStealEvent != end; ++itVoiceStealEvent) {
505     EngineChannel* pEngineChannel = (EngineChannel*) itVoiceStealEvent->pEngineChannel;
506     Pool<Voice>::Iterator itNewVoice =
507 schoenebeck 668 LaunchVoice(pEngineChannel, itVoiceStealEvent, itVoiceStealEvent->Param.Note.Layer, itVoiceStealEvent->Param.Note.ReleaseTrigger, false, false);
508 schoenebeck 460 if (itNewVoice) {
509     itNewVoice->Render(Samples);
510     if (itNewVoice->IsActive()) ActiveVoiceCountTemp++; // still active
511     else { // voice reached end, is now inactive
512     FreeVoice(pEngineChannel, itNewVoice); // remove voice from the list of active voices
513 schoenebeck 250 }
514     }
515 schoenebeck 460 else dmsg(1,("gig::Engine: ERROR, voice stealing didn't work out!\n"));
516 schoenebeck 473
517     // we need to clear the key's event list explicitly here in case key was never active
518     midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[itVoiceStealEvent->Param.Note.Key];
519     pKey->VoiceTheftsQueued--;
520     if (!pKey->Active && !pKey->VoiceTheftsQueued) pKey->pEvents->clear();
521 schoenebeck 250 }
522 schoenebeck 460 }
523 schoenebeck 250
524 schoenebeck 473 /**
525     * Free all keys which have turned inactive in this audio fragment, from
526     * the list of active keys and clear all event lists on that engine
527     * channel.
528     *
529     * @param pEngineChannel - engine channel to cleanup
530     */
531 schoenebeck 460 void Engine::PostProcess(EngineChannel* pEngineChannel) {
532 schoenebeck 287 // free all keys which have no active voices left
533     {
534 schoenebeck 411 RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
535     RTList<uint>::Iterator end = pEngineChannel->pActiveKeys->end();
536 schoenebeck 287 while (iuiKey != end) { // iterate through all active keys
537 schoenebeck 411 midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];
538 schoenebeck 287 ++iuiKey;
539 schoenebeck 411 if (pKey->pActiveVoices->isEmpty()) FreeKey(pEngineChannel, pKey);
540 schoenebeck 554 #if CONFIG_DEVMODE
541 schoenebeck 563 else { // just a sanity check for debugging
542 schoenebeck 287 RTList<Voice>::Iterator itVoice = pKey->pActiveVoices->first();
543     RTList<Voice>::Iterator itVoicesEnd = pKey->pActiveVoices->end();
544     for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
545     if (itVoice->itKillEvent) {
546     dmsg(1,("gig::Engine: ERROR, killed voice survived !!!\n"));
547     }
548     }
549     }
550 schoenebeck 554 #endif // CONFIG_DEVMODE
551 schoenebeck 287 }
552     }
553 schoenebeck 460
554     // empty the engine channel's own event lists
555     pEngineChannel->ClearEventLists();
556 schoenebeck 412 }
557 schoenebeck 287
558 schoenebeck 53 /**
559 schoenebeck 244 * Will be called by the MIDI input device whenever a MIDI system
560     * exclusive message has arrived.
561     *
562     * @param pData - pointer to sysex data
563     * @param Size - lenght of sysex data (in bytes)
564     */
565     void Engine::SendSysex(void* pData, uint Size) {
566 schoenebeck 246 Event event = pEventGenerator->CreateEvent();
567     event.Type = Event::type_sysex;
568     event.Param.Sysex.Size = Size;
569 schoenebeck 412 event.pEngineChannel = NULL; // as Engine global event
570 schoenebeck 244 if (pEventQueue->write_space() > 0) {
571     if (pSysexBuffer->write_space() >= Size) {
572     // copy sysex data to input buffer
573     uint toWrite = Size;
574     uint8_t* pPos = (uint8_t*) pData;
575     while (toWrite) {
576     const uint writeNow = RTMath::Min(toWrite, pSysexBuffer->write_space_to_end());
577     pSysexBuffer->write(pPos, writeNow);
578     toWrite -= writeNow;
579     pPos += writeNow;
580    
581     }
582     // finally place sysex event into input event queue
583     pEventQueue->push(&event);
584     }
585 schoenebeck 554 else dmsg(1,("Engine: Sysex message too large (%d byte) for input buffer (%d byte)!",Size,CONFIG_SYSEX_BUFFER_SIZE));
586 schoenebeck 244 }
587     else dmsg(1,("Engine: Input event queue full!"));
588     }
589    
590     /**
591 schoenebeck 53 * Assigns and triggers a new voice for the respective MIDI key.
592     *
593 schoenebeck 411 * @param pEngineChannel - engine channel on which this event occured on
594 schoenebeck 271 * @param itNoteOnEvent - key, velocity and time stamp of the event
595 schoenebeck 53 */
596 schoenebeck 411 void Engine::ProcessNoteOn(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {
597 iliev 716 #if !CONFIG_PROCESS_MUTED_CHANNELS
598     if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
599     #endif
600 persson 438
601 schoenebeck 354 const int key = itNoteOnEvent->Param.Note.Key;
602    
603     // Change key dimension value if key is in keyswitching area
604 schoenebeck 411 {
605     const ::gig::Instrument* pInstrument = pEngineChannel->pInstrument;
606     if (key >= pInstrument->DimensionKeyRange.low && key <= pInstrument->DimensionKeyRange.high)
607     pEngineChannel->CurrentKeyDimension = ((key - pInstrument->DimensionKeyRange.low) * 128) /
608     (pInstrument->DimensionKeyRange.high - pInstrument->DimensionKeyRange.low + 1);
609     }
610 schoenebeck 354
611 schoenebeck 411 midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[key];
612 schoenebeck 354
613 schoenebeck 53 pKey->KeyPressed = true; // the MIDI key was now pressed down
614 persson 630 pKey->Velocity = itNoteOnEvent->Param.Note.Velocity;
615     pKey->NoteOnTime = FrameTime + itNoteOnEvent->FragmentPos(); // will be used to calculate note length
616 schoenebeck 53
617     // cancel release process of voices on this key if needed
618 schoenebeck 411 if (pKey->Active && !pEngineChannel->SustainPedal) {
619 schoenebeck 271 RTList<Event>::Iterator itCancelReleaseEvent = pKey->pEvents->allocAppend();
620     if (itCancelReleaseEvent) {
621     *itCancelReleaseEvent = *itNoteOnEvent; // copy event
622     itCancelReleaseEvent->Type = Event::type_cancel_release; // transform event type
623 schoenebeck 239 }
624     else dmsg(1,("Event pool emtpy!\n"));
625 schoenebeck 53 }
626    
627 schoenebeck 271 // move note on event to the key's own event list
628     RTList<Event>::Iterator itNoteOnEventOnKeyList = itNoteOnEvent.moveToEndOf(pKey->pEvents);
629    
630 schoenebeck 460 // allocate and trigger new voice(s) for the key
631     {
632     // first, get total amount of required voices (dependant on amount of layers)
633     ::gig::Region* pRegion = pEngineChannel->pInstrument->GetRegion(itNoteOnEventOnKeyList->Param.Note.Key);
634     if (pRegion) {
635     int voicesRequired = pRegion->Layers;
636     // now launch the required amount of voices
637     for (int i = 0; i < voicesRequired; i++)
638 schoenebeck 668 LaunchVoice(pEngineChannel, itNoteOnEventOnKeyList, i, false, true, true);
639 schoenebeck 460 }
640     }
641 persson 438
642 schoenebeck 473 // if neither a voice was spawned or postponed then remove note on event from key again
643     if (!pKey->Active && !pKey->VoiceTheftsQueued)
644     pKey->pEvents->free(itNoteOnEventOnKeyList);
645    
646 persson 438 pKey->RoundRobinIndex++;
647 schoenebeck 53 }
648    
649     /**
650     * Releases the voices on the given key if sustain pedal is not pressed.
651     * If sustain is pressed, the release of the note will be postponed until
652     * sustain pedal will be released or voice turned inactive by itself (e.g.
653     * due to completion of sample playback).
654     *
655 schoenebeck 411 * @param pEngineChannel - engine channel on which this event occured on
656 schoenebeck 271 * @param itNoteOffEvent - key, velocity and time stamp of the event
657 schoenebeck 53 */
658 schoenebeck 411 void Engine::ProcessNoteOff(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOffEvent) {
659 iliev 716 #if !CONFIG_PROCESS_MUTED_CHANNELS
660 schoenebeck 705 if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
661 iliev 716 #endif
662 schoenebeck 705
663 schoenebeck 411 midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[itNoteOffEvent->Param.Note.Key];
664 schoenebeck 53 pKey->KeyPressed = false; // the MIDI key was now released
665    
666     // release voices on this key if needed
667 schoenebeck 411 if (pKey->Active && !pEngineChannel->SustainPedal) {
668 schoenebeck 271 itNoteOffEvent->Type = Event::type_release; // transform event type
669 schoenebeck 242
670 persson 497 // move event to the key's own event list
671     RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);
672 schoenebeck 271
673 persson 497 // spawn release triggered voice(s) if needed
674 persson 630 if (pKey->ReleaseTrigger) {
675 persson 497 // first, get total amount of required voices (dependant on amount of layers)
676     ::gig::Region* pRegion = pEngineChannel->pInstrument->GetRegion(itNoteOffEventOnKeyList->Param.Note.Key);
677     if (pRegion) {
678     int voicesRequired = pRegion->Layers;
679 persson 630
680     // MIDI note-on velocity is used instead of note-off velocity
681     itNoteOffEventOnKeyList->Param.Note.Velocity = pKey->Velocity;
682    
683 persson 497 // now launch the required amount of voices
684     for (int i = 0; i < voicesRequired; i++)
685 schoenebeck 668 LaunchVoice(pEngineChannel, itNoteOffEventOnKeyList, i, true, false, false); //FIXME: for the moment we don't perform voice stealing for release triggered samples
686 persson 497 }
687     pKey->ReleaseTrigger = false;
688 schoenebeck 460 }
689 persson 497
690     // if neither a voice was spawned or postponed then remove note off event from key again
691     if (!pKey->Active && !pKey->VoiceTheftsQueued)
692     pKey->pEvents->free(itNoteOffEventOnKeyList);
693 schoenebeck 242 }
694 schoenebeck 53 }
695    
696     /**
697 schoenebeck 738 * Moves pitchbend event from the general (input) event list to the engine
698     * channel's event list. It will actually processed later by the
699     * respective voice.
700 schoenebeck 53 *
701 schoenebeck 411 * @param pEngineChannel - engine channel on which this event occured on
702 schoenebeck 271 * @param itPitchbendEvent - absolute pitch value and time stamp of the event
703 schoenebeck 53 */
704 schoenebeck 411 void Engine::ProcessPitchbend(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itPitchbendEvent) {
705     pEngineChannel->Pitch = itPitchbendEvent->Param.Pitch.Pitch; // store current pitch value
706 schoenebeck 738 itPitchbendEvent.moveToEndOf(pEngineChannel->pEvents);
707 schoenebeck 53 }
708    
709     /**
710 schoenebeck 233 * Allocates and triggers a new voice. This method will usually be
711     * called by the ProcessNoteOn() method and by the voices itself
712     * (e.g. to spawn further voices on the same key for layered sounds).
713     *
714 schoenebeck 411 * @param pEngineChannel - engine channel on which this event occured on
715 schoenebeck 271 * @param itNoteOnEvent - key, velocity and time stamp of the event
716 schoenebeck 242 * @param iLayer - layer index for the new voice (optional - only
717     * in case of layered sounds of course)
718     * @param ReleaseTriggerVoice - if new voice is a release triggered voice
719     * (optional, default = false)
720 schoenebeck 250 * @param VoiceStealing - if voice stealing should be performed
721     * when there is no free voice
722     * (optional, default = true)
723 schoenebeck 668 * @param HandleKeyGroupConflicts - if voices should be killed due to a
724     * key group conflict
725 schoenebeck 250 * @returns pointer to new voice or NULL if there was no free voice or
726 schoenebeck 354 * if the voice wasn't triggered (for example when no region is
727     * defined for the given key).
728 schoenebeck 233 */
729 schoenebeck 668 Pool<Voice>::Iterator Engine::LaunchVoice(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent, int iLayer, bool ReleaseTriggerVoice, bool VoiceStealing, bool HandleKeyGroupConflicts) {
730 schoenebeck 669 int MIDIKey = itNoteOnEvent->Param.Note.Key;
731     midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[MIDIKey];
732     ::gig::Region* pRegion = pEngineChannel->pInstrument->GetRegion(MIDIKey);
733 schoenebeck 233
734 schoenebeck 668 // if nothing defined for this key
735     if (!pRegion) return Pool<Voice>::Iterator(); // nothing to do
736    
737 schoenebeck 669 // only mark the first voice of a layered voice (group) to be in a
738     // key group, so the layered voices won't kill each other
739     int iKeyGroup = (iLayer == 0 && !ReleaseTriggerVoice) ? pRegion->KeyGroup : 0;
740    
741 schoenebeck 668 // handle key group (a.k.a. exclusive group) conflicts
742     if (HandleKeyGroupConflicts) {
743     if (iKeyGroup) { // if this voice / key belongs to a key group
744     uint** ppKeyGroup = &pEngineChannel->ActiveKeyGroups[iKeyGroup];
745     if (*ppKeyGroup) { // if there's already an active key in that key group
746     midi_key_info_t* pOtherKey = &pEngineChannel->pMIDIKeyInfo[**ppKeyGroup];
747     // kill all voices on the (other) key
748     RTList<Voice>::Iterator itVoiceToBeKilled = pOtherKey->pActiveVoices->first();
749     RTList<Voice>::Iterator end = pOtherKey->pActiveVoices->end();
750     for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
751     if (itVoiceToBeKilled->Type != Voice::type_release_trigger) {
752     itVoiceToBeKilled->Kill(itNoteOnEvent);
753     --VoiceSpawnsLeft; //FIXME: just a hack, we should better check in StealVoice() if the voice was killed due to key conflict
754     }
755     }
756     }
757     }
758     }
759    
760 schoenebeck 669 Voice::type_t VoiceType = Voice::type_normal;
761    
762     // get current dimension values to select the right dimension region
763     //TODO: for stolen voices this dimension region selection block is processed twice, this should be changed
764     //FIXME: controller values for selecting the dimension region here are currently not sample accurate
765     uint DimValues[8] = { 0 };
766     for (int i = pRegion->Dimensions - 1; i >= 0; i--) {
767     switch (pRegion->pDimensionDefinitions[i].dimension) {
768     case ::gig::dimension_samplechannel:
769     DimValues[i] = 0; //TODO: we currently ignore this dimension
770     break;
771     case ::gig::dimension_layer:
772     DimValues[i] = iLayer;
773     break;
774     case ::gig::dimension_velocity:
775     DimValues[i] = itNoteOnEvent->Param.Note.Velocity;
776     break;
777     case ::gig::dimension_channelaftertouch:
778     DimValues[i] = 0; //TODO: we currently ignore this dimension
779     break;
780     case ::gig::dimension_releasetrigger:
781     VoiceType = (ReleaseTriggerVoice) ? Voice::type_release_trigger : (!iLayer) ? Voice::type_release_trigger_required : Voice::type_normal;
782     DimValues[i] = (uint) ReleaseTriggerVoice;
783     break;
784     case ::gig::dimension_keyboard:
785     DimValues[i] = (uint) pEngineChannel->CurrentKeyDimension;
786     break;
787     case ::gig::dimension_roundrobin:
788     DimValues[i] = (uint) pEngineChannel->pMIDIKeyInfo[MIDIKey].RoundRobinIndex; // incremented for each note on
789     break;
790     case ::gig::dimension_random:
791     RandomSeed = RandomSeed * 1103515245 + 12345; // classic pseudo random number generator
792     DimValues[i] = (uint) RandomSeed >> (32 - pRegion->pDimensionDefinitions[i].bits); // highest bits are most random
793     break;
794     case ::gig::dimension_modwheel:
795     DimValues[i] = pEngineChannel->ControllerTable[1];
796     break;
797     case ::gig::dimension_breath:
798     DimValues[i] = pEngineChannel->ControllerTable[2];
799     break;
800     case ::gig::dimension_foot:
801     DimValues[i] = pEngineChannel->ControllerTable[4];
802     break;
803     case ::gig::dimension_portamentotime:
804     DimValues[i] = pEngineChannel->ControllerTable[5];
805     break;
806     case ::gig::dimension_effect1:
807     DimValues[i] = pEngineChannel->ControllerTable[12];
808     break;
809     case ::gig::dimension_effect2:
810     DimValues[i] = pEngineChannel->ControllerTable[13];
811     break;
812     case ::gig::dimension_genpurpose1:
813     DimValues[i] = pEngineChannel->ControllerTable[16];
814     break;
815     case ::gig::dimension_genpurpose2:
816     DimValues[i] = pEngineChannel->ControllerTable[17];
817     break;
818     case ::gig::dimension_genpurpose3:
819     DimValues[i] = pEngineChannel->ControllerTable[18];
820     break;
821     case ::gig::dimension_genpurpose4:
822     DimValues[i] = pEngineChannel->ControllerTable[19];
823     break;
824     case ::gig::dimension_sustainpedal:
825     DimValues[i] = pEngineChannel->ControllerTable[64];
826     break;
827     case ::gig::dimension_portamento:
828     DimValues[i] = pEngineChannel->ControllerTable[65];
829     break;
830     case ::gig::dimension_sostenutopedal:
831     DimValues[i] = pEngineChannel->ControllerTable[66];
832     break;
833     case ::gig::dimension_softpedal:
834     DimValues[i] = pEngineChannel->ControllerTable[67];
835     break;
836     case ::gig::dimension_genpurpose5:
837     DimValues[i] = pEngineChannel->ControllerTable[80];
838     break;
839     case ::gig::dimension_genpurpose6:
840     DimValues[i] = pEngineChannel->ControllerTable[81];
841     break;
842     case ::gig::dimension_genpurpose7:
843     DimValues[i] = pEngineChannel->ControllerTable[82];
844     break;
845     case ::gig::dimension_genpurpose8:
846     DimValues[i] = pEngineChannel->ControllerTable[83];
847     break;
848     case ::gig::dimension_effect1depth:
849     DimValues[i] = pEngineChannel->ControllerTable[91];
850     break;
851     case ::gig::dimension_effect2depth:
852     DimValues[i] = pEngineChannel->ControllerTable[92];
853     break;
854     case ::gig::dimension_effect3depth:
855     DimValues[i] = pEngineChannel->ControllerTable[93];
856     break;
857     case ::gig::dimension_effect4depth:
858     DimValues[i] = pEngineChannel->ControllerTable[94];
859     break;
860     case ::gig::dimension_effect5depth:
861     DimValues[i] = pEngineChannel->ControllerTable[95];
862     break;
863     case ::gig::dimension_none:
864     std::cerr << "gig::Engine::LaunchVoice() Error: dimension=none\n" << std::flush;
865     break;
866     default:
867     std::cerr << "gig::Engine::LaunchVoice() Error: Unknown dimension\n" << std::flush;
868     }
869     }
870     ::gig::DimensionRegion* pDimRgn = pRegion->GetDimensionRegionByValue(DimValues);
871    
872     // no need to continue if sample is silent
873     if (!pDimRgn->pSample || !pDimRgn->pSample->SamplesTotal) return Pool<Voice>::Iterator();
874    
875 schoenebeck 233 // allocate a new voice for the key
876 schoenebeck 271 Pool<Voice>::Iterator itNewVoice = pKey->pActiveVoices->allocAppend();
877     if (itNewVoice) {
878 schoenebeck 233 // launch the new voice
879 schoenebeck 669 if (itNewVoice->Trigger(pEngineChannel, itNoteOnEvent, pEngineChannel->Pitch, pDimRgn, VoiceType, iKeyGroup) < 0) {
880 schoenebeck 354 dmsg(4,("Voice not triggered\n"));
881 schoenebeck 271 pKey->pActiveVoices->free(itNewVoice);
882 schoenebeck 233 }
883 schoenebeck 239 else { // on success
884 schoenebeck 663 --VoiceSpawnsLeft;
885 schoenebeck 239 if (!pKey->Active) { // mark as active key
886     pKey->Active = true;
887 schoenebeck 411 pKey->itSelf = pEngineChannel->pActiveKeys->allocAppend();
888 schoenebeck 271 *pKey->itSelf = itNoteOnEvent->Param.Note.Key;
889 schoenebeck 239 }
890 schoenebeck 271 if (itNewVoice->KeyGroup) {
891 schoenebeck 668 uint** ppKeyGroup = &pEngineChannel->ActiveKeyGroups[itNewVoice->KeyGroup];
892 schoenebeck 271 *ppKeyGroup = &*pKey->itSelf; // put key as the (new) active key to its key group
893 schoenebeck 239 }
894 schoenebeck 271 if (itNewVoice->Type == Voice::type_release_trigger_required) pKey->ReleaseTrigger = true; // mark key for the need of release triggered voice(s)
895     return itNewVoice; // success
896 schoenebeck 233 }
897     }
898 schoenebeck 285 else if (VoiceStealing) {
899 schoenebeck 460 // try to steal one voice
900 schoenebeck 473 int result = StealVoice(pEngineChannel, itNoteOnEvent);
901     if (!result) { // voice stolen successfully
902     // put note-on event into voice-stealing queue, so it will be reprocessed after killed voice died
903     RTList<Event>::Iterator itStealEvent = pVoiceStealingQueue->allocAppend();
904     if (itStealEvent) {
905     *itStealEvent = *itNoteOnEvent; // copy event
906     itStealEvent->Param.Note.Layer = iLayer;
907     itStealEvent->Param.Note.ReleaseTrigger = ReleaseTriggerVoice;
908     pKey->VoiceTheftsQueued++;
909     }
910     else dmsg(1,("Voice stealing queue full!\n"));
911 schoenebeck 285 }
912     }
913    
914 schoenebeck 271 return Pool<Voice>::Iterator(); // no free voice or error
915 schoenebeck 233 }
916    
917     /**
918 schoenebeck 250 * Will be called by LaunchVoice() method in case there are no free
919     * voices left. This method will select and kill one old voice for
920     * voice stealing and postpone the note-on event until the selected
921     * voice actually died.
922     *
923 schoenebeck 411 * @param pEngineChannel - engine channel on which this event occured on
924 schoenebeck 285 * @param itNoteOnEvent - key, velocity and time stamp of the event
925 schoenebeck 473 * @returns 0 on success, a value < 0 if no active voice could be picked for voice stealing
926 schoenebeck 250 */
927 schoenebeck 473 int Engine::StealVoice(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {
928 schoenebeck 663 if (VoiceSpawnsLeft <= 0) {
929 schoenebeck 554 dmsg(1,("Max. voice thefts per audio fragment reached (you may raise CONFIG_MAX_VOICES).\n"));
930 schoenebeck 473 return -1;
931 schoenebeck 460 }
932 schoenebeck 271 if (!pEventPool->poolIsEmpty()) {
933 schoenebeck 250
934 schoenebeck 460 RTList<Voice>::Iterator itSelectedVoice;
935 schoenebeck 250
936     // Select one voice for voice stealing
937 schoenebeck 554 switch (CONFIG_VOICE_STEAL_ALGO) {
938 schoenebeck 250
939     // try to pick the oldest voice on the key where the new
940     // voice should be spawned, if there is no voice on that
941 schoenebeck 563 // key, or no voice left to kill, then procceed with
942 schoenebeck 250 // 'oldestkey' algorithm
943 schoenebeck 460 case voice_steal_algo_oldestvoiceonkey: {
944     midi_key_info_t* pSelectedKey = &pEngineChannel->pMIDIKeyInfo[itNoteOnEvent->Param.Note.Key];
945 schoenebeck 563 itSelectedVoice = pSelectedKey->pActiveVoices->first();
946     // proceed iterating if voice was created in this fragment cycle
947 schoenebeck 663 while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice;
948 schoenebeck 563 // if we haven't found a voice then proceed with algorithm 'oldestkey'
949 schoenebeck 663 if (itSelectedVoice && itSelectedVoice->IsStealable()) break;
950 schoenebeck 250 } // no break - intentional !
951    
952     // try to pick the oldest voice on the oldest active key
953 schoenebeck 563 // from the same engine channel
954 schoenebeck 460 // (caution: must stay after 'oldestvoiceonkey' algorithm !)
955 schoenebeck 250 case voice_steal_algo_oldestkey: {
956 schoenebeck 649 // if we already stole in this fragment, try to proceed on same key
957 schoenebeck 460 if (this->itLastStolenVoice) {
958     itSelectedVoice = this->itLastStolenVoice;
959 schoenebeck 649 do {
960     ++itSelectedVoice;
961 schoenebeck 663 } while (itSelectedVoice && !itSelectedVoice->IsStealable()); // proceed iterating if voice was created in this fragment cycle
962 schoenebeck 649 // found a "stealable" voice ?
963 schoenebeck 663 if (itSelectedVoice && itSelectedVoice->IsStealable()) {
964 schoenebeck 649 // remember which voice we stole, so we can simply proceed on next voice stealing
965     this->itLastStolenVoice = itSelectedVoice;
966 schoenebeck 460 break; // selection succeeded
967 schoenebeck 250 }
968     }
969 schoenebeck 649 // get (next) oldest key
970     RTList<uint>::Iterator iuiSelectedKey = (this->iuiLastStolenKey) ? ++this->iuiLastStolenKey : pEngineChannel->pActiveKeys->first();
971     while (iuiSelectedKey) {
972     midi_key_info_t* pSelectedKey = &pEngineChannel->pMIDIKeyInfo[*iuiSelectedKey];
973 schoenebeck 659 itSelectedVoice = pSelectedKey->pActiveVoices->first();
974 schoenebeck 649 // proceed iterating if voice was created in this fragment cycle
975 schoenebeck 663 while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice;
976 schoenebeck 649 // found a "stealable" voice ?
977 schoenebeck 663 if (itSelectedVoice && itSelectedVoice->IsStealable()) {
978 schoenebeck 649 // remember which voice on which key we stole, so we can simply proceed on next voice stealing
979     this->iuiLastStolenKey = iuiSelectedKey;
980     this->itLastStolenVoice = itSelectedVoice;
981     break; // selection succeeded
982     }
983     ++iuiSelectedKey; // get next oldest key
984     }
985 schoenebeck 250 break;
986     }
987    
988     // don't steal anything
989     case voice_steal_algo_none:
990     default: {
991     dmsg(1,("No free voice (voice stealing disabled)!\n"));
992 schoenebeck 473 return -1;
993 schoenebeck 250 }
994     }
995    
996 schoenebeck 563 // if we couldn't steal a voice from the same engine channel then
997     // steal oldest voice on the oldest key from any other engine channel
998 schoenebeck 649 // (the smaller engine channel number, the higher priority)
999 schoenebeck 663 if (!itSelectedVoice || !itSelectedVoice->IsStealable()) {
1000 schoenebeck 649 EngineChannel* pSelectedChannel;
1001     int iChannelIndex;
1002     // select engine channel
1003     if (pLastStolenChannel) {
1004     pSelectedChannel = pLastStolenChannel;
1005     iChannelIndex = pSelectedChannel->iEngineIndexSelf;
1006     } else { // pick the engine channel followed by this engine channel
1007     iChannelIndex = (pEngineChannel->iEngineIndexSelf + 1) % engineChannels.size();
1008     pSelectedChannel = engineChannels[iChannelIndex];
1009     }
1010 schoenebeck 663
1011     // if we already stole in this fragment, try to proceed on same key
1012     if (this->itLastStolenVoiceGlobally) {
1013     itSelectedVoice = this->itLastStolenVoiceGlobally;
1014     do {
1015     ++itSelectedVoice;
1016     } while (itSelectedVoice && !itSelectedVoice->IsStealable()); // proceed iterating if voice was created in this fragment cycle
1017     }
1018    
1019     #if CONFIG_DEVMODE
1020     EngineChannel* pBegin = pSelectedChannel; // to detect endless loop
1021     #endif // CONFIG_DEVMODE
1022    
1023     // did we find a 'stealable' voice?
1024     if (itSelectedVoice && itSelectedVoice->IsStealable()) {
1025     // remember which voice we stole, so we can simply proceed on next voice stealing
1026     this->itLastStolenVoiceGlobally = itSelectedVoice;
1027     } else while (true) { // iterate through engine channels
1028 schoenebeck 649 // get (next) oldest key
1029 schoenebeck 663 RTList<uint>::Iterator iuiSelectedKey = (this->iuiLastStolenKeyGlobally) ? ++this->iuiLastStolenKeyGlobally : pSelectedChannel->pActiveKeys->first();
1030     this->iuiLastStolenKeyGlobally = RTList<uint>::Iterator(); // to prevent endless loop (see line above)
1031 schoenebeck 649 while (iuiSelectedKey) {
1032 schoenebeck 663 midi_key_info_t* pSelectedKey = &pSelectedChannel->pMIDIKeyInfo[*iuiSelectedKey];
1033 schoenebeck 649 itSelectedVoice = pSelectedKey->pActiveVoices->first();
1034     // proceed iterating if voice was created in this fragment cycle
1035 schoenebeck 663 while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice;
1036 schoenebeck 649 // found a "stealable" voice ?
1037 schoenebeck 663 if (itSelectedVoice && itSelectedVoice->IsStealable()) {
1038 schoenebeck 649 // remember which voice on which key on which engine channel we stole, so we can simply proceed on next voice stealing
1039     this->iuiLastStolenKeyGlobally = iuiSelectedKey;
1040     this->itLastStolenVoiceGlobally = itSelectedVoice;
1041     this->pLastStolenChannel = pSelectedChannel;
1042 schoenebeck 665 goto stealable_voice_found; // selection succeeded
1043 schoenebeck 649 }
1044     ++iuiSelectedKey; // get next key on current engine channel
1045     }
1046     // get next engine channel
1047 schoenebeck 460 iChannelIndex = (iChannelIndex + 1) % engineChannels.size();
1048 schoenebeck 649 pSelectedChannel = engineChannels[iChannelIndex];
1049 schoenebeck 663
1050     #if CONFIG_DEVMODE
1051     if (pSelectedChannel == pBegin) {
1052     dmsg(1,("FATAL ERROR: voice stealing endless loop!\n"));
1053     dmsg(1,("VoiceSpawnsLeft=%d.\n", VoiceSpawnsLeft));
1054     dmsg(1,("Exiting.\n"));
1055     exit(-1);
1056     }
1057     #endif // CONFIG_DEVMODE
1058 schoenebeck 460 }
1059     }
1060    
1061 schoenebeck 665 // jump point if a 'stealable' voice was found
1062     stealable_voice_found:
1063    
1064 schoenebeck 563 #if CONFIG_DEVMODE
1065 schoenebeck 473 if (!itSelectedVoice->IsActive()) {
1066     dmsg(1,("gig::Engine: ERROR, tried to steal a voice which was not active !!!\n"));
1067     return -1;
1068     }
1069 schoenebeck 563 #endif // CONFIG_DEVMODE
1070 schoenebeck 287
1071 schoenebeck 250 // now kill the selected voice
1072 schoenebeck 659 itSelectedVoice->Kill(itNoteOnEvent);
1073 schoenebeck 460
1074 schoenebeck 663 --VoiceSpawnsLeft;
1075 schoenebeck 473
1076     return 0; // success
1077 schoenebeck 250 }
1078 schoenebeck 473 else {
1079     dmsg(1,("Event pool emtpy!\n"));
1080     return -1;
1081     }
1082 schoenebeck 250 }
1083    
1084     /**
1085 schoenebeck 285 * Removes the given voice from the MIDI key's list of active voices.
1086     * This method will be called when a voice went inactive, e.g. because
1087     * it finished to playback its sample, finished its release stage or
1088     * just was killed.
1089 schoenebeck 53 *
1090 schoenebeck 411 * @param pEngineChannel - engine channel on which this event occured on
1091 schoenebeck 285 * @param itVoice - points to the voice to be freed
1092 schoenebeck 53 */
1093 schoenebeck 411 void Engine::FreeVoice(EngineChannel* pEngineChannel, Pool<Voice>::Iterator& itVoice) {
1094 schoenebeck 271 if (itVoice) {
1095 schoenebeck 411 midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[itVoice->MIDIKey];
1096 schoenebeck 53
1097 schoenebeck 271 uint keygroup = itVoice->KeyGroup;
1098    
1099 schoenebeck 53 // free the voice object
1100 schoenebeck 271 pVoicePool->free(itVoice);
1101 schoenebeck 53
1102 schoenebeck 287 // if no other voices left and member of a key group, remove from key group
1103     if (pKey->pActiveVoices->isEmpty() && keygroup) {
1104 schoenebeck 411 uint** ppKeyGroup = &pEngineChannel->ActiveKeyGroups[keygroup];
1105 schoenebeck 287 if (*ppKeyGroup == &*pKey->itSelf) *ppKeyGroup = NULL; // remove key from key group
1106 schoenebeck 53 }
1107     }
1108 schoenebeck 285 else std::cerr << "Couldn't release voice! (!itVoice)\n" << std::flush;
1109 schoenebeck 53 }
1110    
1111     /**
1112 schoenebeck 287 * Called when there's no more voice left on a key, this call will
1113     * update the key info respectively.
1114     *
1115 schoenebeck 411 * @param pEngineChannel - engine channel on which this event occured on
1116 schoenebeck 287 * @param pKey - key which is now inactive
1117     */
1118 schoenebeck 411 void Engine::FreeKey(EngineChannel* pEngineChannel, midi_key_info_t* pKey) {
1119 schoenebeck 287 if (pKey->pActiveVoices->isEmpty()) {
1120     pKey->Active = false;
1121 schoenebeck 411 pEngineChannel->pActiveKeys->free(pKey->itSelf); // remove key from list of active keys
1122 schoenebeck 287 pKey->itSelf = RTList<uint>::Iterator();
1123     pKey->ReleaseTrigger = false;
1124     pKey->pEvents->clear();
1125     dmsg(3,("Key has no more voices now\n"));
1126     }
1127     else dmsg(1,("gig::Engine: Oops, tried to free a key which contains voices.\n"));
1128     }
1129    
1130     /**
1131 schoenebeck 53 * Reacts on supported control change commands (e.g. pitch bend wheel,
1132     * modulation wheel, aftertouch).
1133     *
1134 schoenebeck 411 * @param pEngineChannel - engine channel on which this event occured on
1135 schoenebeck 271 * @param itControlChangeEvent - controller, value and time stamp of the event
1136 schoenebeck 53 */
1137 schoenebeck 411 void Engine::ProcessControlChange(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itControlChangeEvent) {
1138 schoenebeck 271 dmsg(4,("Engine::ContinuousController cc=%d v=%d\n", itControlChangeEvent->Param.CC.Controller, itControlChangeEvent->Param.CC.Value));
1139 schoenebeck 53
1140 schoenebeck 473 // update controller value in the engine channel's controller table
1141     pEngineChannel->ControllerTable[itControlChangeEvent->Param.CC.Controller] = itControlChangeEvent->Param.CC.Value;
1142    
1143 schoenebeck 738 // move event from the import event list to the engine channel's CC and pitchbend event list
1144     Pool<Event>::Iterator itControlChangeEventOnCCList = itControlChangeEvent.moveToEndOf(pEngineChannel->pEvents);
1145 schoenebeck 473
1146     switch (itControlChangeEventOnCCList->Param.CC.Controller) {
1147 schoenebeck 424 case 7: { // volume
1148     //TODO: not sample accurate yet
1149 schoenebeck 473 pEngineChannel->GlobalVolume = (float) itControlChangeEventOnCCList->Param.CC.Value / 127.0f;
1150 schoenebeck 660 pEngineChannel->bStatusChanged = true; // engine channel status has changed, so set notify flag
1151 schoenebeck 424 break;
1152     }
1153     case 10: { // panpot
1154     //TODO: not sample accurate yet
1155 schoenebeck 473 const int pan = (int) itControlChangeEventOnCCList->Param.CC.Value - 64;
1156 schoenebeck 424 pEngineChannel->GlobalPanLeft = 1.0f - float(RTMath::Max(pan, 0)) / 63.0f;
1157     pEngineChannel->GlobalPanRight = 1.0f - float(RTMath::Min(pan, 0)) / -64.0f;
1158     break;
1159     }
1160     case 64: { // sustain
1161 schoenebeck 473 if (itControlChangeEventOnCCList->Param.CC.Value >= 64 && !pEngineChannel->SustainPedal) {
1162 schoenebeck 53 dmsg(4,("PEDAL DOWN\n"));
1163 schoenebeck 411 pEngineChannel->SustainPedal = true;
1164 schoenebeck 53
1165 iliev 716 #if !CONFIG_PROCESS_MUTED_CHANNELS
1166 schoenebeck 705 if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
1167 iliev 716 #endif
1168 schoenebeck 705
1169 schoenebeck 53 // cancel release process of voices if necessary
1170 schoenebeck 411 RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
1171 schoenebeck 473 for (; iuiKey; ++iuiKey) {
1172     midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];
1173     if (!pKey->KeyPressed) {
1174     RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend();
1175     if (itNewEvent) {
1176     *itNewEvent = *itControlChangeEventOnCCList; // copy event to the key's own event list
1177     itNewEvent->Type = Event::type_cancel_release; // transform event type
1178 schoenebeck 53 }
1179 schoenebeck 473 else dmsg(1,("Event pool emtpy!\n"));
1180 schoenebeck 53 }
1181     }
1182     }
1183 schoenebeck 473 if (itControlChangeEventOnCCList->Param.CC.Value < 64 && pEngineChannel->SustainPedal) {
1184 schoenebeck 53 dmsg(4,("PEDAL UP\n"));
1185 schoenebeck 411 pEngineChannel->SustainPedal = false;
1186 schoenebeck 53
1187 iliev 716 #if !CONFIG_PROCESS_MUTED_CHANNELS
1188 schoenebeck 705 if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
1189 iliev 716 #endif
1190 schoenebeck 705
1191 schoenebeck 53 // release voices if their respective key is not pressed
1192 schoenebeck 411 RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
1193 schoenebeck 473 for (; iuiKey; ++iuiKey) {
1194     midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];
1195     if (!pKey->KeyPressed) {
1196     RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend();
1197     if (itNewEvent) {
1198     *itNewEvent = *itControlChangeEventOnCCList; // copy event to the key's own event list
1199     itNewEvent->Type = Event::type_release; // transform event type
1200 schoenebeck 53 }
1201 schoenebeck 473 else dmsg(1,("Event pool emtpy!\n"));
1202 schoenebeck 53 }
1203     }
1204     }
1205     break;
1206     }
1207    
1208    
1209 schoenebeck 473 // Channel Mode Messages
1210    
1211     case 120: { // all sound off
1212     KillAllVoices(pEngineChannel, itControlChangeEventOnCCList);
1213     break;
1214     }
1215     case 121: { // reset all controllers
1216     pEngineChannel->ResetControllers();
1217     break;
1218     }
1219     case 123: { // all notes off
1220     ReleaseAllVoices(pEngineChannel, itControlChangeEventOnCCList);
1221     break;
1222     }
1223     }
1224 schoenebeck 53 }
1225    
1226     /**
1227 schoenebeck 244 * Reacts on MIDI system exclusive messages.
1228     *
1229 schoenebeck 271 * @param itSysexEvent - sysex data size and time stamp of the sysex event
1230 schoenebeck 244 */
1231 schoenebeck 271 void Engine::ProcessSysex(Pool<Event>::Iterator& itSysexEvent) {
1232 schoenebeck 244 RingBuffer<uint8_t>::NonVolatileReader reader = pSysexBuffer->get_non_volatile_reader();
1233    
1234     uint8_t exclusive_status, id;
1235     if (!reader.pop(&exclusive_status)) goto free_sysex_data;
1236     if (!reader.pop(&id)) goto free_sysex_data;
1237     if (exclusive_status != 0xF0) goto free_sysex_data;
1238    
1239     switch (id) {
1240     case 0x41: { // Roland
1241 schoenebeck 493 dmsg(3,("Roland Sysex\n"));
1242 schoenebeck 244 uint8_t device_id, model_id, cmd_id;
1243     if (!reader.pop(&device_id)) goto free_sysex_data;
1244     if (!reader.pop(&model_id)) goto free_sysex_data;
1245     if (!reader.pop(&cmd_id)) goto free_sysex_data;
1246     if (model_id != 0x42 /*GS*/) goto free_sysex_data;
1247     if (cmd_id != 0x12 /*DT1*/) goto free_sysex_data;
1248    
1249     // command address
1250     uint8_t addr[3]; // 2 byte addr MSB, followed by 1 byte addr LSB)
1251     const RingBuffer<uint8_t>::NonVolatileReader checksum_reader = reader; // so we can calculate the check sum later
1252     if (reader.read(&addr[0], 3) != 3) goto free_sysex_data;
1253     if (addr[0] == 0x40 && addr[1] == 0x00) { // System Parameters
1254 schoenebeck 493 dmsg(3,("\tSystem Parameter\n"));
1255 schoenebeck 244 }
1256     else if (addr[0] == 0x40 && addr[1] == 0x01) { // Common Parameters
1257 schoenebeck 493 dmsg(3,("\tCommon Parameter\n"));
1258 schoenebeck 244 }
1259     else if (addr[0] == 0x40 && (addr[1] & 0xf0) == 0x10) { // Part Parameters (1)
1260 schoenebeck 493 dmsg(3,("\tPart Parameter\n"));
1261     switch (addr[2]) {
1262 schoenebeck 244 case 0x40: { // scale tuning
1263 schoenebeck 493 dmsg(3,("\t\tScale Tuning\n"));
1264 schoenebeck 244 uint8_t scale_tunes[12]; // detuning of all 12 semitones of an octave
1265     if (reader.read(&scale_tunes[0], 12) != 12) goto free_sysex_data;
1266     uint8_t checksum;
1267 schoenebeck 493 if (!reader.pop(&checksum)) goto free_sysex_data;
1268 schoenebeck 563 #if CONFIG_ASSERT_GS_SYSEX_CHECKSUM
1269     if (GSCheckSum(checksum_reader, 12)) goto free_sysex_data;
1270     #endif // CONFIG_ASSERT_GS_SYSEX_CHECKSUM
1271 schoenebeck 244 for (int i = 0; i < 12; i++) scale_tunes[i] -= 64;
1272     AdjustScale((int8_t*) scale_tunes);
1273 schoenebeck 493 dmsg(3,("\t\t\tNew scale applied.\n"));
1274 schoenebeck 244 break;
1275     }
1276     }
1277     }
1278     else if (addr[0] == 0x40 && (addr[1] & 0xf0) == 0x20) { // Part Parameters (2)
1279     }
1280     else if (addr[0] == 0x41) { // Drum Setup Parameters
1281     }
1282     break;
1283     }
1284     }
1285    
1286     free_sysex_data: // finally free sysex data
1287 schoenebeck 271 pSysexBuffer->increment_read_ptr(itSysexEvent->Param.Sysex.Size);
1288 schoenebeck 244 }
1289    
1290     /**
1291     * Calculates the Roland GS sysex check sum.
1292     *
1293     * @param AddrReader - reader which currently points to the first GS
1294     * command address byte of the GS sysex message in
1295     * question
1296     * @param DataSize - size of the GS message data (in bytes)
1297     */
1298     uint8_t Engine::GSCheckSum(const RingBuffer<uint8_t>::NonVolatileReader AddrReader, uint DataSize) {
1299     RingBuffer<uint8_t>::NonVolatileReader reader = AddrReader;
1300     uint bytes = 3 /*addr*/ + DataSize;
1301     uint8_t addr_and_data[bytes];
1302     reader.read(&addr_and_data[0], bytes);
1303     uint8_t sum = 0;
1304     for (uint i = 0; i < bytes; i++) sum += addr_and_data[i];
1305     return 128 - sum % 128;
1306     }
1307    
1308     /**
1309     * Allows to tune each of the twelve semitones of an octave.
1310     *
1311     * @param ScaleTunes - detuning of all twelve semitones (in cents)
1312     */
1313     void Engine::AdjustScale(int8_t ScaleTunes[12]) {
1314     memcpy(&this->ScaleTuning[0], &ScaleTunes[0], 12); //TODO: currently not sample accurate
1315     }
1316    
1317     /**
1318 schoenebeck 473 * Releases all voices on an engine channel. All voices will go into
1319     * the release stage and thus it might take some time (e.g. dependant to
1320     * their envelope release time) until they actually die.
1321     *
1322     * @param pEngineChannel - engine channel on which all voices should be released
1323     * @param itReleaseEvent - event which caused this releasing of all voices
1324     */
1325     void Engine::ReleaseAllVoices(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itReleaseEvent) {
1326     RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
1327     while (iuiKey) {
1328     midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];
1329     ++iuiKey;
1330     // append a 'release' event to the key's own event list
1331     RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend();
1332     if (itNewEvent) {
1333     *itNewEvent = *itReleaseEvent; // copy original event (to the key's event list)
1334     itNewEvent->Type = Event::type_release; // transform event type
1335     }
1336     else dmsg(1,("Event pool emtpy!\n"));
1337     }
1338     }
1339    
1340     /**
1341     * Kills all voices on an engine channel as soon as possible. Voices
1342     * won't get into release state, their volume level will be ramped down
1343     * as fast as possible.
1344     *
1345     * @param pEngineChannel - engine channel on which all voices should be killed
1346     * @param itKillEvent - event which caused this killing of all voices
1347     */
1348     void Engine::KillAllVoices(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itKillEvent) {
1349     RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
1350     RTList<uint>::Iterator end = pEngineChannel->pActiveKeys->end();
1351     while (iuiKey != end) { // iterate through all active keys
1352     midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];
1353     ++iuiKey;
1354     RTList<Voice>::Iterator itVoice = pKey->pActiveVoices->first();
1355     RTList<Voice>::Iterator itVoicesEnd = pKey->pActiveVoices->end();
1356     for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
1357     itVoice->Kill(itKillEvent);
1358 schoenebeck 663 --VoiceSpawnsLeft; //FIXME: just a temporary workaround, we should check the cause in StealVoice() instead
1359 schoenebeck 473 }
1360     }
1361     }
1362    
1363 schoenebeck 53 uint Engine::VoiceCount() {
1364     return ActiveVoiceCount;
1365     }
1366    
1367     uint Engine::VoiceCountMax() {
1368     return ActiveVoiceCountMax;
1369     }
1370    
1371     bool Engine::DiskStreamSupported() {
1372     return true;
1373     }
1374    
1375     uint Engine::DiskStreamCount() {
1376     return (pDiskThread) ? pDiskThread->ActiveStreamCount : 0;
1377     }
1378    
1379     uint Engine::DiskStreamCountMax() {
1380     return (pDiskThread) ? pDiskThread->ActiveStreamCountMax : 0;
1381     }
1382    
1383     String Engine::DiskStreamBufferFillBytes() {
1384     return pDiskThread->GetBufferFillBytes();
1385     }
1386    
1387     String Engine::DiskStreamBufferFillPercentage() {
1388     return pDiskThread->GetBufferFillPercentage();
1389     }
1390    
1391 senkov 112 String Engine::EngineName() {
1392 schoenebeck 475 return LS_GIG_ENGINE_NAME;
1393 senkov 112 }
1394    
1395 schoenebeck 53 String Engine::Description() {
1396     return "Gigasampler Engine";
1397     }
1398    
1399     String Engine::Version() {
1400 schoenebeck 738 String s = "$Revision: 1.52 $";
1401 schoenebeck 123 return s.substr(11, s.size() - 13); // cut dollar signs, spaces and CVS macro keyword
1402 schoenebeck 53 }
1403    
1404     }} // namespace LinuxSampler::gig

  ViewVC Help
Powered by ViewVC