/[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 239 - (hide annotations) (download)
Sun Sep 12 14:48:19 2004 UTC (19 years, 6 months ago) by schoenebeck
File size: 32886 byte(s)
* implemented key groups (a.k.a exclusive groups) which is important for
  drum patches and monphonic instruments
* src/engines/gig/Engine.cpp: bugfix in ProcessNoteOn() - did not always
  stick the note on event to the respective key's own event list although
  e.g. the EGADRS expects it to find there

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

  ViewVC Help
Powered by ViewVC