97 |
pAudioOutputDevice = NULL; |
pAudioOutputDevice = NULL; |
98 |
pDiskThread = NULL; |
pDiskThread = NULL; |
99 |
pEventGenerator = NULL; |
pEventGenerator = NULL; |
100 |
pSysexBuffer = new RingBuffer<uint8_t>(CONFIG_SYSEX_BUFFER_SIZE, 0); |
pSysexBuffer = new RingBuffer<uint8_t,false>(CONFIG_SYSEX_BUFFER_SIZE, 0); |
101 |
pEventQueue = new RingBuffer<Event>(CONFIG_MAX_EVENTS_PER_FRAGMENT, 0); |
pEventQueue = new RingBuffer<Event,false>(CONFIG_MAX_EVENTS_PER_FRAGMENT, 0); |
102 |
pEventPool = new Pool<Event>(CONFIG_MAX_EVENTS_PER_FRAGMENT); |
pEventPool = new Pool<Event>(CONFIG_MAX_EVENTS_PER_FRAGMENT); |
103 |
pVoicePool = new Pool<Voice>(CONFIG_MAX_VOICES); |
pVoicePool = new Pool<Voice>(CONFIG_MAX_VOICES); |
104 |
pVoiceStealingQueue = new RTList<Event>(pEventPool); |
pVoiceStealingQueue = new RTList<Event>(pEventPool); |
306 |
* current audio cycle |
* current audio cycle |
307 |
*/ |
*/ |
308 |
void Engine::ImportEvents(uint Samples) { |
void Engine::ImportEvents(uint Samples) { |
309 |
RingBuffer<Event>::NonVolatileReader eventQueueReader = pEventQueue->get_non_volatile_reader(); |
RingBuffer<Event,false>::NonVolatileReader eventQueueReader = pEventQueue->get_non_volatile_reader(); |
310 |
Event* pEvent; |
Event* pEvent; |
311 |
while (true) { |
while (true) { |
312 |
// get next event from input event queue |
// get next event from input event queue |
329 |
} |
} |
330 |
|
|
331 |
/** |
/** |
332 |
* 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. |
333 |
* calculated audio data of all voices of this engine will be placed into |
* The engine will iterate through all engine channels and render audio |
334 |
* the engine's audio sum buffer which has to be copied and eventually be |
* for each engine channel independently. The calculated audio data of |
335 |
* 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 |
336 |
* AlsaIO or JackIO) right after. |
* buffers of the respective audio output device, connected to the |
337 |
|
* respective engine channel. |
338 |
* |
* |
339 |
* @param Samples - number of sample points to be rendered |
* @param Samples - number of sample points to be rendered |
340 |
* @returns 0 on success |
* @returns 0 on success |
341 |
*/ |
*/ |
342 |
int Engine::RenderAudio(uint Samples) { |
int Engine::RenderAudio(uint Samples) { |
343 |
dmsg(5,("RenderAudio(Samples=%d)\n", Samples)); |
dmsg(7,("RenderAudio(Samples=%d)\n", Samples)); |
344 |
|
|
345 |
// return if engine disabled |
// return if engine disabled |
346 |
if (EngineDisabled.Pop()) { |
if (EngineDisabled.Pop()) { |
392 |
// now that all ordinary voices on ALL engine channels are rendered, render new stolen voices |
// now that all ordinary voices on ALL engine channels are rendered, render new stolen voices |
393 |
RenderStolenVoices(Samples); |
RenderStolenVoices(Samples); |
394 |
|
|
395 |
|
// handle audio routing for engine channels with FX sends |
396 |
|
for (int i = 0; i < engineChannels.size(); i++) { |
397 |
|
if (engineChannels[i]->fxSends.empty()) continue; // ignore if no FX sends |
398 |
|
RouteAudio(engineChannels[i], Samples); |
399 |
|
} |
400 |
|
|
401 |
// handle cleanup on all engine channels for the next audio fragment |
// handle cleanup on all engine channels for the next audio fragment |
402 |
for (int i = 0; i < engineChannels.size(); i++) { |
for (int i = 0; i < engineChannels.size(); i++) { |
403 |
if (!engineChannels[i]->pInstrument) continue; // ignore if no instrument loaded |
if (!engineChannels[i]->pInstrument) continue; // ignore if no instrument loaded |
538 |
} |
} |
539 |
|
|
540 |
/** |
/** |
541 |
|
* Will be called in case the respective engine channel sports FX send |
542 |
|
* channels. In this particular case, engine channel local buffers are |
543 |
|
* used to render and mix all voices to. This method is responsible for |
544 |
|
* copying the audio data from those local buffers to the master audio |
545 |
|
* output channels as well as to the FX send audio output channels with |
546 |
|
* their respective FX send levels. |
547 |
|
* |
548 |
|
* @param pEngineChannel - engine channel from which audio should be |
549 |
|
* routed |
550 |
|
* @param Samples - amount of sample points to be routed in |
551 |
|
* this audio fragment cycle |
552 |
|
*/ |
553 |
|
void Engine::RouteAudio(EngineChannel* pEngineChannel, uint Samples) { |
554 |
|
// route master signal |
555 |
|
{ |
556 |
|
AudioChannel* pDstL = pAudioOutputDevice->Channel(pEngineChannel->AudioDeviceChannelLeft); |
557 |
|
AudioChannel* pDstR = pAudioOutputDevice->Channel(pEngineChannel->AudioDeviceChannelRight); |
558 |
|
pEngineChannel->pChannelLeft->CopyTo(pDstL, Samples); |
559 |
|
pEngineChannel->pChannelRight->CopyTo(pDstR, Samples); |
560 |
|
} |
561 |
|
// route FX send signal |
562 |
|
{ |
563 |
|
for (int iFxSend = 0; iFxSend < pEngineChannel->GetFxSendCount(); iFxSend++) { |
564 |
|
FxSend* pFxSend = pEngineChannel->GetFxSend(iFxSend); |
565 |
|
// left channel |
566 |
|
const int iDstL = pFxSend->DestinationChannel(0); |
567 |
|
if (iDstL < 0) { |
568 |
|
dmsg(1,("Engine::RouteAudio() Error: invalid FX send (L) destination channel")); |
569 |
|
} else { |
570 |
|
AudioChannel* pDstL = pAudioOutputDevice->Channel(iDstL); |
571 |
|
if (!pDstL) { |
572 |
|
dmsg(1,("Engine::RouteAudio() Error: invalid FX send (L) destination channel")); |
573 |
|
} else pEngineChannel->pChannelLeft->CopyTo(pDstL, Samples, pFxSend->Level()); |
574 |
|
} |
575 |
|
// right channel |
576 |
|
const int iDstR = pFxSend->DestinationChannel(1); |
577 |
|
if (iDstR < 0) { |
578 |
|
dmsg(1,("Engine::RouteAudio() Error: invalid FX send (R) destination channel")); |
579 |
|
} else { |
580 |
|
AudioChannel* pDstR = pAudioOutputDevice->Channel(iDstR); |
581 |
|
if (!pDstR) { |
582 |
|
dmsg(1,("Engine::RouteAudio() Error: invalid FX send (R) destination channel")); |
583 |
|
} else pEngineChannel->pChannelRight->CopyTo(pDstR, Samples, pFxSend->Level()); |
584 |
|
} |
585 |
|
} |
586 |
|
} |
587 |
|
// reset buffers with silence (zero out) for the next audio cycle |
588 |
|
pEngineChannel->pChannelLeft->Clear(); |
589 |
|
pEngineChannel->pChannelRight->Clear(); |
590 |
|
} |
591 |
|
|
592 |
|
/** |
593 |
* Free all keys which have turned inactive in this audio fragment, from |
* Free all keys which have turned inactive in this audio fragment, from |
594 |
* the list of active keys and clear all event lists on that engine |
* the list of active keys and clear all event lists on that engine |
595 |
* channel. |
* channel. |
1294 |
// update controller value in the engine channel's controller table |
// update controller value in the engine channel's controller table |
1295 |
pEngineChannel->ControllerTable[itControlChangeEvent->Param.CC.Controller] = itControlChangeEvent->Param.CC.Value; |
pEngineChannel->ControllerTable[itControlChangeEvent->Param.CC.Controller] = itControlChangeEvent->Param.CC.Value; |
1296 |
|
|
1297 |
|
// handle hard coded MIDI controllers |
1298 |
switch (itControlChangeEvent->Param.CC.Controller) { |
switch (itControlChangeEvent->Param.CC.Controller) { |
1299 |
case 5: { // portamento time |
case 5: { // portamento time |
1300 |
pEngineChannel->PortamentoTime = (float) itControlChangeEvent->Param.CC.Value / 127.0f * (float) CONFIG_PORTAMENTO_TIME_MAX + (float) CONFIG_PORTAMENTO_TIME_MIN; |
pEngineChannel->PortamentoTime = (float) itControlChangeEvent->Param.CC.Value / 127.0f * (float) CONFIG_PORTAMENTO_TIME_MAX + (float) CONFIG_PORTAMENTO_TIME_MIN; |
1302 |
} |
} |
1303 |
case 7: { // volume |
case 7: { // volume |
1304 |
//TODO: not sample accurate yet |
//TODO: not sample accurate yet |
1305 |
pEngineChannel->GlobalVolume = VolumeCurve[itControlChangeEvent->Param.CC.Value] * CONFIG_GLOBAL_ATTENUATION; |
pEngineChannel->MidiVolume = VolumeCurve[itControlChangeEvent->Param.CC.Value]; |
1306 |
pEngineChannel->bStatusChanged = true; // engine channel status has changed, so set notify flag |
pEngineChannel->bStatusChanged = true; // engine channel status has changed, so set notify flag |
1307 |
break; |
break; |
1308 |
} |
} |
1433 |
break; |
break; |
1434 |
} |
} |
1435 |
} |
} |
1436 |
|
|
1437 |
|
// handle FX send controllers |
1438 |
|
if (!pEngineChannel->fxSends.empty()) { |
1439 |
|
for (int iFxSend = 0; iFxSend < pEngineChannel->GetFxSendCount(); iFxSend++) { |
1440 |
|
FxSend* pFxSend = pEngineChannel->GetFxSend(iFxSend); |
1441 |
|
if (pFxSend->MidiController() == itControlChangeEvent->Param.CC.Controller) |
1442 |
|
pFxSend->SetLevel(itControlChangeEvent->Param.CC.Value); |
1443 |
|
} |
1444 |
|
} |
1445 |
} |
} |
1446 |
|
|
1447 |
/** |
/** |
1450 |
* @param itSysexEvent - sysex data size and time stamp of the sysex event |
* @param itSysexEvent - sysex data size and time stamp of the sysex event |
1451 |
*/ |
*/ |
1452 |
void Engine::ProcessSysex(Pool<Event>::Iterator& itSysexEvent) { |
void Engine::ProcessSysex(Pool<Event>::Iterator& itSysexEvent) { |
1453 |
RingBuffer<uint8_t>::NonVolatileReader reader = pSysexBuffer->get_non_volatile_reader(); |
RingBuffer<uint8_t,false>::NonVolatileReader reader = pSysexBuffer->get_non_volatile_reader(); |
1454 |
|
|
1455 |
uint8_t exclusive_status, id; |
uint8_t exclusive_status, id; |
1456 |
if (!reader.pop(&exclusive_status)) goto free_sysex_data; |
if (!reader.pop(&exclusive_status)) goto free_sysex_data; |
1469 |
|
|
1470 |
// command address |
// command address |
1471 |
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) |
1472 |
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 |
1473 |
if (reader.read(&addr[0], 3) != 3) goto free_sysex_data; |
if (reader.read(&addr[0], 3) != 3) goto free_sysex_data; |
1474 |
if (addr[0] == 0x40 && addr[1] == 0x00) { // System Parameters |
if (addr[0] == 0x40 && addr[1] == 0x00) { // System Parameters |
1475 |
dmsg(3,("\tSystem Parameter\n")); |
dmsg(3,("\tSystem Parameter\n")); |
1516 |
* question |
* question |
1517 |
* @param DataSize - size of the GS message data (in bytes) |
* @param DataSize - size of the GS message data (in bytes) |
1518 |
*/ |
*/ |
1519 |
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) { |
1520 |
RingBuffer<uint8_t>::NonVolatileReader reader = AddrReader; |
RingBuffer<uint8_t,false>::NonVolatileReader reader = AddrReader; |
1521 |
uint bytes = 3 /*addr*/ + DataSize; |
uint bytes = 3 /*addr*/ + DataSize; |
1522 |
uint8_t addr_and_data[bytes]; |
uint8_t addr_and_data[bytes]; |
1523 |
reader.read(&addr_and_data[0], bytes); |
reader.read(&addr_and_data[0], bytes); |
1636 |
} |
} |
1637 |
|
|
1638 |
String Engine::Version() { |
String Engine::Version() { |
1639 |
String s = "$Revision: 1.64 $"; |
String s = "$Revision: 1.68 $"; |
1640 |
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 |
1641 |
} |
} |
1642 |
|
|
1643 |
|
InstrumentManager* Engine::GetInstrumentManager() { |
1644 |
|
return &instruments; |
1645 |
|
} |
1646 |
|
|
1647 |
// static constant initializers |
// static constant initializers |
1648 |
const float* Engine::VolumeCurve(InitVolumeCurve()); |
const float* Engine::VolumeCurve(InitVolumeCurve()); |
1649 |
const float* Engine::PanCurve(InitPanCurve()); |
const float* Engine::PanCurve(InitPanCurve()); |