/[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 133 - (show annotations) (download)
Fri Jun 18 14:29:02 2004 UTC (19 years, 9 months ago) by capela
File size: 28139 byte(s)
* Load Instrument patch applied; this patch makes the
  LOAD INSTRUMENT command to return immediately,
  almost/always with an OK response, while spawning
  the proper instrument file loading in the background.

* New INSTRUMENT_STATUS field on GET CHANNEL INFO result
  set; the instrument status value holds the load progress
  percentage if positive, otherwise a negative value is
  evidence of a load exception error.

* VERSION is now set to 0.2.

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

  ViewVC Help
Powered by ViewVC