Vita/examples/normalized_control_demo.py

93 lines
3.5 KiB
Python

"""
Demo: VST-style normalized parameter control
This example shows how to control Vital synthesizer parameters using
normalized 0-1 values, similar to how VST/AU plugins work in DAWs.
"""
import vita
from scipy.io import wavfile
SAMPLE_RATE = 44_100
def main():
synth = vita.Synth()
synth.set_bpm(120.0)
# Direct control - linear interpolation of actual values
controls = synth.get_controls()
# Turn the filter on
controls["filter_1_on"].set(1.0)
# Example 1: Comparing direct vs normalized control (Filter 1 Cutoff)
print("=== Comparing Direct vs Normalized Control ===")
# Get info about the filter 1 cutoff parameter
info = synth.get_control_details("filter_1_cutoff")
print(f"Parameter: {info.display_name}")
print(f"Range: {info.min} to {info.max}")
print(f"Scale: {str(info.scale)}")
print()
print("Direct control (linear interpolation):")
for pct in [0.0, 0.25, 0.5, 0.75, 1.0]:
value = info.min + pct * (info.max - info.min)
controls["filter_1_cutoff"].set(value)
print(f" {pct*100:3.0f}% → value={value:.3f}")
print("\nNormalized control (VST-style):")
for norm in [0.0, 0.25, 0.5, 0.75, 1.0]:
controls["filter_1_cutoff"].set_normalized(norm)
actual = controls["filter_1_cutoff"].value()
display_text = synth.get_control_text("filter_1_cutoff")
print(f" {norm*100:3.0f}% → value={actual:.3f} (displays as {display_text})")
# Render a short note
audio = synth.render(36, 0.8, 0.9, 1) # C2, velocity 0.8, 0.9s note, 1.0s render
filename = f"filter_sweep_{int(norm*100):03d}.wav"
wavfile.write(filename, SAMPLE_RATE, audio.T)
print(f"Rendered {filename} with filter at {norm*100:.0f}%")
# Example 2: Comparing direct vs normalized control (Env 1 Delay)
print("\n=== Comparing Direct vs Normalized Control ===")
# Get info about the Env 1 Delay parameter
info = synth.get_control_details("env_1_delay")
print(f"Parameter: {info.display_name}")
print(f"Range: {info.min} to {info.max}")
print(f"Scale: {str(info.scale)}")
print()
print("Direct control (linear interpolation):")
for pct in [0.0, 0.25, 0.5, 0.75, 1.0]:
value = info.min + pct * (info.max - info.min)
controls["env_1_delay"].set(value)
print(f" {pct*100:3.0f}% → value={value:.3f}")
print("\nNormalized control (VST-style):")
print("(Note: knob position has quartic relationship to display value)")
for norm in [0.0, 0.25, 0.5, 0.75, 1.0]:
controls["env_1_delay"].set_normalized(norm)
actual = controls["env_1_delay"].value()
display_text = synth.get_control_text("env_1_delay")
expected_display = 4.0 * (norm ** 4)
print(f" {norm*100:3.0f}% → value={actual:.3f} (displays as {display_text}, expected ~{expected_display:.2f}s)")
# Example 3: Discrete parameter control (Delay Style)
print("\n=== Discrete Parameter Control ===")
info = synth.get_control_details("delay_style")
print(f"Delay styles: {info.options}")
# Cycle through delay styles using normalized values
num_styles = len(info.options)
for i in range(num_styles):
normalized = i / (num_styles - 1) if num_styles > 1 else 0
controls["delay_style"].set_normalized(normalized)
style = controls["delay_style"].get_text()
print(f"Normalized {normalized:.2f}{style}")
if __name__ == "__main__":
main()