23 |
|
|
24 |
#include "../../common/Features.h" |
#include "../../common/Features.h" |
25 |
#include "Synthesizer.h" |
#include "Synthesizer.h" |
26 |
|
#include "Profiler.h" |
27 |
|
|
28 |
#include "Voice.h" |
#include "Voice.h" |
29 |
|
|
50 |
#else |
#else |
51 |
SYNTHESIS_MODE_SET_IMPLEMENTATION(SynthesisMode, false); |
SYNTHESIS_MODE_SET_IMPLEMENTATION(SynthesisMode, false); |
52 |
#endif |
#endif |
53 |
SYNTHESIS_MODE_SET_PROFILING(SynthesisMode, true); |
SYNTHESIS_MODE_SET_PROFILING(SynthesisMode, Profiler::isEnabled()); |
54 |
|
|
55 |
FilterLeft.Reset(); |
finalSynthesisParameters.filterLeft.Reset(); |
56 |
FilterRight.Reset(); |
finalSynthesisParameters.filterRight.Reset(); |
57 |
} |
} |
58 |
|
|
59 |
Voice::~Voice() { |
Voice::~Voice() { |
139 |
PanLeft = 1.0f - float(RTMath::Max(pDimRgn->Pan, 0)) / 63.0f; |
PanLeft = 1.0f - float(RTMath::Max(pDimRgn->Pan, 0)) / 63.0f; |
140 |
PanRight = 1.0f - float(RTMath::Min(pDimRgn->Pan, 0)) / -64.0f; |
PanRight = 1.0f - float(RTMath::Min(pDimRgn->Pan, 0)) / -64.0f; |
141 |
|
|
142 |
Pos = pDimRgn->SampleStartOffset; // offset where we should start playback of sample (0 - 2000 sample points) |
finalSynthesisParameters.dPos = pDimRgn->SampleStartOffset; // offset where we should start playback of sample (0 - 2000 sample points) |
143 |
|
Pos = pDimRgn->SampleStartOffset; |
144 |
|
|
145 |
// Check if the sample needs disk streaming or is too short for that |
// Check if the sample needs disk streaming or is too short for that |
146 |
long cachedsamples = pSample->GetCache().Size / pSample->FrameSize; |
long cachedsamples = pSample->GetCache().Size / pSample->FrameSize; |
151 |
|
|
152 |
// check if there's a loop defined which completely fits into the cached (RAM) part of the sample |
// check if there's a loop defined which completely fits into the cached (RAM) part of the sample |
153 |
if (pSample->Loops && pSample->LoopEnd <= MaxRAMPos) { |
if (pSample->Loops && pSample->LoopEnd <= MaxRAMPos) { |
154 |
RAMLoop = true; |
RAMLoop = true; |
155 |
LoopCyclesLeft = pSample->LoopPlayCount; |
loop.uiTotalCycles = pSample->LoopPlayCount; |
156 |
|
loop.uiCyclesLeft = pSample->LoopPlayCount; |
157 |
|
loop.uiStart = pSample->LoopStart; |
158 |
|
loop.uiEnd = pSample->LoopEnd; |
159 |
|
loop.uiSize = pSample->LoopSize; |
160 |
} |
} |
161 |
else RAMLoop = false; |
else RAMLoop = false; |
162 |
|
|
170 |
else { // RAM only voice |
else { // RAM only voice |
171 |
MaxRAMPos = cachedsamples; |
MaxRAMPos = cachedsamples; |
172 |
if (pSample->Loops) { |
if (pSample->Loops) { |
173 |
RAMLoop = true; |
RAMLoop = true; |
174 |
LoopCyclesLeft = pSample->LoopPlayCount; |
loop.uiCyclesLeft = pSample->LoopPlayCount; |
175 |
} |
} |
176 |
else RAMLoop = false; |
else RAMLoop = false; |
177 |
dmsg(4,("RAM only voice launched (Looping: %s)\n", (RAMLoop) ? "yes" : "no")); |
dmsg(4,("RAM only voice launched (Looping: %s)\n", (RAMLoop) ? "yes" : "no")); |
220 |
EG1.trigger(pDimRgn->EG1PreAttack, |
EG1.trigger(pDimRgn->EG1PreAttack, |
221 |
pDimRgn->EG1Attack * eg1attack, |
pDimRgn->EG1Attack * eg1attack, |
222 |
pDimRgn->EG1Hold, |
pDimRgn->EG1Hold, |
|
pSample->LoopStart, |
|
223 |
pDimRgn->EG1Decay1 * eg1decay * velrelease, |
pDimRgn->EG1Decay1 * eg1decay * velrelease, |
224 |
pDimRgn->EG1Decay2 * eg1decay * velrelease, |
pDimRgn->EG1Decay2 * eg1decay * velrelease, |
225 |
pDimRgn->EG1InfiniteSustain, |
pDimRgn->EG1InfiniteSustain, |
258 |
EG2.trigger(pDimRgn->EG2PreAttack, |
EG2.trigger(pDimRgn->EG2PreAttack, |
259 |
pDimRgn->EG2Attack * eg2attack, |
pDimRgn->EG2Attack * eg2attack, |
260 |
false, |
false, |
|
pSample->LoopStart, |
|
261 |
pDimRgn->EG2Decay1 * eg2decay * velrelease, |
pDimRgn->EG2Decay1 * eg2decay * velrelease, |
262 |
pDimRgn->EG2Decay2 * eg2decay * velrelease, |
pDimRgn->EG2Decay2 * eg2decay * velrelease, |
263 |
pDimRgn->EG2InfiniteSustain, |
pDimRgn->EG2InfiniteSustain, |
473 |
#endif // CONFIG_OVERRIDE_RESONANCE_CTRL |
#endif // CONFIG_OVERRIDE_RESONANCE_CTRL |
474 |
|
|
475 |
#ifndef CONFIG_OVERRIDE_FILTER_TYPE |
#ifndef CONFIG_OVERRIDE_FILTER_TYPE |
476 |
FilterLeft.SetType(pDimRgn->VCFType); |
finalSynthesisParameters.filterLeft.SetType(pDimRgn->VCFType); |
477 |
FilterRight.SetType(pDimRgn->VCFType); |
finalSynthesisParameters.filterRight.SetType(pDimRgn->VCFType); |
478 |
#else // override filter type |
#else // override filter type |
479 |
FilterLeft.SetType(CONFIG_OVERRIDE_FILTER_TYPE); |
FilterLeft.SetType(CONFIG_OVERRIDE_FILTER_TYPE); |
480 |
FilterRight.SetType(CONFIG_OVERRIDE_FILTER_TYPE); |
FilterRight.SetType(CONFIG_OVERRIDE_FILTER_TYPE); |
551 |
|
|
552 |
if (DiskVoice) { |
if (DiskVoice) { |
553 |
// check if we reached the allowed limit of the sample RAM cache |
// check if we reached the allowed limit of the sample RAM cache |
554 |
if (Pos > MaxRAMPos) { |
if (finalSynthesisParameters.dPos > MaxRAMPos) { |
555 |
dmsg(5,("Voice: switching to disk playback (Pos=%f)\n", Pos)); |
dmsg(5,("Voice: switching to disk playback (Pos=%f)\n", finalSynthesisParameters.dPos)); |
556 |
this->PlaybackState = playback_state_disk; |
this->PlaybackState = playback_state_disk; |
557 |
} |
} |
558 |
} |
} else if (finalSynthesisParameters.dPos >= pSample->GetCache().Size / pSample->FrameSize) { |
|
else if (Pos >= pSample->GetCache().Size / pSample->FrameSize) { |
|
559 |
this->PlaybackState = playback_state_end; |
this->PlaybackState = playback_state_end; |
560 |
} |
} |
561 |
} |
} |
570 |
KillImmediately(); |
KillImmediately(); |
571 |
return; |
return; |
572 |
} |
} |
573 |
DiskStreamRef.pStream->IncrementReadPos(pSample->Channels * (int(Pos) - MaxRAMPos)); |
DiskStreamRef.pStream->IncrementReadPos(pSample->Channels * (int(finalSynthesisParameters.dPos) - MaxRAMPos)); |
574 |
Pos -= int(Pos); |
finalSynthesisParameters.dPos -= int(finalSynthesisParameters.dPos); |
575 |
RealSampleWordsLeftToRead = -1; // -1 means no silence has been added yet |
RealSampleWordsLeftToRead = -1; // -1 means no silence has been added yet |
576 |
} |
} |
577 |
|
|
592 |
// render current audio fragment |
// render current audio fragment |
593 |
Synthesize(Samples, ptr, Delay); |
Synthesize(Samples, ptr, Delay); |
594 |
|
|
595 |
const int iPos = (int) Pos; |
const int iPos = (int) finalSynthesisParameters.dPos; |
596 |
const int readSampleWords = iPos * pSample->Channels; // amount of sample words actually been read |
const int readSampleWords = iPos * pSample->Channels; // amount of sample words actually been read |
597 |
DiskStreamRef.pStream->IncrementReadPos(readSampleWords); |
DiskStreamRef.pStream->IncrementReadPos(readSampleWords); |
598 |
Pos -= iPos; // just keep fractional part of Pos |
finalSynthesisParameters.dPos -= iPos; // just keep fractional part of playback position |
599 |
|
|
600 |
// change state of voice to 'end' if we really reached the end of the sample data |
// change state of voice to 'end' if we really reached the end of the sample data |
601 |
if (RealSampleWordsLeftToRead >= 0) { |
if (RealSampleWordsLeftToRead >= 0) { |
610 |
break; |
break; |
611 |
} |
} |
612 |
|
|
|
// Reset synthesis event lists |
|
|
pEngineChannel->pEvents->clear(); |
|
|
|
|
613 |
// Reset delay |
// Reset delay |
614 |
Delay = 0; |
Delay = 0; |
615 |
|
|
624 |
* suspended / not running. |
* suspended / not running. |
625 |
*/ |
*/ |
626 |
void Voice::Reset() { |
void Voice::Reset() { |
627 |
FilterLeft.Reset(); |
finalSynthesisParameters.filterLeft.Reset(); |
628 |
FilterRight.Reset(); |
finalSynthesisParameters.filterRight.Reset(); |
629 |
DiskStreamRef.pStream = NULL; |
DiskStreamRef.pStream = NULL; |
630 |
DiskStreamRef.hStream = 0; |
DiskStreamRef.hStream = 0; |
631 |
DiskStreamRef.State = Stream::state_unused; |
DiskStreamRef.State = Stream::state_unused; |
645 |
void Voice::processTransitionEvents(RTList<Event>::Iterator& itEvent, uint End) { |
void Voice::processTransitionEvents(RTList<Event>::Iterator& itEvent, uint End) { |
646 |
for (; itEvent && itEvent->FragmentPos() <= End; ++itEvent) { |
for (; itEvent && itEvent->FragmentPos() <= End; ++itEvent) { |
647 |
if (itEvent->Type == Event::type_release) { |
if (itEvent->Type == Event::type_release) { |
648 |
EG1.update(EGADSR::event_release, this->Pos, fFinalPitch, pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
EG1.update(EGADSR::event_release, pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
649 |
EG2.update(EGADSR::event_release, this->Pos, fFinalPitch, pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
EG2.update(EGADSR::event_release, pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
650 |
} else if (itEvent->Type == Event::type_cancel_release) { |
} else if (itEvent->Type == Event::type_cancel_release) { |
651 |
EG1.update(EGADSR::event_cancel_release, this->Pos, fFinalPitch, pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
EG1.update(EGADSR::event_cancel_release, pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
652 |
EG2.update(EGADSR::event_cancel_release, this->Pos, fFinalPitch, pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
EG2.update(EGADSR::event_cancel_release, pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
653 |
} |
} |
654 |
} |
} |
655 |
} |
} |
692 |
|
|
693 |
void Voice::processPitchEvent(RTList<Event>::Iterator& itEvent) { |
void Voice::processPitchEvent(RTList<Event>::Iterator& itEvent) { |
694 |
const float pitch = RTMath::CentsToFreqRatio(((double) itEvent->Param.Pitch.Pitch / 8192.0) * 200.0); // +-two semitones = +-200 cents |
const float pitch = RTMath::CentsToFreqRatio(((double) itEvent->Param.Pitch.Pitch / 8192.0) * 200.0); // +-two semitones = +-200 cents |
695 |
fFinalPitch *= pitch; |
finalSynthesisParameters.fFinalPitch *= pitch; |
696 |
|
PitchBend = pitch; |
697 |
} |
} |
698 |
|
|
699 |
void Voice::processCrossFadeEvent(RTList<Event>::Iterator& itEvent) { |
void Voice::processCrossFadeEvent(RTList<Event>::Iterator& itEvent) { |
738 |
* @param Skip - number of sample points to skip in output buffer |
* @param Skip - number of sample points to skip in output buffer |
739 |
*/ |
*/ |
740 |
void Voice::Synthesize(uint Samples, sample_t* pSrc, uint Skip) { |
void Voice::Synthesize(uint Samples, sample_t* pSrc, uint Skip) { |
741 |
|
finalSynthesisParameters.pOutLeft = &pEngineChannel->pOutputLeft[Skip]; |
742 |
|
finalSynthesisParameters.pOutRight = &pEngineChannel->pOutputRight[Skip]; |
743 |
|
finalSynthesisParameters.pSrc = pSrc; |
744 |
|
|
745 |
RTList<Event>::Iterator itCCEvent = pEngineChannel->pEvents->first(); |
RTList<Event>::Iterator itCCEvent = pEngineChannel->pEvents->first(); |
746 |
RTList<Event>::Iterator itNoteEvent = pEngineChannel->pMIDIKeyInfo[MIDIKey].pEvents->first(); |
RTList<Event>::Iterator itNoteEvent = pEngineChannel->pMIDIKeyInfo[MIDIKey].pEvents->first(); |
747 |
|
|
748 |
if (Skip) { // skip events that happened before this voice was triggered |
if (Skip) { // skip events that happened before this voice was triggered |
749 |
while (itCCEvent && itCCEvent->FragmentPos() <= Skip) ++itCCEvent; |
while (itCCEvent && itCCEvent->FragmentPos() <= Skip) ++itCCEvent; |
750 |
while (itNoteEvent && itNoteEvent->FragmentPos() <= Skip) ++itNoteEvent; |
while (itNoteEvent && itNoteEvent->FragmentPos() <= Skip) ++itNoteEvent; |
751 |
} |
} |
752 |
|
|
753 |
uint i = Skip; |
uint i = Skip; |
754 |
while (i < Samples) { |
while (i < Samples) { |
755 |
int iSubFragmentEnd = RTMath::Min(i + CONFIG_DEFAULT_SUBFRAGMENT_SIZE, Samples); |
int iSubFragmentEnd = RTMath::Min(i + CONFIG_DEFAULT_SUBFRAGMENT_SIZE, Samples); |
756 |
|
|
757 |
// initialize all final synthesis parameters |
// initialize all final synthesis parameters |
758 |
fFinalPitch = PitchBase * PitchBend; |
finalSynthesisParameters.fFinalPitch = PitchBase * PitchBend; |
759 |
#if CONFIG_PROCESS_MUTED_CHANNELS |
#if CONFIG_PROCESS_MUTED_CHANNELS |
760 |
fFinalVolume = this->Volume * this->CrossfadeVolume * (pEngineChannel->GetMute() ? 0 : pEngineChannel->GlobalVolume)); |
fFinalVolume = this->Volume * this->CrossfadeVolume * (pEngineChannel->GetMute() ? 0 : pEngineChannel->GlobalVolume); |
761 |
#else |
#else |
762 |
fFinalVolume = this->Volume * this->CrossfadeVolume * pEngineChannel->GlobalVolume; |
fFinalVolume = this->Volume * this->CrossfadeVolume * pEngineChannel->GlobalVolume; |
763 |
#endif |
#endif |
764 |
fFinalCutoff = VCFCutoffCtrl.fvalue; |
fFinalCutoff = VCFCutoffCtrl.fvalue; |
765 |
fFinalResonance = VCFResonanceCtrl.fvalue; |
fFinalResonance = VCFResonanceCtrl.fvalue; |
766 |
|
|
767 |
// process MIDI control change and pitchbend events for this subfragment |
// process MIDI control change and pitchbend events for this subfragment |
768 |
processCCEvents(itCCEvent, iSubFragmentEnd); |
processCCEvents(itCCEvent, iSubFragmentEnd); |
769 |
|
|
770 |
// process transition events (note on, note off & sustain pedal) |
// process transition events (note on, note off & sustain pedal) |
771 |
processTransitionEvents(itNoteEvent, iSubFragmentEnd); |
processTransitionEvents(itNoteEvent, iSubFragmentEnd); |
772 |
|
|
773 |
// process envelope generators |
// process envelope generators |
774 |
switch (EG1.getSegmentType()) { |
switch (EG1.getSegmentType()) { |
775 |
case EGADSR::segment_lin: |
case EGADSR::segment_lin: |
793 |
fFinalCutoff *= EG2.getLevel(); |
fFinalCutoff *= EG2.getLevel(); |
794 |
break; // noop |
break; // noop |
795 |
} |
} |
796 |
fFinalPitch *= RTMath::CentsToFreqRatio(EG3.render()); |
if (EG3.active()) finalSynthesisParameters.fFinalPitch *= RTMath::CentsToFreqRatio(EG3.render()); |
797 |
|
|
798 |
// process low frequency oscillators |
// process low frequency oscillators |
799 |
if (bLFO1Enabled) fFinalVolume *= pLFO1->render(); |
if (bLFO1Enabled) fFinalVolume *= pLFO1->render(); |
800 |
if (bLFO2Enabled) fFinalCutoff *= pLFO2->render(); |
if (bLFO2Enabled) fFinalCutoff *= pLFO2->render(); |
801 |
if (bLFO3Enabled) fFinalPitch *= RTMath::CentsToFreqRatio(pLFO3->render()); |
if (bLFO3Enabled) finalSynthesisParameters.fFinalPitch *= RTMath::CentsToFreqRatio(pLFO3->render()); |
802 |
|
|
803 |
// if filter enabled then update filter coefficients |
// if filter enabled then update filter coefficients |
804 |
if (SYNTHESIS_MODE_GET_FILTER(SynthesisMode)) { |
if (SYNTHESIS_MODE_GET_FILTER(SynthesisMode)) { |
805 |
FilterLeft.SetParameters(fFinalCutoff, fFinalResonance, pEngine->SampleRate); |
finalSynthesisParameters.filterLeft.SetParameters(fFinalCutoff, fFinalResonance, pEngine->SampleRate); |
806 |
FilterRight.SetParameters(fFinalCutoff, fFinalResonance, pEngine->SampleRate); |
finalSynthesisParameters.filterRight.SetParameters(fFinalCutoff, fFinalResonance, pEngine->SampleRate); |
807 |
} |
} |
808 |
|
|
809 |
// how many steps do we calculate for this next subfragment |
// do we need resampling? |
810 |
const int steps = iSubFragmentEnd - i; |
const float __PLUS_ONE_CENT = 1.000577789506554859250142541782224725466f; |
811 |
|
const float __MINUS_ONE_CENT = 0.9994225441413807496009516495583113737666f; |
812 |
// select the appropriate synthesis mode |
const bool bResamplingRequired = !(finalSynthesisParameters.fFinalPitch <= __PLUS_ONE_CENT && |
813 |
SYNTHESIS_MODE_SET_INTERPOLATE(SynthesisMode, fFinalPitch != 1.0f); |
finalSynthesisParameters.fFinalPitch >= __MINUS_ONE_CENT); |
814 |
|
SYNTHESIS_MODE_SET_INTERPOLATE(SynthesisMode, bResamplingRequired); |
815 |
|
|
816 |
|
// prepare final synthesis parameters structure |
817 |
|
finalSynthesisParameters.fFinalVolumeLeft = fFinalVolume * PanLeft; |
818 |
|
finalSynthesisParameters.fFinalVolumeRight = fFinalVolume * PanRight; |
819 |
|
finalSynthesisParameters.uiToGo = iSubFragmentEnd - i; |
820 |
|
|
821 |
// render audio for one subfragment |
// render audio for one subfragment |
822 |
RunSynthesisFunction(SynthesisMode, *this, iSubFragmentEnd, pSrc, i); |
RunSynthesisFunction(SynthesisMode, &finalSynthesisParameters, &loop); |
823 |
|
|
824 |
// increment envelopes' positions |
const double newPos = Pos + (iSubFragmentEnd - i) * finalSynthesisParameters.fFinalPitch; |
825 |
|
|
826 |
|
// increment envelopes' positions |
827 |
if (EG1.active()) { |
if (EG1.active()) { |
828 |
EG1.increment(steps); |
|
829 |
if (!EG1.toStageEndLeft()) EG1.update(EGADSR::event_stage_end, this->Pos, fFinalPitch, pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
// if sample has a loop and loop start has been reached in this subfragment, send a special event to EG1 to let it finish the attack hold stage |
830 |
|
if (pSample->Loops && Pos <= pSample->LoopStart && pSample->LoopStart < newPos) { |
831 |
|
EG1.update(EGADSR::event_hold_end, pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
832 |
|
} |
833 |
|
|
834 |
|
EG1.increment(1); |
835 |
|
if (!EG1.toStageEndLeft()) EG1.update(EGADSR::event_stage_end, pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
836 |
} |
} |
837 |
if (EG2.active()) { |
if (EG2.active()) { |
838 |
EG2.increment(steps); |
EG2.increment(1); |
839 |
if (!EG2.toStageEndLeft()) EG2.update(EGADSR::event_stage_end, this->Pos, fFinalPitch, pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
if (!EG2.toStageEndLeft()) EG2.update(EGADSR::event_stage_end, pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
840 |
} |
} |
841 |
EG3.increment(steps); |
EG3.increment(1); |
842 |
if (!EG3.toEndLeft()) EG3.update(); // neutralize envelope coefficient if end reached |
if (!EG3.toEndLeft()) EG3.update(); // neutralize envelope coefficient if end reached |
843 |
|
|
844 |
|
Pos = newPos; |
845 |
|
i = iSubFragmentEnd; |
846 |
} |
} |
847 |
} |
} |
848 |
|
|