Examples
How to time events using set_event_time
require "libsunvox"
SunVox.start_engine(no_debug_output: true, one_thread: true)
slot = SunVox.open_slot(SunVox::Slot::One)
fm_synth_number = SunVox.new_module(slot, SunVox::Modules::Synths::FM)
# Connect the module to the output
SunVox.connect_module(slot, fm_synth_number, SunVox::OUTPUT_MODULE)
puts "Sending Events"
tps = SunVox.ticks_per_second
ticks = SunVox.ticks + tps
# Send events
10.times do
20.times do |x|
SunVox.set_event_time(slot, ticks += (tps*0.25).to_i)
SunVox.send_event(slot, 0, SunVox::Note::C5 + x, 0, fm_synth_number)
end
SunVox.set_event_time(slot, ticks += tps)
SunVox.send_event(slot, 0, SunVox::Note::Off, 128, fm_synth_number)
end
Playing Scales
require "libsunvox"
SunVox.start_engine(no_debug_output: true, one_thread: false)
slot = SunVox.open_slot(SunVox::Slot::One)
fm_synth_number = SunVox.new_module(slot, SunVox::Modules::Synths::GENERATOR)
# Connect the module to the output
SunVox.connect_module(slot, fm_synth_number, SunVox::OUTPUT_MODULE)
scale = SunVox::Scales.make(SunVox::Note::C3, SunVox::Scales::HEXATONIC)
pp scale
tps = SunVox.ticks_per_second
starting_ticks = SunVox.ticks
ticks = starting_ticks
# Send events
10.times do
scale.each do |note|
SunVox.set_event_time(slot, ticks += (tps*0.25).to_i)
SunVox.send_event(slot, 0, note, 0, fm_synth_number)
end
SunVox.set_event_time(slot, ticks += tps)
SunVox.send_event(slot, 0, SunVox::Note::Off, 0, fm_synth_number)
end
sleep
Simple Instrument
require "libsunvox"
SunVox.start_engine(no_debug_output: true, one_thread: true)
slot = SunVox.open_slot(SunVox::Slot::One)
generator_number = SunVox.new_module(slot, SunVox::Modules::Synths::GENERATOR)
reverb_number = SunVox.new_module(slot, SunVox::Modules::Effects::REVERB)
# Connect the module to the output
SunVox.connect_module(slot, generator_number, reverb_number)
SunVox.connect_module(slot, reverb_number, SunVox::OUTPUT_MODULE)
# Set up the sound settings
# Change waveform to noise
SunVox.send_event(slot, 0, SunVox::Note::None, 0, generator_number, ctl: 2, ctl_value: 0)
100.times do
attack_low = 0xb80
attack_high = 0x1540
release_low = 0x31c0
release_high = 0x6000
attack = Random.rand(attack_low..attack_high)
release = Random.rand(release_low..release_high)
note = Random.rand(SunVox::Note::C2.to_i..SunVox::Note::C4.to_i)
# Change Attack
SunVox.send_event(slot, 0, SunVox::Note::None, 0, generator_number, ctl: 4, ctl_value: attack)
# Change Release
SunVox.send_event(slot, 0, SunVox::Note::None, 0, generator_number, ctl: 5, ctl_value: release)
# Send a note
SunVox.send_event(slot, 0, note, 0, generator_number)
sleep 0.3
SunVox.send_event(slot, 0, SunVox::Note::Off, 0, generator_number)
sleep 3
end
sleep
Bad Generative Music Example
require "libsunvox"
SunVox.start_engine(config: "audiodevice=hw:0,0", no_debug_output: true, one_thread: false)
slot = SunVox.open_slot(SunVox::Slot::One)
generator = SunVox.new_module(slot, SunVox::Modules::Synths::GENERATOR)
reverb = SunVox.new_module(slot, SunVox::Modules::Effects::REVERB)
drum_synth = SunVox.new_module(slot, SunVox::Modules::Synths::DRUM_SYNTH)
# Connect the module to the output
SunVox.connect_module(slot, generator, reverb)
SunVox.connect_module(slot, reverb, SunVox::OUTPUT_MODULE)
SunVox.connect_module(slot, drum_synth, reverb)
# Set up the sound settings
# Change waveform to noise
SunVox.send_event(slot, 0, SunVox::Note::None, 0, generator, ctl: 2, ctl_value: 0)
# Change Attack and release
SunVox.send_event(slot, 0, SunVox::Note::None, 0, generator, ctl: 4, ctl_value: 0x1000)
SunVox.send_event(slot, 0, SunVox::Note::None, 0, generator, ctl: 5, ctl_value: 0x1000)
spawn do
1_000_000.times do |x|
if x % 2 == 0
SunVox.send_event(slot, 0, SunVox::Note::C5, 0, drum_synth)
sleep 0.25
SunVox.send_event(slot, 0, SunVox::Note::C5, 0, drum_synth)
sleep 0.25
else
SunVox.send_event(slot, 0, SunVox::Note::D5, 0, drum_synth)
sleep 0.5
end
2.times do
SunVox.send_event(slot, 0, SunVox::Note::FSharp1, 0, drum_synth)
sleep 0.5
end
SunVox.send_event(slot, 0, SunVox::Note::FSharp1, 0, drum_synth)
sleep 0.25
SunVox.send_event(slot, 0, SunVox::Note::FSharp1, 0, drum_synth)
sleep 0.25
end
end
spawn do
scale = SunVox::Scales.make(SunVox::Note::F3, SunVox::Scales::MINOR_HEXATONIC)
scale_size = scale.size
scale = scale + SunVox::Scales.make(SunVox::Note::F4, SunVox::Scales::MINOR_HEXATONIC)
1_000_000.times do
3.times do
note = rand(scale_size)
SunVox.send_event(slot, 0, scale[note], 0, generator)
sleep 0.25/2
SunVox.send_event(slot, 1, scale[note + 2], 0, generator)
sleep 0.25/2
SunVox.send_event(slot, 2, scale[note + 4], 0, generator)
sleep 0.75
SunVox.send_event(slot, 0, SunVox::Note::Off, 0, generator)
SunVox.send_event(slot, 1, SunVox::Note::Off, 0, generator)
SunVox.send_event(slot, 2, SunVox::Note::Off, 0, generator)
sleep 1
end
note = rand(scale_size)
SunVox.send_event(slot, 3, scale[note], 0, generator)
sleep 1
SunVox.send_event(slot, 3, SunVox::Note::Off, 0, generator)
sleep 1
end
end
sleep
Make a live vocoder - https://youtu.be/PoH34XjlLLE
require "libsunvox"
# Set the audiodevice and audiodevice_in to your device then speak into your microphone :)
SunVox.start_engine(config: "audiodriver=alsa|audiodevice=hw:0,0|audiodevice_in=hw:2,0", no_debug_output: true, one_thread: false)
slot = SunVox.open_slot(SunVox::Slot::One)
input = SunVox.new_module(slot, SunVox::Modules::Synths::INPUT)
generator = SunVox.new_module(slot, SunVox::Modules::Synths::GENERATOR)
carrier = SunVox.new_module(slot, SunVox::Modules::Effects::AMPLIFIER)
modulator = SunVox.new_module(slot, SunVox::Modules::Effects::AMPLIFIER)
vocoder = SunVox.load_module(slot, "./rsrc/vocoder.sunsynth")
# Connect the module to the output
SunVox.connect_module(slot, input, modulator)
SunVox.connect_module(slot, generator, carrier)
SunVox.connect_module(slot, carrier, vocoder)
SunVox.connect_module(slot, modulator, vocoder)
SunVox.connect_module(slot, vocoder, SunVox::OUTPUT_MODULE)
SunVox.update_input
SunVox.send_event(slot, 0, SunVox::Note::None, 0, generator, ctl: 2, ctl_value: 0x1)
# Set carrier controls
SunVox.send_event(slot, 0, SunVox::Note::None, 0, carrier, ctl: 1, ctl_value: 0x4000)
SunVox.send_event(slot, 0, SunVox::Note::None, 0, carrier, ctl: 2, ctl_value: 0x8000)
# Set modulator controls
SunVox.send_event(slot, 0, SunVox::Note::None, 0, modulator, ctl: 1, ctl_value: 0x69c0)
SunVox.send_event(slot, 0, SunVox::Note::None, 0, modulator, ctl: 2, ctl_value: 0)
SunVox.send_event(slot, 0, SunVox::Note::D1, 0, generator)
SunVox.send_event(slot, 1, SunVox::Note::D2, 0, generator)
SunVox.send_event(slot, 2, SunVox::Note::D3, 0, generator)
SunVox.send_event(slot, 3, SunVox::Note::G4, 0, generator)
SunVox.send_event(slot, 4, SunVox::Note::D5, 0, generator)
sleep
Live monitor output levels
require "crysterm" # github: crystallabs/crysterm
require "libsunvox"
include Crysterm
COLORS = [10, 11, 9]
SunVox.start_engine(config: "audiodriver=alsa|audiodevice=hw:0,0|audiodevice_in=hw:2,0", no_debug_output: true, one_thread: false)
# Opens a slot for us to use
slot = SunVox.open_slot(SunVox::Slot::Zero)
SunVox.load(slot, "./rsrc/song.sunvox")
SunVox.play_from_beginning(slot)
def draw(s : Screen, x, y, fg = 0, bg = 0, char = ' ')
s.fill_region(Widget.sattr(Namespace::Style.new, fg, bg), char, x, x+1, y, y+1)
end
def draw_region(s : Screen, x1, y1, x2, y2, fg = 0, bg = 0, char = ' ')
s.fill_region(Widget.sattr(Namespace::Style.new, fg, bg), char, x1, x2, y1, y2)
end
def clear(s : Screen)
draw_region(s, 0, 0, s.width, s.height)
end
def draw_frame(s)
output_level = (SunVox.get_current_signal_level(SunVox::Slot::Zero, 0)/100.0).clamp(0, 0.9)
output_color = COLORS[(COLORS.size*output_level).to_i]
draw_region(s, 0, 5, (s.width*output_level).to_i , 10, bg: output_color)
output_level =(SunVox.get_current_signal_level(SunVox::Slot::Zero, 1)/100.0).clamp(0, 0.9)
output_color = COLORS[(COLORS.size*output_level).to_i]
draw_region(s, 0, 12, (s.width*output_level).to_i , 17, bg: output_color-8)
end
# `Display` is a phyiscal device (terminal hardware or emulator).
# It can be instantiated manually as shown, or for quick coding it can be
# skipped and it will be created automatically when needed.
d = Display.new
# `Screen` is a full-screen surface which contains visual elements (Widgets),
# on which graphics is rendered, and which is then drawn onto the terminal.
# An app can have multiple screens, but only one can be showing at a time.
s = Screen.new display: d
# When q is pressed, exit the demo.
s.on(Event::KeyPress) do |e|
if e.char == 'q'
exit
end
end
spawn do
loop do
sleep 0.1
clear(s)
draw_frame(s)
s.render
end
end
d.exec