/[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 123 - (show annotations) (download)
Mon Jun 14 19:33:16 2004 UTC (19 years, 9 months ago) by schoenebeck
File size: 27883 byte(s)
* src/common: added template class 'optional<>' which can be used e.g. as
  return type whenever a value might be returned, but don't has to; this
  template class pretty much acts like a pointer of the given type, but is
  much more safer than a simple pointer
* src/audiodriver: added static class AudioDeviceFactory to create audio
  devices at runtime by using a string and to obtain driver informations
  of drivers at runtime, driver classes should simply use the macro
  REGISTER_AUDIO_OUTPUT_DRIVER(DriverName,DriverClass) in their cpp file
  to register the driver to LinuxSampler (no changes needed anymore in the
  LS code to add a new audio output driver)
* src/drivers: added classes to dynamically manage driver parameters; there
  are two different kinds of parameters: parameters which are need to
  create a new device (DeviceCreationParameterX) used to e.g. create an
  audio output device or a MIDI input device and parameters which are only
  available at runtime, means when a device is already created
  (DeviceRuntimeParameterX) which will be e.g. used as audio channel
  parameters and MIDI port parameters
* src/linuxsampler.cpp: all registered audio output drivers will be shown
  on the console on startup
* src/network: implemented configuration of audio output devices via LSCP

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

  ViewVC Help
Powered by ViewVC