/[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 80 - (show annotations) (download)
Sun May 23 19:16:33 2004 UTC (19 years, 10 months ago) by schoenebeck
File size: 27463 byte(s)
* biquad filter parameters are now calculated outside the interpolate
  loop for better performance
* couple of loop unroll optimizations
* filter is now enabled by default
* cubic interpolation is now enabled by default
* reduced debug level to 1 to lower verbosity
* raised default limit for voices to 128
* raised default limit for streams to 150
* added some compiler optimization flags (-ffast-math -march -mcpu)

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

  ViewVC Help
Powered by ViewVC