Skip to content

Instantly share code, notes, and snippets.

@garcia
Last active November 18, 2024 21:21
Show Gist options
  • Save garcia/ad2dff9ffd33a8a6800f1ff00d28ce98 to your computer and use it in GitHub Desktop.
Save garcia/ad2dff9ffd33a8a6800f1ff00d28ce98 to your computer and use it in GitHub Desktop.
Map Fruity Keyboard Controller's note value to any other software's frequency parameter

fruity_controller_frequencies.py

This script enables you to map the Note output value from Fruity Keyboard Controller (set to the full keyboard range) to any other software's frequency or cutoff knob. All you need to specify is the target control's maximum and median frequencies (freq_max and freq_mid). The script prints a Fruity Formula Controller expression that takes Fruity Keyboard Controller's Note value as the "a" knob and outputs the equivalent frequency for your desired software. Note that the target frequency/cutoff knob must be logarithmic.

How to use

  • Add a Fruity Keyboard Controller in the Channel rack.
    • Select the full keyboard range and auto-map it to white & black notes.
  • Add a Fruity Formula Controller in the Mixer window. Paste the output from this script into the Formula input.
    • Set the "b" and "c" knobs to their median values of 0.5. From there, you can tweak them to adjust the semitone or octave.
  • Right-click Fruity Formula Controller's "a" knob, select "Link to controller...", and assign it to Fruity Keyboard Controller's Note value.
  • Assign your software's frequency knob to Fruity Formula Controller's output value.

Create custom mappings for other VSTs

Values for freq_max and freq_mid corresponding to Kilohearts software (e.g. Phase Plant) and Xfer's Serum VST's OSC and FX filter cutoffs are provided. To find these values for other software, set freq_max to the value when the frequency knob is turned all the way up and set freq_mid to the frequency when the control is set to its exact midpoint (0.5).

Why does the script require the midpoint frequency and not the minimum frequency? The minimum for some software (e.g. 8 Hz for Serum's frequency knobs) isn't precise enough to accurately map frequencies to notes.

from math import exp, log
# Kilohearts (e.g. Phase Plant, works on most frequency controls):
freq_max = 20500
freq_mid = 640
# Serum OSC Filter cutoff:
# freq_max = 22050
# freq_mid = 425
# Serum FX Filter cutoff:
# freq_max = 13290
# freq_mid = 330
freq_min = exp(log(freq_mid) - (log(freq_max) - log(freq_mid)))
freq_log_range = log(freq_max) - log(freq_min)
def shift_semitones(freq, semitones):
return freq * 2**(semitones/12)
note_a4 = 440
semitones_to_c0 = -12*5 + 3
semitones_to_b10 = 12*6 + 2
note_c0 = shift_semitones(note_a4, semitones_to_c0)
note_b10 = shift_semitones(note_a4, semitones_to_b10)
note_c0_position = (log(note_c0) - log(freq_min)) / freq_log_range
note_g10_position = (log(note_b10) - log(freq_min)) / freq_log_range
note_range = note_g10_position - note_c0_position
interval_semitone = note_range / (semitones_to_b10 - semitones_to_c0)
print(f"a*{note_range:.10f}{note_c0_position:+.10f}+((Round(c*8)-4)*12+Round(b*24)-12)*{interval_semitone:.10f}")
@garcia
Copy link
Author

garcia commented Nov 18, 2024

Output for the supplied frequency values:

Kilohearts: a*1.0913592975-0.0289078771+((Round(c*8)-4)*12+Round(b*24)-12)*0.0083309870
Serum FX Filter cutoff: a*1.0237450196+0.0934751508+((Round(c*8)-4)*12+Round(b*24)-12)*0.0078148475
Serum OSC Filter cutoff: a*0.9580776795+0.0875182183+((Round(c*8)-4)*12+Round(b*24)-12)*0.0073135701

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment