42 |
pEventPool = new RTELMemoryPool<Event>(MAX_EVENTS_PER_FRAGMENT); |
pEventPool = new RTELMemoryPool<Event>(MAX_EVENTS_PER_FRAGMENT); |
43 |
pVoicePool = new RTELMemoryPool<Voice>(MAX_AUDIO_VOICES); |
pVoicePool = new RTELMemoryPool<Voice>(MAX_AUDIO_VOICES); |
44 |
pActiveKeys = new RTELMemoryPool<uint>(128); |
pActiveKeys = new RTELMemoryPool<uint>(128); |
45 |
|
pVoiceStealingQueue = new RTEList<Event>(pEventPool); |
46 |
pEvents = new RTEList<Event>(pEventPool); |
pEvents = new RTEList<Event>(pEventPool); |
47 |
pCCEvents = new RTEList<Event>(pEventPool); |
pCCEvents = new RTEList<Event>(pEventPool); |
48 |
for (uint i = 0; i < Event::destination_count; i++) { |
for (uint i = 0; i < Event::destination_count; i++) { |
100 |
if (pMainFilterParameters) delete[] pMainFilterParameters; |
if (pMainFilterParameters) delete[] pMainFilterParameters; |
101 |
if (pBasicFilterParameters) delete[] pBasicFilterParameters; |
if (pBasicFilterParameters) delete[] pBasicFilterParameters; |
102 |
if (pSynthesisParameters[0]) delete[] pSynthesisParameters[0]; |
if (pSynthesisParameters[0]) delete[] pSynthesisParameters[0]; |
103 |
|
if (pVoiceStealingQueue) delete pVoiceStealingQueue; |
104 |
} |
} |
105 |
|
|
106 |
void Engine::Enable() { |
void Engine::Enable() { |
159 |
ActiveVoiceCountMax = 0; |
ActiveVoiceCountMax = 0; |
160 |
GlobalVolume = 1.0; |
GlobalVolume = 1.0; |
161 |
|
|
162 |
|
// reset voice stealing parameters |
163 |
|
pLastStolenVoice = NULL; |
164 |
|
puiLastStolenKey = NULL; |
165 |
|
pVoiceStealingQueue->clear(); |
166 |
|
|
167 |
// reset to normal chromatic scale (means equal temper) |
// reset to normal chromatic scale (means equal temper) |
168 |
memset(&ScaleTuning[0], 0x00, 12); |
memset(&ScaleTuning[0], 0x00, 12); |
169 |
|
|
399 |
for (uint i = 0; i < Event::destination_count; i++) { |
for (uint i = 0; i < Event::destination_count; i++) { |
400 |
pSynthesisEvents[i]->clear(); |
pSynthesisEvents[i]->clear(); |
401 |
} |
} |
402 |
|
for (uint* puiKey = pActiveKeys->first(); puiKey; puiKey = pActiveKeys->next()) { |
403 |
|
midi_key_info_t* pKey = &pMIDIKeyInfo[*puiKey]; |
404 |
|
pKey->pEvents->clear(); // free all events on the key |
405 |
|
} |
406 |
|
|
407 |
// read and copy events from input queue |
// read and copy events from input queue |
408 |
Event event = pEventGenerator->CreateEvent(); |
Event event = pEventGenerator->CreateEvent(); |
469 |
KillVoiceImmediately(pVoice); // remove voice from the list of active voices |
KillVoiceImmediately(pVoice); // remove voice from the list of active voices |
470 |
} |
} |
471 |
} |
} |
|
pKey->pEvents->clear(); // free all events on the key |
|
472 |
} |
} |
473 |
|
|
474 |
|
|
475 |
|
// now render all postponed voices from voice stealing |
476 |
|
Event* pVoiceStealEvent = pVoiceStealingQueue->first(); |
477 |
|
while (pVoiceStealEvent) { |
478 |
|
Voice* pNewVoice = LaunchVoice(pVoiceStealEvent, pVoiceStealEvent->Param.Note.Layer, pVoiceStealEvent->Param.Note.ReleaseTrigger, false); |
479 |
|
if (pNewVoice) { |
480 |
|
pNewVoice->Render(Samples); |
481 |
|
if (pNewVoice->IsActive()) active_voices++; // still active |
482 |
|
else { // voice reached end, is now inactive |
483 |
|
KillVoiceImmediately(pNewVoice); // remove voice from the list of active voices |
484 |
|
} |
485 |
|
} |
486 |
|
else dmsg(1,("Ouch, voice stealing didn't work out!\n")); |
487 |
|
pVoiceStealEvent = pVoiceStealingQueue->next(); |
488 |
|
} |
489 |
|
// reset voice stealing for the new fragment |
490 |
|
pVoiceStealingQueue->clear(); |
491 |
|
pLastStolenVoice = NULL; |
492 |
|
puiLastStolenKey = NULL; |
493 |
|
|
494 |
|
|
495 |
// write that to the disk thread class so that it can print it |
// write that to the disk thread class so that it can print it |
496 |
// on the console for debugging purposes |
// on the console for debugging purposes |
497 |
ActiveVoiceCount = active_voices; |
ActiveVoiceCount = active_voices; |
509 |
* @param Velocity - MIDI velocity value of the triggered key |
* @param Velocity - MIDI velocity value of the triggered key |
510 |
*/ |
*/ |
511 |
void Engine::SendNoteOn(uint8_t Key, uint8_t Velocity) { |
void Engine::SendNoteOn(uint8_t Key, uint8_t Velocity) { |
512 |
Event event = pEventGenerator->CreateEvent(); |
Event event = pEventGenerator->CreateEvent(); |
513 |
event.Type = Event::type_note_on; |
event.Type = Event::type_note_on; |
514 |
event.Key = Key; |
event.Param.Note.Key = Key; |
515 |
event.Velocity = Velocity; |
event.Param.Note.Velocity = Velocity; |
516 |
if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event); |
if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event); |
517 |
else dmsg(1,("Engine: Input event queue full!")); |
else dmsg(1,("Engine: Input event queue full!")); |
518 |
} |
} |
525 |
* @param Velocity - MIDI release velocity value of the released key |
* @param Velocity - MIDI release velocity value of the released key |
526 |
*/ |
*/ |
527 |
void Engine::SendNoteOff(uint8_t Key, uint8_t Velocity) { |
void Engine::SendNoteOff(uint8_t Key, uint8_t Velocity) { |
528 |
Event event = pEventGenerator->CreateEvent(); |
Event event = pEventGenerator->CreateEvent(); |
529 |
event.Type = Event::type_note_off; |
event.Type = Event::type_note_off; |
530 |
event.Key = Key; |
event.Param.Note.Key = Key; |
531 |
event.Velocity = Velocity; |
event.Param.Note.Velocity = Velocity; |
532 |
if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event); |
if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event); |
533 |
else dmsg(1,("Engine: Input event queue full!")); |
else dmsg(1,("Engine: Input event queue full!")); |
534 |
} |
} |
540 |
* @param Pitch - MIDI pitch value (-8192 ... +8191) |
* @param Pitch - MIDI pitch value (-8192 ... +8191) |
541 |
*/ |
*/ |
542 |
void Engine::SendPitchbend(int Pitch) { |
void Engine::SendPitchbend(int Pitch) { |
543 |
Event event = pEventGenerator->CreateEvent(); |
Event event = pEventGenerator->CreateEvent(); |
544 |
event.Type = Event::type_pitchbend; |
event.Type = Event::type_pitchbend; |
545 |
event.Pitch = Pitch; |
event.Param.Pitch.Pitch = Pitch; |
546 |
if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event); |
if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event); |
547 |
else dmsg(1,("Engine: Input event queue full!")); |
else dmsg(1,("Engine: Input event queue full!")); |
548 |
} |
} |
555 |
* @param Value - value of the control change |
* @param Value - value of the control change |
556 |
*/ |
*/ |
557 |
void Engine::SendControlChange(uint8_t Controller, uint8_t Value) { |
void Engine::SendControlChange(uint8_t Controller, uint8_t Value) { |
558 |
Event event = pEventGenerator->CreateEvent(); |
Event event = pEventGenerator->CreateEvent(); |
559 |
event.Type = Event::type_control_change; |
event.Type = Event::type_control_change; |
560 |
event.Controller = Controller; |
event.Param.CC.Controller = Controller; |
561 |
event.Value = Value; |
event.Param.CC.Value = Value; |
562 |
if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event); |
if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event); |
563 |
else dmsg(1,("Engine: Input event queue full!")); |
else dmsg(1,("Engine: Input event queue full!")); |
564 |
} |
} |
571 |
* @param Size - lenght of sysex data (in bytes) |
* @param Size - lenght of sysex data (in bytes) |
572 |
*/ |
*/ |
573 |
void Engine::SendSysex(void* pData, uint Size) { |
void Engine::SendSysex(void* pData, uint Size) { |
574 |
Event event = pEventGenerator->CreateEvent(); |
Event event = pEventGenerator->CreateEvent(); |
575 |
event.Type = Event::type_sysex; |
event.Type = Event::type_sysex; |
576 |
event.Size = Size; |
event.Param.Sysex.Size = Size; |
577 |
if (pEventQueue->write_space() > 0) { |
if (pEventQueue->write_space() > 0) { |
578 |
if (pSysexBuffer->write_space() >= Size) { |
if (pSysexBuffer->write_space() >= Size) { |
579 |
// copy sysex data to input buffer |
// copy sysex data to input buffer |
600 |
* @param pNoteOnEvent - key, velocity and time stamp of the event |
* @param pNoteOnEvent - key, velocity and time stamp of the event |
601 |
*/ |
*/ |
602 |
void Engine::ProcessNoteOn(Event* pNoteOnEvent) { |
void Engine::ProcessNoteOn(Event* pNoteOnEvent) { |
603 |
midi_key_info_t* pKey = &pMIDIKeyInfo[pNoteOnEvent->Key]; |
midi_key_info_t* pKey = &pMIDIKeyInfo[pNoteOnEvent->Param.Note.Key]; |
604 |
|
|
605 |
pKey->KeyPressed = true; // the MIDI key was now pressed down |
pKey->KeyPressed = true; // the MIDI key was now pressed down |
606 |
|
|
630 |
* @param pNoteOffEvent - key, velocity and time stamp of the event |
* @param pNoteOffEvent - key, velocity and time stamp of the event |
631 |
*/ |
*/ |
632 |
void Engine::ProcessNoteOff(Event* pNoteOffEvent) { |
void Engine::ProcessNoteOff(Event* pNoteOffEvent) { |
633 |
midi_key_info_t* pKey = &pMIDIKeyInfo[pNoteOffEvent->Key]; |
midi_key_info_t* pKey = &pMIDIKeyInfo[pNoteOffEvent->Param.Note.Key]; |
634 |
|
|
635 |
pKey->KeyPressed = false; // the MIDI key was now released |
pKey->KeyPressed = false; // the MIDI key was now released |
636 |
|
|
656 |
* @param pPitchbendEvent - absolute pitch value and time stamp of the event |
* @param pPitchbendEvent - absolute pitch value and time stamp of the event |
657 |
*/ |
*/ |
658 |
void Engine::ProcessPitchbend(Event* pPitchbendEvent) { |
void Engine::ProcessPitchbend(Event* pPitchbendEvent) { |
659 |
this->Pitch = pPitchbendEvent->Pitch; // store current pitch value |
this->Pitch = pPitchbendEvent->Param.Pitch.Pitch; // store current pitch value |
660 |
pEvents->move(pPitchbendEvent, pSynthesisEvents[Event::destination_vco]); |
pEvents->move(pPitchbendEvent, pSynthesisEvents[Event::destination_vco]); |
661 |
} |
} |
662 |
|
|
670 |
* in case of layered sounds of course) |
* in case of layered sounds of course) |
671 |
* @param ReleaseTriggerVoice - if new voice is a release triggered voice |
* @param ReleaseTriggerVoice - if new voice is a release triggered voice |
672 |
* (optional, default = false) |
* (optional, default = false) |
673 |
|
* @param VoiceStealing - if voice stealing should be performed |
674 |
|
* when there is no free voice |
675 |
|
* (optional, default = true) |
676 |
|
* @returns pointer to new voice or NULL if there was no free voice or |
677 |
|
* if an error occured while trying to trigger the new voice |
678 |
*/ |
*/ |
679 |
void Engine::LaunchVoice(Event* pNoteOnEvent, int iLayer, bool ReleaseTriggerVoice) { |
Voice* Engine::LaunchVoice(Event* pNoteOnEvent, int iLayer, bool ReleaseTriggerVoice, bool VoiceStealing) { |
680 |
midi_key_info_t* pKey = &pMIDIKeyInfo[pNoteOnEvent->Key]; |
midi_key_info_t* pKey = &pMIDIKeyInfo[pNoteOnEvent->Param.Note.Key]; |
681 |
|
|
682 |
// allocate a new voice for the key |
// allocate a new voice for the key |
683 |
Voice* pNewVoice = pKey->pActiveVoices->alloc(); |
Voice* pNewVoice = pKey->pActiveVoices->alloc(); |
706 |
if (!pKey->Active) { // mark as active key |
if (!pKey->Active) { // mark as active key |
707 |
pKey->Active = true; |
pKey->Active = true; |
708 |
pKey->pSelf = pActiveKeys->alloc(); |
pKey->pSelf = pActiveKeys->alloc(); |
709 |
*pKey->pSelf = pNoteOnEvent->Key; |
*pKey->pSelf = pNoteOnEvent->Param.Note.Key; |
710 |
} |
} |
711 |
if (pNewVoice->KeyGroup) { |
if (pNewVoice->KeyGroup) { |
712 |
*ppKeyGroup = pKey->pSelf; // put key as the (new) active key to its key group |
*ppKeyGroup = pKey->pSelf; // put key as the (new) active key to its key group |
713 |
} |
} |
714 |
if (pNewVoice->Type == Voice::type_release_trigger_required) pKey->ReleaseTrigger = true; // mark key for the need of release triggered voice(s) |
if (pNewVoice->Type == Voice::type_release_trigger_required) pKey->ReleaseTrigger = true; // mark key for the need of release triggered voice(s) |
715 |
|
return pNewVoice; // success |
716 |
} |
} |
717 |
} |
} |
718 |
else std::cerr << "No free voice!" << std::endl << std::flush; |
else if (VoiceStealing) StealVoice(pNoteOnEvent, iLayer, ReleaseTriggerVoice); // no free voice left, so steal one |
719 |
|
|
720 |
|
return NULL; // no free voice or error |
721 |
|
} |
722 |
|
|
723 |
|
/** |
724 |
|
* Will be called by LaunchVoice() method in case there are no free |
725 |
|
* voices left. This method will select and kill one old voice for |
726 |
|
* voice stealing and postpone the note-on event until the selected |
727 |
|
* voice actually died. |
728 |
|
* |
729 |
|
* @param pNoteOnEvent - key, velocity and time stamp of the event |
730 |
|
* @param iLayer - layer index for the new voice |
731 |
|
* @param ReleaseTriggerVoice - if new voice is a release triggered voice |
732 |
|
*/ |
733 |
|
void Engine::StealVoice(Event* pNoteOnEvent, int iLayer, bool ReleaseTriggerVoice) { |
734 |
|
if (!pEventPool->pool_is_empty()) { |
735 |
|
|
736 |
|
uint* puiOldestKey; |
737 |
|
Voice* pOldestVoice; |
738 |
|
|
739 |
|
// Select one voice for voice stealing |
740 |
|
switch (VOICE_STEAL_ALGORITHM) { |
741 |
|
|
742 |
|
// try to pick the oldest voice on the key where the new |
743 |
|
// voice should be spawned, if there is no voice on that |
744 |
|
// key, or no voice left to kill there, then procceed with |
745 |
|
// 'oldestkey' algorithm |
746 |
|
case voice_steal_algo_keymask: { |
747 |
|
midi_key_info_t* pOldestKey = &pMIDIKeyInfo[pNoteOnEvent->Param.Note.Key]; |
748 |
|
if (pLastStolenVoice) { |
749 |
|
pOldestKey->pActiveVoices->set_current(pLastStolenVoice); |
750 |
|
pOldestVoice = pOldestKey->pActiveVoices->next(); |
751 |
|
} |
752 |
|
else { // no voice stolen in this audio fragment cycle yet |
753 |
|
pOldestVoice = pOldestKey->pActiveVoices->first(); |
754 |
|
} |
755 |
|
if (pOldestVoice) { |
756 |
|
puiOldestKey = pOldestKey->pSelf; |
757 |
|
break; // selection succeeded |
758 |
|
} |
759 |
|
} // no break - intentional ! |
760 |
|
|
761 |
|
// try to pick the oldest voice on the oldest active key |
762 |
|
// (caution: must stay after 'keymask' algorithm !) |
763 |
|
case voice_steal_algo_oldestkey: { |
764 |
|
if (pLastStolenVoice) { |
765 |
|
midi_key_info_t* pOldestKey = &pMIDIKeyInfo[*puiLastStolenKey]; |
766 |
|
pOldestKey->pActiveVoices->set_current(pLastStolenVoice); |
767 |
|
pOldestVoice = pOldestKey->pActiveVoices->next(); |
768 |
|
if (!pOldestVoice) { |
769 |
|
pActiveKeys->set_current(puiLastStolenKey); |
770 |
|
puiOldestKey = pActiveKeys->next(); |
771 |
|
if (puiOldestKey) { |
772 |
|
midi_key_info_t* pOldestKey = &pMIDIKeyInfo[*puiOldestKey]; |
773 |
|
pOldestVoice = pOldestKey->pActiveVoices->first(); |
774 |
|
} |
775 |
|
else { // too less voices, even for voice stealing |
776 |
|
dmsg(1,("Voice overflow! - You might recompile with higher MAX_AUDIO_VOICES!\n")); |
777 |
|
return; |
778 |
|
} |
779 |
|
} |
780 |
|
else puiOldestKey = puiLastStolenKey; |
781 |
|
} |
782 |
|
else { // no voice stolen in this audio fragment cycle yet |
783 |
|
puiOldestKey = pActiveKeys->first(); |
784 |
|
midi_key_info_t* pOldestKey = &pMIDIKeyInfo[*puiOldestKey]; |
785 |
|
pOldestVoice = pOldestKey->pActiveVoices->first(); |
786 |
|
} |
787 |
|
break; |
788 |
|
} |
789 |
|
|
790 |
|
// don't steal anything |
791 |
|
case voice_steal_algo_none: |
792 |
|
default: { |
793 |
|
dmsg(1,("No free voice (voice stealing disabled)!\n")); |
794 |
|
return; |
795 |
|
} |
796 |
|
} |
797 |
|
|
798 |
|
// now kill the selected voice |
799 |
|
pOldestVoice->Kill(pNoteOnEvent); |
800 |
|
// remember which voice on which key we stole, so we can simply proceed for the next voice stealing |
801 |
|
this->pLastStolenVoice = pOldestVoice; |
802 |
|
this->puiLastStolenKey = puiOldestKey; |
803 |
|
// put note-on event into voice-stealing queue, so it will be reprocessed after killed voice died |
804 |
|
Event* pStealEvent = pVoiceStealingQueue->alloc(); |
805 |
|
*pStealEvent = *pNoteOnEvent; |
806 |
|
pStealEvent->Param.Note.Layer = iLayer; |
807 |
|
pStealEvent->Param.Note.ReleaseTrigger = ReleaseTriggerVoice; |
808 |
|
} |
809 |
|
else dmsg(1,("Event pool emtpy!\n")); |
810 |
} |
} |
811 |
|
|
812 |
/** |
/** |
835 |
pActiveKeys->free(pKey->pSelf); // remove key from list of active keys |
pActiveKeys->free(pKey->pSelf); // remove key from list of active keys |
836 |
pKey->pSelf = NULL; |
pKey->pSelf = NULL; |
837 |
pKey->ReleaseTrigger = false; |
pKey->ReleaseTrigger = false; |
838 |
|
pKey->pEvents->clear(); |
839 |
dmsg(3,("Key has no more voices now\n")); |
dmsg(3,("Key has no more voices now\n")); |
840 |
} |
} |
841 |
} |
} |
849 |
* @param pControlChangeEvent - controller, value and time stamp of the event |
* @param pControlChangeEvent - controller, value and time stamp of the event |
850 |
*/ |
*/ |
851 |
void Engine::ProcessControlChange(Event* pControlChangeEvent) { |
void Engine::ProcessControlChange(Event* pControlChangeEvent) { |
852 |
dmsg(4,("Engine::ContinuousController cc=%d v=%d\n", pControlChangeEvent->Controller, pControlChangeEvent->Value)); |
dmsg(4,("Engine::ContinuousController cc=%d v=%d\n", pControlChangeEvent->Param.CC.Controller, pControlChangeEvent->Param.CC.Value)); |
853 |
|
|
854 |
switch (pControlChangeEvent->Controller) { |
switch (pControlChangeEvent->Param.CC.Controller) { |
855 |
case 64: { |
case 64: { |
856 |
if (pControlChangeEvent->Value >= 64 && !SustainPedal) { |
if (pControlChangeEvent->Param.CC.Value >= 64 && !SustainPedal) { |
857 |
dmsg(4,("PEDAL DOWN\n")); |
dmsg(4,("PEDAL DOWN\n")); |
858 |
SustainPedal = true; |
SustainPedal = true; |
859 |
|
|
873 |
} |
} |
874 |
} |
} |
875 |
} |
} |
876 |
if (pControlChangeEvent->Value < 64 && SustainPedal) { |
if (pControlChangeEvent->Param.CC.Value < 64 && SustainPedal) { |
877 |
dmsg(4,("PEDAL UP\n")); |
dmsg(4,("PEDAL UP\n")); |
878 |
SustainPedal = false; |
SustainPedal = false; |
879 |
|
|
898 |
} |
} |
899 |
|
|
900 |
// update controller value in the engine's controller table |
// update controller value in the engine's controller table |
901 |
ControllerTable[pControlChangeEvent->Controller] = pControlChangeEvent->Value; |
ControllerTable[pControlChangeEvent->Param.CC.Controller] = pControlChangeEvent->Param.CC.Value; |
902 |
|
|
903 |
// move event from the unsorted event list to the control change event list |
// move event from the unsorted event list to the control change event list |
904 |
pEvents->move(pControlChangeEvent, pCCEvents); |
pEvents->move(pControlChangeEvent, pCCEvents); |
957 |
} |
} |
958 |
|
|
959 |
free_sysex_data: // finally free sysex data |
free_sysex_data: // finally free sysex data |
960 |
pSysexBuffer->increment_read_ptr(pSysexEvent->Size); |
pSysexBuffer->increment_read_ptr(pSysexEvent->Param.Sysex.Size); |
961 |
} |
} |
962 |
|
|
963 |
/** |
/** |
1091 |
} |
} |
1092 |
|
|
1093 |
String Engine::Version() { |
String Engine::Version() { |
1094 |
String s = "$Revision: 1.12 $"; |
String s = "$Revision: 1.14 $"; |
1095 |
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 |
1096 |
} |
} |
1097 |
|
|