/[svn]/linuxsampler/trunk/src/engines/gig/Engine.cpp
ViewVC logotype

Annotation of /linuxsampler/trunk/src/engines/gig/Engine.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 80 - (hide 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 schoenebeck 53 /***************************************************************************
2     * *
3     * LinuxSampler - modular, streaming capable sampler *
4     * *
5 schoenebeck 56 * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6 schoenebeck 53 * *
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 schoenebeck 80 pBasicFilterParameters = NULL;
63     pMainFilterParameters = NULL;
64 schoenebeck 53
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 schoenebeck 80 if (pMainFilterParameters) delete[] pMainFilterParameters;
91     if (pBasicFilterParameters) delete[] pBasicFilterParameters;
92 schoenebeck 53 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 schoenebeck 64 dmsg(3,("gig::Engine: enabled (val=%d)\n", EngineDisabled.GetUnsafe()));
99 schoenebeck 53 }
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 schoenebeck 80 // (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 schoenebeck 53 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 schoenebeck 80 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 schoenebeck 53 }
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