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; |
50 |
// check if there's already an engine for the given audio output device |
// check if there's already an engine for the given audio output device |
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"); |
62 |
pEngine->Connect(pDevice); |
pEngine->Connect(pDevice); |
63 |
engines[pDevice] = pEngine; |
engines[pDevice] = pEngine; |
64 |
} |
} |
65 |
// register engine channel to the engine instance |
// register engine channel to the engine instance |
66 |
pEngine->engineChannels.push_back(pChannel); |
pEngine->engineChannels.add(pChannel); |
67 |
|
// remember index in the ArrayList |
68 |
|
pChannel->iEngineIndexSelf = pEngine->engineChannels.size() - 1; |
69 |
dmsg(4,("This gig::Engine has now %d EngineChannels.\n",pEngine->engineChannels.size())); |
dmsg(4,("This gig::Engine has now %d EngineChannels.\n",pEngine->engineChannels.size())); |
70 |
return pEngine; |
return pEngine; |
71 |
} |
} |
95 |
else dmsg(4,("This gig::Engine has now %d EngineChannels.\n",pEngine->engineChannels.size())); |
else dmsg(4,("This gig::Engine has now %d EngineChannels.\n",pEngine->engineChannels.size())); |
96 |
} |
} |
97 |
|
|
98 |
|
/** |
99 |
|
* Constructor |
100 |
|
*/ |
101 |
Engine::Engine() { |
Engine::Engine() { |
102 |
pAudioOutputDevice = NULL; |
pAudioOutputDevice = NULL; |
103 |
pDiskThread = NULL; |
pDiskThread = NULL; |
104 |
pEventGenerator = NULL; |
pEventGenerator = NULL; |
105 |
pSysexBuffer = new RingBuffer<uint8_t>(SYSEX_BUFFER_SIZE, 0); |
pSysexBuffer = new RingBuffer<uint8_t,false>(CONFIG_SYSEX_BUFFER_SIZE, 0); |
106 |
pEventQueue = new RingBuffer<Event>(MAX_EVENTS_PER_FRAGMENT, 0); |
pEventQueue = new RingBuffer<Event,false>(CONFIG_MAX_EVENTS_PER_FRAGMENT, 0); |
107 |
pEventPool = new Pool<Event>(MAX_EVENTS_PER_FRAGMENT); |
pEventPool = new Pool<Event>(CONFIG_MAX_EVENTS_PER_FRAGMENT); |
108 |
pVoicePool = new Pool<Voice>(MAX_AUDIO_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 |
pEvents = new RTList<Event>(pEventPool); |
pGlobalEvents = new RTList<Event>(pEventPool); |
112 |
pCCEvents = new RTList<Event>(pEventPool); |
InstrumentChangeQueue = new RingBuffer<instrument_change_command_t,false>(1, 0); |
113 |
|
InstrumentChangeReplyQueue = new RingBuffer<instrument_change_reply_t,false>(1, 0); |
114 |
for (uint i = 0; i < Event::destination_count; i++) { |
|
|
pSynthesisEvents[i] = new RTList<Event>(pEventPool); |
|
|
} |
|
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(); |
122 |
} |
} |
123 |
|
|
124 |
|
/** |
125 |
|
* 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(); |
132 |
delete pDiskThread; |
delete pDiskThread; |
133 |
dmsg(1,("OK\n")); |
dmsg(1,("OK\n")); |
134 |
} |
} |
|
for (uint i = 0; i < Event::destination_count; i++) { |
|
|
if (pSynthesisEvents[i]) delete pSynthesisEvents[i]; |
|
|
} |
|
|
if (pEvents) delete pEvents; |
|
|
if (pCCEvents) delete pCCEvents; |
|
135 |
if (pEventQueue) delete pEventQueue; |
if (pEventQueue) delete pEventQueue; |
136 |
if (pEventPool) delete pEventPool; |
if (pEventPool) delete pEventPool; |
137 |
if (pVoicePool) { |
if (pVoicePool) { |
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); |
if (pGlobalEvents) delete pGlobalEvents; |
145 |
|
if (InstrumentChangeQueue) delete InstrumentChangeQueue; |
146 |
|
if (InstrumentChangeReplyQueue) delete InstrumentChangeReplyQueue; |
147 |
|
if (pDimRegionsInUse) delete[] pDimRegionsInUse; |
148 |
|
Unregister(); |
149 |
} |
} |
150 |
|
|
151 |
void Engine::Enable() { |
void Engine::Enable() { |
173 |
void Engine::Reset() { |
void Engine::Reset() { |
174 |
DisableAndLock(); |
DisableAndLock(); |
175 |
ResetInternal(); |
ResetInternal(); |
176 |
|
ResetScaleTuning(); |
177 |
Enable(); |
Enable(); |
178 |
} |
} |
179 |
|
|
180 |
/** |
/** |
181 |
* 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 |
182 |
* control and status variables. This method is not thread safe! |
* control and status variables. This method is protected by a mutex. |
183 |
*/ |
*/ |
184 |
void Engine::ResetInternal() { |
void Engine::ResetInternal() { |
185 |
|
ResetInternalMutex.Lock(); |
186 |
|
|
187 |
|
// make sure that the engine does not get any sysex messages |
188 |
|
// while it's reseting |
189 |
|
bool sysexDisabled = MidiInputPort::RemoveSysexListener(this); |
190 |
ActiveVoiceCount = 0; |
ActiveVoiceCount = 0; |
191 |
ActiveVoiceCountMax = 0; |
ActiveVoiceCountMax = 0; |
192 |
|
|
193 |
// reset voice stealing parameters |
// reset voice stealing parameters |
194 |
pVoiceStealingQueue->clear(); |
pVoiceStealingQueue->clear(); |
195 |
|
itLastStolenVoice = RTList<Voice>::Iterator(); |
196 |
// reset to normal chromatic scale (means equal temper) |
itLastStolenVoiceGlobally = RTList<Voice>::Iterator(); |
197 |
memset(&ScaleTuning[0], 0x00, 12); |
iuiLastStolenKey = RTList<uint>::Iterator(); |
198 |
|
iuiLastStolenKeyGlobally = RTList<uint>::Iterator(); |
199 |
|
pLastStolenChannel = NULL; |
200 |
|
|
201 |
// reset all voices |
// reset all voices |
202 |
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()) { |
209 |
|
|
210 |
// delete all input events |
// delete all input events |
211 |
pEventQueue->init(); |
pEventQueue->init(); |
212 |
} |
pSysexBuffer->init(); |
213 |
|
if (sysexDisabled) MidiInputPort::AddSysexListener(this); |
214 |
|
ResetInternalMutex.Unlock(); |
215 |
|
} |
216 |
|
|
217 |
|
/** |
218 |
|
* Reset to normal, chromatic scale (means equal tempered). |
219 |
|
*/ |
220 |
|
void Engine::ResetScaleTuning() { |
221 |
|
memset(&ScaleTuning[0], 0x00, 12); |
222 |
|
} |
223 |
|
|
224 |
|
/** |
225 |
|
* Connect this engine instance with the given audio output device. |
226 |
|
* This method will be called when an Engine instance is created. |
227 |
|
* All of the engine's data structures which are dependant to the used |
228 |
|
* audio output device / driver will be (re)allocated and / or |
229 |
|
* adjusted appropriately. |
230 |
|
* |
231 |
|
* @param pAudioOut - audio output device to connect to |
232 |
|
*/ |
233 |
void Engine::Connect(AudioOutputDevice* pAudioOut) { |
void Engine::Connect(AudioOutputDevice* pAudioOut) { |
234 |
pAudioOutputDevice = pAudioOut; |
pAudioOutputDevice = pAudioOut; |
235 |
|
|
241 |
} |
} |
242 |
catch (AudioOutputException e) { |
catch (AudioOutputException e) { |
243 |
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(); |
244 |
throw LinuxSamplerException(msg); |
throw Exception(msg); |
245 |
} |
} |
246 |
|
|
247 |
this->MaxSamplesPerCycle = pAudioOutputDevice->MaxSamplesPerCycle(); |
this->MaxSamplesPerCycle = pAudioOutputDevice->MaxSamplesPerCycle(); |
248 |
this->SampleRate = pAudioOutputDevice->SampleRate(); |
this->SampleRate = pAudioOutputDevice->SampleRate(); |
249 |
|
|
250 |
// FIXME: audio drivers with varying fragment sizes might be a problem here |
// FIXME: audio drivers with varying fragment sizes might be a problem here |
251 |
MaxFadeOutPos = MaxSamplesPerCycle - int(double(SampleRate) * EG_MIN_RELEASE_TIME) - 1; |
MaxFadeOutPos = MaxSamplesPerCycle - int(double(SampleRate) * CONFIG_EG_MIN_RELEASE_TIME) - 1; |
252 |
if (MaxFadeOutPos < 0) |
if (MaxFadeOutPos < 0) { |
253 |
throw LinuxSamplerException("EG_MIN_RELEASE_TIME in EGADSR.h too big for current audio fragment size / sampling rate!"); |
std::cerr << "gig::Engine: WARNING, CONFIG_EG_MIN_RELEASE_TIME " |
254 |
|
<< "too big for current audio fragment size & sampling rate! " |
255 |
|
<< "May lead to click sounds if voice stealing chimes in!\n" << std::flush; |
256 |
|
// force volume ramp downs at the beginning of each fragment |
257 |
|
MaxFadeOutPos = 0; |
258 |
|
// lower minimum release time |
259 |
|
const float minReleaseTime = (float) MaxSamplesPerCycle / (float) SampleRate; |
260 |
|
for (RTList<Voice>::Iterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) { |
261 |
|
iterVoice->EG1.CalculateFadeOutCoeff(minReleaseTime, SampleRate); |
262 |
|
} |
263 |
|
pVoicePool->clear(); |
264 |
|
} |
265 |
|
|
266 |
// (re)create disk thread |
// (re)create disk thread |
267 |
if (this->pDiskThread) { |
if (this->pDiskThread) { |
270 |
delete this->pDiskThread; |
delete this->pDiskThread; |
271 |
dmsg(1,("OK\n")); |
dmsg(1,("OK\n")); |
272 |
} |
} |
273 |
this->pDiskThread = new DiskThread(((pAudioOut->MaxSamplesPerCycle() << MAX_PITCH) << 1) + 6); //FIXME: assuming stereo |
this->pDiskThread = new DiskThread(((pAudioOut->MaxSamplesPerCycle() << CONFIG_MAX_PITCH) << 1) + 6, //FIXME: assuming stereo |
274 |
|
&instruments); |
275 |
if (!pDiskThread) { |
if (!pDiskThread) { |
276 |
dmsg(0,("gig::Engine new diskthread = NULL\n")); |
dmsg(0,("gig::Engine new diskthread = NULL\n")); |
277 |
exit(EXIT_FAILURE); |
exit(EXIT_FAILURE); |
287 |
if (pEventGenerator) delete pEventGenerator; |
if (pEventGenerator) delete pEventGenerator; |
288 |
pEventGenerator = new EventGenerator(pAudioOut->SampleRate()); |
pEventGenerator = new EventGenerator(pAudioOut->SampleRate()); |
289 |
|
|
|
// (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()]; |
|
|
|
|
290 |
dmsg(1,("Starting disk thread...")); |
dmsg(1,("Starting disk thread...")); |
291 |
pDiskThread->StartThread(); |
pDiskThread->StartThread(); |
292 |
dmsg(1,("OK\n")); |
dmsg(1,("OK\n")); |
299 |
} |
} |
300 |
} |
} |
301 |
|
|
302 |
|
/** |
303 |
|
* Clear all engine global event lists. |
304 |
|
*/ |
305 |
void Engine::ClearEventLists() { |
void Engine::ClearEventLists() { |
306 |
pEvents->clear(); |
pGlobalEvents->clear(); |
|
pCCEvents->clear(); |
|
|
for (uint i = 0; i < Event::destination_count; i++) { |
|
|
pSynthesisEvents[i]->clear(); |
|
|
} |
|
307 |
} |
} |
308 |
|
|
309 |
/** |
/** |
310 |
* Copy all events from the given input queue buffer to the engine's |
* Copy all events from the engine's global input queue buffer to the |
311 |
* internal event list. This will be done at the beginning of each audio |
* engine's internal event list. This will be done at the beginning of |
312 |
* cycle (that is each RenderAudio() call) to get all events which have |
* each audio cycle (that is each RenderAudio() call) to distinguish |
313 |
* to be processed in the current audio cycle. Each EngineChannel has |
* all global events which have to be processed in the current audio |
314 |
* it's own input event queue for the common channel specific events |
* cycle. These events are usually just SysEx messages. Every |
315 |
* (like NoteOn, NoteOff and ControlChange events). Beside that, the |
* EngineChannel has it's own input event queue buffer and event list |
316 |
* engine also has a input event queue for global events (usually SysEx |
* to handle common events like NoteOn, NoteOff and ControlChange |
317 |
* message). |
* events. |
318 |
* |
* |
319 |
* @param pEventQueue - input event buffer to read from |
* @param Samples - number of sample points to be processed in the |
320 |
* @param Samples - number of sample points to be processed in the |
* current audio cycle |
|
* current audio cycle |
|
321 |
*/ |
*/ |
322 |
void Engine::ImportEvents(RingBuffer<Event>* pEventQueue, uint Samples) { |
void Engine::ImportEvents(uint Samples) { |
323 |
RingBuffer<Event>::NonVolatileReader eventQueueReader = pEventQueue->get_non_volatile_reader(); |
RingBuffer<Event,false>::NonVolatileReader eventQueueReader = pEventQueue->get_non_volatile_reader(); |
324 |
Event* pEvent; |
Event* pEvent; |
325 |
while (true) { |
while (true) { |
326 |
// get next event from input event queue |
// get next event from input event queue |
333 |
break; |
break; |
334 |
} |
} |
335 |
// copy event to internal event list |
// copy event to internal event list |
336 |
if (pEvents->poolIsEmpty()) { |
if (pGlobalEvents->poolIsEmpty()) { |
337 |
dmsg(1,("Event pool emtpy!\n")); |
dmsg(1,("Event pool emtpy!\n")); |
338 |
break; |
break; |
339 |
} |
} |
340 |
*pEvents->allocAppend() = *pEvent; |
*pGlobalEvents->allocAppend() = *pEvent; |
341 |
} |
} |
342 |
eventQueueReader.free(); // free all copied events from input queue |
eventQueueReader.free(); // free all copied events from input queue |
343 |
} |
} |
344 |
|
|
345 |
/** |
/** |
346 |
* 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. |
347 |
* calculated audio data of all voices of this engine will be placed into |
* The engine will iterate through all engine channels and render audio |
348 |
* the engine's audio sum buffer which has to be copied and eventually be |
* for each engine channel independently. The calculated audio data of |
349 |
* 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 |
350 |
* AlsaIO or JackIO) right after. |
* buffers of the respective audio output device, connected to the |
351 |
|
* respective engine channel. |
352 |
* |
* |
353 |
* @param Samples - number of sample points to be rendered |
* @param Samples - number of sample points to be rendered |
354 |
* @returns 0 on success |
* @returns 0 on success |
355 |
*/ |
*/ |
356 |
int Engine::RenderAudio(uint Samples) { |
int Engine::RenderAudio(uint Samples) { |
357 |
dmsg(5,("RenderAudio(Samples=%d)\n", Samples)); |
dmsg(7,("RenderAudio(Samples=%d)\n", Samples)); |
358 |
|
|
359 |
// return if engine disabled |
// return if engine disabled |
360 |
if (EngineDisabled.Pop()) { |
if (EngineDisabled.Pop()) { |
365 |
// update time of start and end of this audio fragment (as events' time stamps relate to this) |
// update time of start and end of this audio fragment (as events' time stamps relate to this) |
366 |
pEventGenerator->UpdateFragmentTime(Samples); |
pEventGenerator->UpdateFragmentTime(Samples); |
367 |
|
|
368 |
// empty the engine's event lists for the new fragment |
// We only allow a maximum of CONFIG_MAX_VOICES voices to be spawned |
369 |
ClearEventLists(); |
// in each audio fragment. All subsequent request for spawning new |
370 |
|
// voices in the same audio fragment will be ignored. |
371 |
|
VoiceSpawnsLeft = CONFIG_MAX_VOICES; |
372 |
|
|
373 |
// get all events from the engine's global input event queue which belong to the current fragment |
// get all events from the engine's global input event queue which belong to the current fragment |
374 |
// (these are usually just SysEx messages) |
// (these are usually just SysEx messages) |
375 |
ImportEvents(this->pEventQueue, Samples); |
ImportEvents(Samples); |
376 |
|
|
377 |
// process engine global events (these are currently only MIDI System Exclusive messages) |
// process engine global events (these are currently only MIDI System Exclusive messages) |
378 |
{ |
{ |
379 |
RTList<Event>::Iterator itEvent = pEvents->first(); |
RTList<Event>::Iterator itEvent = pGlobalEvents->first(); |
380 |
RTList<Event>::Iterator end = pEvents->end(); |
RTList<Event>::Iterator end = pGlobalEvents->end(); |
381 |
for (; itEvent != end; ++itEvent) { |
for (; itEvent != end; ++itEvent) { |
382 |
switch (itEvent->Type) { |
switch (itEvent->Type) { |
383 |
case Event::type_sysex: |
case Event::type_sysex: |
391 |
// reset internal voice counter (just for statistic of active voices) |
// reset internal voice counter (just for statistic of active voices) |
392 |
ActiveVoiceCountTemp = 0; |
ActiveVoiceCountTemp = 0; |
393 |
|
|
394 |
// render audio for all engine channels |
// handle instrument change commands |
395 |
// TODO: should we make voice stealing engine globally? unfortunately this would mean other disadvantages so I left voice stealing in the engine channel space for now |
instrument_change_command_t command; |
396 |
{ |
if (InstrumentChangeQueue->pop(&command) > 0) { |
397 |
std::list<EngineChannel*>::iterator itChannel = engineChannels.begin(); |
EngineChannel* pEngineChannel = command.pEngineChannel; |
398 |
std::list<EngineChannel*>::iterator end = engineChannels.end(); |
pEngineChannel->pInstrument = command.pInstrument; |
399 |
for (; itChannel != end; itChannel++) { |
|
400 |
if (!(*itChannel)->pInstrument) continue; // ignore if no instrument loaded |
// iterate through all active voices and mark their |
401 |
RenderAudio(*itChannel, Samples); |
// dimension regions as "in use". The instrument resource |
402 |
|
// manager may delete all of the instrument except the |
403 |
|
// dimension regions and samples that are in use. |
404 |
|
int i = 0; |
405 |
|
RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first(); |
406 |
|
RTList<uint>::Iterator end = pEngineChannel->pActiveKeys->end(); |
407 |
|
while (iuiKey != end) { // iterate through all active keys |
408 |
|
midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey]; |
409 |
|
++iuiKey; |
410 |
|
|
411 |
|
RTList<Voice>::Iterator itVoice = pKey->pActiveVoices->first(); |
412 |
|
RTList<Voice>::Iterator itVoicesEnd = pKey->pActiveVoices->end(); |
413 |
|
for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key |
414 |
|
if (!itVoice->Orphan) { |
415 |
|
itVoice->Orphan = true; |
416 |
|
pDimRegionsInUse[i++] = itVoice->pDimRgn; |
417 |
|
} |
418 |
|
} |
419 |
} |
} |
420 |
|
pDimRegionsInUse[i] = 0; // end of list |
421 |
|
|
422 |
|
// send a reply to the calling thread, which is waiting |
423 |
|
instrument_change_reply_t reply; |
424 |
|
InstrumentChangeReplyQueue->push(&reply); |
425 |
} |
} |
426 |
|
|
427 |
|
// handle events on all engine channels |
428 |
|
for (int i = 0; i < engineChannels.size(); i++) { |
429 |
|
ProcessEvents(engineChannels[i], Samples); |
430 |
|
} |
431 |
|
|
432 |
|
// render all 'normal', active voices on all engine channels |
433 |
|
for (int i = 0; i < engineChannels.size(); i++) { |
434 |
|
RenderActiveVoices(engineChannels[i], Samples); |
435 |
|
} |
436 |
|
|
437 |
|
// now that all ordinary voices on ALL engine channels are rendered, render new stolen voices |
438 |
|
RenderStolenVoices(Samples); |
439 |
|
|
440 |
|
// handle audio routing for engine channels with FX sends |
441 |
|
for (int i = 0; i < engineChannels.size(); i++) { |
442 |
|
if (engineChannels[i]->fxSends.empty()) continue; // ignore if no FX sends |
443 |
|
RouteAudio(engineChannels[i], Samples); |
444 |
|
} |
445 |
|
|
446 |
|
// handle cleanup on all engine channels for the next audio fragment |
447 |
|
for (int i = 0; i < engineChannels.size(); i++) { |
448 |
|
PostProcess(engineChannels[i]); |
449 |
|
} |
450 |
|
|
451 |
|
|
452 |
|
// empty the engine's event list for the next audio fragment |
453 |
|
ClearEventLists(); |
454 |
|
|
455 |
|
// reset voice stealing for the next audio fragment |
456 |
|
pVoiceStealingQueue->clear(); |
457 |
|
|
458 |
// just some statistics about this engine instance |
// just some statistics about this engine instance |
459 |
ActiveVoiceCount = ActiveVoiceCountTemp; |
ActiveVoiceCount = ActiveVoiceCountTemp; |
460 |
if (ActiveVoiceCount > ActiveVoiceCountMax) ActiveVoiceCountMax = ActiveVoiceCount; |
if (ActiveVoiceCount > ActiveVoiceCountMax) ActiveVoiceCountMax = ActiveVoiceCount; |
461 |
|
|
462 |
|
FrameTime += Samples; |
463 |
|
|
464 |
return 0; |
return 0; |
465 |
} |
} |
466 |
|
|
467 |
void Engine::RenderAudio(EngineChannel* pEngineChannel, uint Samples) { |
/** |
468 |
// empty the engine's event lists for the new fragment |
* Dispatch and handle all events in this audio fragment for the given |
469 |
ClearEventLists(); |
* engine channel. |
470 |
// empty the engine channel's, MIDI key specific event lists |
* |
471 |
{ |
* @param pEngineChannel - engine channel on which events should be |
472 |
RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first(); |
* processed |
473 |
RTList<uint>::Iterator end = pEngineChannel->pActiveKeys->end(); |
* @param Samples - amount of sample points to be processed in |
474 |
for(; iuiKey != end; ++iuiKey) { |
* this audio fragment cycle |
475 |
pEngineChannel->pMIDIKeyInfo[*iuiKey].pEvents->clear(); // free all events on the key |
*/ |
476 |
} |
void Engine::ProcessEvents(EngineChannel* pEngineChannel, uint Samples) { |
|
} |
|
|
|
|
|
|
|
477 |
// get all events from the engine channels's input event queue which belong to the current fragment |
// get all events from the engine channels's input event queue which belong to the current fragment |
478 |
// (these are the common events like NoteOn, NoteOff, ControlChange, etc.) |
// (these are the common events like NoteOn, NoteOff, ControlChange, etc.) |
479 |
ImportEvents(pEngineChannel->pEventQueue, Samples); |
pEngineChannel->ImportEvents(Samples); |
|
|
|
480 |
|
|
481 |
// process events |
// process events |
482 |
{ |
{ |
483 |
RTList<Event>::Iterator itEvent = pEvents->first(); |
RTList<Event>::Iterator itEvent = pEngineChannel->pEvents->first(); |
484 |
RTList<Event>::Iterator end = pEvents->end(); |
RTList<Event>::Iterator end = pEngineChannel->pEvents->end(); |
485 |
for (; itEvent != end; ++itEvent) { |
for (; itEvent != end; ++itEvent) { |
486 |
switch (itEvent->Type) { |
switch (itEvent->Type) { |
487 |
case Event::type_note_on: |
case Event::type_note_on: |
504 |
} |
} |
505 |
} |
} |
506 |
|
|
507 |
|
// reset voice stealing for the next engine channel (or next audio fragment) |
508 |
|
itLastStolenVoice = RTList<Voice>::Iterator(); |
509 |
|
itLastStolenVoiceGlobally = RTList<Voice>::Iterator(); |
510 |
|
iuiLastStolenKey = RTList<uint>::Iterator(); |
511 |
|
iuiLastStolenKeyGlobally = RTList<uint>::Iterator(); |
512 |
|
pLastStolenChannel = NULL; |
513 |
|
} |
514 |
|
|
515 |
// render audio from all active voices |
/** |
516 |
{ |
* Render all 'normal' voices (that is voices which were not stolen in |
517 |
RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first(); |
* this fragment) on the given engine channel. |
518 |
RTList<uint>::Iterator end = pEngineChannel->pActiveKeys->end(); |
* |
519 |
while (iuiKey != end) { // iterate through all active keys |
* @param pEngineChannel - engine channel on which audio should be |
520 |
midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey]; |
* rendered |
521 |
++iuiKey; |
* @param Samples - amount of sample points to be rendered in |
522 |
|
* this audio fragment cycle |
523 |
|
*/ |
524 |
|
void Engine::RenderActiveVoices(EngineChannel* pEngineChannel, uint Samples) { |
525 |
|
#if !CONFIG_PROCESS_MUTED_CHANNELS |
526 |
|
if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted |
527 |
|
#endif |
528 |
|
|
529 |
RTList<Voice>::Iterator itVoice = pKey->pActiveVoices->first(); |
RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first(); |
530 |
RTList<Voice>::Iterator itVoicesEnd = pKey->pActiveVoices->end(); |
RTList<uint>::Iterator end = pEngineChannel->pActiveKeys->end(); |
531 |
for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key |
while (iuiKey != end) { // iterate through all active keys |
532 |
// now render current voice |
midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey]; |
533 |
itVoice->Render(Samples); |
++iuiKey; |
534 |
if (itVoice->IsActive()) ActiveVoiceCountTemp++; // still active |
|
535 |
else { // voice reached end, is now inactive |
RTList<Voice>::Iterator itVoice = pKey->pActiveVoices->first(); |
536 |
FreeVoice(pEngineChannel, itVoice); // remove voice from the list of active voices |
RTList<Voice>::Iterator itVoicesEnd = pKey->pActiveVoices->end(); |
537 |
} |
for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key |
538 |
|
// now render current voice |
539 |
|
itVoice->Render(Samples); |
540 |
|
if (itVoice->IsActive()) ActiveVoiceCountTemp++; // still active |
541 |
|
else { // voice reached end, is now inactive |
542 |
|
FreeVoice(pEngineChannel, itVoice); // remove voice from the list of active voices |
543 |
} |
} |
544 |
} |
} |
545 |
} |
} |
546 |
|
} |
547 |
|
|
548 |
|
/** |
549 |
|
* Render all stolen voices (only voices which were stolen in this |
550 |
|
* fragment) on the given engine channel. Stolen voices are rendered |
551 |
|
* after all normal voices have been rendered; this is needed to render |
552 |
|
* audio of those voices which were selected for voice stealing until |
553 |
|
* the point were the stealing (that is the take over of the voice) |
554 |
|
* actually happened. |
555 |
|
* |
556 |
|
* @param pEngineChannel - engine channel on which audio should be |
557 |
|
* rendered |
558 |
|
* @param Samples - amount of sample points to be rendered in |
559 |
|
* this audio fragment cycle |
560 |
|
*/ |
561 |
|
void Engine::RenderStolenVoices(uint Samples) { |
562 |
|
RTList<Event>::Iterator itVoiceStealEvent = pVoiceStealingQueue->first(); |
563 |
|
RTList<Event>::Iterator end = pVoiceStealingQueue->end(); |
564 |
|
for (; itVoiceStealEvent != end; ++itVoiceStealEvent) { |
565 |
|
EngineChannel* pEngineChannel = (EngineChannel*) itVoiceStealEvent->pEngineChannel; |
566 |
|
if (!pEngineChannel->pInstrument) continue; // ignore if no instrument loaded |
567 |
|
Pool<Voice>::Iterator itNewVoice = |
568 |
|
LaunchVoice(pEngineChannel, itVoiceStealEvent, itVoiceStealEvent->Param.Note.Layer, itVoiceStealEvent->Param.Note.ReleaseTrigger, false, false); |
569 |
|
if (itNewVoice) { |
570 |
|
itNewVoice->Render(Samples); |
571 |
|
if (itNewVoice->IsActive()) ActiveVoiceCountTemp++; // still active |
572 |
|
else { // voice reached end, is now inactive |
573 |
|
FreeVoice(pEngineChannel, itNewVoice); // remove voice from the list of active voices |
574 |
|
} |
575 |
|
} |
576 |
|
else dmsg(1,("gig::Engine: ERROR, voice stealing didn't work out!\n")); |
577 |
|
|
578 |
|
// we need to clear the key's event list explicitly here in case key was never active |
579 |
// now render all postponed voices from voice stealing |
midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[itVoiceStealEvent->Param.Note.Key]; |
580 |
|
pKey->VoiceTheftsQueued--; |
581 |
|
if (!pKey->Active && !pKey->VoiceTheftsQueued) pKey->pEvents->clear(); |
582 |
|
} |
583 |
|
} |
584 |
|
|
585 |
|
/** |
586 |
|
* Will be called in case the respective engine channel sports FX send |
587 |
|
* channels. In this particular case, engine channel local buffers are |
588 |
|
* used to render and mix all voices to. This method is responsible for |
589 |
|
* copying the audio data from those local buffers to the master audio |
590 |
|
* output channels as well as to the FX send audio output channels with |
591 |
|
* their respective FX send levels. |
592 |
|
* |
593 |
|
* @param pEngineChannel - engine channel from which audio should be |
594 |
|
* routed |
595 |
|
* @param Samples - amount of sample points to be routed in |
596 |
|
* this audio fragment cycle |
597 |
|
*/ |
598 |
|
void Engine::RouteAudio(EngineChannel* pEngineChannel, uint Samples) { |
599 |
|
// route master signal |
600 |
{ |
{ |
601 |
RTList<Event>::Iterator itVoiceStealEvent = pVoiceStealingQueue->first(); |
AudioChannel* pDstL = pAudioOutputDevice->Channel(pEngineChannel->AudioDeviceChannelLeft); |
602 |
RTList<Event>::Iterator end = pVoiceStealingQueue->end(); |
AudioChannel* pDstR = pAudioOutputDevice->Channel(pEngineChannel->AudioDeviceChannelRight); |
603 |
for (; itVoiceStealEvent != end; ++itVoiceStealEvent) { |
pEngineChannel->pChannelLeft->MixTo(pDstL, Samples); |
604 |
Pool<Voice>::Iterator itNewVoice = |
pEngineChannel->pChannelRight->MixTo(pDstR, Samples); |
605 |
LaunchVoice(pEngineChannel, itVoiceStealEvent, itVoiceStealEvent->Param.Note.Layer, itVoiceStealEvent->Param.Note.ReleaseTrigger, false); |
} |
606 |
if (itNewVoice) { |
// route FX send signal |
607 |
for (; itNewVoice; itNewVoice = itNewVoice->itChildVoice) { |
{ |
608 |
itNewVoice->Render(Samples); |
for (int iFxSend = 0; iFxSend < pEngineChannel->GetFxSendCount(); iFxSend++) { |
609 |
if (itNewVoice->IsActive()) ActiveVoiceCountTemp++; // still active |
FxSend* pFxSend = pEngineChannel->GetFxSend(iFxSend); |
610 |
else { // voice reached end, is now inactive |
// left channel |
611 |
FreeVoice(pEngineChannel, itNewVoice); // remove voice from the list of active voices |
const int iDstL = pFxSend->DestinationChannel(0); |
612 |
} |
if (iDstL < 0) { |
613 |
} |
dmsg(1,("Engine::RouteAudio() Error: invalid FX send (L) destination channel")); |
614 |
|
} else { |
615 |
|
AudioChannel* pDstL = pAudioOutputDevice->Channel(iDstL); |
616 |
|
if (!pDstL) { |
617 |
|
dmsg(1,("Engine::RouteAudio() Error: invalid FX send (L) destination channel")); |
618 |
|
} else pEngineChannel->pChannelLeft->MixTo(pDstL, Samples, pFxSend->Level()); |
619 |
|
} |
620 |
|
// right channel |
621 |
|
const int iDstR = pFxSend->DestinationChannel(1); |
622 |
|
if (iDstR < 0) { |
623 |
|
dmsg(1,("Engine::RouteAudio() Error: invalid FX send (R) destination channel")); |
624 |
|
} else { |
625 |
|
AudioChannel* pDstR = pAudioOutputDevice->Channel(iDstR); |
626 |
|
if (!pDstR) { |
627 |
|
dmsg(1,("Engine::RouteAudio() Error: invalid FX send (R) destination channel")); |
628 |
|
} else pEngineChannel->pChannelRight->MixTo(pDstR, Samples, pFxSend->Level()); |
629 |
} |
} |
|
else dmsg(1,("gig::Engine: ERROR, voice stealing didn't work out!\n")); |
|
630 |
} |
} |
631 |
} |
} |
632 |
// reset voice stealing for the new fragment |
// reset buffers with silence (zero out) for the next audio cycle |
633 |
pVoiceStealingQueue->clear(); |
pEngineChannel->pChannelLeft->Clear(); |
634 |
pEngineChannel->itLastStolenVoice = RTList<Voice>::Iterator(); |
pEngineChannel->pChannelRight->Clear(); |
635 |
pEngineChannel->iuiLastStolenKey = RTList<uint>::Iterator(); |
} |
|
|
|
636 |
|
|
637 |
|
/** |
638 |
|
* Free all keys which have turned inactive in this audio fragment, from |
639 |
|
* the list of active keys and clear all event lists on that engine |
640 |
|
* channel. |
641 |
|
* |
642 |
|
* @param pEngineChannel - engine channel to cleanup |
643 |
|
*/ |
644 |
|
void Engine::PostProcess(EngineChannel* pEngineChannel) { |
645 |
// free all keys which have no active voices left |
// free all keys which have no active voices left |
646 |
{ |
{ |
647 |
RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first(); |
RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first(); |
650 |
midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey]; |
midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey]; |
651 |
++iuiKey; |
++iuiKey; |
652 |
if (pKey->pActiveVoices->isEmpty()) FreeKey(pEngineChannel, pKey); |
if (pKey->pActiveVoices->isEmpty()) FreeKey(pEngineChannel, pKey); |
653 |
#if DEVMODE |
#if CONFIG_DEVMODE |
654 |
else { // FIXME: should be removed before the final release (purpose: just a sanity check for debugging) |
else { // just a sanity check for debugging |
655 |
RTList<Voice>::Iterator itVoice = pKey->pActiveVoices->first(); |
RTList<Voice>::Iterator itVoice = pKey->pActiveVoices->first(); |
656 |
RTList<Voice>::Iterator itVoicesEnd = pKey->pActiveVoices->end(); |
RTList<Voice>::Iterator itVoicesEnd = pKey->pActiveVoices->end(); |
657 |
for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key |
for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key |
660 |
} |
} |
661 |
} |
} |
662 |
} |
} |
663 |
#endif // DEVMODE |
#endif // CONFIG_DEVMODE |
664 |
} |
} |
665 |
} |
} |
666 |
|
|
667 |
|
// empty the engine channel's own event lists |
668 |
|
pEngineChannel->ClearEventLists(); |
669 |
} |
} |
670 |
|
|
671 |
/** |
/** |
695 |
// finally place sysex event into input event queue |
// finally place sysex event into input event queue |
696 |
pEventQueue->push(&event); |
pEventQueue->push(&event); |
697 |
} |
} |
698 |
else dmsg(1,("Engine: Sysex message too large (%d byte) for input buffer (%d byte)!",Size,SYSEX_BUFFER_SIZE)); |
else dmsg(1,("Engine: Sysex message too large (%d byte) for input buffer (%d byte)!",Size,CONFIG_SYSEX_BUFFER_SIZE)); |
699 |
} |
} |
700 |
else dmsg(1,("Engine: Input event queue full!")); |
else dmsg(1,("Engine: Input event queue full!")); |
701 |
} |
} |
707 |
* @param itNoteOnEvent - key, velocity and time stamp of the event |
* @param itNoteOnEvent - key, velocity and time stamp of the event |
708 |
*/ |
*/ |
709 |
void Engine::ProcessNoteOn(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) { |
void Engine::ProcessNoteOn(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) { |
710 |
|
#if !CONFIG_PROCESS_MUTED_CHANNELS |
711 |
|
if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted |
712 |
|
#endif |
713 |
|
|
714 |
|
if (!pEngineChannel->pInstrument) return; // ignore if no instrument loaded |
715 |
|
|
716 |
|
//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 |
717 |
|
itNoteOnEvent->Param.Note.Key += pEngineChannel->GlobalTranspose; |
718 |
|
|
719 |
const int key = itNoteOnEvent->Param.Note.Key; |
const int key = itNoteOnEvent->Param.Note.Key; |
720 |
|
midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[key]; |
721 |
|
|
722 |
|
// move note on event to the key's own event list |
723 |
|
RTList<Event>::Iterator itNoteOnEventOnKeyList = itNoteOnEvent.moveToEndOf(pKey->pEvents); |
724 |
|
|
725 |
|
// if Solo Mode then kill all already active voices |
726 |
|
if (pEngineChannel->SoloMode) { |
727 |
|
Pool<uint>::Iterator itYoungestKey = pEngineChannel->pActiveKeys->last(); |
728 |
|
if (itYoungestKey) { |
729 |
|
const int iYoungestKey = *itYoungestKey; |
730 |
|
const midi_key_info_t* pOtherKey = &pEngineChannel->pMIDIKeyInfo[iYoungestKey]; |
731 |
|
if (pOtherKey->Active) { |
732 |
|
// get final portamento position of currently active voice |
733 |
|
if (pEngineChannel->PortamentoMode) { |
734 |
|
RTList<Voice>::Iterator itVoice = pOtherKey->pActiveVoices->last(); |
735 |
|
if (itVoice) itVoice->UpdatePortamentoPos(itNoteOnEventOnKeyList); |
736 |
|
} |
737 |
|
// kill all voices on the (other) key |
738 |
|
RTList<Voice>::Iterator itVoiceToBeKilled = pOtherKey->pActiveVoices->first(); |
739 |
|
RTList<Voice>::Iterator end = pOtherKey->pActiveVoices->end(); |
740 |
|
for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) { |
741 |
|
if (itVoiceToBeKilled->Type != Voice::type_release_trigger) |
742 |
|
itVoiceToBeKilled->Kill(itNoteOnEventOnKeyList); |
743 |
|
} |
744 |
|
} |
745 |
|
} |
746 |
|
// set this key as 'currently active solo key' |
747 |
|
pEngineChannel->SoloKey = key; |
748 |
|
} |
749 |
|
|
750 |
// Change key dimension value if key is in keyswitching area |
// Change key dimension value if key is in keyswitching area |
751 |
{ |
{ |
752 |
const ::gig::Instrument* pInstrument = pEngineChannel->pInstrument; |
const ::gig::Instrument* pInstrument = pEngineChannel->pInstrument; |
753 |
if (key >= pInstrument->DimensionKeyRange.low && key <= pInstrument->DimensionKeyRange.high) |
if (key >= pInstrument->DimensionKeyRange.low && key <= pInstrument->DimensionKeyRange.high) |
754 |
pEngineChannel->CurrentKeyDimension = ((key - pInstrument->DimensionKeyRange.low) * 128) / |
pEngineChannel->CurrentKeyDimension = float(key - pInstrument->DimensionKeyRange.low) / |
755 |
(pInstrument->DimensionKeyRange.high - pInstrument->DimensionKeyRange.low + 1); |
(pInstrument->DimensionKeyRange.high - pInstrument->DimensionKeyRange.low + 1); |
756 |
} |
} |
757 |
|
|
|
midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[key]; |
|
|
|
|
758 |
pKey->KeyPressed = true; // the MIDI key was now pressed down |
pKey->KeyPressed = true; // the MIDI key was now pressed down |
759 |
|
pKey->Velocity = itNoteOnEventOnKeyList->Param.Note.Velocity; |
760 |
|
pKey->NoteOnTime = FrameTime + itNoteOnEventOnKeyList->FragmentPos(); // will be used to calculate note length |
761 |
|
|
762 |
// cancel release process of voices on this key if needed |
// cancel release process of voices on this key if needed |
763 |
if (pKey->Active && !pEngineChannel->SustainPedal) { |
if (pKey->Active && !pEngineChannel->SustainPedal) { |
764 |
RTList<Event>::Iterator itCancelReleaseEvent = pKey->pEvents->allocAppend(); |
RTList<Event>::Iterator itCancelReleaseEvent = pKey->pEvents->allocAppend(); |
765 |
if (itCancelReleaseEvent) { |
if (itCancelReleaseEvent) { |
766 |
*itCancelReleaseEvent = *itNoteOnEvent; // copy event |
*itCancelReleaseEvent = *itNoteOnEventOnKeyList; // copy event |
767 |
itCancelReleaseEvent->Type = Event::type_cancel_release; // transform event type |
itCancelReleaseEvent->Type = Event::type_cancel_release; // transform event type |
768 |
} |
} |
769 |
else dmsg(1,("Event pool emtpy!\n")); |
else dmsg(1,("Event pool emtpy!\n")); |
770 |
} |
} |
771 |
|
|
772 |
// move note on event to the key's own event list |
// allocate and trigger new voice(s) for the key |
773 |
RTList<Event>::Iterator itNoteOnEventOnKeyList = itNoteOnEvent.moveToEndOf(pKey->pEvents); |
{ |
774 |
|
// first, get total amount of required voices (dependant on amount of layers) |
775 |
|
::gig::Region* pRegion = pEngineChannel->pInstrument->GetRegion(itNoteOnEventOnKeyList->Param.Note.Key); |
776 |
|
if (pRegion) { |
777 |
|
int voicesRequired = pRegion->Layers; |
778 |
|
// now launch the required amount of voices |
779 |
|
for (int i = 0; i < voicesRequired; i++) |
780 |
|
LaunchVoice(pEngineChannel, itNoteOnEventOnKeyList, i, false, true, true); |
781 |
|
} |
782 |
|
} |
783 |
|
|
784 |
|
// if neither a voice was spawned or postponed then remove note on event from key again |
785 |
|
if (!pKey->Active && !pKey->VoiceTheftsQueued) |
786 |
|
pKey->pEvents->free(itNoteOnEventOnKeyList); |
787 |
|
|
788 |
// allocate and trigger a new voice for the key |
if (!pEngineChannel->SoloMode || pEngineChannel->PortamentoPos < 0.0f) pEngineChannel->PortamentoPos = (float) key; |
789 |
LaunchVoice(pEngineChannel, itNoteOnEventOnKeyList, 0, false, true); |
pKey->RoundRobinIndex++; |
790 |
} |
} |
791 |
|
|
792 |
/** |
/** |
799 |
* @param itNoteOffEvent - key, velocity and time stamp of the event |
* @param itNoteOffEvent - key, velocity and time stamp of the event |
800 |
*/ |
*/ |
801 |
void Engine::ProcessNoteOff(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOffEvent) { |
void Engine::ProcessNoteOff(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOffEvent) { |
802 |
midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[itNoteOffEvent->Param.Note.Key]; |
#if !CONFIG_PROCESS_MUTED_CHANNELS |
803 |
|
if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted |
804 |
|
#endif |
805 |
|
|
806 |
pKey->KeyPressed = false; // the MIDI key was now released |
//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 |
807 |
|
itNoteOffEvent->Param.Note.Key += pEngineChannel->GlobalTranspose; |
808 |
|
|
809 |
// release voices on this key if needed |
const int iKey = itNoteOffEvent->Param.Note.Key; |
810 |
if (pKey->Active && !pEngineChannel->SustainPedal) { |
midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[iKey]; |
811 |
itNoteOffEvent->Type = Event::type_release; // transform event type |
pKey->KeyPressed = false; // the MIDI key was now released |
|
} |
|
812 |
|
|
813 |
// move event to the key's own event list |
// move event to the key's own event list |
814 |
RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents); |
RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents); |
815 |
|
|
816 |
// spawn release triggered voice(s) if needed |
bool bShouldRelease = pKey->Active && ShouldReleaseVoice(pEngineChannel, itNoteOffEventOnKeyList->Param.Note.Key); |
817 |
if (pKey->ReleaseTrigger) { |
|
818 |
LaunchVoice(pEngineChannel, itNoteOffEventOnKeyList, 0, true, false); //FIXME: for the moment we don't perform voice stealing for release triggered samples |
// in case Solo Mode is enabled, kill all voices on this key and respawn a voice on the highest pressed key (if any) |
819 |
pKey->ReleaseTrigger = false; |
if (pEngineChannel->SoloMode && pEngineChannel->pInstrument) { //TODO: this feels like too much code just for handling solo mode :P |
820 |
|
bool bOtherKeysPressed = false; |
821 |
|
if (iKey == pEngineChannel->SoloKey) { |
822 |
|
pEngineChannel->SoloKey = -1; |
823 |
|
// if there's still a key pressed down, respawn a voice (group) on the highest key |
824 |
|
for (int i = 127; i > 0; i--) { |
825 |
|
midi_key_info_t* pOtherKey = &pEngineChannel->pMIDIKeyInfo[i]; |
826 |
|
if (pOtherKey->KeyPressed) { |
827 |
|
bOtherKeysPressed = true; |
828 |
|
// make the other key the new 'currently active solo key' |
829 |
|
pEngineChannel->SoloKey = i; |
830 |
|
// get final portamento position of currently active voice |
831 |
|
if (pEngineChannel->PortamentoMode) { |
832 |
|
RTList<Voice>::Iterator itVoice = pKey->pActiveVoices->first(); |
833 |
|
if (itVoice) itVoice->UpdatePortamentoPos(itNoteOffEventOnKeyList); |
834 |
|
} |
835 |
|
// create a pseudo note on event |
836 |
|
RTList<Event>::Iterator itPseudoNoteOnEvent = pOtherKey->pEvents->allocAppend(); |
837 |
|
if (itPseudoNoteOnEvent) { |
838 |
|
// copy event |
839 |
|
*itPseudoNoteOnEvent = *itNoteOffEventOnKeyList; |
840 |
|
// transform event to a note on event |
841 |
|
itPseudoNoteOnEvent->Type = Event::type_note_on; |
842 |
|
itPseudoNoteOnEvent->Param.Note.Key = i; |
843 |
|
itPseudoNoteOnEvent->Param.Note.Velocity = pOtherKey->Velocity; |
844 |
|
// allocate and trigger new voice(s) for the other key |
845 |
|
{ |
846 |
|
// first, get total amount of required voices (dependant on amount of layers) |
847 |
|
::gig::Region* pRegion = pEngineChannel->pInstrument->GetRegion(i); |
848 |
|
if (pRegion) { |
849 |
|
int voicesRequired = pRegion->Layers; |
850 |
|
// now launch the required amount of voices |
851 |
|
for (int iLayer = 0; iLayer < voicesRequired; iLayer++) |
852 |
|
LaunchVoice(pEngineChannel, itPseudoNoteOnEvent, iLayer, false, true, false); |
853 |
|
} |
854 |
|
} |
855 |
|
// if neither a voice was spawned or postponed then remove note on event from key again |
856 |
|
if (!pOtherKey->Active && !pOtherKey->VoiceTheftsQueued) |
857 |
|
pOtherKey->pEvents->free(itPseudoNoteOnEvent); |
858 |
|
|
859 |
|
} else dmsg(1,("Could not respawn voice, no free event left\n")); |
860 |
|
break; // done |
861 |
|
} |
862 |
|
} |
863 |
|
} |
864 |
|
if (bOtherKeysPressed) { |
865 |
|
if (pKey->Active) { // kill all voices on this key |
866 |
|
bShouldRelease = false; // no need to release, as we kill it here |
867 |
|
RTList<Voice>::Iterator itVoiceToBeKilled = pKey->pActiveVoices->first(); |
868 |
|
RTList<Voice>::Iterator end = pKey->pActiveVoices->end(); |
869 |
|
for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) { |
870 |
|
if (itVoiceToBeKilled->Type != Voice::type_release_trigger) |
871 |
|
itVoiceToBeKilled->Kill(itNoteOffEventOnKeyList); |
872 |
|
} |
873 |
|
} |
874 |
|
} else pEngineChannel->PortamentoPos = -1.0f; |
875 |
} |
} |
876 |
|
|
877 |
|
// if no solo mode (the usual case) or if solo mode and no other key pressed, then release voices on this key if needed |
878 |
|
if (bShouldRelease) { |
879 |
|
itNoteOffEventOnKeyList->Type = Event::type_release; // transform event type |
880 |
|
|
881 |
|
// spawn release triggered voice(s) if needed |
882 |
|
if (pKey->ReleaseTrigger && pEngineChannel->pInstrument) { |
883 |
|
// first, get total amount of required voices (dependant on amount of layers) |
884 |
|
::gig::Region* pRegion = pEngineChannel->pInstrument->GetRegion(itNoteOffEventOnKeyList->Param.Note.Key); |
885 |
|
if (pRegion) { |
886 |
|
int voicesRequired = pRegion->Layers; |
887 |
|
|
888 |
|
// MIDI note-on velocity is used instead of note-off velocity |
889 |
|
itNoteOffEventOnKeyList->Param.Note.Velocity = pKey->Velocity; |
890 |
|
|
891 |
|
// now launch the required amount of voices |
892 |
|
for (int i = 0; i < voicesRequired; i++) |
893 |
|
LaunchVoice(pEngineChannel, itNoteOffEventOnKeyList, i, true, false, false); //FIXME: for the moment we don't perform voice stealing for release triggered samples |
894 |
|
} |
895 |
|
pKey->ReleaseTrigger = false; |
896 |
|
} |
897 |
|
} |
898 |
|
|
899 |
|
// if neither a voice was spawned or postponed on this key then remove note off event from key again |
900 |
|
if (!pKey->Active && !pKey->VoiceTheftsQueued) |
901 |
|
pKey->pEvents->free(itNoteOffEventOnKeyList); |
902 |
} |
} |
903 |
|
|
904 |
/** |
/** |
905 |
* Moves pitchbend event from the general (input) event list to the pitch |
* Moves pitchbend event from the general (input) event list to the engine |
906 |
* event list. |
* channel's event list. It will actually processed later by the |
907 |
|
* respective voice. |
908 |
* |
* |
909 |
* @param pEngineChannel - engine channel on which this event occured on |
* @param pEngineChannel - engine channel on which this event occured on |
910 |
* @param itPitchbendEvent - absolute pitch value and time stamp of the event |
* @param itPitchbendEvent - absolute pitch value and time stamp of the event |
911 |
*/ |
*/ |
912 |
void Engine::ProcessPitchbend(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itPitchbendEvent) { |
void Engine::ProcessPitchbend(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itPitchbendEvent) { |
913 |
pEngineChannel->Pitch = itPitchbendEvent->Param.Pitch.Pitch; // store current pitch value |
pEngineChannel->Pitch = itPitchbendEvent->Param.Pitch.Pitch; // store current pitch value |
|
itPitchbendEvent.moveToEndOf(pSynthesisEvents[Event::destination_vco]); |
|
914 |
} |
} |
915 |
|
|
916 |
/** |
/** |
927 |
* @param VoiceStealing - if voice stealing should be performed |
* @param VoiceStealing - if voice stealing should be performed |
928 |
* when there is no free voice |
* when there is no free voice |
929 |
* (optional, default = true) |
* (optional, default = true) |
930 |
|
* @param HandleKeyGroupConflicts - if voices should be killed due to a |
931 |
|
* key group conflict |
932 |
* @returns pointer to new voice or NULL if there was no free voice or |
* @returns pointer to new voice or NULL if there was no free voice or |
933 |
* if the voice wasn't triggered (for example when no region is |
* if the voice wasn't triggered (for example when no region is |
934 |
* defined for the given key). |
* defined for the given key). |
935 |
*/ |
*/ |
936 |
Pool<Voice>::Iterator Engine::LaunchVoice(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent, int iLayer, bool ReleaseTriggerVoice, bool VoiceStealing) { |
Pool<Voice>::Iterator Engine::LaunchVoice(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent, int iLayer, bool ReleaseTriggerVoice, bool VoiceStealing, bool HandleKeyGroupConflicts) { |
937 |
midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[itNoteOnEvent->Param.Note.Key]; |
int MIDIKey = itNoteOnEvent->Param.Note.Key; |
938 |
|
midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[MIDIKey]; |
939 |
|
::gig::Region* pRegion = pEngineChannel->pInstrument->GetRegion(MIDIKey); |
940 |
|
|
941 |
|
// if nothing defined for this key |
942 |
|
if (!pRegion) return Pool<Voice>::Iterator(); // nothing to do |
943 |
|
|
944 |
|
// only mark the first voice of a layered voice (group) to be in a |
945 |
|
// key group, so the layered voices won't kill each other |
946 |
|
int iKeyGroup = (iLayer == 0 && !ReleaseTriggerVoice) ? pRegion->KeyGroup : 0; |
947 |
|
|
948 |
|
// handle key group (a.k.a. exclusive group) conflicts |
949 |
|
if (HandleKeyGroupConflicts) { |
950 |
|
if (iKeyGroup) { // if this voice / key belongs to a key group |
951 |
|
uint** ppKeyGroup = &pEngineChannel->ActiveKeyGroups[iKeyGroup]; |
952 |
|
if (*ppKeyGroup) { // if there's already an active key in that key group |
953 |
|
midi_key_info_t* pOtherKey = &pEngineChannel->pMIDIKeyInfo[**ppKeyGroup]; |
954 |
|
// kill all voices on the (other) key |
955 |
|
RTList<Voice>::Iterator itVoiceToBeKilled = pOtherKey->pActiveVoices->first(); |
956 |
|
RTList<Voice>::Iterator end = pOtherKey->pActiveVoices->end(); |
957 |
|
for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) { |
958 |
|
if (itVoiceToBeKilled->Type != Voice::type_release_trigger) { |
959 |
|
itVoiceToBeKilled->Kill(itNoteOnEvent); |
960 |
|
--VoiceSpawnsLeft; //FIXME: just a hack, we should better check in StealVoice() if the voice was killed due to key conflict |
961 |
|
} |
962 |
|
} |
963 |
|
} |
964 |
|
} |
965 |
|
} |
966 |
|
|
967 |
|
Voice::type_t VoiceType = Voice::type_normal; |
968 |
|
|
969 |
|
// get current dimension values to select the right dimension region |
970 |
|
//TODO: for stolen voices this dimension region selection block is processed twice, this should be changed |
971 |
|
//FIXME: controller values for selecting the dimension region here are currently not sample accurate |
972 |
|
uint DimValues[8] = { 0 }; |
973 |
|
for (int i = pRegion->Dimensions - 1; i >= 0; i--) { |
974 |
|
switch (pRegion->pDimensionDefinitions[i].dimension) { |
975 |
|
case ::gig::dimension_samplechannel: |
976 |
|
DimValues[i] = 0; //TODO: we currently ignore this dimension |
977 |
|
break; |
978 |
|
case ::gig::dimension_layer: |
979 |
|
DimValues[i] = iLayer; |
980 |
|
break; |
981 |
|
case ::gig::dimension_velocity: |
982 |
|
DimValues[i] = itNoteOnEvent->Param.Note.Velocity; |
983 |
|
break; |
984 |
|
case ::gig::dimension_channelaftertouch: |
985 |
|
DimValues[i] = pEngineChannel->ControllerTable[128]; |
986 |
|
break; |
987 |
|
case ::gig::dimension_releasetrigger: |
988 |
|
VoiceType = (ReleaseTriggerVoice) ? Voice::type_release_trigger : (!iLayer) ? Voice::type_release_trigger_required : Voice::type_normal; |
989 |
|
DimValues[i] = (uint) ReleaseTriggerVoice; |
990 |
|
break; |
991 |
|
case ::gig::dimension_keyboard: |
992 |
|
DimValues[i] = (uint) (pEngineChannel->CurrentKeyDimension * pRegion->pDimensionDefinitions[i].zones); |
993 |
|
break; |
994 |
|
case ::gig::dimension_roundrobin: |
995 |
|
DimValues[i] = (uint) pEngineChannel->pMIDIKeyInfo[MIDIKey].RoundRobinIndex; // incremented for each note on |
996 |
|
break; |
997 |
|
case ::gig::dimension_random: |
998 |
|
RandomSeed = RandomSeed * 1103515245 + 12345; // classic pseudo random number generator |
999 |
|
DimValues[i] = (uint) RandomSeed >> (32 - pRegion->pDimensionDefinitions[i].bits); // highest bits are most random |
1000 |
|
break; |
1001 |
|
case ::gig::dimension_modwheel: |
1002 |
|
DimValues[i] = pEngineChannel->ControllerTable[1]; |
1003 |
|
break; |
1004 |
|
case ::gig::dimension_breath: |
1005 |
|
DimValues[i] = pEngineChannel->ControllerTable[2]; |
1006 |
|
break; |
1007 |
|
case ::gig::dimension_foot: |
1008 |
|
DimValues[i] = pEngineChannel->ControllerTable[4]; |
1009 |
|
break; |
1010 |
|
case ::gig::dimension_portamentotime: |
1011 |
|
DimValues[i] = pEngineChannel->ControllerTable[5]; |
1012 |
|
break; |
1013 |
|
case ::gig::dimension_effect1: |
1014 |
|
DimValues[i] = pEngineChannel->ControllerTable[12]; |
1015 |
|
break; |
1016 |
|
case ::gig::dimension_effect2: |
1017 |
|
DimValues[i] = pEngineChannel->ControllerTable[13]; |
1018 |
|
break; |
1019 |
|
case ::gig::dimension_genpurpose1: |
1020 |
|
DimValues[i] = pEngineChannel->ControllerTable[16]; |
1021 |
|
break; |
1022 |
|
case ::gig::dimension_genpurpose2: |
1023 |
|
DimValues[i] = pEngineChannel->ControllerTable[17]; |
1024 |
|
break; |
1025 |
|
case ::gig::dimension_genpurpose3: |
1026 |
|
DimValues[i] = pEngineChannel->ControllerTable[18]; |
1027 |
|
break; |
1028 |
|
case ::gig::dimension_genpurpose4: |
1029 |
|
DimValues[i] = pEngineChannel->ControllerTable[19]; |
1030 |
|
break; |
1031 |
|
case ::gig::dimension_sustainpedal: |
1032 |
|
DimValues[i] = pEngineChannel->ControllerTable[64]; |
1033 |
|
break; |
1034 |
|
case ::gig::dimension_portamento: |
1035 |
|
DimValues[i] = pEngineChannel->ControllerTable[65]; |
1036 |
|
break; |
1037 |
|
case ::gig::dimension_sostenutopedal: |
1038 |
|
DimValues[i] = pEngineChannel->ControllerTable[66]; |
1039 |
|
break; |
1040 |
|
case ::gig::dimension_softpedal: |
1041 |
|
DimValues[i] = pEngineChannel->ControllerTable[67]; |
1042 |
|
break; |
1043 |
|
case ::gig::dimension_genpurpose5: |
1044 |
|
DimValues[i] = pEngineChannel->ControllerTable[80]; |
1045 |
|
break; |
1046 |
|
case ::gig::dimension_genpurpose6: |
1047 |
|
DimValues[i] = pEngineChannel->ControllerTable[81]; |
1048 |
|
break; |
1049 |
|
case ::gig::dimension_genpurpose7: |
1050 |
|
DimValues[i] = pEngineChannel->ControllerTable[82]; |
1051 |
|
break; |
1052 |
|
case ::gig::dimension_genpurpose8: |
1053 |
|
DimValues[i] = pEngineChannel->ControllerTable[83]; |
1054 |
|
break; |
1055 |
|
case ::gig::dimension_effect1depth: |
1056 |
|
DimValues[i] = pEngineChannel->ControllerTable[91]; |
1057 |
|
break; |
1058 |
|
case ::gig::dimension_effect2depth: |
1059 |
|
DimValues[i] = pEngineChannel->ControllerTable[92]; |
1060 |
|
break; |
1061 |
|
case ::gig::dimension_effect3depth: |
1062 |
|
DimValues[i] = pEngineChannel->ControllerTable[93]; |
1063 |
|
break; |
1064 |
|
case ::gig::dimension_effect4depth: |
1065 |
|
DimValues[i] = pEngineChannel->ControllerTable[94]; |
1066 |
|
break; |
1067 |
|
case ::gig::dimension_effect5depth: |
1068 |
|
DimValues[i] = pEngineChannel->ControllerTable[95]; |
1069 |
|
break; |
1070 |
|
case ::gig::dimension_none: |
1071 |
|
std::cerr << "gig::Engine::LaunchVoice() Error: dimension=none\n" << std::flush; |
1072 |
|
break; |
1073 |
|
default: |
1074 |
|
std::cerr << "gig::Engine::LaunchVoice() Error: Unknown dimension\n" << std::flush; |
1075 |
|
} |
1076 |
|
} |
1077 |
|
|
1078 |
|
// return if this is a release triggered voice and there is no |
1079 |
|
// releasetrigger dimension (could happen if an instrument |
1080 |
|
// change has occured between note on and off) |
1081 |
|
if (ReleaseTriggerVoice && VoiceType != Voice::type_release_trigger) return Pool<Voice>::Iterator(); |
1082 |
|
|
1083 |
|
::gig::DimensionRegion* pDimRgn = pRegion->GetDimensionRegionByValue(DimValues); |
1084 |
|
|
1085 |
|
// no need to continue if sample is silent |
1086 |
|
if (!pDimRgn->pSample || !pDimRgn->pSample->SamplesTotal) return Pool<Voice>::Iterator(); |
1087 |
|
|
1088 |
// allocate a new voice for the key |
// allocate a new voice for the key |
1089 |
Pool<Voice>::Iterator itNewVoice = pKey->pActiveVoices->allocAppend(); |
Pool<Voice>::Iterator itNewVoice = pKey->pActiveVoices->allocAppend(); |
1090 |
if (itNewVoice) { |
if (itNewVoice) { |
1091 |
// launch the new voice |
// launch the new voice |
1092 |
if (itNewVoice->Trigger(pEngineChannel, itNoteOnEvent, pEngineChannel->Pitch, pEngineChannel->pInstrument, iLayer, ReleaseTriggerVoice, VoiceStealing) < 0) { |
if (itNewVoice->Trigger(pEngineChannel, itNoteOnEvent, pEngineChannel->Pitch, pDimRgn, VoiceType, iKeyGroup) < 0) { |
1093 |
dmsg(4,("Voice not triggered\n")); |
dmsg(4,("Voice not triggered\n")); |
1094 |
pKey->pActiveVoices->free(itNewVoice); |
pKey->pActiveVoices->free(itNewVoice); |
1095 |
} |
} |
1096 |
else { // on success |
else { // on success |
1097 |
uint** ppKeyGroup = NULL; |
--VoiceSpawnsLeft; |
|
if (itNewVoice->KeyGroup) { // if this voice / key belongs to a key group |
|
|
ppKeyGroup = &pEngineChannel->ActiveKeyGroups[itNewVoice->KeyGroup]; |
|
|
if (*ppKeyGroup) { // if there's already an active key in that key group |
|
|
midi_key_info_t* pOtherKey = &pEngineChannel->pMIDIKeyInfo[**ppKeyGroup]; |
|
|
// kill all voices on the (other) key |
|
|
RTList<Voice>::Iterator itVoiceToBeKilled = pOtherKey->pActiveVoices->first(); |
|
|
RTList<Voice>::Iterator end = pOtherKey->pActiveVoices->end(); |
|
|
for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) { |
|
|
if (itVoiceToBeKilled->Type != Voice::type_release_trigger) itVoiceToBeKilled->Kill(itNoteOnEvent); |
|
|
} |
|
|
} |
|
|
} |
|
1098 |
if (!pKey->Active) { // mark as active key |
if (!pKey->Active) { // mark as active key |
1099 |
pKey->Active = true; |
pKey->Active = true; |
1100 |
pKey->itSelf = pEngineChannel->pActiveKeys->allocAppend(); |
pKey->itSelf = pEngineChannel->pActiveKeys->allocAppend(); |
1101 |
*pKey->itSelf = itNoteOnEvent->Param.Note.Key; |
*pKey->itSelf = itNoteOnEvent->Param.Note.Key; |
1102 |
} |
} |
1103 |
if (itNewVoice->KeyGroup) { |
if (itNewVoice->KeyGroup) { |
1104 |
|
uint** ppKeyGroup = &pEngineChannel->ActiveKeyGroups[itNewVoice->KeyGroup]; |
1105 |
*ppKeyGroup = &*pKey->itSelf; // put key as the (new) active key to its key group |
*ppKeyGroup = &*pKey->itSelf; // put key as the (new) active key to its key group |
1106 |
} |
} |
1107 |
if (itNewVoice->Type == Voice::type_release_trigger_required) pKey->ReleaseTrigger = true; // mark key for the need of release triggered voice(s) |
if (itNewVoice->Type == Voice::type_release_trigger_required) pKey->ReleaseTrigger = true; // mark key for the need of release triggered voice(s) |
1109 |
} |
} |
1110 |
} |
} |
1111 |
else if (VoiceStealing) { |
else if (VoiceStealing) { |
1112 |
// first, get total amount of required voices (dependant on amount of layers) |
// try to steal one voice |
1113 |
::gig::Region* pRegion = pEngineChannel->pInstrument->GetRegion(itNoteOnEvent->Param.Note.Key); |
int result = StealVoice(pEngineChannel, itNoteOnEvent); |
1114 |
if (!pRegion) return Pool<Voice>::Iterator(); // nothing defined for this MIDI key, so no voice needed |
if (!result) { // voice stolen successfully |
1115 |
int voicesRequired = pRegion->Layers; |
// put note-on event into voice-stealing queue, so it will be reprocessed after killed voice died |
1116 |
|
RTList<Event>::Iterator itStealEvent = pVoiceStealingQueue->allocAppend(); |
1117 |
// now steal the (remaining) amount of voices |
if (itStealEvent) { |
1118 |
for (int i = iLayer; i < voicesRequired; i++) |
*itStealEvent = *itNoteOnEvent; // copy event |
1119 |
StealVoice(pEngineChannel, itNoteOnEvent); |
itStealEvent->Param.Note.Layer = iLayer; |
1120 |
|
itStealEvent->Param.Note.ReleaseTrigger = ReleaseTriggerVoice; |
1121 |
// put note-on event into voice-stealing queue, so it will be reprocessed after killed voice died |
pKey->VoiceTheftsQueued++; |
1122 |
RTList<Event>::Iterator itStealEvent = pVoiceStealingQueue->allocAppend(); |
} |
1123 |
if (itStealEvent) { |
else dmsg(1,("Voice stealing queue full!\n")); |
|
*itStealEvent = *itNoteOnEvent; // copy event |
|
|
itStealEvent->Param.Note.Layer = iLayer; |
|
|
itStealEvent->Param.Note.ReleaseTrigger = ReleaseTriggerVoice; |
|
1124 |
} |
} |
|
else dmsg(1,("Voice stealing queue full!\n")); |
|
1125 |
} |
} |
1126 |
|
|
1127 |
return Pool<Voice>::Iterator(); // no free voice or error |
return Pool<Voice>::Iterator(); // no free voice or error |
1135 |
* |
* |
1136 |
* @param pEngineChannel - engine channel on which this event occured on |
* @param pEngineChannel - engine channel on which this event occured on |
1137 |
* @param itNoteOnEvent - key, velocity and time stamp of the event |
* @param itNoteOnEvent - key, velocity and time stamp of the event |
1138 |
|
* @returns 0 on success, a value < 0 if no active voice could be picked for voice stealing |
1139 |
*/ |
*/ |
1140 |
void Engine::StealVoice(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) { |
int Engine::StealVoice(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) { |
1141 |
|
if (VoiceSpawnsLeft <= 0) { |
1142 |
|
dmsg(1,("Max. voice thefts per audio fragment reached (you may raise CONFIG_MAX_VOICES).\n")); |
1143 |
|
return -1; |
1144 |
|
} |
1145 |
if (!pEventPool->poolIsEmpty()) { |
if (!pEventPool->poolIsEmpty()) { |
1146 |
|
|
1147 |
RTList<uint>::Iterator iuiOldestKey; |
RTList<Voice>::Iterator itSelectedVoice; |
|
RTList<Voice>::Iterator itOldestVoice; |
|
1148 |
|
|
1149 |
// Select one voice for voice stealing |
// Select one voice for voice stealing |
1150 |
switch (VOICE_STEAL_ALGORITHM) { |
switch (CONFIG_VOICE_STEAL_ALGO) { |
1151 |
|
|
1152 |
// try to pick the oldest voice on the key where the new |
// try to pick the oldest voice on the key where the new |
1153 |
// voice should be spawned, if there is no voice on that |
// voice should be spawned, if there is no voice on that |
1154 |
// key, or no voice left to kill there, then procceed with |
// key, or no voice left to kill, then procceed with |
1155 |
// 'oldestkey' algorithm |
// 'oldestkey' algorithm |
1156 |
case voice_steal_algo_keymask: { |
case voice_steal_algo_oldestvoiceonkey: { |
1157 |
midi_key_info_t* pOldestKey = &pEngineChannel->pMIDIKeyInfo[itNoteOnEvent->Param.Note.Key]; |
midi_key_info_t* pSelectedKey = &pEngineChannel->pMIDIKeyInfo[itNoteOnEvent->Param.Note.Key]; |
1158 |
if (pEngineChannel->itLastStolenVoice) { |
itSelectedVoice = pSelectedKey->pActiveVoices->first(); |
1159 |
itOldestVoice = pEngineChannel->itLastStolenVoice; |
// proceed iterating if voice was created in this fragment cycle |
1160 |
++itOldestVoice; |
while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice; |
1161 |
} |
// if we haven't found a voice then proceed with algorithm 'oldestkey' |
1162 |
else { // no voice stolen in this audio fragment cycle yet |
if (itSelectedVoice && itSelectedVoice->IsStealable()) break; |
|
itOldestVoice = pOldestKey->pActiveVoices->first(); |
|
|
} |
|
|
if (itOldestVoice) { |
|
|
iuiOldestKey = pOldestKey->itSelf; |
|
|
break; // selection succeeded |
|
|
} |
|
1163 |
} // no break - intentional ! |
} // no break - intentional ! |
1164 |
|
|
1165 |
// try to pick the oldest voice on the oldest active key |
// try to pick the oldest voice on the oldest active key |
1166 |
// (caution: must stay after 'keymask' algorithm !) |
// from the same engine channel |
1167 |
|
// (caution: must stay after 'oldestvoiceonkey' algorithm !) |
1168 |
case voice_steal_algo_oldestkey: { |
case voice_steal_algo_oldestkey: { |
1169 |
if (pEngineChannel->itLastStolenVoice) { |
// if we already stole in this fragment, try to proceed on same key |
1170 |
midi_key_info_t* pOldestKey = &pEngineChannel->pMIDIKeyInfo[*pEngineChannel->iuiLastStolenKey]; |
if (this->itLastStolenVoice) { |
1171 |
itOldestVoice = pEngineChannel->itLastStolenVoice; |
itSelectedVoice = this->itLastStolenVoice; |
1172 |
++itOldestVoice; |
do { |
1173 |
if (!itOldestVoice) { |
++itSelectedVoice; |
1174 |
iuiOldestKey = pEngineChannel->iuiLastStolenKey; |
} while (itSelectedVoice && !itSelectedVoice->IsStealable()); // proceed iterating if voice was created in this fragment cycle |
1175 |
++iuiOldestKey; |
// found a "stealable" voice ? |
1176 |
if (iuiOldestKey) { |
if (itSelectedVoice && itSelectedVoice->IsStealable()) { |
1177 |
midi_key_info_t* pOldestKey = &pEngineChannel->pMIDIKeyInfo[*iuiOldestKey]; |
// remember which voice we stole, so we can simply proceed on next voice stealing |
1178 |
itOldestVoice = pOldestKey->pActiveVoices->first(); |
this->itLastStolenVoice = itSelectedVoice; |
1179 |
} |
break; // selection succeeded |
|
else { |
|
|
dmsg(1,("gig::Engine: Warning, too less voices, even for voice stealing! - Better recompile with higher MAX_AUDIO_VOICES.\n")); |
|
|
return; |
|
|
} |
|
1180 |
} |
} |
|
else iuiOldestKey = pEngineChannel->iuiLastStolenKey; |
|
1181 |
} |
} |
1182 |
else { // no voice stolen in this audio fragment cycle yet |
// get (next) oldest key |
1183 |
iuiOldestKey = pEngineChannel->pActiveKeys->first(); |
RTList<uint>::Iterator iuiSelectedKey = (this->iuiLastStolenKey) ? ++this->iuiLastStolenKey : pEngineChannel->pActiveKeys->first(); |
1184 |
midi_key_info_t* pOldestKey = &pEngineChannel->pMIDIKeyInfo[*iuiOldestKey]; |
while (iuiSelectedKey) { |
1185 |
itOldestVoice = pOldestKey->pActiveVoices->first(); |
midi_key_info_t* pSelectedKey = &pEngineChannel->pMIDIKeyInfo[*iuiSelectedKey]; |
1186 |
|
itSelectedVoice = pSelectedKey->pActiveVoices->first(); |
1187 |
|
// proceed iterating if voice was created in this fragment cycle |
1188 |
|
while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice; |
1189 |
|
// found a "stealable" voice ? |
1190 |
|
if (itSelectedVoice && itSelectedVoice->IsStealable()) { |
1191 |
|
// remember which voice on which key we stole, so we can simply proceed on next voice stealing |
1192 |
|
this->iuiLastStolenKey = iuiSelectedKey; |
1193 |
|
this->itLastStolenVoice = itSelectedVoice; |
1194 |
|
break; // selection succeeded |
1195 |
|
} |
1196 |
|
++iuiSelectedKey; // get next oldest key |
1197 |
} |
} |
1198 |
break; |
break; |
1199 |
} |
} |
1202 |
case voice_steal_algo_none: |
case voice_steal_algo_none: |
1203 |
default: { |
default: { |
1204 |
dmsg(1,("No free voice (voice stealing disabled)!\n")); |
dmsg(1,("No free voice (voice stealing disabled)!\n")); |
1205 |
return; |
return -1; |
1206 |
} |
} |
1207 |
} |
} |
1208 |
|
|
1209 |
//FIXME: can be removed, just a sanity check for debugging |
// if we couldn't steal a voice from the same engine channel then |
1210 |
if (!itOldestVoice->IsActive()) dmsg(1,("gig::Engine: ERROR, tried to steal a voice which was not active !!!\n")); |
// steal oldest voice on the oldest key from any other engine channel |
1211 |
|
// (the smaller engine channel number, the higher priority) |
1212 |
|
if (!itSelectedVoice || !itSelectedVoice->IsStealable()) { |
1213 |
|
EngineChannel* pSelectedChannel; |
1214 |
|
int iChannelIndex; |
1215 |
|
// select engine channel |
1216 |
|
if (pLastStolenChannel) { |
1217 |
|
pSelectedChannel = pLastStolenChannel; |
1218 |
|
iChannelIndex = pSelectedChannel->iEngineIndexSelf; |
1219 |
|
} else { // pick the engine channel followed by this engine channel |
1220 |
|
iChannelIndex = (pEngineChannel->iEngineIndexSelf + 1) % engineChannels.size(); |
1221 |
|
pSelectedChannel = engineChannels[iChannelIndex]; |
1222 |
|
} |
1223 |
|
|
1224 |
|
// if we already stole in this fragment, try to proceed on same key |
1225 |
|
if (this->itLastStolenVoiceGlobally) { |
1226 |
|
itSelectedVoice = this->itLastStolenVoiceGlobally; |
1227 |
|
do { |
1228 |
|
++itSelectedVoice; |
1229 |
|
} while (itSelectedVoice && !itSelectedVoice->IsStealable()); // proceed iterating if voice was created in this fragment cycle |
1230 |
|
} |
1231 |
|
|
1232 |
|
#if CONFIG_DEVMODE |
1233 |
|
EngineChannel* pBegin = pSelectedChannel; // to detect endless loop |
1234 |
|
#endif // CONFIG_DEVMODE |
1235 |
|
|
1236 |
|
// did we find a 'stealable' voice? |
1237 |
|
if (itSelectedVoice && itSelectedVoice->IsStealable()) { |
1238 |
|
// remember which voice we stole, so we can simply proceed on next voice stealing |
1239 |
|
this->itLastStolenVoiceGlobally = itSelectedVoice; |
1240 |
|
} else while (true) { // iterate through engine channels |
1241 |
|
// get (next) oldest key |
1242 |
|
RTList<uint>::Iterator iuiSelectedKey = (this->iuiLastStolenKeyGlobally) ? ++this->iuiLastStolenKeyGlobally : pSelectedChannel->pActiveKeys->first(); |
1243 |
|
this->iuiLastStolenKeyGlobally = RTList<uint>::Iterator(); // to prevent endless loop (see line above) |
1244 |
|
while (iuiSelectedKey) { |
1245 |
|
midi_key_info_t* pSelectedKey = &pSelectedChannel->pMIDIKeyInfo[*iuiSelectedKey]; |
1246 |
|
itSelectedVoice = pSelectedKey->pActiveVoices->first(); |
1247 |
|
// proceed iterating if voice was created in this fragment cycle |
1248 |
|
while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice; |
1249 |
|
// found a "stealable" voice ? |
1250 |
|
if (itSelectedVoice && itSelectedVoice->IsStealable()) { |
1251 |
|
// remember which voice on which key on which engine channel we stole, so we can simply proceed on next voice stealing |
1252 |
|
this->iuiLastStolenKeyGlobally = iuiSelectedKey; |
1253 |
|
this->itLastStolenVoiceGlobally = itSelectedVoice; |
1254 |
|
this->pLastStolenChannel = pSelectedChannel; |
1255 |
|
goto stealable_voice_found; // selection succeeded |
1256 |
|
} |
1257 |
|
++iuiSelectedKey; // get next key on current engine channel |
1258 |
|
} |
1259 |
|
// get next engine channel |
1260 |
|
iChannelIndex = (iChannelIndex + 1) % engineChannels.size(); |
1261 |
|
pSelectedChannel = engineChannels[iChannelIndex]; |
1262 |
|
|
1263 |
|
#if CONFIG_DEVMODE |
1264 |
|
if (pSelectedChannel == pBegin) { |
1265 |
|
dmsg(1,("FATAL ERROR: voice stealing endless loop!\n")); |
1266 |
|
dmsg(1,("VoiceSpawnsLeft=%d.\n", VoiceSpawnsLeft)); |
1267 |
|
dmsg(1,("Exiting.\n")); |
1268 |
|
exit(-1); |
1269 |
|
} |
1270 |
|
#endif // CONFIG_DEVMODE |
1271 |
|
} |
1272 |
|
} |
1273 |
|
|
1274 |
|
// jump point if a 'stealable' voice was found |
1275 |
|
stealable_voice_found: |
1276 |
|
|
1277 |
|
#if CONFIG_DEVMODE |
1278 |
|
if (!itSelectedVoice->IsActive()) { |
1279 |
|
dmsg(1,("gig::Engine: ERROR, tried to steal a voice which was not active !!!\n")); |
1280 |
|
return -1; |
1281 |
|
} |
1282 |
|
#endif // CONFIG_DEVMODE |
1283 |
|
|
1284 |
// now kill the selected voice |
// now kill the selected voice |
1285 |
itOldestVoice->Kill(itNoteOnEvent); |
itSelectedVoice->Kill(itNoteOnEvent); |
1286 |
// remember which voice on which key we stole, so we can simply proceed for the next voice stealing |
|
1287 |
pEngineChannel->itLastStolenVoice = itOldestVoice; |
--VoiceSpawnsLeft; |
1288 |
pEngineChannel->iuiLastStolenKey = iuiOldestKey; |
|
1289 |
|
return 0; // success |
1290 |
|
} |
1291 |
|
else { |
1292 |
|
dmsg(1,("Event pool emtpy!\n")); |
1293 |
|
return -1; |
1294 |
} |
} |
|
else dmsg(1,("Event pool emtpy!\n")); |
|
1295 |
} |
} |
1296 |
|
|
1297 |
/** |
/** |
1309 |
|
|
1310 |
uint keygroup = itVoice->KeyGroup; |
uint keygroup = itVoice->KeyGroup; |
1311 |
|
|
1312 |
|
// if the sample and dimension region belong to an |
1313 |
|
// instrument that is unloaded, tell the disk thread to |
1314 |
|
// release them |
1315 |
|
if (itVoice->Orphan) { |
1316 |
|
pDiskThread->OrderDeletionOfDimreg(itVoice->pDimRgn); |
1317 |
|
} |
1318 |
|
|
1319 |
// free the voice object |
// free the voice object |
1320 |
pVoicePool->free(itVoice); |
pVoicePool->free(itVoice); |
1321 |
|
|
1357 |
void Engine::ProcessControlChange(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itControlChangeEvent) { |
void Engine::ProcessControlChange(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itControlChangeEvent) { |
1358 |
dmsg(4,("Engine::ContinuousController cc=%d v=%d\n", itControlChangeEvent->Param.CC.Controller, itControlChangeEvent->Param.CC.Value)); |
dmsg(4,("Engine::ContinuousController cc=%d v=%d\n", itControlChangeEvent->Param.CC.Controller, itControlChangeEvent->Param.CC.Value)); |
1359 |
|
|
1360 |
|
// update controller value in the engine channel's controller table |
1361 |
|
pEngineChannel->ControllerTable[itControlChangeEvent->Param.CC.Controller] = itControlChangeEvent->Param.CC.Value; |
1362 |
|
|
1363 |
|
// handle hard coded MIDI controllers |
1364 |
switch (itControlChangeEvent->Param.CC.Controller) { |
switch (itControlChangeEvent->Param.CC.Controller) { |
1365 |
case 64: { |
case 5: { // portamento time |
1366 |
|
pEngineChannel->PortamentoTime = (float) itControlChangeEvent->Param.CC.Value / 127.0f * (float) CONFIG_PORTAMENTO_TIME_MAX + (float) CONFIG_PORTAMENTO_TIME_MIN; |
1367 |
|
break; |
1368 |
|
} |
1369 |
|
case 6: { // data entry (currently only used for RPN controllers) |
1370 |
|
if (pEngineChannel->GetMidiRpnController() == 2) { // coarse tuning in half tones |
1371 |
|
int transpose = (int) itControlChangeEvent->Param.CC.Value - 64; |
1372 |
|
// limit to +- two octaves for now |
1373 |
|
transpose = RTMath::Min(transpose, 24); |
1374 |
|
transpose = RTMath::Max(transpose, -24); |
1375 |
|
pEngineChannel->GlobalTranspose = transpose; |
1376 |
|
// workaround, so we won't have hanging notes |
1377 |
|
ReleaseAllVoices(pEngineChannel, itControlChangeEvent); |
1378 |
|
} |
1379 |
|
// to avoid other MIDI CC #6 messages to be misenterpreted as RPN controller data |
1380 |
|
pEngineChannel->ResetMidiRpnController(); |
1381 |
|
break; |
1382 |
|
} |
1383 |
|
case 7: { // volume |
1384 |
|
//TODO: not sample accurate yet |
1385 |
|
pEngineChannel->MidiVolume = VolumeCurve[itControlChangeEvent->Param.CC.Value]; |
1386 |
|
pEngineChannel->bStatusChanged = true; // engine channel status has changed, so set notify flag |
1387 |
|
break; |
1388 |
|
} |
1389 |
|
case 10: { // panpot |
1390 |
|
//TODO: not sample accurate yet |
1391 |
|
pEngineChannel->GlobalPanLeft = PanCurve[128 - itControlChangeEvent->Param.CC.Value]; |
1392 |
|
pEngineChannel->GlobalPanRight = PanCurve[itControlChangeEvent->Param.CC.Value]; |
1393 |
|
break; |
1394 |
|
} |
1395 |
|
case 64: { // sustain |
1396 |
if (itControlChangeEvent->Param.CC.Value >= 64 && !pEngineChannel->SustainPedal) { |
if (itControlChangeEvent->Param.CC.Value >= 64 && !pEngineChannel->SustainPedal) { |
1397 |
dmsg(4,("PEDAL DOWN\n")); |
dmsg(4,("DAMPER (RIGHT) PEDAL DOWN\n")); |
1398 |
pEngineChannel->SustainPedal = true; |
pEngineChannel->SustainPedal = true; |
1399 |
|
|
1400 |
|
#if !CONFIG_PROCESS_MUTED_CHANNELS |
1401 |
|
if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted |
1402 |
|
#endif |
1403 |
|
|
1404 |
// cancel release process of voices if necessary |
// cancel release process of voices if necessary |
1405 |
RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first(); |
RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first(); |
1406 |
if (iuiKey) { |
for (; iuiKey; ++iuiKey) { |
1407 |
itControlChangeEvent->Type = Event::type_cancel_release; // transform event type |
midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey]; |
1408 |
while (iuiKey) { |
if (!pKey->KeyPressed) { |
1409 |
midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey]; |
RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend(); |
1410 |
++iuiKey; |
if (itNewEvent) { |
1411 |
if (!pKey->KeyPressed) { |
*itNewEvent = *itControlChangeEvent; // copy event to the key's own event list |
1412 |
RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend(); |
itNewEvent->Type = Event::type_cancel_release; // transform event type |
|
if (itNewEvent) *itNewEvent = *itControlChangeEvent; // copy event to the key's own event list |
|
|
else dmsg(1,("Event pool emtpy!\n")); |
|
1413 |
} |
} |
1414 |
|
else dmsg(1,("Event pool emtpy!\n")); |
1415 |
} |
} |
1416 |
} |
} |
1417 |
} |
} |
1418 |
if (itControlChangeEvent->Param.CC.Value < 64 && pEngineChannel->SustainPedal) { |
if (itControlChangeEvent->Param.CC.Value < 64 && pEngineChannel->SustainPedal) { |
1419 |
dmsg(4,("PEDAL UP\n")); |
dmsg(4,("DAMPER (RIGHT) PEDAL UP\n")); |
1420 |
pEngineChannel->SustainPedal = false; |
pEngineChannel->SustainPedal = false; |
1421 |
|
|
1422 |
|
#if !CONFIG_PROCESS_MUTED_CHANNELS |
1423 |
|
if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted |
1424 |
|
#endif |
1425 |
|
|
1426 |
// release voices if their respective key is not pressed |
// release voices if their respective key is not pressed |
1427 |
RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first(); |
RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first(); |
1428 |
if (iuiKey) { |
for (; iuiKey; ++iuiKey) { |
1429 |
itControlChangeEvent->Type = Event::type_release; // transform event type |
midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey]; |
1430 |
while (iuiKey) { |
if (!pKey->KeyPressed && ShouldReleaseVoice(pEngineChannel, *iuiKey)) { |
1431 |
midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey]; |
RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend(); |
1432 |
++iuiKey; |
if (itNewEvent) { |
1433 |
if (!pKey->KeyPressed) { |
*itNewEvent = *itControlChangeEvent; // copy event to the key's own event list |
1434 |
RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend(); |
itNewEvent->Type = Event::type_release; // transform event type |
|
if (itNewEvent) *itNewEvent = *itControlChangeEvent; // copy event to the key's own event list |
|
|
else dmsg(1,("Event pool emtpy!\n")); |
|
1435 |
} |
} |
1436 |
|
else dmsg(1,("Event pool emtpy!\n")); |
1437 |
} |
} |
1438 |
} |
} |
1439 |
} |
} |
1440 |
break; |
break; |
1441 |
} |
} |
1442 |
} |
case 65: { // portamento on / off |
1443 |
|
KillAllVoices(pEngineChannel, itControlChangeEvent); |
1444 |
|
pEngineChannel->PortamentoMode = itControlChangeEvent->Param.CC.Value >= 64; |
1445 |
|
break; |
1446 |
|
} |
1447 |
|
case 66: { // sostenuto |
1448 |
|
if (itControlChangeEvent->Param.CC.Value >= 64 && !pEngineChannel->SostenutoPedal) { |
1449 |
|
dmsg(4,("SOSTENUTO (CENTER) PEDAL DOWN\n")); |
1450 |
|
pEngineChannel->SostenutoPedal = true; |
1451 |
|
|
1452 |
|
#if !CONFIG_PROCESS_MUTED_CHANNELS |
1453 |
|
if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted |
1454 |
|
#endif |
1455 |
|
|
1456 |
// update controller value in the engine's controller table |
SostenutoKeyCount = 0; |
1457 |
pEngineChannel->ControllerTable[itControlChangeEvent->Param.CC.Controller] = itControlChangeEvent->Param.CC.Value; |
// Remeber the pressed keys |
1458 |
|
RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first(); |
1459 |
|
for (; iuiKey; ++iuiKey) { |
1460 |
|
midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey]; |
1461 |
|
if (pKey->KeyPressed && SostenutoKeyCount < 128) SostenutoKeys[SostenutoKeyCount++] = *iuiKey; |
1462 |
|
} |
1463 |
|
} |
1464 |
|
if (itControlChangeEvent->Param.CC.Value < 64 && pEngineChannel->SostenutoPedal) { |
1465 |
|
dmsg(4,("SOSTENUTO (CENTER) PEDAL UP\n")); |
1466 |
|
pEngineChannel->SostenutoPedal = false; |
1467 |
|
|
1468 |
|
#if !CONFIG_PROCESS_MUTED_CHANNELS |
1469 |
|
if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted |
1470 |
|
#endif |
1471 |
|
|
1472 |
|
// release voices if the damper pedal is up and their respective key is not pressed |
1473 |
|
for (int i = 0; i < SostenutoKeyCount; i++) { |
1474 |
|
midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[SostenutoKeys[i]]; |
1475 |
|
if (!pKey->KeyPressed && !pEngineChannel->SustainPedal) { |
1476 |
|
RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend(); |
1477 |
|
if (itNewEvent) { |
1478 |
|
*itNewEvent = *itControlChangeEvent; // copy event to the key's own event list |
1479 |
|
itNewEvent->Type = Event::type_release; // transform event type |
1480 |
|
} |
1481 |
|
else dmsg(1,("Event pool emtpy!\n")); |
1482 |
|
} |
1483 |
|
} |
1484 |
|
} |
1485 |
|
break; |
1486 |
|
} |
1487 |
|
case 100: { // RPN controller LSB |
1488 |
|
pEngineChannel->SetMidiRpnControllerLsb(itControlChangeEvent->Param.CC.Value); |
1489 |
|
break; |
1490 |
|
} |
1491 |
|
case 101: { // RPN controller MSB |
1492 |
|
pEngineChannel->SetMidiRpnControllerMsb(itControlChangeEvent->Param.CC.Value); |
1493 |
|
break; |
1494 |
|
} |
1495 |
|
|
1496 |
|
|
1497 |
|
// Channel Mode Messages |
1498 |
|
|
1499 |
|
case 120: { // all sound off |
1500 |
|
KillAllVoices(pEngineChannel, itControlChangeEvent); |
1501 |
|
break; |
1502 |
|
} |
1503 |
|
case 121: { // reset all controllers |
1504 |
|
pEngineChannel->ResetControllers(); |
1505 |
|
break; |
1506 |
|
} |
1507 |
|
case 123: { // all notes off |
1508 |
|
#if CONFIG_PROCESS_ALL_NOTES_OFF |
1509 |
|
ReleaseAllVoices(pEngineChannel, itControlChangeEvent); |
1510 |
|
#endif // CONFIG_PROCESS_ALL_NOTES_OFF |
1511 |
|
break; |
1512 |
|
} |
1513 |
|
case 126: { // mono mode on |
1514 |
|
KillAllVoices(pEngineChannel, itControlChangeEvent); |
1515 |
|
pEngineChannel->SoloMode = true; |
1516 |
|
break; |
1517 |
|
} |
1518 |
|
case 127: { // poly mode on |
1519 |
|
KillAllVoices(pEngineChannel, itControlChangeEvent); |
1520 |
|
pEngineChannel->SoloMode = false; |
1521 |
|
break; |
1522 |
|
} |
1523 |
|
} |
1524 |
|
|
1525 |
// move event from the unsorted event list to the control change event list |
// handle FX send controllers |
1526 |
itControlChangeEvent.moveToEndOf(pCCEvents); |
if (!pEngineChannel->fxSends.empty()) { |
1527 |
|
for (int iFxSend = 0; iFxSend < pEngineChannel->GetFxSendCount(); iFxSend++) { |
1528 |
|
FxSend* pFxSend = pEngineChannel->GetFxSend(iFxSend); |
1529 |
|
if (pFxSend->MidiController() == itControlChangeEvent->Param.CC.Controller) |
1530 |
|
pFxSend->SetLevel(itControlChangeEvent->Param.CC.Value); |
1531 |
|
pFxSend->SetInfoChanged(true); |
1532 |
|
} |
1533 |
|
} |
1534 |
} |
} |
1535 |
|
|
1536 |
/** |
/** |
1539 |
* @param itSysexEvent - sysex data size and time stamp of the sysex event |
* @param itSysexEvent - sysex data size and time stamp of the sysex event |
1540 |
*/ |
*/ |
1541 |
void Engine::ProcessSysex(Pool<Event>::Iterator& itSysexEvent) { |
void Engine::ProcessSysex(Pool<Event>::Iterator& itSysexEvent) { |
1542 |
RingBuffer<uint8_t>::NonVolatileReader reader = pSysexBuffer->get_non_volatile_reader(); |
RingBuffer<uint8_t,false>::NonVolatileReader reader = pSysexBuffer->get_non_volatile_reader(); |
1543 |
|
|
1544 |
uint8_t exclusive_status, id; |
uint8_t exclusive_status, id; |
1545 |
if (!reader.pop(&exclusive_status)) goto free_sysex_data; |
if (!reader.pop(&exclusive_status)) goto free_sysex_data; |
1548 |
|
|
1549 |
switch (id) { |
switch (id) { |
1550 |
case 0x41: { // Roland |
case 0x41: { // Roland |
1551 |
|
dmsg(3,("Roland Sysex\n")); |
1552 |
uint8_t device_id, model_id, cmd_id; |
uint8_t device_id, model_id, cmd_id; |
1553 |
if (!reader.pop(&device_id)) goto free_sysex_data; |
if (!reader.pop(&device_id)) goto free_sysex_data; |
1554 |
if (!reader.pop(&model_id)) goto free_sysex_data; |
if (!reader.pop(&model_id)) goto free_sysex_data; |
1558 |
|
|
1559 |
// command address |
// command address |
1560 |
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) |
1561 |
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 |
1562 |
if (reader.read(&addr[0], 3) != 3) goto free_sysex_data; |
if (reader.read(&addr[0], 3) != 3) goto free_sysex_data; |
1563 |
if (addr[0] == 0x40 && addr[1] == 0x00) { // System Parameters |
if (addr[0] == 0x40 && addr[1] == 0x00) { // System Parameters |
1564 |
|
dmsg(3,("\tSystem Parameter\n")); |
1565 |
} |
} |
1566 |
else if (addr[0] == 0x40 && addr[1] == 0x01) { // Common Parameters |
else if (addr[0] == 0x40 && addr[1] == 0x01) { // Common Parameters |
1567 |
|
dmsg(3,("\tCommon Parameter\n")); |
1568 |
} |
} |
1569 |
else if (addr[0] == 0x40 && (addr[1] & 0xf0) == 0x10) { // Part Parameters (1) |
else if (addr[0] == 0x40 && (addr[1] & 0xf0) == 0x10) { // Part Parameters (1) |
1570 |
switch (addr[3]) { |
dmsg(3,("\tPart Parameter\n")); |
1571 |
|
switch (addr[2]) { |
1572 |
case 0x40: { // scale tuning |
case 0x40: { // scale tuning |
1573 |
|
dmsg(3,("\t\tScale Tuning\n")); |
1574 |
uint8_t scale_tunes[12]; // detuning of all 12 semitones of an octave |
uint8_t scale_tunes[12]; // detuning of all 12 semitones of an octave |
1575 |
if (reader.read(&scale_tunes[0], 12) != 12) goto free_sysex_data; |
if (reader.read(&scale_tunes[0], 12) != 12) goto free_sysex_data; |
1576 |
uint8_t checksum; |
uint8_t checksum; |
1577 |
if (!reader.pop(&checksum)) goto free_sysex_data; |
if (!reader.pop(&checksum)) goto free_sysex_data; |
1578 |
if (GSCheckSum(checksum_reader, 12) != checksum) goto free_sysex_data; |
#if CONFIG_ASSERT_GS_SYSEX_CHECKSUM |
1579 |
|
if (GSCheckSum(checksum_reader, 12)) goto free_sysex_data; |
1580 |
|
#endif // CONFIG_ASSERT_GS_SYSEX_CHECKSUM |
1581 |
for (int i = 0; i < 12; i++) scale_tunes[i] -= 64; |
for (int i = 0; i < 12; i++) scale_tunes[i] -= 64; |
1582 |
AdjustScale((int8_t*) scale_tunes); |
AdjustScale((int8_t*) scale_tunes); |
1583 |
|
dmsg(3,("\t\t\tNew scale applied.\n")); |
1584 |
break; |
break; |
1585 |
} |
} |
1586 |
} |
} |
1605 |
* question |
* question |
1606 |
* @param DataSize - size of the GS message data (in bytes) |
* @param DataSize - size of the GS message data (in bytes) |
1607 |
*/ |
*/ |
1608 |
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) { |
1609 |
RingBuffer<uint8_t>::NonVolatileReader reader = AddrReader; |
RingBuffer<uint8_t,false>::NonVolatileReader reader = AddrReader; |
1610 |
uint bytes = 3 /*addr*/ + DataSize; |
uint bytes = 3 /*addr*/ + DataSize; |
1611 |
uint8_t addr_and_data[bytes]; |
uint8_t addr_and_data[bytes]; |
1612 |
reader.read(&addr_and_data[0], bytes); |
reader.read(&addr_and_data[0], bytes); |
1625 |
} |
} |
1626 |
|
|
1627 |
/** |
/** |
1628 |
* Initialize the parameter sequence for the modulation destination given by |
* Releases all voices on an engine channel. All voices will go into |
1629 |
* by 'dst' with the constant value given by val. |
* the release stage and thus it might take some time (e.g. dependant to |
1630 |
|
* their envelope release time) until they actually die. |
1631 |
|
* |
1632 |
|
* @param pEngineChannel - engine channel on which all voices should be released |
1633 |
|
* @param itReleaseEvent - event which caused this releasing of all voices |
1634 |
|
*/ |
1635 |
|
void Engine::ReleaseAllVoices(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itReleaseEvent) { |
1636 |
|
RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first(); |
1637 |
|
while (iuiKey) { |
1638 |
|
midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey]; |
1639 |
|
++iuiKey; |
1640 |
|
// append a 'release' event to the key's own event list |
1641 |
|
RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend(); |
1642 |
|
if (itNewEvent) { |
1643 |
|
*itNewEvent = *itReleaseEvent; // copy original event (to the key's event list) |
1644 |
|
itNewEvent->Type = Event::type_release; // transform event type |
1645 |
|
} |
1646 |
|
else dmsg(1,("Event pool emtpy!\n")); |
1647 |
|
} |
1648 |
|
} |
1649 |
|
|
1650 |
|
/** |
1651 |
|
* Kills all voices on an engine channel as soon as possible. Voices |
1652 |
|
* won't get into release state, their volume level will be ramped down |
1653 |
|
* as fast as possible. |
1654 |
|
* |
1655 |
|
* @param pEngineChannel - engine channel on which all voices should be killed |
1656 |
|
* @param itKillEvent - event which caused this killing of all voices |
1657 |
|
*/ |
1658 |
|
void Engine::KillAllVoices(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itKillEvent) { |
1659 |
|
RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first(); |
1660 |
|
RTList<uint>::Iterator end = pEngineChannel->pActiveKeys->end(); |
1661 |
|
while (iuiKey != end) { // iterate through all active keys |
1662 |
|
midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey]; |
1663 |
|
++iuiKey; |
1664 |
|
RTList<Voice>::Iterator itVoice = pKey->pActiveVoices->first(); |
1665 |
|
RTList<Voice>::Iterator itVoicesEnd = pKey->pActiveVoices->end(); |
1666 |
|
for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key |
1667 |
|
itVoice->Kill(itKillEvent); |
1668 |
|
--VoiceSpawnsLeft; //FIXME: just a temporary workaround, we should check the cause in StealVoice() instead |
1669 |
|
} |
1670 |
|
} |
1671 |
|
} |
1672 |
|
|
1673 |
|
/** |
1674 |
|
* Determines whether the specified voice should be released. |
1675 |
|
* |
1676 |
|
* @param pEngineChannel - The engine channel on which the voice should be checked |
1677 |
|
* @param Key - The key number |
1678 |
|
* @returns true if the specified should be released, false otherwise. |
1679 |
*/ |
*/ |
1680 |
void Engine::ResetSynthesisParameters(Event::destination_t dst, float val) { |
bool Engine::ShouldReleaseVoice(EngineChannel* pEngineChannel, int Key) { |
1681 |
int maxsamples = pAudioOutputDevice->MaxSamplesPerCycle(); |
if (pEngineChannel->SustainPedal) return false; |
1682 |
float* m = &pSynthesisParameters[dst][0]; |
|
1683 |
for (int i = 0; i < maxsamples; i += 4) { |
if (pEngineChannel->SostenutoPedal) { |
1684 |
m[i] = val; |
for (int i = 0; i < SostenutoKeyCount; i++) |
1685 |
m[i+1] = val; |
if (Key == SostenutoKeys[i]) return false; |
|
m[i+2] = val; |
|
|
m[i+3] = val; |
|
1686 |
} |
} |
1687 |
} |
|
1688 |
|
return true; |
1689 |
|
} |
1690 |
|
|
1691 |
uint Engine::VoiceCount() { |
uint Engine::VoiceCount() { |
1692 |
return ActiveVoiceCount; |
return ActiveVoiceCount; |
1717 |
} |
} |
1718 |
|
|
1719 |
String Engine::EngineName() { |
String Engine::EngineName() { |
1720 |
return "GigEngine"; |
return LS_GIG_ENGINE_NAME; |
1721 |
} |
} |
1722 |
|
|
1723 |
String Engine::Description() { |
String Engine::Description() { |
1725 |
} |
} |
1726 |
|
|
1727 |
String Engine::Version() { |
String Engine::Version() { |
1728 |
String s = "$Revision: 1.28 $"; |
String s = "$Revision: 1.77 $"; |
1729 |
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 |
1730 |
} |
} |
1731 |
|
|
1732 |
|
InstrumentManager* Engine::GetInstrumentManager() { |
1733 |
|
return &instruments; |
1734 |
|
} |
1735 |
|
|
1736 |
|
// static constant initializers |
1737 |
|
const float* Engine::VolumeCurve(InitVolumeCurve()); |
1738 |
|
const float* Engine::PanCurve(InitPanCurve()); |
1739 |
|
const float* Engine::CrossfadeCurve(InitCrossfadeCurve()); |
1740 |
|
|
1741 |
|
float* Engine::InitVolumeCurve() { |
1742 |
|
// line-segment approximation |
1743 |
|
const float segments[] = { |
1744 |
|
0, 0, 2, 0.0046, 16, 0.016, 31, 0.051, 45, 0.115, 54.5, 0.2, |
1745 |
|
64.5, 0.39, 74, 0.74, 92, 1.03, 114, 1.94, 119.2, 2.2, 127, 2.2 |
1746 |
|
}; |
1747 |
|
return InitCurve(segments); |
1748 |
|
} |
1749 |
|
|
1750 |
|
float* Engine::InitPanCurve() { |
1751 |
|
// line-segment approximation |
1752 |
|
const float segments[] = { |
1753 |
|
0, 0, 1, 0, |
1754 |
|
2, 0.05, 31.5, 0.7, 51, 0.851, 74.5, 1.12, |
1755 |
|
127, 1.41, 128, 1.41 |
1756 |
|
}; |
1757 |
|
return InitCurve(segments, 129); |
1758 |
|
} |
1759 |
|
|
1760 |
|
float* Engine::InitCrossfadeCurve() { |
1761 |
|
// line-segment approximation |
1762 |
|
const float segments[] = { |
1763 |
|
0, 0, 1, 0.03, 10, 0.1, 51, 0.58, 127, 1 |
1764 |
|
}; |
1765 |
|
return InitCurve(segments); |
1766 |
|
} |
1767 |
|
|
1768 |
|
float* Engine::InitCurve(const float* segments, int size) { |
1769 |
|
float* y = new float[size]; |
1770 |
|
for (int x = 0 ; x < size ; x++) { |
1771 |
|
if (x > segments[2]) segments += 2; |
1772 |
|
y[x] = segments[1] + (x - segments[0]) * |
1773 |
|
(segments[3] - segments[1]) / (segments[2] - segments[0]); |
1774 |
|
} |
1775 |
|
return y; |
1776 |
|
} |
1777 |
|
|
1778 |
|
/** |
1779 |
|
* Changes the instrument for an engine channel. |
1780 |
|
* |
1781 |
|
* @param pEngineChannel - engine channel on which the instrument |
1782 |
|
* should be changed |
1783 |
|
* @param pInstrument - new instrument |
1784 |
|
* @returns a list of dimension regions from the old instrument |
1785 |
|
* that are still in use |
1786 |
|
*/ |
1787 |
|
::gig::DimensionRegion** Engine::ChangeInstrument(EngineChannel* pEngineChannel, ::gig::Instrument* pInstrument) { |
1788 |
|
instrument_change_command_t command; |
1789 |
|
command.pEngineChannel = pEngineChannel; |
1790 |
|
command.pInstrument = pInstrument; |
1791 |
|
InstrumentChangeQueue->push(&command); |
1792 |
|
|
1793 |
|
// wait for the audio thread to confirm that the instrument |
1794 |
|
// change has been done |
1795 |
|
instrument_change_reply_t reply; |
1796 |
|
while (InstrumentChangeReplyQueue->pop(&reply) == 0) { |
1797 |
|
usleep(10000); |
1798 |
|
} |
1799 |
|
return pDimRegionsInUse; |
1800 |
|
} |
1801 |
|
|
1802 |
}} // namespace LinuxSampler::gig |
}} // namespace LinuxSampler::gig |