/[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 56 - (show annotations) (download)
Tue Apr 27 09:21:58 2004 UTC (19 years, 11 months ago) by schoenebeck
File size: 26751 byte(s)
updated copyright header for 2004

1 /***************************************************************************
2 * *
3 * LinuxSampler - modular, streaming capable sampler *
4 * *
5 * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6 * *
7 * This program is free software; you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation; either version 2 of the License, or *
10 * (at your option) any later version. *
11 * *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program; if not, write to the Free Software *
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
20 * MA 02111-1307 USA *
21 ***************************************************************************/
22
23 #include <sstream>
24 #include "DiskThread.h"
25 #include "Voice.h"
26
27 #include "Engine.h"
28
29 namespace LinuxSampler { namespace gig {
30
31 InstrumentResourceManager Engine::Instruments;
32
33 Engine::Engine() {
34 pRIFF = NULL;
35 pGig = NULL;
36 pInstrument = NULL;
37 pAudioOutputDevice = NULL;
38 pDiskThread = NULL;
39 pEventGenerator = NULL;
40 pEventQueue = new RingBuffer<Event>(MAX_EVENTS_PER_FRAGMENT);
41 pEventPool = new RTELMemoryPool<Event>(MAX_EVENTS_PER_FRAGMENT);
42 pVoicePool = new RTELMemoryPool<Voice>(MAX_AUDIO_VOICES);
43 pActiveKeys = new RTELMemoryPool<uint>(128);
44 pEvents = new RTEList<Event>(pEventPool);
45 pCCEvents = new RTEList<Event>(pEventPool);
46 for (uint i = 0; i < Event::destination_count; i++) {
47 pSynthesisEvents[i] = new RTEList<Event>(pEventPool);
48 }
49 for (uint i = 0; i < 128; i++) {
50 pMIDIKeyInfo[i].pActiveVoices = new RTEList<Voice>(pVoicePool);
51 pMIDIKeyInfo[i].KeyPressed = false;
52 pMIDIKeyInfo[i].Active = false;
53 pMIDIKeyInfo[i].pSelf = NULL;
54 pMIDIKeyInfo[i].pEvents = new RTEList<Event>(pEventPool);
55 }
56 for (Voice* pVoice = pVoicePool->alloc(); pVoice; pVoice = pVoicePool->alloc()) {
57 pVoice->SetEngine(this);
58 }
59 pVoicePool->clear();
60
61 pSynthesisParameters[0] = NULL; // we allocate when an audio device is connected
62
63 ResetInternal();
64 }
65
66 Engine::~Engine() {
67 if (pDiskThread) {
68 pDiskThread->StopThread();
69 delete pDiskThread;
70 }
71 if (pGig) delete pGig;
72 if (pRIFF) delete pRIFF;
73 for (uint i = 0; i < 128; i++) {
74 if (pMIDIKeyInfo[i].pActiveVoices) delete pMIDIKeyInfo[i].pActiveVoices;
75 if (pMIDIKeyInfo[i].pEvents) delete pMIDIKeyInfo[i].pEvents;
76 }
77 for (uint i = 0; i < Event::destination_count; i++) {
78 if (pSynthesisEvents[i]) delete pSynthesisEvents[i];
79 }
80 delete[] pSynthesisEvents;
81 if (pEvents) delete pEvents;
82 if (pCCEvents) delete pCCEvents;
83 if (pEventQueue) delete pEventQueue;
84 if (pEventPool) delete pEventPool;
85 if (pVoicePool) delete pVoicePool;
86 if (pActiveKeys) delete pActiveKeys;
87 if (pEventGenerator) delete pEventGenerator;
88 if (pSynthesisParameters[0]) delete[] pSynthesisParameters[0];
89 }
90
91 void Engine::Enable() {
92 dmsg(3,("gig::Engine: enabling\n"));
93 EngineDisabled.PushAndUnlock(false, 2); // set condition object 'EngineDisabled' to false (wait max. 2s)
94 dmsg(1,("gig::Engine: enabled (val=%d)\n", EngineDisabled.GetUnsafe()));
95 }
96
97 void Engine::Disable() {
98 dmsg(3,("gig::Engine: disabling\n"));
99 bool* pWasDisabled = EngineDisabled.PushAndUnlock(true, 2); // wait max. 2s
100 if (!pWasDisabled) dmsg(3,("gig::Engine warning: Timeout waiting to disable engine.\n"));
101 }
102
103 void Engine::DisableAndLock() {
104 dmsg(3,("gig::Engine: disabling\n"));
105 bool* pWasDisabled = EngineDisabled.Push(true, 2); // wait max. 2s
106 if (!pWasDisabled) dmsg(3,("gig::Engine warning: Timeout waiting to disable engine.\n"));
107 }
108
109 /**
110 * Reset all voices and disk thread and clear input event queue and all
111 * control and status variables.
112 */
113 void Engine::Reset() {
114 DisableAndLock();
115
116 //if (pAudioOutputDevice->IsPlaying()) { // if already running
117 /*
118 // signal audio thread not to enter render part anymore
119 SuspensionRequested = true;
120 // sleep until wakened by audio thread
121 pthread_mutex_lock(&__render_state_mutex);
122 pthread_cond_wait(&__render_exit_condition, &__render_state_mutex);
123 pthread_mutex_unlock(&__render_state_mutex);
124 */
125 //}
126
127 //if (wasplaying) pAudioOutputDevice->Stop();
128
129 ResetInternal();
130
131 // signal audio thread to continue with rendering
132 //SuspensionRequested = false;
133 Enable();
134 }
135
136 /**
137 * Reset all voices and disk thread and clear input event queue and all
138 * control and status variables. This method is not thread safe!
139 */
140 void Engine::ResetInternal() {
141 Pitch = 0;
142 SustainPedal = false;
143 ActiveVoiceCount = 0;
144 ActiveVoiceCountMax = 0;
145
146 // set all MIDI controller values to zero
147 memset(ControllerTable, 0x00, 128);
148
149 // reset key info
150 for (uint i = 0; i < 128; i++) {
151 pMIDIKeyInfo[i].pActiveVoices->clear();
152 pMIDIKeyInfo[i].pEvents->clear();
153 pMIDIKeyInfo[i].KeyPressed = false;
154 pMIDIKeyInfo[i].Active = false;
155 pMIDIKeyInfo[i].pSelf = NULL;
156 }
157
158 // reset all voices
159 for (Voice* pVoice = pVoicePool->alloc(); pVoice; pVoice = pVoicePool->alloc()) {
160 pVoice->Reset();
161 }
162 pVoicePool->clear();
163
164 // free all active keys
165 pActiveKeys->clear();
166
167 // reset disk thread
168 if (pDiskThread) pDiskThread->Reset();
169
170 // delete all input events
171 pEventQueue->init();
172 }
173
174 /**
175 * Load an instrument from a .gig file.
176 *
177 * @param FileName - file name of the Gigasampler instrument file
178 * @param Instrument - index of the instrument in the .gig file
179 * @throws LinuxSamplerException on error
180 * @returns detailed description of the method call result
181 */
182 void Engine::LoadInstrument(const char* FileName, uint Instrument) {
183
184 DisableAndLock();
185
186 ResetInternal(); // reset engine
187
188 // free old instrument
189 if (pInstrument) {
190 // give old instrument back to instrument manager
191 Instruments.HandBack(pInstrument, this);
192 }
193
194 // request gig instrument from instrument manager
195 try {
196 instrument_id_t instrid;
197 instrid.FileName = FileName;
198 instrid.iInstrument = Instrument;
199 pInstrument = Instruments.Borrow(instrid, this);
200 if (!pInstrument) {
201 dmsg(1,("no instrument loaded!!!\n"));
202 exit(EXIT_FAILURE);
203 }
204 }
205 catch (RIFF::Exception e) {
206 String msg = "gig::Engine error: Failed to load instrument, cause: " + e.Message;
207 throw LinuxSamplerException(msg);
208 }
209 catch (InstrumentResourceManagerException e) {
210 String msg = "gig::Engine error: Failed to load instrument, cause: " + e.Message();
211 throw LinuxSamplerException(msg);
212 }
213 catch (...) {
214 throw LinuxSamplerException("gig::Engine error: Failed to load instrument, cause: Unknown exception while trying to parse gig file.");
215 }
216
217 // inform audio driver for the need of two channels
218 try {
219 if (pAudioOutputDevice) pAudioOutputDevice->AcquireChannels(2); // gig Engine only stereo
220 }
221 catch (AudioOutputException e) {
222 String msg = "Audio output device unable to provide 2 audio channels, cause: " + e.Message();
223 throw LinuxSamplerException(msg);
224 }
225
226 Enable();
227 }
228
229 /**
230 * Will be called by the InstrumentResourceManager when the instrument
231 * we are currently using in this engine is going to be updated, so we
232 * can stop playback before that happens.
233 */
234 void Engine::ResourceToBeUpdated(::gig::Instrument* pResource, void*& pUpdateArg) {
235 dmsg(3,("gig::Engine: Received instrument update message.\n"));
236 DisableAndLock();
237 ResetInternal();
238 this->pInstrument = NULL;
239 }
240
241 /**
242 * Will be called by the InstrumentResourceManager when the instrument
243 * update process was completed, so we can continue with playback.
244 */
245 void Engine::ResourceUpdated(::gig::Instrument* pOldResource, ::gig::Instrument* pNewResource, void* pUpdateArg) {
246 this->pInstrument = pNewResource;
247 Enable();
248 }
249
250 void Engine::Connect(AudioOutputDevice* pAudioOut) {
251 pAudioOutputDevice = pAudioOut;
252
253 ResetInternal();
254
255 // inform audio driver for the need of two channels
256 try {
257 pAudioOutputDevice->AcquireChannels(2); // gig engine only stereo
258 }
259 catch (AudioOutputException e) {
260 String msg = "Audio output device unable to provide 2 audio channels, cause: " + e.Message();
261 throw LinuxSamplerException(msg);
262 }
263
264 // (re)create disk thread
265 if (this->pDiskThread) {
266 this->pDiskThread->StopThread();
267 delete this->pDiskThread;
268 }
269 this->pDiskThread = new DiskThread(((pAudioOut->MaxSamplesPerCycle() << MAX_PITCH) << 1) + 6); //FIXME: assuming stereo
270 if (!pDiskThread) {
271 dmsg(0,("gig::Engine new diskthread = NULL\n"));
272 exit(EXIT_FAILURE);
273 }
274
275 for (Voice* pVoice = pVoicePool->alloc(); pVoice; pVoice = pVoicePool->alloc()) {
276 pVoice->pDiskThread = this->pDiskThread;
277 pVoice->SetOutput(pAudioOut);
278 dmsg(3,("d"));
279 }
280 pVoicePool->clear();
281
282 // (re)create event generator
283 if (pEventGenerator) delete pEventGenerator;
284 pEventGenerator = new EventGenerator(pAudioOut->SampleRate());
285
286 // (re)allocate synthesis parameter matrix
287 if (pSynthesisParameters[0]) delete[] pSynthesisParameters[0];
288 pSynthesisParameters[0] = new float[Event::destination_count * pAudioOut->MaxSamplesPerCycle()];
289 for (int dst = 1; dst < Event::destination_count; dst++)
290 pSynthesisParameters[dst] = pSynthesisParameters[dst - 1] + pAudioOut->MaxSamplesPerCycle();
291
292 dmsg(1,("Starting disk thread..."));
293 pDiskThread->StartThread();
294 dmsg(1,("OK\n"));
295
296 for (Voice* pVoice = pVoicePool->first(); pVoice; pVoice = pVoicePool->next()) {
297 if (!pVoice->pDiskThread) {
298 dmsg(0,("Engine -> voice::trigger: !pDiskThread\n"));
299 exit(EXIT_FAILURE);
300 }
301 }
302 }
303
304 void Engine::DisconnectAudioOutputDevice() {
305 if (pAudioOutputDevice) { // if clause to prevent disconnect loops
306 AudioOutputDevice* olddevice = pAudioOutputDevice;
307 pAudioOutputDevice = NULL;
308 olddevice->Disconnect(this);
309 }
310 }
311
312 /**
313 * Let this engine proceed to render the given amount of sample points. The
314 * calculated audio data of all voices of this engine will be placed into
315 * the engine's audio sum buffer which has to be copied and eventually be
316 * converted to the appropriate value range by the audio output class (e.g.
317 * AlsaIO or JackIO) right after.
318 *
319 * @param Samples - number of sample points to be rendered
320 * @returns 0 on success
321 */
322 int Engine::RenderAudio(uint Samples) {
323 dmsg(5,("RenderAudio(Samples=%d)\n", Samples));
324
325 // return if no instrument loaded or engine disabled
326 if (EngineDisabled.Pop()) {
327 dmsg(5,("gig::Engine: engine disabled (val=%d)\n",EngineDisabled.GetUnsafe()));
328 return 0;
329 }
330 if (!pInstrument) {
331 dmsg(5,("gig::Engine: no instrument loaded\n"));
332 return 0;
333 }
334
335
336 // empty the event lists for the new fragment
337 pEvents->clear();
338 pCCEvents->clear();
339 for (uint i = 0; i < Event::destination_count; i++) {
340 pSynthesisEvents[i]->clear();
341 }
342
343 // read and copy events from input queue
344 Event event = pEventGenerator->CreateEvent();
345 while (true) {
346 if (!pEventQueue->pop(&event)) break;
347 pEvents->alloc_assign(event);
348 }
349
350
351 // update time of start and end of this audio fragment (as events' time stamps relate to this)
352 pEventGenerator->UpdateFragmentTime(Samples);
353
354
355 // process events
356 Event* pNextEvent = pEvents->first();
357 while (pNextEvent) {
358 Event* pEvent = pNextEvent;
359 pEvents->set_current(pEvent);
360 pNextEvent = pEvents->next();
361 switch (pEvent->Type) {
362 case Event::type_note_on:
363 dmsg(5,("Audio Thread: Note on received\n"));
364 ProcessNoteOn(pEvent);
365 break;
366 case Event::type_note_off:
367 dmsg(5,("Audio Thread: Note off received\n"));
368 ProcessNoteOff(pEvent);
369 break;
370 case Event::type_control_change:
371 dmsg(5,("Audio Thread: MIDI CC received\n"));
372 ProcessControlChange(pEvent);
373 break;
374 case Event::type_pitchbend:
375 dmsg(5,("Audio Thread: Pitchbend received\n"));
376 ProcessPitchbend(pEvent);
377 break;
378 }
379 }
380
381
382 // render audio from all active voices
383 int active_voices = 0;
384 uint* piKey = pActiveKeys->first();
385 while (piKey) { // iterate through all active keys
386 midi_key_info_t* pKey = &pMIDIKeyInfo[*piKey];
387 pActiveKeys->set_current(piKey);
388 piKey = pActiveKeys->next();
389
390 Voice* pVoiceNext = pKey->pActiveVoices->first();
391 while (pVoiceNext) { // iterate through all voices on this key
392 // already get next voice on key
393 Voice* pVoice = pVoiceNext;
394 pKey->pActiveVoices->set_current(pVoice);
395 pVoiceNext = pKey->pActiveVoices->next();
396
397 // now render current voice
398 pVoice->Render(Samples);
399 if (pVoice->IsActive()) active_voices++; // still active
400 else { // voice reached end, is now inactive
401 KillVoice(pVoice); // remove voice from the list of active voices
402 }
403 }
404 pKey->pEvents->clear(); // free all events on the key
405 }
406
407
408 // write that to the disk thread class so that it can print it
409 // on the console for debugging purposes
410 ActiveVoiceCount = active_voices;
411 if (ActiveVoiceCount > ActiveVoiceCountMax) ActiveVoiceCountMax = ActiveVoiceCount;
412
413
414 return 0;
415 }
416
417 /**
418 * Will be called by the MIDIIn Thread to let the audio thread trigger a new
419 * voice for the given key.
420 *
421 * @param Key - MIDI key number of the triggered key
422 * @param Velocity - MIDI velocity value of the triggered key
423 */
424 void Engine::SendNoteOn(uint8_t Key, uint8_t Velocity) {
425 Event event = pEventGenerator->CreateEvent();
426 event.Type = Event::type_note_on;
427 event.Key = Key;
428 event.Velocity = Velocity;
429 if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
430 else dmsg(1,("Engine: Input event queue full!"));
431 }
432
433 /**
434 * Will be called by the MIDIIn Thread to signal the audio thread to release
435 * voice(s) on the given key.
436 *
437 * @param Key - MIDI key number of the released key
438 * @param Velocity - MIDI release velocity value of the released key
439 */
440 void Engine::SendNoteOff(uint8_t Key, uint8_t Velocity) {
441 Event event = pEventGenerator->CreateEvent();
442 event.Type = Event::type_note_off;
443 event.Key = Key;
444 event.Velocity = Velocity;
445 if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
446 else dmsg(1,("Engine: Input event queue full!"));
447 }
448
449 /**
450 * Will be called by the MIDIIn Thread to signal the audio thread to change
451 * the pitch value for all voices.
452 *
453 * @param Pitch - MIDI pitch value (-8192 ... +8191)
454 */
455 void Engine::SendPitchbend(int Pitch) {
456 Event event = pEventGenerator->CreateEvent();
457 event.Type = Event::type_pitchbend;
458 event.Pitch = Pitch;
459 if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
460 else dmsg(1,("Engine: Input event queue full!"));
461 }
462
463 /**
464 * Will be called by the MIDIIn Thread to signal the audio thread that a
465 * continuous controller value has changed.
466 *
467 * @param Controller - MIDI controller number of the occured control change
468 * @param Value - value of the control change
469 */
470 void Engine::SendControlChange(uint8_t Controller, uint8_t Value) {
471 Event event = pEventGenerator->CreateEvent();
472 event.Type = Event::type_control_change;
473 event.Controller = Controller;
474 event.Value = Value;
475 if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
476 else dmsg(1,("Engine: Input event queue full!"));
477 }
478
479 /**
480 * Assigns and triggers a new voice for the respective MIDI key.
481 *
482 * @param pNoteOnEvent - key, velocity and time stamp of the event
483 */
484 void Engine::ProcessNoteOn(Event* pNoteOnEvent) {
485 midi_key_info_t* pKey = &pMIDIKeyInfo[pNoteOnEvent->Key];
486
487 pKey->KeyPressed = true; // the MIDI key was now pressed down
488
489 // cancel release process of voices on this key if needed
490 if (pKey->Active && !SustainPedal) {
491 pNoteOnEvent->Type = Event::type_cancel_release; // transform event type
492 pEvents->move(pNoteOnEvent, pKey->pEvents); // move event to the key's own event list
493 }
494
495 // allocate a new voice for the key
496 Voice* pNewVoice = pKey->pActiveVoices->alloc();
497 if (pNewVoice) {
498 // launch the new voice
499 if (pNewVoice->Trigger(pNoteOnEvent, this->Pitch, this->pInstrument) < 0) {
500 dmsg(1,("Triggering new voice failed!\n"));
501 pKey->pActiveVoices->free(pNewVoice);
502 }
503 else if (!pKey->Active) { // mark as active key
504 pKey->Active = true;
505 pKey->pSelf = pActiveKeys->alloc();
506 *pKey->pSelf = pNoteOnEvent->Key;
507 }
508 }
509 else std::cerr << "No free voice!" << std::endl << std::flush;
510 }
511
512 /**
513 * Releases the voices on the given key if sustain pedal is not pressed.
514 * If sustain is pressed, the release of the note will be postponed until
515 * sustain pedal will be released or voice turned inactive by itself (e.g.
516 * due to completion of sample playback).
517 *
518 * @param pNoteOffEvent - key, velocity and time stamp of the event
519 */
520 void Engine::ProcessNoteOff(Event* pNoteOffEvent) {
521 midi_key_info_t* pKey = &pMIDIKeyInfo[pNoteOffEvent->Key];
522
523 pKey->KeyPressed = false; // the MIDI key was now released
524
525 // release voices on this key if needed
526 if (pKey->Active && !SustainPedal) {
527 pNoteOffEvent->Type = Event::type_release; // transform event type
528 pEvents->move(pNoteOffEvent, pKey->pEvents); // move event to the key's own event list
529 }
530 }
531
532 /**
533 * Moves pitchbend event from the general (input) event list to the pitch
534 * event list.
535 *
536 * @param pPitchbendEvent - absolute pitch value and time stamp of the event
537 */
538 void Engine::ProcessPitchbend(Event* pPitchbendEvent) {
539 this->Pitch = pPitchbendEvent->Pitch; // store current pitch value
540 pEvents->move(pPitchbendEvent, pSynthesisEvents[Event::destination_vco]);
541 }
542
543 /**
544 * Immediately kills the voice given with pVoice (no matter if sustain is
545 * pressed or not) and removes it from the MIDI key's list of active voice.
546 * This method will e.g. be called if a voice went inactive by itself.
547 *
548 * @param pVoice - points to the voice to be killed
549 */
550 void Engine::KillVoice(Voice* pVoice) {
551 if (pVoice) {
552 if (pVoice->IsActive()) pVoice->Kill();
553
554 midi_key_info_t* pKey = &pMIDIKeyInfo[pVoice->MIDIKey];
555
556 // free the voice object
557 pVoicePool->free(pVoice);
558
559 // check if there are no voices left on the MIDI key and update the key info if so
560 if (pKey->pActiveVoices->is_empty()) {
561 pKey->Active = false;
562 pActiveKeys->free(pKey->pSelf); // remove key from list of active keys
563 pKey->pSelf = NULL;
564 dmsg(3,("Key has no more voices now\n"));
565 }
566 }
567 else std::cerr << "Couldn't release voice! (pVoice == NULL)\n" << std::flush;
568 }
569
570 /**
571 * Reacts on supported control change commands (e.g. pitch bend wheel,
572 * modulation wheel, aftertouch).
573 *
574 * @param pControlChangeEvent - controller, value and time stamp of the event
575 */
576 void Engine::ProcessControlChange(Event* pControlChangeEvent) {
577 dmsg(4,("Engine::ContinuousController cc=%d v=%d\n", pControlChangeEvent->Controller, pControlChangeEvent->Value));
578
579 switch (pControlChangeEvent->Controller) {
580 case 64: {
581 if (pControlChangeEvent->Value >= 64 && !SustainPedal) {
582 dmsg(4,("PEDAL DOWN\n"));
583 SustainPedal = true;
584
585 // cancel release process of voices if necessary
586 uint* piKey = pActiveKeys->first();
587 if (piKey) {
588 pControlChangeEvent->Type = Event::type_cancel_release; // transform event type
589 while (piKey) {
590 midi_key_info_t* pKey = &pMIDIKeyInfo[*piKey];
591 pActiveKeys->set_current(piKey);
592 piKey = pActiveKeys->next();
593 if (!pKey->KeyPressed) {
594 Event* pNewEvent = pKey->pEvents->alloc();
595 if (pNewEvent) *pNewEvent = *pControlChangeEvent; // copy event to the key's own event list
596 else dmsg(1,("Event pool emtpy!\n"));
597 }
598 }
599 }
600 }
601 if (pControlChangeEvent->Value < 64 && SustainPedal) {
602 dmsg(4,("PEDAL UP\n"));
603 SustainPedal = false;
604
605 // release voices if their respective key is not pressed
606 uint* piKey = pActiveKeys->first();
607 if (piKey) {
608 pControlChangeEvent->Type = Event::type_release; // transform event type
609 while (piKey) {
610 midi_key_info_t* pKey = &pMIDIKeyInfo[*piKey];
611 pActiveKeys->set_current(piKey);
612 piKey = pActiveKeys->next();
613 if (!pKey->KeyPressed) {
614 Event* pNewEvent = pKey->pEvents->alloc();
615 if (pNewEvent) *pNewEvent = *pControlChangeEvent; // copy event to the key's own event list
616 else dmsg(1,("Event pool emtpy!\n"));
617 }
618 }
619 }
620 }
621 break;
622 }
623 }
624
625 // update controller value in the engine's controller table
626 ControllerTable[pControlChangeEvent->Controller] = pControlChangeEvent->Value;
627
628 // move event from the unsorted event list to the control change event list
629 pEvents->move(pControlChangeEvent, pCCEvents);
630 }
631
632 /**
633 * Initialize the parameter sequence for the modulation destination given by
634 * by 'dst' with the constant value given by val.
635 */
636 void Engine::ResetSynthesisParameters(Event::destination_t dst, float val) {
637 int maxsamples = pAudioOutputDevice->MaxSamplesPerCycle();
638 for (int i = 0; i < maxsamples; i++) pSynthesisParameters[dst][i] = val;
639 }
640
641 float Engine::Volume() {
642 return GlobalVolume;
643 }
644
645 void Engine::Volume(float f) {
646 GlobalVolume = f;
647 }
648
649 uint Engine::VoiceCount() {
650 return ActiveVoiceCount;
651 }
652
653 uint Engine::VoiceCountMax() {
654 return ActiveVoiceCountMax;
655 }
656
657 bool Engine::DiskStreamSupported() {
658 return true;
659 }
660
661 uint Engine::DiskStreamCount() {
662 return (pDiskThread) ? pDiskThread->ActiveStreamCount : 0;
663 }
664
665 uint Engine::DiskStreamCountMax() {
666 return (pDiskThread) ? pDiskThread->ActiveStreamCountMax : 0;
667 }
668
669 String Engine::DiskStreamBufferFillBytes() {
670 return pDiskThread->GetBufferFillBytes();
671 }
672
673 String Engine::DiskStreamBufferFillPercentage() {
674 return pDiskThread->GetBufferFillPercentage();
675 }
676
677 String Engine::Description() {
678 return "Gigasampler Engine";
679 }
680
681 String Engine::Version() {
682 return "0.0.1-0cvs20040423";
683 }
684
685 }} // namespace LinuxSampler::gig

  ViewVC Help
Powered by ViewVC