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; |
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->Param.Note.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 |
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 |
} |
} |
1091 |
} |
} |
1092 |
|
|
1093 |
String Engine::Version() { |
String Engine::Version() { |
1094 |
String s = "$Revision: 1.13 $"; |
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 |
|
|