BogaudioModules

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

commit 2aeb0c15671fad693e43ec88e1722d0d34e140d7
parent 4c9d6c319b0b27dfbd7c2163938f333eb9a43d39
Author: Matt Demanett <matt@demanett.net>
Date:   Thu, 18 Jan 2018 00:19:37 -0500

Add functions for pitch calculations in dsp lib; refactor Reftone to use them; implement Detune.

Diffstat:
Msrc/Detune.cpp | 52++++++++++++++++++++++++++++++++++++++++++++++------
Msrc/Reftone.cpp | 12++++++------
Asrc/dsp/pitch.hpp | 36++++++++++++++++++++++++++++++++++++
3 files changed, 88 insertions(+), 12 deletions(-)

diff --git a/src/Detune.cpp b/src/Detune.cpp @@ -1,5 +1,8 @@ #include "bogaudio.hpp" +#include "dsp/pitch.hpp" + +using namespace bogaudio::dsp; struct Detune : Module { enum ParamsIds { @@ -31,15 +34,52 @@ struct Detune : Module { reset(); } - virtual void reset() override; virtual void step() override; }; -void Detune::reset() { -} - void Detune::step() { - lights[QUANTIZE_LIGHT].value = params[QUANTIZE_PARAM].value == 1.0; + if (!(outputs[OUT_PLUS_OUTPUT].active || outputs[OUT_MINUS_OUTPUT].active || outputs[THRU_OUTPUT].active)) { + return; + } + + float cents = params[CENTS_PARAM].value; + if (inputs[CV_INPUT].active) { + cents *= clampf(inputs[CV_INPUT].value, 0.0, 10.0) / 10.0; + } + if (params[QUANTIZE_PARAM].value > 0.5) { + cents = roundf(cents); + } + cents /= 100.0; + + if (inputs[IN_INPUT].active) { + float cv = inputs[IN_INPUT].value; + outputs[THRU_OUTPUT].value = cv; + if (cents < 0.001) { + outputs[OUT_PLUS_OUTPUT].value = cv; + outputs[OUT_MINUS_OUTPUT].value = cv; + } + else { + float semitone = cvToSemitone(cv); + outputs[OUT_PLUS_OUTPUT].value = semitoneToCV(semitone + cents); + outputs[OUT_MINUS_OUTPUT].value = semitoneToCV(semitone - cents); + } + } + else { + const float frequency = 440.0; + const float cv = frequencyToCV(frequency); + const float semitone = frequencyToSemitone(frequency); + outputs[THRU_OUTPUT].value = cv; + if (cents < 0.001) { + outputs[OUT_PLUS_OUTPUT].value = cv; + outputs[OUT_MINUS_OUTPUT].value = cv; + } + else { + outputs[OUT_PLUS_OUTPUT].value = semitoneToCV(semitone + cents); + outputs[OUT_MINUS_OUTPUT].value = semitoneToCV(semitone - cents); + } + } + + lights[QUANTIZE_LIGHT].value = params[QUANTIZE_PARAM].value > 0.5; } @@ -74,7 +114,7 @@ DetuneWidget::DetuneWidget() { // end generated by svg_widgets.rb { - auto w = createParam<Knob26>(centsParamPosition, module, Detune::CENTS_PARAM, 0.0, 10.0, 0.0); + auto w = createParam<Knob26>(centsParamPosition, module, Detune::CENTS_PARAM, 0.0, 50.0, 0.0); dynamic_cast<Knob*>(w)->snap = true; addParam(w); } diff --git a/src/Reftone.cpp b/src/Reftone.cpp @@ -1,6 +1,7 @@ #include "bogaudio.hpp" #include "dsp/oscillator.hpp" +#include "dsp/pitch.hpp" using namespace bogaudio::dsp; @@ -46,18 +47,17 @@ struct Reftone : Module { }; void Reftone::step() { - const float f0 = 261.626; - const int f0Pitch = 0; - const int f0Octave = 4; - const float twelfthRootTwo = 1.0594630943592953; + // C4 -- the pitch.hpp reference frequency -- in knob values: + const int referencePitch = 0; + const int referenceOctave = 4; _pitch = clampf(params[PITCH_PARAM].value, 0.0, 11.0); _octave = clampf(params[OCTAVE_PARAM].value, 1.0, 8.0); _fine = clampf(params[FINE_PARAM].value, -0.99, 0.99); - _frequency = f0*powf(twelfthRootTwo, 12*(_octave - f0Octave) + (_pitch - f0Pitch) + _fine); + _frequency = semitoneToFrequency(referenceSemitone + 12*(_octave - referenceOctave) + (_pitch - referencePitch) + _fine); if (outputs[CV_OUTPUT].active) { - outputs[CV_OUTPUT].value = log2f(_frequency / f0); + outputs[CV_OUTPUT].value = frequencyToCV(_frequency); } else { outputs[CV_OUTPUT].value = 0.0; diff --git a/src/dsp/pitch.hpp b/src/dsp/pitch.hpp @@ -0,0 +1,36 @@ +#pragma once + +namespace bogaudio { +namespace dsp { + +const float referenceFrequency = 261.626; // C4; frequency at which Rack 1v/octave CVs are zero. +const float referenceSemitone = 60.0; // C4; value of C4 in semitones is arbitrary here, so have it match midi note numbers when rounded to integer. +const float twelfthRootTwo = 1.0594630943592953; +const float logTwelfthRootTwo = logf(1.0594630943592953); + +inline float frequencyToSemitone(float frequency) { + return logf(frequency / referenceFrequency) / logTwelfthRootTwo + referenceSemitone; +} + +inline float semitoneToFrequency(float semitone) { + return powf(twelfthRootTwo, semitone - referenceSemitone) * referenceFrequency; +} + +inline float frequencyToCV(float frequency) { + return log2f(frequency / referenceFrequency); +} + +inline float cvToFrequency(float cv) { + return powf(2.0, cv) * referenceFrequency; +} + +inline float cvToSemitone(float cv) { + return frequencyToSemitone(cvToFrequency(cv)); +} + +inline float semitoneToCV(float semitone) { + return frequencyToCV(semitoneToFrequency(semitone)); +} + +} // namespace dsp +} // namespace bogaudio