mirror of
https://github.com/yokemura/Magical8bitPlug2.git
synced 2025-07-17 11:04:16 -04:00
Added code
This commit is contained in:
226
Source/BaseVoice.cpp
Normal file
226
Source/BaseVoice.cpp
Normal file
@ -0,0 +1,226 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
BaseVoice.cpp
|
||||
Created: 11 Nov 2019 9:38:44pm
|
||||
Author: 除村 武志
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#include "BaseVoice.h"
|
||||
|
||||
//---------------------------------------------
|
||||
//
|
||||
// Base Voice
|
||||
// (Abstract)
|
||||
//
|
||||
//---------------------------------------------
|
||||
BaseVoice::BaseVoice (SettingRefs* sRefs)
|
||||
{
|
||||
settingRefs = sRefs;
|
||||
}
|
||||
|
||||
bool BaseVoice::canPlaySound (SynthesiserSound* sound)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void BaseVoice::startNote (int midiNoteNumber, float velocity, SynthesiserSound*, int currentPitchBendPosition)
|
||||
{
|
||||
|
||||
noteNumber = midiNoteNumber;
|
||||
|
||||
envelopePhase = kEnvelopePhaseA;
|
||||
currentAngle = 0.0;
|
||||
currentEnvelopeLevel = 0.0;
|
||||
|
||||
ampByVelocityAndGain = * (settingRefs->gain) * velocity; // velocity value range is 0.0f-1.0f
|
||||
|
||||
calculateAngleDelta();
|
||||
|
||||
//
|
||||
// Envelope
|
||||
//
|
||||
double srate = getSampleRate();
|
||||
|
||||
if (* (settingRefs->attack) == 0 ) { attack_slope = 1.0; }
|
||||
else
|
||||
{
|
||||
attack_slope = 1.0 / (* (settingRefs->attack) * srate);
|
||||
}
|
||||
|
||||
if (* (settingRefs->decay) == 0 ) { decay_slope = 1.0; }
|
||||
else
|
||||
{
|
||||
decay_slope = 1.0 / (* (settingRefs->decay) * srate);
|
||||
}
|
||||
|
||||
sustain_level = * (settingRefs->suslevel);
|
||||
|
||||
if (* (settingRefs->release) == 0 ) { release_slope = 1.0; }
|
||||
else
|
||||
{
|
||||
release_slope = 1.0 / (* (settingRefs->release) * srate);
|
||||
}
|
||||
|
||||
//
|
||||
// Control frame
|
||||
//
|
||||
controlFrameTimer = 0;
|
||||
currentVolumeSequenceFrame = 0;
|
||||
|
||||
if (settingRefs->isVolumeSequenceEnabled())
|
||||
{
|
||||
currentEnvelopeLevel = (float) (settingRefs->volumeSequence.valueAt (0)) / 15.0f;
|
||||
}
|
||||
}
|
||||
|
||||
void BaseVoice::stopNote (float, bool allowTailOff)
|
||||
{
|
||||
if (!allowTailOff)
|
||||
{
|
||||
clearCurrentNote();
|
||||
angleDelta = 0.0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (settingRefs->isVolumeSequenceEnabled())
|
||||
{
|
||||
if (settingRefs->volumeSequence.hasRelease)
|
||||
{
|
||||
currentVolumeSequenceFrame = settingRefs->volumeSequence.releaseSequenceStartIndex;
|
||||
currentEnvelopeLevel = (float) (settingRefs->volumeSequence.valueAt (0)) / 15.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
clearCurrentNote();
|
||||
angleDelta = 0.0;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
envelopePhase = kEnvelopePhaseR;
|
||||
}
|
||||
|
||||
void BaseVoice::renderNextBlock (AudioSampleBuffer& outputBuffer, int startSample, int numSamples)
|
||||
{
|
||||
if (angleDelta == 0.0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
while (--numSamples >= 0)
|
||||
{
|
||||
//
|
||||
// Envelope
|
||||
//
|
||||
if (settingRefs->isVolumeSequenceEnabled())
|
||||
{
|
||||
currentEnvelopeLevel = (float) (settingRefs->volumeSequence.valueAt (currentVolumeSequenceFrame)) / 15.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (envelopePhase)
|
||||
{
|
||||
case kEnvelopePhaseA:
|
||||
currentEnvelopeLevel += attack_slope;
|
||||
|
||||
if (currentEnvelopeLevel > 1.0)
|
||||
{
|
||||
currentEnvelopeLevel = 1.0;
|
||||
envelopePhase = kEnvelopePhaseD;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case kEnvelopePhaseD:
|
||||
currentEnvelopeLevel -= decay_slope;
|
||||
|
||||
if (currentEnvelopeLevel < sustain_level)
|
||||
{
|
||||
envelopePhase = kEnvelopePhaseS;
|
||||
currentEnvelopeLevel = sustain_level;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case kEnvelopePhaseS:
|
||||
currentEnvelopeLevel = sustain_level;
|
||||
break;
|
||||
|
||||
case kEnvelopePhaseR:
|
||||
currentEnvelopeLevel -= release_slope;
|
||||
|
||||
if (currentEnvelopeLevel < 0)
|
||||
{
|
||||
currentEnvelopeLevel = 0;
|
||||
clearCurrentNote();
|
||||
angleDelta = 0.0;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Write to buffer
|
||||
//
|
||||
float currentSample = voltageForAngle (currentAngle) * currentEnvelopeLevel * ampByVelocityAndGain;
|
||||
|
||||
for (auto i = outputBuffer.getNumChannels(); --i >= 0;)
|
||||
outputBuffer.addSample (i, startSample, currentSample);
|
||||
|
||||
//
|
||||
// Advance phase
|
||||
//
|
||||
calculateAngleDelta();
|
||||
|
||||
currentAngle += angleDelta;
|
||||
|
||||
while (currentAngle > 2.0 * MathConstants<float>::pi)
|
||||
{
|
||||
currentAngle -= 2.0 * MathConstants<float>::pi;
|
||||
}
|
||||
|
||||
//
|
||||
// Advance control frame
|
||||
//
|
||||
controlFrameTimer += 1.0 / getSampleRate();
|
||||
|
||||
if (controlFrameTimer >= controlFrameLength)
|
||||
{
|
||||
advanceControlFrame();
|
||||
|
||||
while (controlFrameTimer >= controlFrameLength)
|
||||
{
|
||||
controlFrameTimer -= controlFrameLength;
|
||||
}
|
||||
}
|
||||
|
||||
onFrameAdvanced();
|
||||
|
||||
++startSample;
|
||||
}
|
||||
}
|
||||
|
||||
void BaseVoice::calculateAngleDelta()
|
||||
{
|
||||
auto cyclesPerSecond = MidiMessage::getMidiNoteInHertz (noteNumber);
|
||||
auto cyclesPerSample = cyclesPerSecond / getSampleRate();
|
||||
|
||||
angleDelta = cyclesPerSample * 2.0 * MathConstants<double>::pi;
|
||||
}
|
||||
|
||||
void BaseVoice::advanceControlFrame()
|
||||
{
|
||||
currentVolumeSequenceFrame = settingRefs->volumeSequence.nextIndexOf (currentVolumeSequenceFrame);
|
||||
|
||||
if (currentVolumeSequenceFrame == FrameSequence::SHOULD_RETIRE)
|
||||
{
|
||||
currentEnvelopeLevel = 0;
|
||||
clearCurrentNote();
|
||||
angleDelta = 0.0;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user