7#include "signals/hart_signal.hpp"
17template<
typename SampleType>
25 Sawtooth (
double frequencyHz = 1000.0,
double phaseRadians = 0.0):
26 m_frequencyHz (frequencyHz),
28 m_phaseRadians (m_initialPhaseRadians)
30 if (frequencyHz <= 0.0)
34 void prepare (
double sampleRateHz, size_t , size_t )
override
36 m_sampleRateHz = sampleRateHz;
37 m_phaseIncrementRadians =
hart::twoPi * m_frequencyHz / m_sampleRateHz;
38 m_ratio = m_frequencyHz / m_sampleRateHz;
44 for (size_t frame = 0; frame < output.getNumFrames(); ++frame)
46 const double portion = m_phaseRadians /
hart::twoPi;
47 SampleType value = SampleType (2.0 * portion - 1.0);
49 if (portion < m_ratio)
51 const double t = portion / m_ratio;
52 value += SampleType ((t - 1.0) * (t - 1.0));
54 else if (portion > 1.0 - m_ratio)
56 const double t = (portion - 1.0) / m_ratio;
57 value -= SampleType ((t + 1.0) * (t + 1.0));
60 value *= m_makeupGainLinear;
62 for (size_t channel = 0; channel < output.getNumChannels(); ++channel)
63 output[channel][frame] = value;
65 m_phaseRadians =
wrapPhase (m_phaseRadians + m_phaseIncrementRadians
);
71 m_phaseRadians = m_initialPhaseRadians;
74 void represent (std::ostream& stream)
const override
76 stream <<
"Sawtooth ("
82 const double m_frequencyHz;
83 const double m_initialPhaseRadians;
84 double m_phaseRadians = 0.0;
85 double m_sampleRateHz = 44100.0;
86 double m_phaseIncrementRadians =
hart::twoPi * m_frequencyHz / m_sampleRateHz;
87 double m_ratio = m_frequencyHz / m_sampleRateHz;
88 SampleType m_makeupGainLinear = (SampleType) 1;
90 inline void updateMakeupGain()
99 m_makeupGainLinear = approximateMakeupGain (0.9999792899251587, -4.535565865100019e-05, 5.14460147253294e-10);
105 m_makeupGainLinear = approximateMakeupGain (0.9999806254677883, -4.16723249855034e-05, 4.342374921390162e-10);
111 m_makeupGainLinear = approximateMakeupGain (0.9999858295396981, -2.267921714003928e-05, 1.287471954911674e-10);
117 m_makeupGainLinear = approximateMakeupGain (0.9999827886316706, -2.089171398739896e-05, 1.118510164833643e-10);
123 m_makeupGainLinear = approximateMakeupGain (1.000109987458273, -1.047641814174239e-05, 2.964600179948776e-11);
128 m_makeupGainLinear = measureMakeupGain();
131 inline SampleType approximateMakeupGain (
double a0,
double a1,
double a2)
133 return static_cast<SampleType> (1.0 / (m_frequencyHz * (a2 * m_frequencyHz + a1) + a0));
136 SampleType measureMakeupGain()
138 const double cyclesToMeasure = 32.0;
139 const size_t framesToMeasure =
static_cast<size_t> (cyclesToMeasure * m_sampleRateHz / m_frequencyHz);
140 const double originalPhaseRadians = m_phaseRadians;
142 AudioBuffer<SampleType> buffer (1, framesToMeasure);
145 SampleType peakLinear = (SampleType) 0;
147 for (size_t i = 0; i < framesToMeasure; ++i)
148 peakLinear = std::max (peakLinear, std::abs (buffer[0][i]));
150 m_phaseRadians = originalPhaseRadians;
151 return static_cast<SampleType> ((peakLinear > (SampleType) 0) ? SampleType (1) / peakLinear : (SampleType) 1);
Produces a bandlimited sawtooth wave at fixed frequency.
void renderNextBlock(AudioBuffer< SampleType > &output) override
Renders next block audio for the signal.
Sawtooth(double frequencyHz=1000.0, double phaseRadians=0.0)
Creates a sawtooth signal instance.
void represent(std::ostream &stream) const override
Makes a text representation of this Signal for test failure outputs.
void prepare(double sampleRateHz, size_t, size_t) override
Prepare the signal for rendering.
void reset() override
Resets the Signal to initial state.
std::ostream & radPrecision(std::ostream &stream)
Sets number of decimal places for values in radians.
std::ostream & hzPrecision(std::ostream &stream)
Sets number of decimal places for values in hertz.
constexpr double twoPi
2 * pi
SampleType wrapPhase(const SampleType phaseRadians)
Keeps phase in 0..twoPi range.
static SampleType floatsEqual(SampleType a, SampleType b, SampleType epsilon=(SampleType) 1e-8)
Compares two floating point numbers within a given tolerance.
#define HART_THROW(ExceptionType, message)
#define HART_SIGNAL_DECLARE_ALIASES_FOR(ClassName)