Frequency to 1v/oct, and a few other conversions

Helper functions that might to useful to others, and round out the mtof function in DaisySP/Source/Utility/dsp.h, which looks like this for completeness:

/** Midi to frequency helper 
powf(2, (midi_note - A4_midi_note) / semitones_per_octave) * A4_frequency;
*/
inline float mtof(float m)
{
    return powf(2, (m - 69.0f) / 12.0f) * 440.0f;
}

Please let me know if you find errors or can improve on these!

/** frequency to Midi helper 
ceil(A4_midi_value + ( log(frequency / A4_reference_frequency) / log(2) ) * semitones_per_octave)
*/
inline float ftom(float f)
{
	return ceil(69.0f + (logf(f / 440.0f) / logf(2.0f)) * 12.0f);	
}

/** 1v/oct to Midi helper 
ceil(midi_note_at_zero_volts + ceil(volts * semitones_per_octave));
*/
inline float vtom(float v)
{
	return ceil(12.0f + ceil(v * 12.0f));
}

/** Midi to 1v/oct helper
fmax(midi_note - midi_note_at_zero_volts),0) * (1.0f / semitones_per_octave);
using fmax(float a, float b) to prevent negative results
*/
inline float mtov(float m) 
{
	return fmax((m - 12.0f),0) * (1.0f / 12.0f);
}

/** 1v/oct to frequency helper
powf(2, (((volts * semitones_per_octave) + midi_note_at_zero_volts) - A4_midi_note) / semitones_per_octave) * A4_frequency
*/
inline float vtof(float v)
{  
	return powf(2, (((v * 12.0f) + 12.0f) - 69.0f) / 12.0f) * 440.0f;
}

/** frequency to 1v/oct helper
(A4_midi_note + logf(frequency / A4_frequency) / logf(2.0f) * semitones_per_octave) - midi_note_at_zero_volts) * (1.0f / semitones_per_octave);
*/
inline float ftov(float f)
{
	return (69.0f + (logf(f / 440.0f) / logf(2.0f) * 12.0f) - 12.0f) * (1.0f / 12.0f);	
}
2 Likes

Thanks @corvin , I learned a lot that I needed to know from the new functions.

One question (or maybe 2 or 3) - mtof was ‘inlined’ I assume for performance reasons, why else? Did you decide not to inline your new functions (and if so, why?) or just ‘forget’ to do so, or…?

1 Like

With the 1v/oct standard 0v is typically set to the middle C, aka C4. At equal temperament standard tuning of 440hz this should be 261.625565 Hz

The calculation I had found for this was simply pow(2, v) * 261.625565 to convert the voltage to a 1v/oct frequency.
The midi notes and semitones shouldn’t be needed here.

See also: Best way to set 1V/Oct CV out? - #2 by 3HR - Development - VCV Community

4 Likes

I just forgot to add inline, thanks for catching that. I’ve added them.

Thanks @dreamer, I will take a look at this!

Okay, with much thanks to @dreamer, here are updated versions of the vtof and ftov functions without my misadventures through midi.

/** 1v/oct to frequency helper
powf(2, volts) * C4_frequency
*/
inline float vtof(float v)
{  
	return powf(2, v) * 261.625565;
}

/** frequency to 1v/oct helper
logf(frequency / C4_frequency) / logf(2.0f)
*/
inline float ftov(float f)
{
	return logf(f / 261.625565) / logf(2.0f);
}
3 Likes