You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
182 lines
5.5 KiB
182 lines
5.5 KiB
4 years ago
|
#include "../utility/dsp.h"
|
||
|
#include "variableshapeosc.h"
|
||
|
#include <math.h>
|
||
|
|
||
|
using namespace daisysp;
|
||
|
|
||
|
void VariableShapeOscillator::Init(float sample_rate)
|
||
|
{
|
||
|
sample_rate_ = sample_rate;
|
||
|
|
||
|
master_phase_ = 0.0f;
|
||
|
slave_phase_ = 0.0f;
|
||
|
next_sample_ = 0.0f;
|
||
|
previous_pw_ = 0.5f;
|
||
|
high_ = false;
|
||
|
|
||
|
SetFreq(440.f);
|
||
|
SetWaveshape(0.f);
|
||
|
SetPW(0.f);
|
||
|
SetSync(false);
|
||
|
SetSyncFreq(220.f);
|
||
|
}
|
||
|
|
||
|
float VariableShapeOscillator::Process()
|
||
|
{
|
||
|
float next_sample = next_sample_;
|
||
|
|
||
|
bool reset = false;
|
||
|
bool transition_during_reset = false;
|
||
|
float reset_time = 0.0f;
|
||
|
|
||
|
float this_sample = next_sample;
|
||
|
next_sample = 0.0f;
|
||
|
|
||
|
const float square_amount = fmax(waveshape_ - 0.5f, 0.0f) * 2.0f;
|
||
|
const float triangle_amount = fmax(1.0f - waveshape_ * 2.0f, 0.0f);
|
||
|
const float slope_up = 1.0f / (pw_);
|
||
|
const float slope_down = 1.0f / (1.0f - pw_);
|
||
|
|
||
|
if(enable_sync_)
|
||
|
{
|
||
|
master_phase_ += master_frequency_;
|
||
|
if(master_phase_ >= 1.0f)
|
||
|
{
|
||
|
master_phase_ -= 1.0f;
|
||
|
reset_time = master_phase_ / master_frequency_;
|
||
|
|
||
|
float slave_phase_at_reset
|
||
|
= slave_phase_ + (1.0f - reset_time) * slave_frequency_;
|
||
|
reset = true;
|
||
|
if(slave_phase_at_reset >= 1.0f)
|
||
|
{
|
||
|
slave_phase_at_reset -= 1.0f;
|
||
|
transition_during_reset = true;
|
||
|
}
|
||
|
if(!high_ && slave_phase_at_reset >= pw_)
|
||
|
{
|
||
|
transition_during_reset = true;
|
||
|
}
|
||
|
float value = ComputeNaiveSample(slave_phase_at_reset,
|
||
|
pw_,
|
||
|
slope_up,
|
||
|
slope_down,
|
||
|
triangle_amount,
|
||
|
square_amount);
|
||
|
this_sample -= value * ThisBlepSample(reset_time);
|
||
|
next_sample -= value * NextBlepSample(reset_time);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
slave_phase_ += slave_frequency_;
|
||
|
while(transition_during_reset || !reset)
|
||
|
{
|
||
|
if(!high_)
|
||
|
{
|
||
|
if(slave_phase_ < pw_)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
float t = (slave_phase_ - pw_)
|
||
|
/ (previous_pw_ - pw_ + slave_frequency_);
|
||
|
float triangle_step = (slope_up + slope_down) * slave_frequency_;
|
||
|
triangle_step *= triangle_amount;
|
||
|
|
||
|
this_sample += square_amount * ThisBlepSample(t);
|
||
|
next_sample += square_amount * NextBlepSample(t);
|
||
|
this_sample -= triangle_step * ThisIntegratedBlepSample(t);
|
||
|
next_sample -= triangle_step * NextIntegratedBlepSample(t);
|
||
|
high_ = true;
|
||
|
}
|
||
|
|
||
|
if(high_)
|
||
|
{
|
||
|
if(slave_phase_ < 1.0f)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
slave_phase_ -= 1.0f;
|
||
|
float t = slave_phase_ / slave_frequency_;
|
||
|
float triangle_step = (slope_up + slope_down) * slave_frequency_;
|
||
|
triangle_step *= triangle_amount;
|
||
|
|
||
|
this_sample -= (1.0f - triangle_amount) * ThisBlepSample(t);
|
||
|
next_sample -= (1.0f - triangle_amount) * NextBlepSample(t);
|
||
|
this_sample += triangle_step * ThisIntegratedBlepSample(t);
|
||
|
next_sample += triangle_step * NextIntegratedBlepSample(t);
|
||
|
high_ = false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(enable_sync_ && reset)
|
||
|
{
|
||
|
slave_phase_ = reset_time * slave_frequency_;
|
||
|
high_ = false;
|
||
|
}
|
||
|
|
||
|
next_sample += ComputeNaiveSample(slave_phase_,
|
||
|
pw_,
|
||
|
slope_up,
|
||
|
slope_down,
|
||
|
triangle_amount,
|
||
|
square_amount);
|
||
|
previous_pw_ = pw_;
|
||
|
|
||
|
|
||
|
next_sample_ = next_sample;
|
||
|
return (2.0f * this_sample - 1.0f);
|
||
|
}
|
||
|
|
||
|
void VariableShapeOscillator::SetFreq(float frequency)
|
||
|
{
|
||
|
frequency = frequency / sample_rate_;
|
||
|
frequency = frequency >= .25f ? .25f : frequency;
|
||
|
master_frequency_ = frequency;
|
||
|
}
|
||
|
|
||
|
void VariableShapeOscillator::SetPW(float pw)
|
||
|
{
|
||
|
if(slave_frequency_ >= .25f)
|
||
|
{
|
||
|
pw_ = .5f;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pw_ = fclamp(
|
||
|
pw, slave_frequency_ * 2.0f, 1.0f - 2.0f * slave_frequency_);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void VariableShapeOscillator::SetWaveshape(float waveshape)
|
||
|
{
|
||
|
waveshape_ = waveshape;
|
||
|
}
|
||
|
|
||
|
void VariableShapeOscillator::SetSync(bool enable_sync)
|
||
|
{
|
||
|
enable_sync_ = enable_sync;
|
||
|
}
|
||
|
|
||
|
void VariableShapeOscillator::SetSyncFreq(float frequency)
|
||
|
{
|
||
|
frequency = frequency / sample_rate_;
|
||
|
pw_ = frequency >= .25f ? .5f : pw_;
|
||
|
frequency = frequency >= .25f ? .25f : frequency;
|
||
|
slave_frequency_ = frequency;
|
||
|
}
|
||
|
|
||
|
float VariableShapeOscillator::ComputeNaiveSample(float phase,
|
||
|
float pw,
|
||
|
float slope_up,
|
||
|
float slope_down,
|
||
|
float triangle_amount,
|
||
|
float square_amount)
|
||
|
{
|
||
|
float saw = phase;
|
||
|
float square = phase < pw ? 0.0f : 1.0f;
|
||
|
float triangle
|
||
|
= phase < pw ? phase * slope_up : 1.0f - (phase - pw) * slope_down;
|
||
|
saw += (square - saw) * square_amount;
|
||
|
saw += (triangle - saw) * triangle_amount;
|
||
|
return saw;
|
||
|
}
|