2020-11-27 05:16:22 -05:00
|
|
|
//
|
|
|
|
// FILE: functionGenerator.cpp
|
|
|
|
// AUTHOR: Rob Tillaart
|
2024-07-07 04:18:00 -04:00
|
|
|
// VERSION: 0.3.0
|
2020-11-27 05:16:22 -05:00
|
|
|
// PURPOSE: wave form generating functions (use with care)
|
|
|
|
// URL: https://github.com/RobTillaart/FunctionGenerator
|
2021-11-02 06:27:01 -04:00
|
|
|
|
2020-11-27 05:16:22 -05:00
|
|
|
|
|
|
|
#include "functionGenerator.h"
|
|
|
|
|
2021-11-02 06:27:01 -04:00
|
|
|
|
2020-11-27 05:16:22 -05:00
|
|
|
funcgen::funcgen(float period, float amplitude, float phase, float yShift)
|
|
|
|
{
|
|
|
|
setPeriod(period);
|
|
|
|
setAmplitude(amplitude);
|
|
|
|
setPhase(phase);
|
|
|
|
setYShift(yShift);
|
2023-03-26 04:32:34 -04:00
|
|
|
setDutyCycle(50); // TODO param?
|
2020-11-27 05:16:22 -05:00
|
|
|
}
|
|
|
|
|
2021-11-02 06:27:01 -04:00
|
|
|
|
2023-03-26 04:32:34 -04:00
|
|
|
/////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// CONFIGURATION
|
|
|
|
//
|
2020-11-27 05:16:22 -05:00
|
|
|
void funcgen::setPeriod(float period)
|
|
|
|
{
|
|
|
|
_period = period;
|
|
|
|
_freq1 = 1 / period;
|
|
|
|
_freq2 = 2 * _freq1;
|
|
|
|
_freq4 = 4 * _freq1;
|
|
|
|
_freq0 = TWO_PI * _freq1;
|
|
|
|
}
|
|
|
|
|
2021-11-02 06:27:01 -04:00
|
|
|
|
2023-03-26 04:32:34 -04:00
|
|
|
float funcgen::getPeriod()
|
|
|
|
{
|
|
|
|
return _period;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void funcgen::setFrequency(float freq)
|
|
|
|
{
|
|
|
|
setPeriod(1.0 / freq);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
float funcgen::getFrequency()
|
|
|
|
{
|
|
|
|
return _freq1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void funcgen::setAmplitude(float ampl)
|
|
|
|
{
|
|
|
|
_amplitude = ampl;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
float funcgen::getAmplitude()
|
|
|
|
{
|
|
|
|
return _amplitude;
|
|
|
|
}
|
|
|
|
|
|
|
|
void funcgen::setPhase(float phase)
|
|
|
|
{
|
|
|
|
_phase = phase;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
float funcgen::getPhase()
|
|
|
|
{
|
|
|
|
return _phase;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void funcgen::setYShift(float yShift)
|
|
|
|
{
|
|
|
|
_yShift = yShift;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
float funcgen::getYShift()
|
|
|
|
{
|
|
|
|
return _yShift;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void funcgen::setDutyCycle(float dutyCycle)
|
|
|
|
{
|
2023-11-02 10:09:32 -04:00
|
|
|
// negative dutyCycle? => 1-dc? or abs()?
|
2023-03-26 04:32:34 -04:00
|
|
|
if (dutyCycle < 0) _dutyCycle = 0.0;
|
|
|
|
else if (dutyCycle > 100) _dutyCycle = 1.0;
|
|
|
|
else _dutyCycle = dutyCycle * 0.01;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
float funcgen::getDutyCycle()
|
|
|
|
{
|
|
|
|
return _dutyCycle * 100.0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void funcgen::setRandomSeed(uint32_t a, uint32_t b)
|
|
|
|
{
|
|
|
|
// prevent zero loops in random() function.
|
|
|
|
if (a == 0) a = 123;
|
|
|
|
if (b == 0) b = 456;
|
|
|
|
_m_w = a;
|
|
|
|
_m_z = b;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// FUNCTIONS
|
|
|
|
//
|
2020-11-27 05:16:22 -05:00
|
|
|
float funcgen::line()
|
|
|
|
{
|
|
|
|
return _yShift + _amplitude;
|
|
|
|
}
|
|
|
|
|
2021-11-02 06:27:01 -04:00
|
|
|
|
2020-11-27 05:16:22 -05:00
|
|
|
float funcgen::zero()
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-11-02 06:27:01 -04:00
|
|
|
|
|
|
|
float funcgen::sawtooth(float t, uint8_t mode)
|
2020-11-27 05:16:22 -05:00
|
|
|
{
|
|
|
|
float rv;
|
|
|
|
t += _phase;
|
|
|
|
if (t >= 0.0)
|
|
|
|
{
|
2023-03-26 04:32:34 -04:00
|
|
|
t = fmod(t, _period);
|
2021-11-02 06:27:01 -04:00
|
|
|
if (mode == 1) t = _period - t;
|
2020-11-27 05:16:22 -05:00
|
|
|
rv = _amplitude * (-1.0 + t *_freq2);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
t = -t;
|
2023-03-26 04:32:34 -04:00
|
|
|
t = fmod(t, _period);
|
2021-11-02 06:27:01 -04:00
|
|
|
if (mode == 1) t = _period - t;
|
|
|
|
rv = _amplitude * ( 1.0 - t * _freq2);
|
2020-11-27 05:16:22 -05:00
|
|
|
}
|
|
|
|
rv += _yShift;
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2021-11-02 06:27:01 -04:00
|
|
|
|
2020-11-27 05:16:22 -05:00
|
|
|
float funcgen::triangle(float t)
|
|
|
|
{
|
|
|
|
float rv;
|
|
|
|
t += _phase;
|
|
|
|
if (t < 0.0)
|
|
|
|
{
|
|
|
|
t = -t;
|
|
|
|
}
|
2023-03-26 04:32:34 -04:00
|
|
|
t = fmod(t, _period);
|
|
|
|
if (t < (_period * _dutyCycle))
|
2020-11-27 05:16:22 -05:00
|
|
|
{
|
2023-03-26 04:32:34 -04:00
|
|
|
rv = _amplitude * (-1.0 + t * _freq2 / _dutyCycle);
|
2020-11-27 05:16:22 -05:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2023-03-26 04:32:34 -04:00
|
|
|
// mirror math
|
|
|
|
t = _period - t;
|
|
|
|
rv = _amplitude * (-1.0 + t * _freq2 /(1 - _dutyCycle));
|
2020-11-27 05:16:22 -05:00
|
|
|
}
|
|
|
|
rv += _yShift;
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2021-11-02 06:27:01 -04:00
|
|
|
|
2020-11-27 05:16:22 -05:00
|
|
|
float funcgen::square(float t)
|
|
|
|
{
|
|
|
|
float rv;
|
|
|
|
t += _phase;
|
|
|
|
if (t >= 0)
|
|
|
|
{
|
2023-03-26 04:32:34 -04:00
|
|
|
t = fmod(t, _period);
|
|
|
|
if (t < (_period * _dutyCycle)) rv = _amplitude;
|
2020-11-27 05:16:22 -05:00
|
|
|
else rv = -_amplitude;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
t = -t;
|
2023-03-26 04:32:34 -04:00
|
|
|
t = fmod(t, _period);
|
|
|
|
if (t < (_period * _dutyCycle)) rv = -_amplitude;
|
2020-11-27 05:16:22 -05:00
|
|
|
else rv = _amplitude;
|
|
|
|
}
|
|
|
|
rv += _yShift;
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2021-11-02 06:27:01 -04:00
|
|
|
|
2020-11-27 05:16:22 -05:00
|
|
|
float funcgen::sinus(float t)
|
|
|
|
{
|
|
|
|
float rv;
|
|
|
|
t += _phase;
|
|
|
|
rv = _amplitude * sin(t * _freq0);
|
|
|
|
rv += _yShift;
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2021-11-02 06:27:01 -04:00
|
|
|
|
|
|
|
float funcgen::stair(float t, uint16_t steps, uint8_t mode)
|
2020-11-27 05:16:22 -05:00
|
|
|
{
|
|
|
|
t += _phase;
|
|
|
|
if (t >= 0)
|
|
|
|
{
|
2023-03-26 04:32:34 -04:00
|
|
|
t = fmod(t, _period);
|
2021-11-02 06:27:01 -04:00
|
|
|
if (mode == 1) t = _period - t;
|
2020-11-27 05:16:22 -05:00
|
|
|
int level = steps * t / _period;
|
|
|
|
return _yShift + _amplitude * (-1.0 + 2.0 * level / (steps - 1));
|
|
|
|
}
|
|
|
|
t = -t;
|
2023-03-26 04:32:34 -04:00
|
|
|
t = fmod(t, _period);
|
2021-11-02 06:27:01 -04:00
|
|
|
if (mode == 1) t = _period - t;
|
2020-11-27 05:16:22 -05:00
|
|
|
int level = steps * t / _period;
|
|
|
|
return _yShift + _amplitude * (1.0 - 2.0 * level / (steps - 1));
|
|
|
|
}
|
|
|
|
|
2021-11-02 06:27:01 -04:00
|
|
|
|
2020-11-27 05:16:22 -05:00
|
|
|
float funcgen::random()
|
|
|
|
{
|
2023-11-02 10:09:32 -04:00
|
|
|
float rv = _yShift + _amplitude * _random() * 0.2328306436E-9; // div 0xFFFFFFFF
|
2020-11-27 05:16:22 -05:00
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2021-11-02 06:27:01 -04:00
|
|
|
|
2023-03-26 04:32:34 -04:00
|
|
|
// duty cycle variant takes more than twice as much time.
|
|
|
|
float funcgen::random_DC()
|
|
|
|
{
|
|
|
|
static float rv = 0;
|
|
|
|
float next = _yShift + _amplitude * _random() * 0.2328306436E-9; // div 0xFFFFFFFF
|
|
|
|
rv += (next - rv) * _dutyCycle;
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2024-07-07 04:18:00 -04:00
|
|
|
/////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// EXPERIMENTAL 0.2.7
|
|
|
|
//
|
|
|
|
float funcgen::sinusDiode(float t)
|
|
|
|
{
|
|
|
|
float rv = sinus(t);
|
|
|
|
if (rv < _yShift) return _yShift;
|
|
|
|
return rv;
|
|
|
|
|
|
|
|
// float rv;
|
|
|
|
// t += _phase;
|
|
|
|
// rv = sin(t * _freq0);
|
|
|
|
// if (rv < 0) return _yShift;
|
|
|
|
// rv *= amplitude;
|
|
|
|
// rv += _yShift;
|
|
|
|
// return rv;
|
|
|
|
}
|
2023-03-26 04:32:34 -04:00
|
|
|
|
2024-07-07 04:18:00 -04:00
|
|
|
|
|
|
|
float funcgen::sinusRectified(float t)
|
|
|
|
{
|
|
|
|
// float rv = sinus(t);
|
|
|
|
// if (rv < _yShift) return _yShift - rv;
|
|
|
|
// return rv;
|
|
|
|
|
|
|
|
float rv;
|
|
|
|
t += _phase;
|
|
|
|
rv = _amplitude * sin(t * _freq0);
|
|
|
|
if (rv < 0) rv = -rv;
|
|
|
|
rv += _yShift;
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
float funcgen::trapezium1(float t)
|
|
|
|
{
|
|
|
|
t += _phase + _period * _dutyCycle / 4; // zero point for t = 0
|
|
|
|
if (t < 0)
|
|
|
|
{
|
|
|
|
t = -t;
|
|
|
|
}
|
|
|
|
t = fmod(t, _period);
|
|
|
|
|
|
|
|
if (t < _period * 0.5 * _dutyCycle) // rising part
|
|
|
|
{
|
|
|
|
return _yShift + -_amplitude + 2 * _amplitude * (t * 2 / (_period * _dutyCycle));
|
|
|
|
}
|
|
|
|
else if (t < _period * 0.5) // high part
|
|
|
|
{
|
|
|
|
return _yShift + _amplitude;
|
|
|
|
}
|
|
|
|
else if (t < _period * (0.5 + 0.5 * _dutyCycle)) // falling part
|
|
|
|
{
|
|
|
|
return _yShift + _amplitude - 2 * _amplitude * ( (t * 2 - _period) / (_period * _dutyCycle));
|
|
|
|
}
|
|
|
|
else // low part
|
|
|
|
{
|
|
|
|
return _yShift + -_amplitude;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
float funcgen::trapezium2(float t)
|
|
|
|
{
|
|
|
|
t += _phase + _period * _dutyCycle / 4; // zero point for t = 0
|
|
|
|
if (t < 0)
|
|
|
|
{
|
|
|
|
t = -t;
|
|
|
|
}
|
|
|
|
t = fmod(t, _period);
|
|
|
|
|
|
|
|
if (t < _period * 0.25) // rising part
|
|
|
|
{
|
|
|
|
return _yShift + -_amplitude + 2 * _amplitude * (t * 4 / _period);
|
|
|
|
}
|
|
|
|
else if (t < _period * (0.25 + 0.5 * _dutyCycle)) // high part
|
|
|
|
{
|
|
|
|
return _yShift + _amplitude;
|
|
|
|
}
|
|
|
|
else if (t < _period * (0.5 + 0.5 * _dutyCycle)) // falling part
|
|
|
|
{
|
|
|
|
return _yShift + _amplitude - 2 * _amplitude * ((t - _period * (0.25 + 0.5 * _dutyCycle)) * 4 / _period);
|
|
|
|
}
|
|
|
|
else // low part
|
|
|
|
{
|
|
|
|
return _yShift + -_amplitude;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
// no DC version (50%
|
|
|
|
float funcgen::trapezium(float t)
|
|
|
|
{
|
|
|
|
t += _phase;
|
|
|
|
if (t < 0)
|
|
|
|
{
|
|
|
|
t = -t;
|
|
|
|
}
|
|
|
|
t = fmod(t, _period);
|
|
|
|
|
|
|
|
if (t < _period * 0.25) // rising part
|
|
|
|
{
|
|
|
|
return -_amplitude + 2 * _amplitude * (t * 4 / _period);
|
|
|
|
}
|
|
|
|
else if (t < _period * 0.5) // high part
|
|
|
|
{
|
|
|
|
return _amplitude;
|
|
|
|
}
|
|
|
|
else if (t < _period * 0.75) // high part
|
|
|
|
{
|
|
|
|
return _amplitude - 2 * _amplitude * ((t - _period/2) * 4 / _period);
|
|
|
|
}
|
|
|
|
else // low part
|
|
|
|
{
|
|
|
|
return -_amplitude;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// EXPERIMENTAL HEARTBEAT
|
|
|
|
// => setFrequency(72.0 / 60.0); // BPM/60 = BPS.
|
|
|
|
float funcgen::heartBeat(float t)
|
|
|
|
{
|
|
|
|
int16_t out[32] = {
|
|
|
|
0, 0, 1000, 2500,
|
|
|
|
1000, 1000, -50, 10000,
|
|
|
|
-2500, 2000, 2500, 3000,
|
|
|
|
3000, 2000, 0, 0,
|
|
|
|
0,0,0,0,
|
|
|
|
0,0,0,0,
|
|
|
|
0,0,0,0,
|
|
|
|
0,0,0,0,
|
|
|
|
};
|
|
|
|
// use duty cycle to determine zero level duration.
|
|
|
|
int pts = map(_dutyCycle * 100, 0, 100, 31, 15);
|
|
|
|
|
|
|
|
return freeWave(t, out, pts);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
// points need to be optimized,
|
|
|
|
// 0.2.7 uses 160 bytes for the two arrays.
|
|
|
|
// wrapper around freeWave?
|
|
|
|
float funcgen::heartBeat(float t)
|
|
|
|
{
|
|
|
|
// based upon MultiMap in[] array is normalized to 0.0 - 1.0
|
|
|
|
// Heart beat phase P Q R S T U
|
|
|
|
float in[21] = { 0.0, 0.07, 0.13, 0.20, 0.27, 0.33, 0.40, 0.46, 0.53, 0.60, 0.66, 0.73, 0.80, 0.86, 0.93, 1.00 };
|
|
|
|
float out[21] = { 0.0, 0.00, 0.10, 0.25, 0.10, 0.10, -0.05, 1.00, -0.25, 0.20, 0.25, 0.30, 0.30, 0.20, 0.00, 0.00 };
|
|
|
|
|
|
|
|
t += _phase;
|
|
|
|
t = fmod(t, _period);
|
|
|
|
|
|
|
|
// normalize t to 0.0 - 1.0
|
|
|
|
t *= _freq1;
|
|
|
|
// search interval
|
|
|
|
int idx = 0;
|
|
|
|
while (t > in[idx]) idx++;
|
|
|
|
if (t == in[idx]) return _yShift + _amplitude * out[idx];
|
|
|
|
idx--;
|
|
|
|
// interpolate.
|
|
|
|
float factor = (t - in[idx]) / (in[idx+1] - in[idx]);
|
|
|
|
return _yShift + _amplitude * (out[idx] + factor * (out[idx+1] - out[idx]));
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
float funcgen::freeWave(float t, int16_t * arr, int16_t size)
|
|
|
|
{
|
|
|
|
t += _phase;
|
|
|
|
// normalize t to 0.0 - 1.0
|
|
|
|
t = fmod(t, _period);
|
|
|
|
t *= _freq1;
|
|
|
|
|
|
|
|
// search interval, as arr is based upon N equidistant points,
|
|
|
|
// we can easily calculate the points for direct access
|
|
|
|
float factor = t * size;
|
|
|
|
int idx = factor; // truncate to get index of output array.
|
|
|
|
factor = factor - idx; // remainder is interpolate factor.
|
|
|
|
// interpolate.
|
|
|
|
return _yShift + _amplitude * 1e-4 * (arr[idx] + factor * (arr[idx+1] - arr[idx]));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// PRIVATE
|
|
|
|
//
|
2023-03-26 04:32:34 -04:00
|
|
|
// An example of a simple pseudo-random number generator is the
|
|
|
|
// Multiply-with-carry method invented by George Marsaglia.
|
|
|
|
// two initializers (not null)
|
2020-11-27 05:16:22 -05:00
|
|
|
uint32_t funcgen::_random()
|
|
|
|
{
|
|
|
|
_m_z = 36969L * (_m_z & 65535L) + (_m_z >> 16);
|
|
|
|
_m_w = 18000L * (_m_w & 65535L) + (_m_w >> 16);
|
|
|
|
return (_m_z << 16) + _m_w; /* 32-bit result */
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2024-07-07 04:18:00 -04:00
|
|
|
|
2023-03-26 04:32:34 -04:00
|
|
|
/////////////////////////////////////////////////////////////
|
2020-11-27 05:16:22 -05:00
|
|
|
//
|
2023-03-26 04:32:34 -04:00
|
|
|
// INTEGER VERSIONS FOR 8 BIT DAC
|
2020-11-27 05:16:22 -05:00
|
|
|
//
|
2023-03-26 04:32:34 -04:00
|
|
|
// 8 bits version
|
|
|
|
// t = 0..9999 period 10000 in millis, returns 0..255
|
2020-11-27 05:16:22 -05:00
|
|
|
|
|
|
|
/*
|
2021-11-02 06:27:01 -04:00
|
|
|
|
2020-11-27 05:16:22 -05:00
|
|
|
uint8_t ifgsaw(uint16_t t, uint16_t period = 1000)
|
|
|
|
{
|
|
|
|
return 255L * t / period;
|
|
|
|
}
|
|
|
|
|
2021-11-02 06:27:01 -04:00
|
|
|
|
2020-11-27 05:16:22 -05:00
|
|
|
uint8_t ifgtri(uint16_t t, uint16_t period = 1000)
|
|
|
|
{
|
|
|
|
if (t * 2 < period) return 510L * t / period;
|
|
|
|
return 255L - 510L * t / period;
|
|
|
|
}
|
|
|
|
|
2021-11-02 06:27:01 -04:00
|
|
|
|
2020-11-27 05:16:22 -05:00
|
|
|
uint8_t ifgsqr(uint16_t t, uint16_t period = 1000)
|
|
|
|
{
|
|
|
|
if (t * 2 < period) return 510L * t / period;
|
|
|
|
return 255L - 510L * t / period;
|
|
|
|
}
|
|
|
|
|
2021-11-02 06:27:01 -04:00
|
|
|
|
2020-11-27 05:16:22 -05:00
|
|
|
uint8_t ifgsin(uint16_t t, uint16_t period = 1000)
|
|
|
|
{
|
|
|
|
return sin(355L * t / period / 113); // LUT
|
|
|
|
}
|
|
|
|
|
2021-11-02 06:27:01 -04:00
|
|
|
|
2020-11-27 05:16:22 -05:00
|
|
|
uint8_t ifgstr(uint16_t t, uint16_t period = 1000, uint16_t steps = 8)
|
|
|
|
{
|
|
|
|
int level = 1L * steps * t / period;
|
|
|
|
return 255L * level / (steps - 1);
|
|
|
|
}
|
2021-11-02 06:27:01 -04:00
|
|
|
|
2020-11-27 05:16:22 -05:00
|
|
|
*/
|
|
|
|
|
2021-11-02 06:27:01 -04:00
|
|
|
|
2023-03-26 04:32:34 -04:00
|
|
|
/////////////////////////////////////////////////////////////
|
2020-11-27 05:16:22 -05:00
|
|
|
//
|
2023-03-26 04:32:34 -04:00
|
|
|
// SIMPLE float ONES
|
2020-11-27 05:16:22 -05:00
|
|
|
//
|
2023-03-26 04:32:34 -04:00
|
|
|
// t = 0..period
|
|
|
|
// period = 0.001 ... 10000 ?
|
2021-11-02 06:27:01 -04:00
|
|
|
|
2023-03-26 04:32:34 -04:00
|
|
|
/*
|
2020-11-27 05:16:22 -05:00
|
|
|
float fgsaw(float t, float period = 1.0)
|
|
|
|
{
|
|
|
|
if (t >= 0) return -1.0 + 2 * t / period;
|
|
|
|
return 1.0 + 2 * t / period;
|
|
|
|
}
|
|
|
|
|
2021-11-02 06:27:01 -04:00
|
|
|
|
2020-11-27 05:16:22 -05:00
|
|
|
float fgtri(float t, float period = 1.0)
|
|
|
|
{
|
|
|
|
if (t < 0) t = -t;
|
|
|
|
if (t * 2 < period) return -1.0 + 4 * t / period;
|
|
|
|
return 3.0 - 4 * t / period;
|
|
|
|
}
|
|
|
|
|
2021-11-02 06:27:01 -04:00
|
|
|
|
2020-11-27 05:16:22 -05:00
|
|
|
float fgsqr(float t, float period = 1.0)
|
|
|
|
{
|
|
|
|
if (t >= 0)
|
|
|
|
{
|
|
|
|
if ( 2 * t < period) return 1.0;
|
|
|
|
return -1.0;
|
|
|
|
}
|
|
|
|
t = -t;
|
|
|
|
if (2 * t < period) return -1.0;
|
|
|
|
return 1.0;
|
|
|
|
}
|
|
|
|
|
2021-11-02 06:27:01 -04:00
|
|
|
|
2020-11-27 05:16:22 -05:00
|
|
|
float fgsin(float t, float period = 1.0)
|
|
|
|
{
|
|
|
|
return sin(TWO_PI * t / period);
|
|
|
|
}
|
|
|
|
|
2021-11-02 06:27:01 -04:00
|
|
|
|
2020-11-27 05:16:22 -05:00
|
|
|
float fgstr(float t, float period = 1.0, uint16_t steps = 8)
|
|
|
|
{
|
|
|
|
if (t >= 0)
|
|
|
|
{
|
|
|
|
int level = steps * t / period;
|
|
|
|
return -1.0 + 2.0 * level / (steps - 1);
|
|
|
|
}
|
|
|
|
t = -t;
|
|
|
|
int level = steps * t / period;
|
|
|
|
return 1.0 - 2.0 * level / (steps - 1);
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
2021-11-02 06:27:01 -04:00
|
|
|
|
2023-03-26 04:32:34 -04:00
|
|
|
/////////////////////////////////////////////////////////////
|
2020-11-27 05:16:22 -05:00
|
|
|
//
|
2023-03-26 04:32:34 -04:00
|
|
|
// FULL floatS ONES
|
2020-11-27 05:16:22 -05:00
|
|
|
//
|
2024-07-07 04:18:00 -04:00
|
|
|
// SAWTOOTH
|
2020-11-27 05:16:22 -05:00
|
|
|
float fgsaw(float t, float period = 1.0, float amplitude = 1.0, float phase = 0.0, float yShift = 0.0)
|
|
|
|
{
|
|
|
|
t += phase;
|
|
|
|
if (t >= 0)
|
|
|
|
{
|
|
|
|
if (t >= period) t = fmod(t, period);
|
|
|
|
return yShift + amplitude * (-1.0 + 2 * t / period);
|
|
|
|
}
|
|
|
|
t = -t;
|
|
|
|
if (t >= period) t = fmod(t, period);
|
|
|
|
return yShift + amplitude * ( 1.0 - 2 * t / period);
|
|
|
|
}
|
|
|
|
|
2021-11-02 06:27:01 -04:00
|
|
|
|
2024-07-07 04:18:00 -04:00
|
|
|
// TRIANGLE
|
2020-11-27 05:16:22 -05:00
|
|
|
float fgtri(float t, float period = 1.0, float amplitude = 1.0, float phase = 0.0, float yShift = 0.0, float dutyCycle = 0.50)
|
|
|
|
{
|
|
|
|
t += phase;
|
|
|
|
if (t < 0) t = -t;
|
|
|
|
if (t >= period) t = fmod(t, period);
|
|
|
|
// 50 % dutyCycle = faster
|
|
|
|
// if (t * 2 < period) return yShift + amplitude * (-1.0 + 4 * t / period);
|
|
|
|
// return yShift + amplitude * (3.0 - 4 * t / period);
|
|
|
|
if (t < dutyCycle * period) return yShift + amplitude * (-1.0 + 2 * t / (dutyCycle * period));
|
|
|
|
// return yShift + amplitude * (-1.0 + 2 / (1 - dutyCycle) - 2 * t / ((1 - dutyCycle) * period));
|
|
|
|
return yShift + amplitude * (-1.0 + 2 / (1 - dutyCycle) * ( 1 - t / period));
|
|
|
|
}
|
|
|
|
|
2021-11-02 06:27:01 -04:00
|
|
|
|
2024-07-07 04:18:00 -04:00
|
|
|
// SQUARE
|
2020-11-27 05:16:22 -05:00
|
|
|
float fgsqr(float t, float period = 1.0, float amplitude = 1.0, float phase = 0.0, float yShift = 0.0, float dutyCycle = 0.50)
|
|
|
|
{
|
|
|
|
t += phase;
|
|
|
|
if (t >= 0)
|
|
|
|
{
|
|
|
|
if (t >= period) t = fmod(t, period);
|
|
|
|
if (t < dutyCycle * period) return yShift + amplitude;
|
|
|
|
return yShift - amplitude;
|
|
|
|
}
|
|
|
|
t = -t;
|
|
|
|
if (t >= period) t = fmod(t, period);
|
|
|
|
if (t < dutyCycle * period) return yShift - amplitude;
|
|
|
|
return yShift + amplitude;
|
|
|
|
}
|
|
|
|
|
2021-11-02 06:27:01 -04:00
|
|
|
|
2024-07-07 04:18:00 -04:00
|
|
|
// SINUS
|
2020-11-27 05:16:22 -05:00
|
|
|
float fgsin(float t, float period = 1.0, float amplitude = 1.0, float phase = 0.0, float yShift = 0.0)
|
|
|
|
{
|
|
|
|
t += phase;
|
|
|
|
float rv = yShift + amplitude * sin(TWO_PI * t / period);
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2021-11-02 06:27:01 -04:00
|
|
|
|
2024-07-07 04:18:00 -04:00
|
|
|
// STAIR
|
2020-11-27 05:16:22 -05:00
|
|
|
float fgstr(float t, float period = 1.0, float amplitude = 1.0, float phase = 0.0, float yShift = 0.0, uint16_t steps = 8)
|
|
|
|
{
|
|
|
|
t += phase;
|
|
|
|
if (t >= 0)
|
|
|
|
{
|
|
|
|
if (t >= period) t = fmod(t, period);
|
|
|
|
int level = steps * t / period;
|
|
|
|
return yShift + amplitude * (-1.0 + 2.0 * level / (steps - 1));
|
|
|
|
}
|
|
|
|
t = -t;
|
|
|
|
if (t >= period) t = fmod(t, period);
|
|
|
|
int level = steps * t / period;
|
|
|
|
return yShift + amplitude * (1.0 - 2.0 * level / (steps - 1));
|
|
|
|
}
|
|
|
|
|
2021-11-02 06:27:01 -04:00
|
|
|
|
2023-03-26 04:32:34 -04:00
|
|
|
// -- END OF FILE --
|
2021-11-02 06:27:01 -04:00
|
|
|
|