/[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 133 - (hide annotations) (download)
Fri Jun 18 14:29:02 2004 UTC (19 years, 10 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 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 123
65 senkov 112 InstrumentIdx = -1;
66 capela 133 InstrumentStat = -1;
67 schoenebeck 53
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 schoenebeck 80 if (pMainFilterParameters) delete[] pMainFilterParameters;
94     if (pBasicFilterParameters) delete[] pBasicFilterParameters;
95 schoenebeck 53 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 schoenebeck 64 dmsg(3,("gig::Engine: enabled (val=%d)\n", EngineDisabled.GetUnsafe()));
102 schoenebeck 53 }
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 capela 133 InstrumentFile = FileName;
202     InstrumentIdx = Instrument;
203     InstrumentStat = 0;
204 senkov 112
205 schoenebeck 53 // 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 capela 133 InstrumentStat = -1;
213 schoenebeck 53 dmsg(1,("no instrument loaded!!!\n"));
214     exit(EXIT_FAILURE);
215     }
216     }
217     catch (RIFF::Exception e) {
218 capela 133 InstrumentStat = -2;
219 schoenebeck 53 String msg = "gig::Engine error: Failed to load instrument, cause: " + e.Message;
220     throw LinuxSamplerException(msg);
221     }
222     catch (InstrumentResourceManagerException e) {
223 capela 133 InstrumentStat = -3;
224 schoenebeck 53 String msg = "gig::Engine error: Failed to load instrument, cause: " + e.Message();
225     throw LinuxSamplerException(msg);
226     }
227     catch (...) {
228 capela 133 InstrumentStat = -4;
229 schoenebeck 53 throw LinuxSamplerException("gig::Engine error: Failed to load instrument, cause: Unknown exception while trying to parse gig file.");
230     }
231    
232 capela 133 InstrumentStat = 100;
233 senkov 112
234 schoenebeck 53 // 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 schoenebeck 80 // (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 schoenebeck 53 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 schoenebeck 80 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 schoenebeck 53 }
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 senkov 112 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 capela 133 int Engine::InstrumentStatus() {
719     return InstrumentStat;
720     }
721    
722 schoenebeck 53 String Engine::Description() {
723     return "Gigasampler Engine";
724     }
725    
726     String Engine::Version() {
727 capela 133 String s = "$Revision: 1.7 $";
728 schoenebeck 123 return s.substr(11, s.size() - 13); // cut dollar signs, spaces and CVS macro keyword
729 schoenebeck 53 }
730    
731     }} // namespace LinuxSampler::gig

  ViewVC Help
Powered by ViewVC