Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add wavetable oscillator #176

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
Open
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ Source/Utility/dcblock.cpp
Source/Utility/jitter.cpp
Source/Utility/metro.cpp
Source/Utility/port.cpp
Source/Utility/wavetables.cpp
)


Expand Down
3 changes: 2 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,8 @@ UTILITY_MODULES = \
dcblock \
jitter \
metro \
port
port \
wavetables
#delayline
#dsp
#looper
Expand Down
141 changes: 141 additions & 0 deletions Source/Synthesis/wavetable_osc.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
#pragma once
#ifndef DSY_WAVETABLEOSC_H
#define DSY_WAVETABLEOSC_H

#include "Utility/wavetables.h"


namespace daisysp
{
/**
* @brief Wave table oscillator
*
* Based on implementation from STK (by Perry R. Cook and Gary P. Scavone, 1995--2021)
*/
class WavetableOsc
{
public:
enum Waveform
{
WAVE_SIN,
WAVE_TRI,
WAVE_SAW,
WAVE_SQUARE,
WAVE_LAST,
};

void Init(float sample_rate_)
{
sample_rate = sample_rate_;
sr_resiprocal = 1 / sample_rate;
SetWaveform(WAVE_SQUARE);
SetFreq(440);
SetAmp(0.7f);
}

void SetWaveform(const Waveform wf)
{
switch(wf)
{
case Waveform::WAVE_SIN: SetWaveTable(&Tables::Sine); break;
case Waveform::WAVE_TRI: SetWaveTable(&Tables::Tri); break;
case Waveform::WAVE_SAW: SetWaveTable(&Tables::Saw); break;
case Waveform::WAVE_SQUARE: SetWaveTable(&Tables::Square); break;
default: SetWaveTable(&Tables::Sine);
Comment on lines +40 to +44
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These now throw the error(s)
'template<class T, void (* fft_func)(int, T*, T*)> class daisysp::Tables' used without template arguments and so on.

}
}

void SetWaveTable(WaveTable *table)
{
m_table = table;
table_size = m_table->buff->wt_size;
}

/**
* @brief Set the data interpolation rate based on a looping frequency.
*
* This function determines the interpolation rate based on the file
* size and the current Stk::sampleRate. The \e frequency value
* corresponds to file cycles per second. The frequency can be
* negative, in which case the loop is read in reverse order.
*
* @param frequency Osc frequency in Hz.
*/
void SetFreq(float frequency)
{
auto norm_freq = frequency * sr_resiprocal;
this->SetRate(table_size * norm_freq);

// update the current wave table selector
m_table->SetTopFreq(norm_freq);
}

/**
* @brief Add a phase offset in cycles, where 1.0 = fileSize.
*
*
* This function determines a time offset based on the file
* size and the current sample sate. The \e angle value
* is a multiple of file size.
*
* @param angle Phase offset in cycles.
*/
void PhaseAdd(float angle)
{
time_ += table_size * angle;

if(time_ < 0.0f)
time_ += table_size;
else if(time_ >= table_size)
time_ -= table_size;
}

void SetAmp(const float a) { amp = a; }

/**
* @brief Compute a sample frame and return the value.
*/
float Process()
{
while(time_ < 0.0f)
time_ += table_size;
while(time_ >= table_size)
time_ -= table_size;

float out = m_table->GetSample(time_);

time_ += rate_;

return out * amp;
}

private:
/**
* @brief Set the data read rate in samples. The rate can be negative.
*
* If the rate value is negative, the data is read in reverse order.
*
* @param rate
*/
void SetRate(float rate)
{
rate_ = rate;

if(std::fmod(rate_, 1.0f) != 0.0f)
interpolate_ = true;
else
interpolate_ = false;
}

WaveTable *m_table;
float sample_rate;
float sr_resiprocal;
float time_ = 0.f;
bool interpolate_ = false;
float rate_;
float amp = 1;
uint16_t table_size = 1;
};

} // namespace daisysp
#endif
27 changes: 27 additions & 0 deletions Source/Utility/wavetables.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#include "wavetables.h"

// hackish way to make it work for both mcu and computer
#ifndef DSY_SDRAM_BSS
#define DSY_SDRAM_BSS /* emtpy */
#endif

namespace daisysp
{
template <typename T, FFTFunction<T> fft>
bool Tables<T, fft>::generated = false;

template <typename T, FFTFunction<T> fft>
WaveBuffer DSY_SDRAM_BSS Tables<T, fft>::buffer_pool[40];
template <typename T, FFTFunction<T> fft>
uint8_t Tables<T, fft>::num_buffers = 0;

template <typename T, FFTFunction<T> fft>
WaveTable Tables<T, fft>::Sine;
template <typename T, FFTFunction<T> fft>
WaveTable Tables<T, fft>::Square;
template <typename T, FFTFunction<T> fft>
WaveTable Tables<T, fft>::Tri;
template <typename T, FFTFunction<T> fft>
WaveTable Tables<T, fft>::Saw;

} // namespace daisysp
Loading
Loading