2 |
* * |
* * |
3 |
* LinuxSampler - modular, streaming capable sampler * |
* LinuxSampler - modular, streaming capable sampler * |
4 |
* * |
* * |
5 |
* Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck * |
* Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck * |
6 |
* Copyright (C) 2005 Christian Schoenebeck * |
* Copyright (C) 2005-2007 Christian Schoenebeck * |
7 |
* * |
* * |
8 |
* This program is free software; you can redistribute it and/or modify * |
* This program is free software; you can redistribute it and/or modify * |
9 |
* it under the terms of the GNU General Public License as published by * |
* it under the terms of the GNU General Public License as published by * |
29 |
|
|
30 |
#include "Engine.h" |
#include "Engine.h" |
31 |
|
|
|
#if defined(__APPLE__) |
|
|
# include <stdlib.h> |
|
|
#else |
|
|
# include <malloc.h> |
|
|
#endif |
|
|
|
|
32 |
namespace LinuxSampler { namespace gig { |
namespace LinuxSampler { namespace gig { |
33 |
|
|
34 |
InstrumentResourceManager Engine::instruments; |
InstrumentResourceManager Engine::instruments; |
51 |
if (engines.count(pDevice)) { |
if (engines.count(pDevice)) { |
52 |
dmsg(4,("Using existing gig::Engine.\n")); |
dmsg(4,("Using existing gig::Engine.\n")); |
53 |
pEngine = engines[pDevice]; |
pEngine = engines[pDevice]; |
54 |
|
|
55 |
|
// Disable the engine while the new engine channel is |
56 |
|
// added and initialized. The engine will be enabled again |
57 |
|
// in EngineChannel::Connect. |
58 |
|
pEngine->DisableAndLock(); |
59 |
} else { // create a new engine (and disk thread) instance for the given audio output device |
} else { // create a new engine (and disk thread) instance for the given audio output device |
60 |
dmsg(4,("Creating new gig::Engine.\n")); |
dmsg(4,("Creating new gig::Engine.\n")); |
61 |
pEngine = (Engine*) EngineFactory::Create("gig"); |
pEngine = (Engine*) EngineFactory::Create("gig"); |
102 |
pAudioOutputDevice = NULL; |
pAudioOutputDevice = NULL; |
103 |
pDiskThread = NULL; |
pDiskThread = NULL; |
104 |
pEventGenerator = NULL; |
pEventGenerator = NULL; |
105 |
pSysexBuffer = new RingBuffer<uint8_t>(CONFIG_SYSEX_BUFFER_SIZE, 0); |
pSysexBuffer = new RingBuffer<uint8_t,false>(CONFIG_SYSEX_BUFFER_SIZE, 0); |
106 |
pEventQueue = new RingBuffer<Event>(CONFIG_MAX_EVENTS_PER_FRAGMENT, 0); |
pEventQueue = new RingBuffer<Event,false>(CONFIG_MAX_EVENTS_PER_FRAGMENT, 0); |
107 |
pEventPool = new Pool<Event>(CONFIG_MAX_EVENTS_PER_FRAGMENT); |
pEventPool = new Pool<Event>(CONFIG_MAX_EVENTS_PER_FRAGMENT); |
108 |
pVoicePool = new Pool<Voice>(CONFIG_MAX_VOICES); |
pVoicePool = new Pool<Voice>(CONFIG_MAX_VOICES); |
109 |
|
pDimRegionsInUse = new ::gig::DimensionRegion*[CONFIG_MAX_VOICES + 1]; |
110 |
pVoiceStealingQueue = new RTList<Event>(pEventPool); |
pVoiceStealingQueue = new RTList<Event>(pEventPool); |
111 |
pGlobalEvents = new RTList<Event>(pEventPool); |
pGlobalEvents = new RTList<Event>(pEventPool); |
112 |
|
InstrumentChangeQueue = new RingBuffer<instrument_change_command_t,false>(1, 0); |
113 |
|
InstrumentChangeReplyQueue = new RingBuffer<instrument_change_reply_t,false>(1, 0); |
114 |
|
|
115 |
for (RTList<Voice>::Iterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) { |
for (RTList<Voice>::Iterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) { |
116 |
iterVoice->SetEngine(this); |
iterVoice->SetEngine(this); |
117 |
} |
} |
118 |
pVoicePool->clear(); |
pVoicePool->clear(); |
119 |
|
|
|
pSynthesisParameters[0] = NULL; // we allocate when an audio device is connected |
|
|
pBasicFilterParameters = NULL; |
|
|
pMainFilterParameters = NULL; |
|
|
|
|
120 |
ResetInternal(); |
ResetInternal(); |
121 |
ResetScaleTuning(); |
ResetScaleTuning(); |
122 |
} |
} |
125 |
* Destructor |
* Destructor |
126 |
*/ |
*/ |
127 |
Engine::~Engine() { |
Engine::~Engine() { |
128 |
|
MidiInputPort::RemoveSysexListener(this); |
129 |
if (pDiskThread) { |
if (pDiskThread) { |
130 |
dmsg(1,("Stopping disk thread...")); |
dmsg(1,("Stopping disk thread...")); |
131 |
pDiskThread->StopThread(); |
pDiskThread->StopThread(); |
139 |
delete pVoicePool; |
delete pVoicePool; |
140 |
} |
} |
141 |
if (pEventGenerator) delete pEventGenerator; |
if (pEventGenerator) delete pEventGenerator; |
|
if (pMainFilterParameters) delete[] pMainFilterParameters; |
|
|
if (pBasicFilterParameters) delete[] pBasicFilterParameters; |
|
|
if (pSynthesisParameters[0]) free(pSynthesisParameters[0]); |
|
142 |
if (pVoiceStealingQueue) delete pVoiceStealingQueue; |
if (pVoiceStealingQueue) delete pVoiceStealingQueue; |
143 |
if (pSysexBuffer) delete pSysexBuffer; |
if (pSysexBuffer) delete pSysexBuffer; |
144 |
EngineFactory::Destroy(this); |
Unregister(); |
145 |
} |
} |
146 |
|
|
147 |
void Engine::Enable() { |
void Engine::Enable() { |
175 |
|
|
176 |
/** |
/** |
177 |
* Reset all voices and disk thread and clear input event queue and all |
* Reset all voices and disk thread and clear input event queue and all |
178 |
* control and status variables. This method is not thread safe! |
* control and status variables. This method is protected by a mutex. |
179 |
*/ |
*/ |
180 |
void Engine::ResetInternal() { |
void Engine::ResetInternal() { |
181 |
|
ResetInternalMutex.Lock(); |
182 |
|
|
183 |
|
// make sure that the engine does not get any sysex messages |
184 |
|
// while it's reseting |
185 |
|
bool sysexDisabled = MidiInputPort::RemoveSysexListener(this); |
186 |
ActiveVoiceCount = 0; |
ActiveVoiceCount = 0; |
187 |
ActiveVoiceCountMax = 0; |
ActiveVoiceCountMax = 0; |
188 |
|
|
205 |
|
|
206 |
// delete all input events |
// delete all input events |
207 |
pEventQueue->init(); |
pEventQueue->init(); |
208 |
|
pSysexBuffer->init(); |
209 |
|
if (sysexDisabled) MidiInputPort::AddSysexListener(this); |
210 |
|
ResetInternalMutex.Unlock(); |
211 |
} |
} |
212 |
|
|
213 |
/** |
/** |
237 |
} |
} |
238 |
catch (AudioOutputException e) { |
catch (AudioOutputException e) { |
239 |
String msg = "Audio output device unable to provide 2 audio channels, cause: " + e.Message(); |
String msg = "Audio output device unable to provide 2 audio channels, cause: " + e.Message(); |
240 |
throw LinuxSamplerException(msg); |
throw Exception(msg); |
241 |
} |
} |
242 |
|
|
243 |
this->MaxSamplesPerCycle = pAudioOutputDevice->MaxSamplesPerCycle(); |
this->MaxSamplesPerCycle = pAudioOutputDevice->MaxSamplesPerCycle(); |
254 |
// lower minimum release time |
// lower minimum release time |
255 |
const float minReleaseTime = (float) MaxSamplesPerCycle / (float) SampleRate; |
const float minReleaseTime = (float) MaxSamplesPerCycle / (float) SampleRate; |
256 |
for (RTList<Voice>::Iterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) { |
for (RTList<Voice>::Iterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) { |
257 |
iterVoice->pEG1->CalculateFadeOutCoeff(minReleaseTime, SampleRate); |
iterVoice->EG1.CalculateFadeOutCoeff(minReleaseTime, SampleRate); |
258 |
} |
} |
259 |
pVoicePool->clear(); |
pVoicePool->clear(); |
260 |
} |
} |
266 |
delete this->pDiskThread; |
delete this->pDiskThread; |
267 |
dmsg(1,("OK\n")); |
dmsg(1,("OK\n")); |
268 |
} |
} |
269 |
this->pDiskThread = new DiskThread(((pAudioOut->MaxSamplesPerCycle() << CONFIG_MAX_PITCH) << 1) + 6); //FIXME: assuming stereo |
this->pDiskThread = new DiskThread(((pAudioOut->MaxSamplesPerCycle() << CONFIG_MAX_PITCH) << 1) + 6, //FIXME: assuming stereo |
270 |
|
&instruments); |
271 |
if (!pDiskThread) { |
if (!pDiskThread) { |
272 |
dmsg(0,("gig::Engine new diskthread = NULL\n")); |
dmsg(0,("gig::Engine new diskthread = NULL\n")); |
273 |
exit(EXIT_FAILURE); |
exit(EXIT_FAILURE); |
283 |
if (pEventGenerator) delete pEventGenerator; |
if (pEventGenerator) delete pEventGenerator; |
284 |
pEventGenerator = new EventGenerator(pAudioOut->SampleRate()); |
pEventGenerator = new EventGenerator(pAudioOut->SampleRate()); |
285 |
|
|
|
// (re)allocate synthesis parameter matrix |
|
|
if (pSynthesisParameters[0]) free(pSynthesisParameters[0]); |
|
|
|
|
|
#if defined(__APPLE__) |
|
|
pSynthesisParameters[0] = (float *) malloc(Event::destination_count * sizeof(float) * pAudioOut->MaxSamplesPerCycle()); |
|
|
#else |
|
|
pSynthesisParameters[0] = (float *) memalign(16,(Event::destination_count * sizeof(float) * pAudioOut->MaxSamplesPerCycle())); |
|
|
#endif |
|
|
for (int dst = 1; dst < Event::destination_count; dst++) |
|
|
pSynthesisParameters[dst] = pSynthesisParameters[dst - 1] + pAudioOut->MaxSamplesPerCycle(); |
|
|
|
|
|
// (re)allocate biquad filter parameter sequence |
|
|
if (pBasicFilterParameters) delete[] pBasicFilterParameters; |
|
|
if (pMainFilterParameters) delete[] pMainFilterParameters; |
|
|
pBasicFilterParameters = new biquad_param_t[pAudioOut->MaxSamplesPerCycle()]; |
|
|
pMainFilterParameters = new biquad_param_t[pAudioOut->MaxSamplesPerCycle()]; |
|
|
|
|
286 |
dmsg(1,("Starting disk thread...")); |
dmsg(1,("Starting disk thread...")); |
287 |
pDiskThread->StartThread(); |
pDiskThread->StartThread(); |
288 |
dmsg(1,("OK\n")); |
dmsg(1,("OK\n")); |
316 |
* current audio cycle |
* current audio cycle |
317 |
*/ |
*/ |
318 |
void Engine::ImportEvents(uint Samples) { |
void Engine::ImportEvents(uint Samples) { |
319 |
RingBuffer<Event>::NonVolatileReader eventQueueReader = pEventQueue->get_non_volatile_reader(); |
RingBuffer<Event,false>::NonVolatileReader eventQueueReader = pEventQueue->get_non_volatile_reader(); |
320 |
Event* pEvent; |
Event* pEvent; |
321 |
while (true) { |
while (true) { |
322 |
// get next event from input event queue |
// get next event from input event queue |
339 |
} |
} |
340 |
|
|
341 |
/** |
/** |
342 |
* Let this engine proceed to render the given amount of sample points. The |
* Let this engine proceed to render the given amount of sample points. |
343 |
* calculated audio data of all voices of this engine will be placed into |
* The engine will iterate through all engine channels and render audio |
344 |
* the engine's audio sum buffer which has to be copied and eventually be |
* for each engine channel independently. The calculated audio data of |
345 |
* converted to the appropriate value range by the audio output class (e.g. |
* all voices of each engine channel will be placed into the audio sum |
346 |
* AlsaIO or JackIO) right after. |
* buffers of the respective audio output device, connected to the |
347 |
|
* respective engine channel. |
348 |
* |
* |
349 |
* @param Samples - number of sample points to be rendered |
* @param Samples - number of sample points to be rendered |
350 |
* @returns 0 on success |
* @returns 0 on success |
351 |
*/ |
*/ |
352 |
int Engine::RenderAudio(uint Samples) { |
int Engine::RenderAudio(uint Samples) { |
353 |
dmsg(5,("RenderAudio(Samples=%d)\n", Samples)); |
dmsg(7,("RenderAudio(Samples=%d)\n", Samples)); |
354 |
|
|
355 |
// return if engine disabled |
// return if engine disabled |
356 |
if (EngineDisabled.Pop()) { |
if (EngineDisabled.Pop()) { |
387 |
// reset internal voice counter (just for statistic of active voices) |
// reset internal voice counter (just for statistic of active voices) |
388 |
ActiveVoiceCountTemp = 0; |
ActiveVoiceCountTemp = 0; |
389 |
|
|
390 |
|
// handle instrument change commands |
391 |
|
instrument_change_command_t command; |
392 |
|
if (InstrumentChangeQueue->pop(&command) > 0) { |
393 |
|
EngineChannel* pEngineChannel = command.pEngineChannel; |
394 |
|
pEngineChannel->pInstrument = command.pInstrument; |
395 |
|
|
396 |
|
// iterate through all active voices and mark their |
397 |
|
// dimension regions as "in use". The instrument resource |
398 |
|
// manager may delete all of the instrument except the |
399 |
|
// dimension regions and samples that are in use. |
400 |
|
int i = 0; |
401 |
|
RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first(); |
402 |
|
RTList<uint>::Iterator end = pEngineChannel->pActiveKeys->end(); |
403 |
|
while (iuiKey != end) { // iterate through all active keys |
404 |
|
midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey]; |
405 |
|
++iuiKey; |
406 |
|
|
407 |
|
RTList<Voice>::Iterator itVoice = pKey->pActiveVoices->first(); |
408 |
|
RTList<Voice>::Iterator itVoicesEnd = pKey->pActiveVoices->end(); |
409 |
|
for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key |
410 |
|
if (!itVoice->Orphan) { |
411 |
|
itVoice->Orphan = true; |
412 |
|
pDimRegionsInUse[i++] = itVoice->pDimRgn; |
413 |
|
} |
414 |
|
} |
415 |
|
} |
416 |
|
pDimRegionsInUse[i] = 0; // end of list |
417 |
|
|
418 |
|
// send a reply to the calling thread, which is waiting |
419 |
|
instrument_change_reply_t reply; |
420 |
|
InstrumentChangeReplyQueue->push(&reply); |
421 |
|
} |
422 |
|
|
423 |
// handle events on all engine channels |
// handle events on all engine channels |
424 |
for (int i = 0; i < engineChannels.size(); i++) { |
for (int i = 0; i < engineChannels.size(); i++) { |
|
if (!engineChannels[i]->pInstrument) continue; // ignore if no instrument loaded |
|
425 |
ProcessEvents(engineChannels[i], Samples); |
ProcessEvents(engineChannels[i], Samples); |
426 |
} |
} |
427 |
|
|
428 |
// render all 'normal', active voices on all engine channels |
// render all 'normal', active voices on all engine channels |
429 |
for (int i = 0; i < engineChannels.size(); i++) { |
for (int i = 0; i < engineChannels.size(); i++) { |
|
if (!engineChannels[i]->pInstrument) continue; // ignore if no instrument loaded |
|
430 |
RenderActiveVoices(engineChannels[i], Samples); |
RenderActiveVoices(engineChannels[i], Samples); |
431 |
} |
} |
432 |
|
|
433 |
// now that all ordinary voices on ALL engine channels are rendered, render new stolen voices |
// now that all ordinary voices on ALL engine channels are rendered, render new stolen voices |
434 |
RenderStolenVoices(Samples); |
RenderStolenVoices(Samples); |
435 |
|
|
436 |
|
// handle audio routing for engine channels with FX sends |
437 |
|
for (int i = 0; i < engineChannels.size(); i++) { |
438 |
|
if (engineChannels[i]->fxSends.empty()) continue; // ignore if no FX sends |
439 |
|
RouteAudio(engineChannels[i], Samples); |
440 |
|
} |
441 |
|
|
442 |
// handle cleanup on all engine channels for the next audio fragment |
// handle cleanup on all engine channels for the next audio fragment |
443 |
for (int i = 0; i < engineChannels.size(); i++) { |
for (int i = 0; i < engineChannels.size(); i++) { |
|
if (!engineChannels[i]->pInstrument) continue; // ignore if no instrument loaded |
|
444 |
PostProcess(engineChannels[i]); |
PostProcess(engineChannels[i]); |
445 |
} |
} |
446 |
|
|
518 |
* this audio fragment cycle |
* this audio fragment cycle |
519 |
*/ |
*/ |
520 |
void Engine::RenderActiveVoices(EngineChannel* pEngineChannel, uint Samples) { |
void Engine::RenderActiveVoices(EngineChannel* pEngineChannel, uint Samples) { |
521 |
|
#if !CONFIG_PROCESS_MUTED_CHANNELS |
522 |
if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted |
if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted |
523 |
|
#endif |
524 |
|
|
525 |
RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first(); |
RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first(); |
526 |
RTList<uint>::Iterator end = pEngineChannel->pActiveKeys->end(); |
RTList<uint>::Iterator end = pEngineChannel->pActiveKeys->end(); |
559 |
RTList<Event>::Iterator end = pVoiceStealingQueue->end(); |
RTList<Event>::Iterator end = pVoiceStealingQueue->end(); |
560 |
for (; itVoiceStealEvent != end; ++itVoiceStealEvent) { |
for (; itVoiceStealEvent != end; ++itVoiceStealEvent) { |
561 |
EngineChannel* pEngineChannel = (EngineChannel*) itVoiceStealEvent->pEngineChannel; |
EngineChannel* pEngineChannel = (EngineChannel*) itVoiceStealEvent->pEngineChannel; |
562 |
|
if (!pEngineChannel->pInstrument) continue; // ignore if no instrument loaded |
563 |
Pool<Voice>::Iterator itNewVoice = |
Pool<Voice>::Iterator itNewVoice = |
564 |
LaunchVoice(pEngineChannel, itVoiceStealEvent, itVoiceStealEvent->Param.Note.Layer, itVoiceStealEvent->Param.Note.ReleaseTrigger, false, false); |
LaunchVoice(pEngineChannel, itVoiceStealEvent, itVoiceStealEvent->Param.Note.Layer, itVoiceStealEvent->Param.Note.ReleaseTrigger, false, false); |
565 |
if (itNewVoice) { |
if (itNewVoice) { |
579 |
} |
} |
580 |
|
|
581 |
/** |
/** |
582 |
|
* Will be called in case the respective engine channel sports FX send |
583 |
|
* channels. In this particular case, engine channel local buffers are |
584 |
|
* used to render and mix all voices to. This method is responsible for |
585 |
|
* copying the audio data from those local buffers to the master audio |
586 |
|
* output channels as well as to the FX send audio output channels with |
587 |
|
* their respective FX send levels. |
588 |
|
* |
589 |
|
* @param pEngineChannel - engine channel from which audio should be |
590 |
|
* routed |
591 |
|
* @param Samples - amount of sample points to be routed in |
592 |
|
* this audio fragment cycle |
593 |
|
*/ |
594 |
|
void Engine::RouteAudio(EngineChannel* pEngineChannel, uint Samples) { |
595 |
|
// route master signal |
596 |
|
{ |
597 |
|
AudioChannel* pDstL = pAudioOutputDevice->Channel(pEngineChannel->AudioDeviceChannelLeft); |
598 |
|
AudioChannel* pDstR = pAudioOutputDevice->Channel(pEngineChannel->AudioDeviceChannelRight); |
599 |
|
pEngineChannel->pChannelLeft->MixTo(pDstL, Samples); |
600 |
|
pEngineChannel->pChannelRight->MixTo(pDstR, Samples); |
601 |
|
} |
602 |
|
// route FX send signal |
603 |
|
{ |
604 |
|
for (int iFxSend = 0; iFxSend < pEngineChannel->GetFxSendCount(); iFxSend++) { |
605 |
|
FxSend* pFxSend = pEngineChannel->GetFxSend(iFxSend); |
606 |
|
// left channel |
607 |
|
const int iDstL = pFxSend->DestinationChannel(0); |
608 |
|
if (iDstL < 0) { |
609 |
|
dmsg(1,("Engine::RouteAudio() Error: invalid FX send (L) destination channel")); |
610 |
|
} else { |
611 |
|
AudioChannel* pDstL = pAudioOutputDevice->Channel(iDstL); |
612 |
|
if (!pDstL) { |
613 |
|
dmsg(1,("Engine::RouteAudio() Error: invalid FX send (L) destination channel")); |
614 |
|
} else pEngineChannel->pChannelLeft->MixTo(pDstL, Samples, pFxSend->Level()); |
615 |
|
} |
616 |
|
// right channel |
617 |
|
const int iDstR = pFxSend->DestinationChannel(1); |
618 |
|
if (iDstR < 0) { |
619 |
|
dmsg(1,("Engine::RouteAudio() Error: invalid FX send (R) destination channel")); |
620 |
|
} else { |
621 |
|
AudioChannel* pDstR = pAudioOutputDevice->Channel(iDstR); |
622 |
|
if (!pDstR) { |
623 |
|
dmsg(1,("Engine::RouteAudio() Error: invalid FX send (R) destination channel")); |
624 |
|
} else pEngineChannel->pChannelRight->MixTo(pDstR, Samples, pFxSend->Level()); |
625 |
|
} |
626 |
|
} |
627 |
|
} |
628 |
|
// reset buffers with silence (zero out) for the next audio cycle |
629 |
|
pEngineChannel->pChannelLeft->Clear(); |
630 |
|
pEngineChannel->pChannelRight->Clear(); |
631 |
|
} |
632 |
|
|
633 |
|
/** |
634 |
* Free all keys which have turned inactive in this audio fragment, from |
* Free all keys which have turned inactive in this audio fragment, from |
635 |
* the list of active keys and clear all event lists on that engine |
* the list of active keys and clear all event lists on that engine |
636 |
* channel. |
* channel. |
703 |
* @param itNoteOnEvent - key, velocity and time stamp of the event |
* @param itNoteOnEvent - key, velocity and time stamp of the event |
704 |
*/ |
*/ |
705 |
void Engine::ProcessNoteOn(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) { |
void Engine::ProcessNoteOn(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) { |
706 |
if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted |
#if !CONFIG_PROCESS_MUTED_CHANNELS |
707 |
|
if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted |
708 |
|
#endif |
709 |
|
|
710 |
|
if (!pEngineChannel->pInstrument) return; // ignore if no instrument loaded |
711 |
|
|
712 |
|
//HACK: we should better add the transpose value only to the most mandatory places (like for retrieving the region and calculating the tuning), because otherwise voices will unintendedly survive when changing transpose while playing |
713 |
|
itNoteOnEvent->Param.Note.Key += pEngineChannel->GlobalTranspose; |
714 |
|
|
715 |
const int key = itNoteOnEvent->Param.Note.Key; |
const int key = itNoteOnEvent->Param.Note.Key; |
716 |
|
midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[key]; |
717 |
|
|
718 |
|
// move note on event to the key's own event list |
719 |
|
RTList<Event>::Iterator itNoteOnEventOnKeyList = itNoteOnEvent.moveToEndOf(pKey->pEvents); |
720 |
|
|
721 |
|
// if Solo Mode then kill all already active voices |
722 |
|
if (pEngineChannel->SoloMode) { |
723 |
|
Pool<uint>::Iterator itYoungestKey = pEngineChannel->pActiveKeys->last(); |
724 |
|
if (itYoungestKey) { |
725 |
|
const int iYoungestKey = *itYoungestKey; |
726 |
|
const midi_key_info_t* pOtherKey = &pEngineChannel->pMIDIKeyInfo[iYoungestKey]; |
727 |
|
if (pOtherKey->Active) { |
728 |
|
// get final portamento position of currently active voice |
729 |
|
if (pEngineChannel->PortamentoMode) { |
730 |
|
RTList<Voice>::Iterator itVoice = pOtherKey->pActiveVoices->last(); |
731 |
|
if (itVoice) itVoice->UpdatePortamentoPos(itNoteOnEventOnKeyList); |
732 |
|
} |
733 |
|
// kill all voices on the (other) key |
734 |
|
RTList<Voice>::Iterator itVoiceToBeKilled = pOtherKey->pActiveVoices->first(); |
735 |
|
RTList<Voice>::Iterator end = pOtherKey->pActiveVoices->end(); |
736 |
|
for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) { |
737 |
|
if (itVoiceToBeKilled->Type != Voice::type_release_trigger) |
738 |
|
itVoiceToBeKilled->Kill(itNoteOnEventOnKeyList); |
739 |
|
} |
740 |
|
} |
741 |
|
} |
742 |
|
// set this key as 'currently active solo key' |
743 |
|
pEngineChannel->SoloKey = key; |
744 |
|
} |
745 |
|
|
746 |
// Change key dimension value if key is in keyswitching area |
// Change key dimension value if key is in keyswitching area |
747 |
{ |
{ |
748 |
const ::gig::Instrument* pInstrument = pEngineChannel->pInstrument; |
const ::gig::Instrument* pInstrument = pEngineChannel->pInstrument; |
749 |
if (key >= pInstrument->DimensionKeyRange.low && key <= pInstrument->DimensionKeyRange.high) |
if (key >= pInstrument->DimensionKeyRange.low && key <= pInstrument->DimensionKeyRange.high) |
750 |
pEngineChannel->CurrentKeyDimension = ((key - pInstrument->DimensionKeyRange.low) * 128) / |
pEngineChannel->CurrentKeyDimension = float(key - pInstrument->DimensionKeyRange.low) / |
751 |
(pInstrument->DimensionKeyRange.high - pInstrument->DimensionKeyRange.low + 1); |
(pInstrument->DimensionKeyRange.high - pInstrument->DimensionKeyRange.low + 1); |
752 |
} |
} |
753 |
|
|
|
midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[key]; |
|
|
|
|
754 |
pKey->KeyPressed = true; // the MIDI key was now pressed down |
pKey->KeyPressed = true; // the MIDI key was now pressed down |
755 |
pKey->Velocity = itNoteOnEvent->Param.Note.Velocity; |
pKey->Velocity = itNoteOnEventOnKeyList->Param.Note.Velocity; |
756 |
pKey->NoteOnTime = FrameTime + itNoteOnEvent->FragmentPos(); // will be used to calculate note length |
pKey->NoteOnTime = FrameTime + itNoteOnEventOnKeyList->FragmentPos(); // will be used to calculate note length |
757 |
|
|
758 |
// cancel release process of voices on this key if needed |
// cancel release process of voices on this key if needed |
759 |
if (pKey->Active && !pEngineChannel->SustainPedal) { |
if (pKey->Active && !pEngineChannel->SustainPedal) { |
760 |
RTList<Event>::Iterator itCancelReleaseEvent = pKey->pEvents->allocAppend(); |
RTList<Event>::Iterator itCancelReleaseEvent = pKey->pEvents->allocAppend(); |
761 |
if (itCancelReleaseEvent) { |
if (itCancelReleaseEvent) { |
762 |
*itCancelReleaseEvent = *itNoteOnEvent; // copy event |
*itCancelReleaseEvent = *itNoteOnEventOnKeyList; // copy event |
763 |
itCancelReleaseEvent->Type = Event::type_cancel_release; // transform event type |
itCancelReleaseEvent->Type = Event::type_cancel_release; // transform event type |
764 |
} |
} |
765 |
else dmsg(1,("Event pool emtpy!\n")); |
else dmsg(1,("Event pool emtpy!\n")); |
766 |
} |
} |
767 |
|
|
|
// move note on event to the key's own event list |
|
|
RTList<Event>::Iterator itNoteOnEventOnKeyList = itNoteOnEvent.moveToEndOf(pKey->pEvents); |
|
|
|
|
768 |
// allocate and trigger new voice(s) for the key |
// allocate and trigger new voice(s) for the key |
769 |
{ |
{ |
770 |
// first, get total amount of required voices (dependant on amount of layers) |
// first, get total amount of required voices (dependant on amount of layers) |
781 |
if (!pKey->Active && !pKey->VoiceTheftsQueued) |
if (!pKey->Active && !pKey->VoiceTheftsQueued) |
782 |
pKey->pEvents->free(itNoteOnEventOnKeyList); |
pKey->pEvents->free(itNoteOnEventOnKeyList); |
783 |
|
|
784 |
|
if (!pEngineChannel->SoloMode || pEngineChannel->PortamentoPos < 0.0f) pEngineChannel->PortamentoPos = (float) key; |
785 |
pKey->RoundRobinIndex++; |
pKey->RoundRobinIndex++; |
786 |
} |
} |
787 |
|
|
795 |
* @param itNoteOffEvent - key, velocity and time stamp of the event |
* @param itNoteOffEvent - key, velocity and time stamp of the event |
796 |
*/ |
*/ |
797 |
void Engine::ProcessNoteOff(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOffEvent) { |
void Engine::ProcessNoteOff(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOffEvent) { |
798 |
|
#if !CONFIG_PROCESS_MUTED_CHANNELS |
799 |
if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted |
if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted |
800 |
|
#endif |
801 |
|
|
802 |
midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[itNoteOffEvent->Param.Note.Key]; |
//HACK: we should better add the transpose value only to the most mandatory places (like for retrieving the region and calculating the tuning), because otherwise voices will unintendedly survive when changing transpose while playing |
803 |
|
itNoteOffEvent->Param.Note.Key += pEngineChannel->GlobalTranspose; |
804 |
|
|
805 |
|
const int iKey = itNoteOffEvent->Param.Note.Key; |
806 |
|
midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[iKey]; |
807 |
pKey->KeyPressed = false; // the MIDI key was now released |
pKey->KeyPressed = false; // the MIDI key was now released |
808 |
|
|
809 |
// release voices on this key if needed |
// move event to the key's own event list |
810 |
if (pKey->Active && !pEngineChannel->SustainPedal) { |
RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents); |
811 |
itNoteOffEvent->Type = Event::type_release; // transform event type |
|
812 |
|
bool bShouldRelease = pKey->Active && ShouldReleaseVoice(pEngineChannel, itNoteOffEventOnKeyList->Param.Note.Key); |
813 |
|
|
814 |
|
// in case Solo Mode is enabled, kill all voices on this key and respawn a voice on the highest pressed key (if any) |
815 |
|
if (pEngineChannel->SoloMode && pEngineChannel->pInstrument) { //TODO: this feels like too much code just for handling solo mode :P |
816 |
|
bool bOtherKeysPressed = false; |
817 |
|
if (iKey == pEngineChannel->SoloKey) { |
818 |
|
pEngineChannel->SoloKey = -1; |
819 |
|
// if there's still a key pressed down, respawn a voice (group) on the highest key |
820 |
|
for (int i = 127; i > 0; i--) { |
821 |
|
midi_key_info_t* pOtherKey = &pEngineChannel->pMIDIKeyInfo[i]; |
822 |
|
if (pOtherKey->KeyPressed) { |
823 |
|
bOtherKeysPressed = true; |
824 |
|
// make the other key the new 'currently active solo key' |
825 |
|
pEngineChannel->SoloKey = i; |
826 |
|
// get final portamento position of currently active voice |
827 |
|
if (pEngineChannel->PortamentoMode) { |
828 |
|
RTList<Voice>::Iterator itVoice = pKey->pActiveVoices->first(); |
829 |
|
if (itVoice) itVoice->UpdatePortamentoPos(itNoteOffEventOnKeyList); |
830 |
|
} |
831 |
|
// create a pseudo note on event |
832 |
|
RTList<Event>::Iterator itPseudoNoteOnEvent = pOtherKey->pEvents->allocAppend(); |
833 |
|
if (itPseudoNoteOnEvent) { |
834 |
|
// copy event |
835 |
|
*itPseudoNoteOnEvent = *itNoteOffEventOnKeyList; |
836 |
|
// transform event to a note on event |
837 |
|
itPseudoNoteOnEvent->Type = Event::type_note_on; |
838 |
|
itPseudoNoteOnEvent->Param.Note.Key = i; |
839 |
|
itPseudoNoteOnEvent->Param.Note.Velocity = pOtherKey->Velocity; |
840 |
|
// allocate and trigger new voice(s) for the other key |
841 |
|
{ |
842 |
|
// first, get total amount of required voices (dependant on amount of layers) |
843 |
|
::gig::Region* pRegion = pEngineChannel->pInstrument->GetRegion(i); |
844 |
|
if (pRegion) { |
845 |
|
int voicesRequired = pRegion->Layers; |
846 |
|
// now launch the required amount of voices |
847 |
|
for (int iLayer = 0; iLayer < voicesRequired; iLayer++) |
848 |
|
LaunchVoice(pEngineChannel, itPseudoNoteOnEvent, iLayer, false, true, false); |
849 |
|
} |
850 |
|
} |
851 |
|
// if neither a voice was spawned or postponed then remove note on event from key again |
852 |
|
if (!pOtherKey->Active && !pOtherKey->VoiceTheftsQueued) |
853 |
|
pOtherKey->pEvents->free(itPseudoNoteOnEvent); |
854 |
|
|
855 |
// move event to the key's own event list |
} else dmsg(1,("Could not respawn voice, no free event left\n")); |
856 |
RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents); |
break; // done |
857 |
|
} |
858 |
|
} |
859 |
|
} |
860 |
|
if (bOtherKeysPressed) { |
861 |
|
if (pKey->Active) { // kill all voices on this key |
862 |
|
bShouldRelease = false; // no need to release, as we kill it here |
863 |
|
RTList<Voice>::Iterator itVoiceToBeKilled = pKey->pActiveVoices->first(); |
864 |
|
RTList<Voice>::Iterator end = pKey->pActiveVoices->end(); |
865 |
|
for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) { |
866 |
|
if (itVoiceToBeKilled->Type != Voice::type_release_trigger) |
867 |
|
itVoiceToBeKilled->Kill(itNoteOffEventOnKeyList); |
868 |
|
} |
869 |
|
} |
870 |
|
} else pEngineChannel->PortamentoPos = -1.0f; |
871 |
|
} |
872 |
|
|
873 |
|
// if no solo mode (the usual case) or if solo mode and no other key pressed, then release voices on this key if needed |
874 |
|
if (bShouldRelease) { |
875 |
|
itNoteOffEventOnKeyList->Type = Event::type_release; // transform event type |
876 |
|
|
877 |
// spawn release triggered voice(s) if needed |
// spawn release triggered voice(s) if needed |
878 |
if (pKey->ReleaseTrigger) { |
if (pKey->ReleaseTrigger && pEngineChannel->pInstrument) { |
879 |
// first, get total amount of required voices (dependant on amount of layers) |
// first, get total amount of required voices (dependant on amount of layers) |
880 |
::gig::Region* pRegion = pEngineChannel->pInstrument->GetRegion(itNoteOffEventOnKeyList->Param.Note.Key); |
::gig::Region* pRegion = pEngineChannel->pInstrument->GetRegion(itNoteOffEventOnKeyList->Param.Note.Key); |
881 |
if (pRegion) { |
if (pRegion) { |
890 |
} |
} |
891 |
pKey->ReleaseTrigger = false; |
pKey->ReleaseTrigger = false; |
892 |
} |
} |
|
|
|
|
// if neither a voice was spawned or postponed then remove note off event from key again |
|
|
if (!pKey->Active && !pKey->VoiceTheftsQueued) |
|
|
pKey->pEvents->free(itNoteOffEventOnKeyList); |
|
893 |
} |
} |
894 |
|
|
895 |
|
// if neither a voice was spawned or postponed on this key then remove note off event from key again |
896 |
|
if (!pKey->Active && !pKey->VoiceTheftsQueued) |
897 |
|
pKey->pEvents->free(itNoteOffEventOnKeyList); |
898 |
} |
} |
899 |
|
|
900 |
/** |
/** |
901 |
* Moves pitchbend event from the general (input) event list to the pitch |
* Moves pitchbend event from the general (input) event list to the engine |
902 |
* event list. |
* channel's event list. It will actually processed later by the |
903 |
|
* respective voice. |
904 |
* |
* |
905 |
* @param pEngineChannel - engine channel on which this event occured on |
* @param pEngineChannel - engine channel on which this event occured on |
906 |
* @param itPitchbendEvent - absolute pitch value and time stamp of the event |
* @param itPitchbendEvent - absolute pitch value and time stamp of the event |
907 |
*/ |
*/ |
908 |
void Engine::ProcessPitchbend(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itPitchbendEvent) { |
void Engine::ProcessPitchbend(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itPitchbendEvent) { |
909 |
pEngineChannel->Pitch = itPitchbendEvent->Param.Pitch.Pitch; // store current pitch value |
pEngineChannel->Pitch = itPitchbendEvent->Param.Pitch.Pitch; // store current pitch value |
|
itPitchbendEvent.moveToEndOf(pEngineChannel->pSynthesisEvents[Event::destination_vco]); |
|
910 |
} |
} |
911 |
|
|
912 |
/** |
/** |
978 |
DimValues[i] = itNoteOnEvent->Param.Note.Velocity; |
DimValues[i] = itNoteOnEvent->Param.Note.Velocity; |
979 |
break; |
break; |
980 |
case ::gig::dimension_channelaftertouch: |
case ::gig::dimension_channelaftertouch: |
981 |
DimValues[i] = 0; //TODO: we currently ignore this dimension |
DimValues[i] = pEngineChannel->ControllerTable[128]; |
982 |
break; |
break; |
983 |
case ::gig::dimension_releasetrigger: |
case ::gig::dimension_releasetrigger: |
984 |
VoiceType = (ReleaseTriggerVoice) ? Voice::type_release_trigger : (!iLayer) ? Voice::type_release_trigger_required : Voice::type_normal; |
VoiceType = (ReleaseTriggerVoice) ? Voice::type_release_trigger : (!iLayer) ? Voice::type_release_trigger_required : Voice::type_normal; |
985 |
DimValues[i] = (uint) ReleaseTriggerVoice; |
DimValues[i] = (uint) ReleaseTriggerVoice; |
986 |
break; |
break; |
987 |
case ::gig::dimension_keyboard: |
case ::gig::dimension_keyboard: |
988 |
DimValues[i] = (uint) pEngineChannel->CurrentKeyDimension; |
DimValues[i] = (uint) (pEngineChannel->CurrentKeyDimension * pRegion->pDimensionDefinitions[i].zones); |
989 |
break; |
break; |
990 |
case ::gig::dimension_roundrobin: |
case ::gig::dimension_roundrobin: |
991 |
DimValues[i] = (uint) pEngineChannel->pMIDIKeyInfo[MIDIKey].RoundRobinIndex; // incremented for each note on |
DimValues[i] = (uint) pEngineChannel->pMIDIKeyInfo[MIDIKey].RoundRobinIndex; // incremented for each note on |
1070 |
std::cerr << "gig::Engine::LaunchVoice() Error: Unknown dimension\n" << std::flush; |
std::cerr << "gig::Engine::LaunchVoice() Error: Unknown dimension\n" << std::flush; |
1071 |
} |
} |
1072 |
} |
} |
1073 |
|
|
1074 |
|
// return if this is a release triggered voice and there is no |
1075 |
|
// releasetrigger dimension (could happen if an instrument |
1076 |
|
// change has occured between note on and off) |
1077 |
|
if (ReleaseTriggerVoice && VoiceType != Voice::type_release_trigger) return Pool<Voice>::Iterator(); |
1078 |
|
|
1079 |
::gig::DimensionRegion* pDimRgn = pRegion->GetDimensionRegionByValue(DimValues); |
::gig::DimensionRegion* pDimRgn = pRegion->GetDimensionRegionByValue(DimValues); |
1080 |
|
|
1081 |
// no need to continue if sample is silent |
// no need to continue if sample is silent |
1305 |
|
|
1306 |
uint keygroup = itVoice->KeyGroup; |
uint keygroup = itVoice->KeyGroup; |
1307 |
|
|
1308 |
|
// if the sample and dimension region belong to an |
1309 |
|
// instrument that is unloaded, tell the disk thread to |
1310 |
|
// release them |
1311 |
|
if (itVoice->Orphan) { |
1312 |
|
pDiskThread->OrderDeletionOfDimreg(itVoice->pDimRgn); |
1313 |
|
} |
1314 |
|
|
1315 |
// free the voice object |
// free the voice object |
1316 |
pVoicePool->free(itVoice); |
pVoicePool->free(itVoice); |
1317 |
|
|
1356 |
// update controller value in the engine channel's controller table |
// update controller value in the engine channel's controller table |
1357 |
pEngineChannel->ControllerTable[itControlChangeEvent->Param.CC.Controller] = itControlChangeEvent->Param.CC.Value; |
pEngineChannel->ControllerTable[itControlChangeEvent->Param.CC.Controller] = itControlChangeEvent->Param.CC.Value; |
1358 |
|
|
1359 |
// move event from the unsorted event list to the control change event list |
// handle hard coded MIDI controllers |
1360 |
Pool<Event>::Iterator itControlChangeEventOnCCList = itControlChangeEvent.moveToEndOf(pEngineChannel->pCCEvents); |
switch (itControlChangeEvent->Param.CC.Controller) { |
1361 |
|
case 5: { // portamento time |
1362 |
switch (itControlChangeEventOnCCList->Param.CC.Controller) { |
pEngineChannel->PortamentoTime = (float) itControlChangeEvent->Param.CC.Value / 127.0f * (float) CONFIG_PORTAMENTO_TIME_MAX + (float) CONFIG_PORTAMENTO_TIME_MIN; |
1363 |
|
break; |
1364 |
|
} |
1365 |
|
case 6: { // data entry (currently only used for RPN controllers) |
1366 |
|
if (pEngineChannel->GetMidiRpnController() == 2) { // coarse tuning in half tones |
1367 |
|
int transpose = (int) itControlChangeEvent->Param.CC.Value - 64; |
1368 |
|
// limit to +- two octaves for now |
1369 |
|
transpose = RTMath::Min(transpose, 24); |
1370 |
|
transpose = RTMath::Max(transpose, -24); |
1371 |
|
pEngineChannel->GlobalTranspose = transpose; |
1372 |
|
// workaround, so we won't have hanging notes |
1373 |
|
ReleaseAllVoices(pEngineChannel, itControlChangeEvent); |
1374 |
|
} |
1375 |
|
// to avoid other MIDI CC #6 messages to be misenterpreted as RPN controller data |
1376 |
|
pEngineChannel->ResetMidiRpnController(); |
1377 |
|
break; |
1378 |
|
} |
1379 |
case 7: { // volume |
case 7: { // volume |
1380 |
//TODO: not sample accurate yet |
//TODO: not sample accurate yet |
1381 |
pEngineChannel->GlobalVolume = (float) itControlChangeEventOnCCList->Param.CC.Value / 127.0f; |
pEngineChannel->MidiVolume = VolumeCurve[itControlChangeEvent->Param.CC.Value]; |
1382 |
pEngineChannel->bStatusChanged = true; // engine channel status has changed, so set notify flag |
pEngineChannel->bStatusChanged = true; // engine channel status has changed, so set notify flag |
1383 |
break; |
break; |
1384 |
} |
} |
1385 |
case 10: { // panpot |
case 10: { // panpot |
1386 |
//TODO: not sample accurate yet |
//TODO: not sample accurate yet |
1387 |
const int pan = (int) itControlChangeEventOnCCList->Param.CC.Value - 64; |
pEngineChannel->GlobalPanLeft = PanCurve[128 - itControlChangeEvent->Param.CC.Value]; |
1388 |
pEngineChannel->GlobalPanLeft = 1.0f - float(RTMath::Max(pan, 0)) / 63.0f; |
pEngineChannel->GlobalPanRight = PanCurve[itControlChangeEvent->Param.CC.Value]; |
|
pEngineChannel->GlobalPanRight = 1.0f - float(RTMath::Min(pan, 0)) / -64.0f; |
|
1389 |
break; |
break; |
1390 |
} |
} |
1391 |
case 64: { // sustain |
case 64: { // sustain |
1392 |
if (itControlChangeEventOnCCList->Param.CC.Value >= 64 && !pEngineChannel->SustainPedal) { |
if (itControlChangeEvent->Param.CC.Value >= 64 && !pEngineChannel->SustainPedal) { |
1393 |
dmsg(4,("PEDAL DOWN\n")); |
dmsg(4,("DAMPER (RIGHT) PEDAL DOWN\n")); |
1394 |
pEngineChannel->SustainPedal = true; |
pEngineChannel->SustainPedal = true; |
1395 |
|
|
1396 |
|
#if !CONFIG_PROCESS_MUTED_CHANNELS |
1397 |
if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted |
if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted |
1398 |
|
#endif |
1399 |
|
|
1400 |
// cancel release process of voices if necessary |
// cancel release process of voices if necessary |
1401 |
RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first(); |
RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first(); |
1404 |
if (!pKey->KeyPressed) { |
if (!pKey->KeyPressed) { |
1405 |
RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend(); |
RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend(); |
1406 |
if (itNewEvent) { |
if (itNewEvent) { |
1407 |
*itNewEvent = *itControlChangeEventOnCCList; // copy event to the key's own event list |
*itNewEvent = *itControlChangeEvent; // copy event to the key's own event list |
1408 |
itNewEvent->Type = Event::type_cancel_release; // transform event type |
itNewEvent->Type = Event::type_cancel_release; // transform event type |
1409 |
} |
} |
1410 |
else dmsg(1,("Event pool emtpy!\n")); |
else dmsg(1,("Event pool emtpy!\n")); |
1411 |
} |
} |
1412 |
} |
} |
1413 |
} |
} |
1414 |
if (itControlChangeEventOnCCList->Param.CC.Value < 64 && pEngineChannel->SustainPedal) { |
if (itControlChangeEvent->Param.CC.Value < 64 && pEngineChannel->SustainPedal) { |
1415 |
dmsg(4,("PEDAL UP\n")); |
dmsg(4,("DAMPER (RIGHT) PEDAL UP\n")); |
1416 |
pEngineChannel->SustainPedal = false; |
pEngineChannel->SustainPedal = false; |
1417 |
|
|
1418 |
|
#if !CONFIG_PROCESS_MUTED_CHANNELS |
1419 |
if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted |
if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted |
1420 |
|
#endif |
1421 |
|
|
1422 |
// release voices if their respective key is not pressed |
// release voices if their respective key is not pressed |
1423 |
RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first(); |
RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first(); |
1424 |
for (; iuiKey; ++iuiKey) { |
for (; iuiKey; ++iuiKey) { |
1425 |
midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey]; |
midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey]; |
1426 |
if (!pKey->KeyPressed) { |
if (!pKey->KeyPressed && ShouldReleaseVoice(pEngineChannel, *iuiKey)) { |
1427 |
|
RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend(); |
1428 |
|
if (itNewEvent) { |
1429 |
|
*itNewEvent = *itControlChangeEvent; // copy event to the key's own event list |
1430 |
|
itNewEvent->Type = Event::type_release; // transform event type |
1431 |
|
} |
1432 |
|
else dmsg(1,("Event pool emtpy!\n")); |
1433 |
|
} |
1434 |
|
} |
1435 |
|
} |
1436 |
|
break; |
1437 |
|
} |
1438 |
|
case 65: { // portamento on / off |
1439 |
|
KillAllVoices(pEngineChannel, itControlChangeEvent); |
1440 |
|
pEngineChannel->PortamentoMode = itControlChangeEvent->Param.CC.Value >= 64; |
1441 |
|
break; |
1442 |
|
} |
1443 |
|
case 66: { // sostenuto |
1444 |
|
if (itControlChangeEvent->Param.CC.Value >= 64 && !pEngineChannel->SostenutoPedal) { |
1445 |
|
dmsg(4,("SOSTENUTO (CENTER) PEDAL DOWN\n")); |
1446 |
|
pEngineChannel->SostenutoPedal = true; |
1447 |
|
|
1448 |
|
#if !CONFIG_PROCESS_MUTED_CHANNELS |
1449 |
|
if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted |
1450 |
|
#endif |
1451 |
|
|
1452 |
|
SostenutoKeyCount = 0; |
1453 |
|
// Remeber the pressed keys |
1454 |
|
RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first(); |
1455 |
|
for (; iuiKey; ++iuiKey) { |
1456 |
|
midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey]; |
1457 |
|
if (pKey->KeyPressed && SostenutoKeyCount < 128) SostenutoKeys[SostenutoKeyCount++] = *iuiKey; |
1458 |
|
} |
1459 |
|
} |
1460 |
|
if (itControlChangeEvent->Param.CC.Value < 64 && pEngineChannel->SostenutoPedal) { |
1461 |
|
dmsg(4,("SOSTENUTO (CENTER) PEDAL UP\n")); |
1462 |
|
pEngineChannel->SostenutoPedal = false; |
1463 |
|
|
1464 |
|
#if !CONFIG_PROCESS_MUTED_CHANNELS |
1465 |
|
if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted |
1466 |
|
#endif |
1467 |
|
|
1468 |
|
// release voices if the damper pedal is up and their respective key is not pressed |
1469 |
|
for (int i = 0; i < SostenutoKeyCount; i++) { |
1470 |
|
midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[SostenutoKeys[i]]; |
1471 |
|
if (!pKey->KeyPressed && !pEngineChannel->SustainPedal) { |
1472 |
RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend(); |
RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend(); |
1473 |
if (itNewEvent) { |
if (itNewEvent) { |
1474 |
*itNewEvent = *itControlChangeEventOnCCList; // copy event to the key's own event list |
*itNewEvent = *itControlChangeEvent; // copy event to the key's own event list |
1475 |
itNewEvent->Type = Event::type_release; // transform event type |
itNewEvent->Type = Event::type_release; // transform event type |
1476 |
} |
} |
1477 |
else dmsg(1,("Event pool emtpy!\n")); |
else dmsg(1,("Event pool emtpy!\n")); |
1480 |
} |
} |
1481 |
break; |
break; |
1482 |
} |
} |
1483 |
|
case 100: { // RPN controller LSB |
1484 |
|
pEngineChannel->SetMidiRpnControllerLsb(itControlChangeEvent->Param.CC.Value); |
1485 |
|
break; |
1486 |
|
} |
1487 |
|
case 101: { // RPN controller MSB |
1488 |
|
pEngineChannel->SetMidiRpnControllerMsb(itControlChangeEvent->Param.CC.Value); |
1489 |
|
break; |
1490 |
|
} |
1491 |
|
|
1492 |
|
|
1493 |
// Channel Mode Messages |
// Channel Mode Messages |
1494 |
|
|
1495 |
case 120: { // all sound off |
case 120: { // all sound off |
1496 |
KillAllVoices(pEngineChannel, itControlChangeEventOnCCList); |
KillAllVoices(pEngineChannel, itControlChangeEvent); |
1497 |
break; |
break; |
1498 |
} |
} |
1499 |
case 121: { // reset all controllers |
case 121: { // reset all controllers |
1501 |
break; |
break; |
1502 |
} |
} |
1503 |
case 123: { // all notes off |
case 123: { // all notes off |
1504 |
ReleaseAllVoices(pEngineChannel, itControlChangeEventOnCCList); |
#if CONFIG_PROCESS_ALL_NOTES_OFF |
1505 |
|
ReleaseAllVoices(pEngineChannel, itControlChangeEvent); |
1506 |
|
#endif // CONFIG_PROCESS_ALL_NOTES_OFF |
1507 |
|
break; |
1508 |
|
} |
1509 |
|
case 126: { // mono mode on |
1510 |
|
KillAllVoices(pEngineChannel, itControlChangeEvent); |
1511 |
|
pEngineChannel->SoloMode = true; |
1512 |
|
break; |
1513 |
|
} |
1514 |
|
case 127: { // poly mode on |
1515 |
|
KillAllVoices(pEngineChannel, itControlChangeEvent); |
1516 |
|
pEngineChannel->SoloMode = false; |
1517 |
break; |
break; |
1518 |
} |
} |
1519 |
} |
} |
1520 |
|
|
1521 |
|
// handle FX send controllers |
1522 |
|
if (!pEngineChannel->fxSends.empty()) { |
1523 |
|
for (int iFxSend = 0; iFxSend < pEngineChannel->GetFxSendCount(); iFxSend++) { |
1524 |
|
FxSend* pFxSend = pEngineChannel->GetFxSend(iFxSend); |
1525 |
|
if (pFxSend->MidiController() == itControlChangeEvent->Param.CC.Controller) |
1526 |
|
pFxSend->SetLevel(itControlChangeEvent->Param.CC.Value); |
1527 |
|
} |
1528 |
|
} |
1529 |
} |
} |
1530 |
|
|
1531 |
/** |
/** |
1534 |
* @param itSysexEvent - sysex data size and time stamp of the sysex event |
* @param itSysexEvent - sysex data size and time stamp of the sysex event |
1535 |
*/ |
*/ |
1536 |
void Engine::ProcessSysex(Pool<Event>::Iterator& itSysexEvent) { |
void Engine::ProcessSysex(Pool<Event>::Iterator& itSysexEvent) { |
1537 |
RingBuffer<uint8_t>::NonVolatileReader reader = pSysexBuffer->get_non_volatile_reader(); |
RingBuffer<uint8_t,false>::NonVolatileReader reader = pSysexBuffer->get_non_volatile_reader(); |
1538 |
|
|
1539 |
uint8_t exclusive_status, id; |
uint8_t exclusive_status, id; |
1540 |
if (!reader.pop(&exclusive_status)) goto free_sysex_data; |
if (!reader.pop(&exclusive_status)) goto free_sysex_data; |
1553 |
|
|
1554 |
// command address |
// command address |
1555 |
uint8_t addr[3]; // 2 byte addr MSB, followed by 1 byte addr LSB) |
uint8_t addr[3]; // 2 byte addr MSB, followed by 1 byte addr LSB) |
1556 |
const RingBuffer<uint8_t>::NonVolatileReader checksum_reader = reader; // so we can calculate the check sum later |
const RingBuffer<uint8_t,false>::NonVolatileReader checksum_reader = reader; // so we can calculate the check sum later |
1557 |
if (reader.read(&addr[0], 3) != 3) goto free_sysex_data; |
if (reader.read(&addr[0], 3) != 3) goto free_sysex_data; |
1558 |
if (addr[0] == 0x40 && addr[1] == 0x00) { // System Parameters |
if (addr[0] == 0x40 && addr[1] == 0x00) { // System Parameters |
1559 |
dmsg(3,("\tSystem Parameter\n")); |
dmsg(3,("\tSystem Parameter\n")); |
1600 |
* question |
* question |
1601 |
* @param DataSize - size of the GS message data (in bytes) |
* @param DataSize - size of the GS message data (in bytes) |
1602 |
*/ |
*/ |
1603 |
uint8_t Engine::GSCheckSum(const RingBuffer<uint8_t>::NonVolatileReader AddrReader, uint DataSize) { |
uint8_t Engine::GSCheckSum(const RingBuffer<uint8_t,false>::NonVolatileReader AddrReader, uint DataSize) { |
1604 |
RingBuffer<uint8_t>::NonVolatileReader reader = AddrReader; |
RingBuffer<uint8_t,false>::NonVolatileReader reader = AddrReader; |
1605 |
uint bytes = 3 /*addr*/ + DataSize; |
uint bytes = 3 /*addr*/ + DataSize; |
1606 |
uint8_t addr_and_data[bytes]; |
uint8_t addr_and_data[bytes]; |
1607 |
reader.read(&addr_and_data[0], bytes); |
reader.read(&addr_and_data[0], bytes); |
1666 |
} |
} |
1667 |
|
|
1668 |
/** |
/** |
1669 |
* Initialize the parameter sequence for the modulation destination given by |
* Determines whether the specified voice should be released. |
1670 |
* by 'dst' with the constant value given by val. |
* |
1671 |
*/ |
* @param pEngineChannel - The engine channel on which the voice should be checked |
1672 |
void Engine::ResetSynthesisParameters(Event::destination_t dst, float val) { |
* @param Key - The key number |
1673 |
int maxsamples = pAudioOutputDevice->MaxSamplesPerCycle(); |
* @returns true if the specified should be released, false otherwise. |
1674 |
float* m = &pSynthesisParameters[dst][0]; |
*/ |
1675 |
for (int i = 0; i < maxsamples; i += 4) { |
bool Engine::ShouldReleaseVoice(EngineChannel* pEngineChannel, int Key) { |
1676 |
m[i] = val; |
if (pEngineChannel->SustainPedal) return false; |
1677 |
m[i+1] = val; |
|
1678 |
m[i+2] = val; |
if (pEngineChannel->SostenutoPedal) { |
1679 |
m[i+3] = val; |
for (int i = 0; i < SostenutoKeyCount; i++) |
1680 |
|
if (Key == SostenutoKeys[i]) return false; |
1681 |
} |
} |
1682 |
|
|
1683 |
|
return true; |
1684 |
} |
} |
1685 |
|
|
1686 |
uint Engine::VoiceCount() { |
uint Engine::VoiceCount() { |
1720 |
} |
} |
1721 |
|
|
1722 |
String Engine::Version() { |
String Engine::Version() { |
1723 |
String s = "$Revision: 1.50 $"; |
String s = "$Revision: 1.75 $"; |
1724 |
return s.substr(11, s.size() - 13); // cut dollar signs, spaces and CVS macro keyword |
return s.substr(11, s.size() - 13); // cut dollar signs, spaces and CVS macro keyword |
1725 |
} |
} |
1726 |
|
|
1727 |
|
InstrumentManager* Engine::GetInstrumentManager() { |
1728 |
|
return &instruments; |
1729 |
|
} |
1730 |
|
|
1731 |
|
// static constant initializers |
1732 |
|
const float* Engine::VolumeCurve(InitVolumeCurve()); |
1733 |
|
const float* Engine::PanCurve(InitPanCurve()); |
1734 |
|
const float* Engine::CrossfadeCurve(InitCrossfadeCurve()); |
1735 |
|
|
1736 |
|
float* Engine::InitVolumeCurve() { |
1737 |
|
// line-segment approximation |
1738 |
|
const float segments[] = { |
1739 |
|
0, 0, 2, 0.0046, 16, 0.016, 31, 0.051, 45, 0.115, 54.5, 0.2, |
1740 |
|
64.5, 0.39, 74, 0.74, 92, 1.03, 114, 1.94, 119.2, 2.2, 127, 2.2 |
1741 |
|
}; |
1742 |
|
return InitCurve(segments); |
1743 |
|
} |
1744 |
|
|
1745 |
|
float* Engine::InitPanCurve() { |
1746 |
|
// line-segment approximation |
1747 |
|
const float segments[] = { |
1748 |
|
0, 0, 1, 0, |
1749 |
|
2, 0.05, 31.5, 0.7, 51, 0.851, 74.5, 1.12, |
1750 |
|
127, 1.41, 128, 1.41 |
1751 |
|
}; |
1752 |
|
return InitCurve(segments, 129); |
1753 |
|
} |
1754 |
|
|
1755 |
|
float* Engine::InitCrossfadeCurve() { |
1756 |
|
// line-segment approximation |
1757 |
|
const float segments[] = { |
1758 |
|
0, 0, 1, 0.03, 10, 0.1, 51, 0.58, 127, 1 |
1759 |
|
}; |
1760 |
|
return InitCurve(segments); |
1761 |
|
} |
1762 |
|
|
1763 |
|
float* Engine::InitCurve(const float* segments, int size) { |
1764 |
|
float* y = new float[size]; |
1765 |
|
for (int x = 0 ; x < size ; x++) { |
1766 |
|
if (x > segments[2]) segments += 2; |
1767 |
|
y[x] = segments[1] + (x - segments[0]) * |
1768 |
|
(segments[3] - segments[1]) / (segments[2] - segments[0]); |
1769 |
|
} |
1770 |
|
return y; |
1771 |
|
} |
1772 |
|
|
1773 |
|
/** |
1774 |
|
* Changes the instrument for an engine channel. |
1775 |
|
* |
1776 |
|
* @param pEngineChannel - engine channel on which the instrument |
1777 |
|
* should be changed |
1778 |
|
* @param pInstrument - new instrument |
1779 |
|
* @returns a list of dimension regions from the old instrument |
1780 |
|
* that are still in use |
1781 |
|
*/ |
1782 |
|
::gig::DimensionRegion** Engine::ChangeInstrument(EngineChannel* pEngineChannel, ::gig::Instrument* pInstrument) { |
1783 |
|
instrument_change_command_t command; |
1784 |
|
command.pEngineChannel = pEngineChannel; |
1785 |
|
command.pInstrument = pInstrument; |
1786 |
|
InstrumentChangeQueue->push(&command); |
1787 |
|
|
1788 |
|
// wait for the audio thread to confirm that the instrument |
1789 |
|
// change has been done |
1790 |
|
instrument_change_reply_t reply; |
1791 |
|
while (InstrumentChangeReplyQueue->pop(&reply) == 0) { |
1792 |
|
usleep(10000); |
1793 |
|
} |
1794 |
|
return pDimRegionsInUse; |
1795 |
|
} |
1796 |
|
|
1797 |
}} // namespace LinuxSampler::gig |
}} // namespace LinuxSampler::gig |