/[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 242 - (hide annotations) (download)
Wed Sep 15 13:59:08 2004 UTC (19 years, 7 months ago) by schoenebeck
File size: 33868 byte(s)
* added support for release trigger dimension (that is voices which are
  spawned when a key was released)
* libgig: bugfix in dimension region switching

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

  ViewVC Help
Powered by ViewVC