BogaudioModules

BogaudioModules for VCV Rack
Log | Files | Refs | README | LICENSE

oscillator.cpp (11234B)


      1 
      2 #include "oscillator.hpp"
      3 #include "noise.hpp"
      4 
      5 using namespace bogaudio::dsp;
      6 
      7 void Phasor::setSampleWidth(float sw) {
      8 	if (sw < 0.0f) {
      9 		sw = 0.0f;
     10 	}
     11 	else if (sw > maxSampleWidth) {
     12 		sw = maxSampleWidth;
     13 	}
     14 	if (_sampleWidth != sw) {
     15 		_sampleWidth = sw;
     16 		if (_sampleWidth > 0.001f) {
     17 			_samplePhase = _sampleWidth * (float)cyclePhase;
     18 		}
     19 		else {
     20 			_samplePhase = 0;
     21 		}
     22 	}
     23 }
     24 
     25 void Phasor::resetPhase() {
     26 	_phase = 0;
     27 }
     28 
     29 void Phasor::setPhase(float radians) {
     30 	_phase = radiansToPhase(radians);
     31 }
     32 
     33 void Phasor::syncPhase(const Phasor& phasor) {
     34 	_phase = phasor._phase;
     35 }
     36 
     37 float Phasor::nextFromPhasor(const Phasor& phasor, phase_delta_t offset) {
     38 	offset += phasor._phase;
     39 	if (_samplePhase > 0) {
     40 		offset -= offset % _samplePhase;
     41 	}
     42 	return nextForPhase(offset);
     43 }
     44 
     45 void Phasor::_update() {
     46 	_delta = ((phase_delta_t)((_frequency / _sampleRate) * cyclePhase)) % cyclePhase;
     47 }
     48 
     49 float Phasor::_next() {
     50 	advancePhase();
     51 	if (_samplePhase > 0) {
     52 		return nextForPhase(_phase - (_phase % _samplePhase));
     53 	}
     54 	return nextForPhase(_phase);
     55 }
     56 
     57 float Phasor::nextForPhase(phase_t phase) {
     58 	return phase;
     59 }
     60 
     61 
     62 void TablePhasor::setInterpolation(Interpolation interpolation) {
     63 	_interpolation = interpolation;
     64 }
     65 
     66 float TablePhasor::nextForPhase(phase_t phase) {
     67 	phase %= cyclePhase;
     68 	if (_interpolation == INTERPOLATION_OFF || (_interpolation == INTERPOLATION_DEFAULT && _tableLength >= 1024)) {
     69 		int i = (((((uint64_t)phase) << 16) / cyclePhase) * _tableLength) >> 16;
     70 		i %= _tableLength;
     71 		return _table.value(i);
     72 	}
     73 
     74 	float fi = phase / (float)cyclePhase;
     75 	assert(fi >= 0.0f && fi < 1.0f);
     76 	fi *= _tableLength;
     77 	int i = fi;
     78 	float v1 = _table.value(i);
     79 	float v2 = _table.value(i + 1 == _tableLength ? 0 : i + 1);
     80 	return v1 + (fi - i)*(v2 - v1);
     81 }
     82 
     83 
     84 // A New Recursive Quadrature Oscillator, Martin Vicanek, 2015 - http://vicanek.de/articles/QuadOsc.pdf
     85 void SineOscillator::setPhase(double phase) {
     86 	_x = cos(phase);
     87 	_y = sin(phase);
     88 }
     89 
     90 void SineOscillator::update() {
     91 	double w = (_frequency / _sampleRate) * 2.0 * M_PI;
     92 	_k1 = tan(w / 2.0);
     93 	_k2 = 2.0 * _k1 / (1 + _k1*_k1);
     94 }
     95 
     96 float SineOscillator::_next() {
     97 	double t = _x - _k1*_y;
     98 	_y = _y + _k2*t;
     99 	_x = t - _k1*_y;
    100 	return _y;
    101 }
    102 
    103 
    104 float SawOscillator::nextForPhase(phase_t phase) {
    105 	return ((phase % cyclePhase) / (float)cyclePhase) * 2.0f - 1.0f;
    106 }
    107 
    108 
    109 void SaturatingSawOscillator::setSaturation(float saturation) {
    110 	if (_saturation != saturation) {
    111 		assert(saturation >= 0.0f);
    112 		_saturation = saturation;
    113 		if (_saturation >= 0.1f) {
    114 			if (_saturation < 1.0f) {
    115 				_saturationNormalization = 1.0f / tanhf(_saturation * M_PI);
    116 			}
    117 			else {
    118 				_saturationNormalization = 1.0f;
    119 			}
    120 		}
    121 	}
    122 }
    123 
    124 float SaturatingSawOscillator::nextForPhase(phase_t phase) {
    125 	float sample = SawOscillator::nextForPhase(phase);
    126 	if (_saturation >= 0.1f) {
    127 		sample = _tanhf.value(sample * _saturation * M_PI) * _saturationNormalization;
    128 	}
    129 	return sample;
    130 }
    131 
    132 
    133 void BandLimitedSawOscillator::setQuality(int quality) {
    134 	if (_quality != quality) {
    135 		assert(quality >= 0);
    136 		_quality = quality;
    137 		_update();
    138 	}
    139 }
    140 
    141 void BandLimitedSawOscillator::_update() {
    142 	Phasor::_update();
    143 	int q = std::min(_quality, (int)(0.5f * (_sampleRate / _frequency)));
    144 	_qd = q * _delta;
    145 }
    146 
    147 float BandLimitedSawOscillator::nextForPhase(phase_t phase) {
    148 	phase %= cyclePhase;
    149 
    150 	float sample = SaturatingSawOscillator::nextForPhase(phase);
    151 	if (phase > cyclePhase - _qd) {
    152 		float i = (cyclePhase - phase) / (float)_qd;
    153 		i = (1.0f - i) * _halfTableLen;
    154 		sample -= _table.value((int)i);
    155 	}
    156 	else if (phase < _qd) {
    157 		float i = phase / (float)_qd;
    158 		i *= _halfTableLen - 1;
    159 		i += _halfTableLen;
    160 		sample -= _table.value((int)i);
    161 	}
    162 	return sample;
    163 }
    164 
    165 
    166 void SquareOscillator::setPulseWidth(float pw) {
    167 	if (_pulseWidthInput == pw) {
    168 		return;
    169 	}
    170 	_pulseWidthInput = pw;
    171 
    172 	if (pw >= maxPulseWidth) {
    173 		pw = maxPulseWidth;
    174 	}
    175 	else if (pw <= minPulseWidth) {
    176 		pw = minPulseWidth;
    177 	}
    178 	_nextPulseWidth = cyclePhase * pw;
    179 }
    180 
    181 float SquareOscillator::nextForPhase(phase_t phase) {
    182 	phase_t cycle = phase / cyclePhase;
    183 	if (_lastCycle != cycle) {
    184 		_lastCycle = cycle;
    185 		_pulseWidth = _nextPulseWidth;
    186 	}
    187 	phase %= cyclePhase;
    188 
    189 	if (positive) {
    190 		if (phase >= _pulseWidth) {
    191 			positive = false;
    192 			return -1.0f;
    193 		}
    194 		return 1.0f;
    195 	}
    196 	if (phase < _pulseWidth) {
    197 		positive = true;
    198 		return 1.0f;
    199 	}
    200 	return -1.0f;
    201 }
    202 
    203 
    204 void BandLimitedSquareOscillator::setPulseWidth(float pw, bool dcCorrection) {
    205 	if (_pulseWidthInput == pw && _dcCorrection == dcCorrection) {
    206 		return;
    207 	}
    208 	_pulseWidthInput = pw;
    209 	_dcCorrection = dcCorrection;
    210 
    211 	if (pw >= maxPulseWidth) {
    212 		pw = maxPulseWidth;
    213 	}
    214 	else if (pw <= minPulseWidth) {
    215 		pw = minPulseWidth;
    216 	}
    217 	_nextPulseWidth = cyclePhase * pw;
    218 
    219 	if (pw > 0.5) {
    220 		_nextOffset = 2.0f * pw - 1.0f;
    221 	}
    222 	else {
    223 		_nextOffset = -(1.0f - 2.0f * pw);
    224 	}
    225 
    226 	_nextDcOffset = _dcCorrection ? 1.0f - 2.0f * pw : 0.0f;
    227 }
    228 
    229 float BandLimitedSquareOscillator::nextForPhase(phase_t phase) {
    230 	phase_t cycle = phase / cyclePhase;
    231 	if (_lastCycle != cycle) {
    232 		_lastCycle = cycle;
    233 		_pulseWidth = _nextPulseWidth;
    234 		_offset = _nextOffset;
    235 		_dcOffset = _nextDcOffset;
    236 	}
    237 
    238 	float sample = -BandLimitedSawOscillator::nextForPhase(phase);
    239 	sample += BandLimitedSawOscillator::nextForPhase(phase - _pulseWidth);
    240 	return sample + _offset + _dcOffset;
    241 }
    242 
    243 
    244 float TriangleOscillator::nextForPhase(phase_t phase) {
    245 	phase %= cyclePhase;
    246 
    247 	float p = (phase / (float)cyclePhase) * 4.0f;
    248 	if (phase < quarterCyclePhase) {
    249 		return p;
    250 	}
    251 	if (phase < threeQuartersCyclePhase) {
    252 		return 2.0f - p;
    253 	}
    254 	return p - 4.0f;
    255 }
    256 
    257 
    258 SteppedRandomOscillator::SteppedRandomOscillator(
    259 	float sampleRate,
    260 	float frequency,
    261 	phase_t seed
    262 )
    263 : Phasor(sampleRate, frequency)
    264 , _n(4096)
    265 , _k(4093) // prime less than _n
    266 {
    267 	if (seed == 0) {
    268 		_seed = Seeds::getInstance().next();
    269 	}
    270 	else {
    271 		_seed = seed;
    272 	}
    273 
    274 	WhiteNoiseGenerator noise;
    275 	_t = new float[_n];
    276 	for (phase_t i = 0; i < _n; ++i) {
    277 		_t[i] = noise.next();
    278 	}
    279 }
    280 
    281 SteppedRandomOscillator::~SteppedRandomOscillator() {
    282 	delete[] _t;
    283 }
    284 
    285 void SteppedRandomOscillator::resetPhase() {
    286 	_phase -= _phase % cyclePhase;
    287 	_phase += cyclePhase;
    288 }
    289 
    290 float SteppedRandomOscillator::nextForPhase(phase_t phase) {
    291 	phase_t i = phase / cyclePhase;
    292 	return _t[(_seed + i + (_seed + i) % _k) % _n];
    293 }
    294 
    295 
    296 void SineBankOscillator::setPartial(int i, float frequencyRatio, float amplitude) {
    297 	setPartialFrequencyRatio(i, frequencyRatio);
    298 	setPartialAmplitude(i, amplitude);
    299 }
    300 
    301 bool SineBankOscillator::setPartialFrequencyRatio(int i, float frequencyRatio) {
    302 	if (i <= (int)_partials.size()) {
    303 		Partial& p = _partials[i - 1];
    304 		p.frequencyRatio = frequencyRatio;
    305 		double f = (double)_frequency * (double)frequencyRatio;
    306 		p.frequency = f;
    307 		p.sine.setFrequency(f);
    308 		return f < _maxPartialFrequency;
    309 	}
    310 	return false;
    311 }
    312 
    313 void SineBankOscillator::setPartialAmplitude(int i, float amplitude, bool envelope) {
    314 	if (i <= (int)_partials.size()) {
    315 		Partial& p = _partials[i - 1];
    316 		if (envelope) {
    317 			p.amplitudeTarget = amplitude;
    318 			p.amplitudeStepDelta = (amplitude - p.amplitude) / (float)_amplitudeEnvelopeSamples;
    319 			p.amplitudeSteps = _amplitudeEnvelopeSamples;
    320 		}
    321 		else if (p.amplitudeSteps > 0) {
    322 			p.amplitudeTarget = amplitude;
    323 			p.amplitudeStepDelta = (amplitude - p.amplitude) / (float)p.amplitudeSteps;
    324 		}
    325 		else {
    326 			p.amplitude = amplitude;
    327 		}
    328 	}
    329 }
    330 
    331 void SineBankOscillator::syncToPhase(float phase) {
    332 	for (Partial& p : _partials) {
    333 		p.sine.setPhase(phase);
    334 	}
    335 }
    336 
    337 void SineBankOscillator::syncTo(const SineBankOscillator& other) {
    338 	for (int i = 0, n = std::min(_partials.size(), other._partials.size()); i < n; ++i) {
    339 		_partials[i].sine.syncPhase(other._partials[i].sine);
    340 	}
    341 }
    342 
    343 void SineBankOscillator::_sampleRateChanged() {
    344 	_maxPartialFrequency = _maxPartialFrequencySRRatio * _sampleRate;
    345 	_amplitudeEnvelopeSamples = _sampleRate * (_amplitudeEnvelopeMS / 1000.0f);
    346 	for (Partial& p : _partials) {
    347 		p.sine.setSampleRate(_sampleRate);
    348 	}
    349 }
    350 
    351 void SineBankOscillator::_frequencyChanged() {
    352 	for (Partial& p : _partials) {
    353 		p.frequency = _frequency * p.frequencyRatio;
    354 		p.sine.setFrequency(_frequency * p.frequencyRatio);
    355 	}
    356 }
    357 
    358 float SineBankOscillator::next(Phasor::phase_t phaseOffset) {
    359 	float next = 0.0;
    360 	for (Partial& p : _partials) {
    361 		p.sine.advancePhase();
    362 		if (p.frequency < _maxPartialFrequency && (p.amplitude > 0.001 || p.amplitude < -0.001 || p.amplitudeSteps > 0)) {
    363 			if (p.amplitudeSteps > 0) {
    364 				if (p.amplitudeSteps == 1) {
    365 					p.amplitude = p.amplitudeTarget;
    366 				}
    367 				else {
    368 					p.amplitude += p.amplitudeStepDelta;
    369 				}
    370 				--p.amplitudeSteps;
    371 			}
    372 			next += p.sine.nextFromPhasor(p.sine, phaseOffset) * p.amplitude;
    373 		}
    374 	}
    375 	return next;
    376 }
    377 
    378 
    379 constexpr float ChirpOscillator::minFrequency;
    380 constexpr float ChirpOscillator::minTimeSeconds;
    381 
    382 void ChirpOscillator::setParams(float frequency1, float frequency2, float time, bool linear) {
    383 	frequency1 = std::max(minFrequency, std::min(frequency1, 0.99f * 0.5f * _sampleRate));
    384 	frequency2 = std::max(minFrequency, std::min(frequency2, 0.99f * 0.5f * _sampleRate));
    385 	assert(time >= minTimeSeconds);
    386 
    387 	if (_f1 != frequency1 || _f2 != frequency2 || _Time != time || _linear != linear) {
    388 		_f1 = frequency1;
    389 		_f2 = frequency2;
    390 		_Time = time;
    391 		_linear = linear;
    392 
    393 		_k = pow((double)(_f2 / _f1), 1.0f / (double)_Time);
    394 	}
    395 }
    396 
    397 void ChirpOscillator::_sampleRateChanged() {
    398 	_oscillator.setSampleRate(_sampleRate);
    399 	_sampleTime = 1.0f / _sampleRate;
    400 }
    401 
    402 float ChirpOscillator::_next() {
    403 	_complete = false;
    404 	if (_time > _Time) {
    405 		_time = 0.0f;
    406 		_complete = true;
    407 	}
    408 	else {
    409 		_time += _sampleTime;
    410 	}
    411 
    412 	if (_linear) {
    413 		_oscillator.setFrequency(_f1 + (_time / _Time) * (_f2 - _f1));
    414 	}
    415 	else {
    416 		_oscillator.setFrequency((double)_f1 * pow(_k, (double)_time));
    417 	}
    418 	return _oscillator.next();
    419 }
    420 
    421 void ChirpOscillator::reset() {
    422 	_time = 0.0f;
    423 	_oscillator.resetPhase();
    424 }
    425 
    426 
    427 constexpr float PureChirpOscillator::minFrequency;
    428 constexpr float PureChirpOscillator::minTimeSeconds;
    429 
    430 void PureChirpOscillator::setParams(float frequency1, float frequency2, double time, bool linear) {
    431 	frequency1 = std::max(minFrequency, std::min(frequency1, 0.99f * 0.5f * _sampleRate));
    432 	frequency2 = std::max(minFrequency, std::min(frequency2, 0.99f * 0.5f * _sampleRate));
    433 	assert(time >= minTimeSeconds);
    434 
    435 	if (_f1 != frequency1 || _f2 != frequency2 || _Time != time || _linear != linear) {
    436 		_f1 = frequency1;
    437 		_f2 = frequency2;
    438 		_Time = time;
    439 		_linear = linear;
    440 		update();
    441 	}
    442 }
    443 
    444 void PureChirpOscillator::_sampleRateChanged() {
    445 	_sampleTime = 1.0 / (double)_sampleRate;
    446 	update();
    447 }
    448 
    449 void PureChirpOscillator::update() {
    450 	_Time = std::max(2.0f * _sampleTime, _Time);
    451 	_c = (double)(_f2 - _f1) / (double)_Time;
    452 	_k = pow((double)(_f2 / _f1), 1.0f / (double)_Time);
    453 	_invlogk = 1.0 / log(_k);
    454 }
    455 
    456 float PureChirpOscillator::_next() {
    457 	// formulas from https://en.wikipedia.org/wiki/Chirp
    458 	double phase = 0.0f;
    459 	if (_linear) {
    460 		phase = 2.0 * M_PI * (0.5 * _c * (double)(_time * _time) + (double)(_f1 * _time));
    461 	}
    462 	else {
    463 		phase = 2.0 * M_PI * (double)_f1 * ((pow(_k, (double)_time) - 1.0) * _invlogk);
    464 	}
    465 
    466 	_complete = false;
    467 	if (_Time - _time < _sampleTime) {
    468 		_time = 0.0f;
    469 		_complete = true;
    470 	}
    471 	else {
    472 		_time += _sampleTime;
    473 	}
    474 
    475 	return sin(phase);
    476 }
    477 
    478 void PureChirpOscillator::reset() {
    479 	_time = 0.0f;
    480 }