/[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 225 - (show annotations) (download)
Sun Aug 22 14:46:47 2004 UTC (19 years, 7 months ago) by schoenebeck
File size: 29995 byte(s)
* set default volume to 1.0 in Gigasampler engine (was 0.0)
* implemented "SET CHANNEL AUDIO_OUTPUT_CHANNEL" LSCP command
* fixed "GET ENGINE INFO" LSCP command
* fixed "GET CHANNEL INFO" LSCP command
* src/network/lscp.y: fixed 'stringval' rule (returned string with formal
  apostrophes), fixed 'dotnum' rule (ignored position after decimal point)

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

  ViewVC Help
Powered by ViewVC