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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 242 - (show 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 /***************************************************************************
2 * *
3 * LinuxSampler - modular, streaming capable sampler *
4 * *
5 * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6 * *
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].ReleaseTrigger = false;
54 pMIDIKeyInfo[i].pSelf = NULL;
55 pMIDIKeyInfo[i].pEvents = new RTEList<Event>(pEventPool);
56 }
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 pBasicFilterParameters = NULL;
64 pMainFilterParameters = NULL;
65
66 InstrumentIdx = -1;
67 InstrumentStat = -1;
68
69 AudioDeviceChannelLeft = -1;
70 AudioDeviceChannelRight = -1;
71
72 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 if (pMainFilterParameters) delete[] pMainFilterParameters;
98 if (pBasicFilterParameters) delete[] pBasicFilterParameters;
99 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 dmsg(3,("gig::Engine: enabled (val=%d)\n", EngineDisabled.GetUnsafe()));
106 }
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 GlobalVolume = 1.0;
157
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 pMIDIKeyInfo[i].KeyPressed = false;
166 pMIDIKeyInfo[i].Active = false;
167 pMIDIKeyInfo[i].ReleaseTrigger = false;
168 pMIDIKeyInfo[i].pSelf = NULL;
169 }
170
171 // reset all key groups
172 map<uint,uint*>::iterator iter = ActiveKeyGroups.begin();
173 for (; iter != ActiveKeyGroups.end(); iter++) iter->second = NULL;
174
175 // 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 InstrumentFile = FileName;
212 InstrumentIdx = Instrument;
213 InstrumentStat = 0;
214
215 // delete all key groups
216 ActiveKeyGroups.clear();
217
218 // 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 InstrumentStat = -1;
226 dmsg(1,("no instrument loaded!!!\n"));
227 exit(EXIT_FAILURE);
228 }
229 }
230 catch (RIFF::Exception e) {
231 InstrumentStat = -2;
232 String msg = "gig::Engine error: Failed to load instrument, cause: " + e.Message;
233 throw LinuxSamplerException(msg);
234 }
235 catch (InstrumentResourceManagerException e) {
236 InstrumentStat = -3;
237 String msg = "gig::Engine error: Failed to load instrument, cause: " + e.Message();
238 throw LinuxSamplerException(msg);
239 }
240 catch (...) {
241 InstrumentStat = -4;
242 throw LinuxSamplerException("gig::Engine error: Failed to load instrument, cause: Unknown exception while trying to parse gig file.");
243 }
244
245 // 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 InstrumentStat = 100;
250
251 // 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 this->pInstrument = pNewResource; //TODO: there are couple of engine parameters we should update here as well if the instrument was updated (see LoadInstrument())
281 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 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 // (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 // (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 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 AudioDeviceChannelLeft = -1;
356 AudioDeviceChannelRight = -1;
357 }
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 KillVoiceImmediately(pVoice); // remove voice from the list of active voices
450 }
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 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 }
546
547 // allocate and trigger a new voice for the key
548 LaunchVoice(pNoteOnEvent);
549
550 // finally move note on event to the key's own event list
551 pEvents->move(pNoteOnEvent, pKey->pEvents);
552 }
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
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 }
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 * 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 * @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 */
604 void Engine::LaunchVoice(Event* pNoteOnEvent, int iLayer, bool ReleaseTriggerVoice) {
605 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 if (pNewVoice->Trigger(pNoteOnEvent, this->Pitch, this->pInstrument, iLayer, ReleaseTriggerVoice) < 0) {
612 dmsg(1,("Triggering new voice failed!\n"));
613 pKey->pActiveVoices->free(pNewVoice);
614 }
615 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 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 }
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 if (pNewVoice->Type == Voice::type_release_trigger_required) pKey->ReleaseTrigger = true; // mark key for the need of release triggered voice(s)
640 }
641 }
642 else std::cerr << "No free voice!" << std::endl << std::flush;
643 }
644
645 /**
646 * 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 void Engine::KillVoiceImmediately(Voice* pVoice) {
653 if (pVoice) {
654 if (pVoice->IsActive()) pVoice->KillImmediately();
655
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 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 pKey->Active = false;
668 pActiveKeys->free(pKey->pSelf); // remove key from list of active keys
669 pKey->pSelf = NULL;
670 pKey->ReleaseTrigger = false;
671 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 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 }
753
754 float Engine::Volume() {
755 return GlobalVolume;
756 }
757
758 void Engine::Volume(float f) {
759 GlobalVolume = f;
760 }
761
762 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 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 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 int Engine::InstrumentStatus() {
835 return InstrumentStat;
836 }
837
838 String Engine::Description() {
839 return "Gigasampler Engine";
840 }
841
842 String Engine::Version() {
843 String s = "$Revision: 1.11 $";
844 return s.substr(11, s.size() - 13); // cut dollar signs, spaces and CVS macro keyword
845 }
846
847 }} // namespace LinuxSampler::gig

  ViewVC Help
Powered by ViewVC