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

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

  ViewVC Help
Powered by ViewVC