Open_file & SecretSound
Hey, I’ve been playing around with a tiny audio synth in Rust and thinking it could be fun to merge code and sound—what do you think about exploring how a little algorithm can shape a whole sonic texture?
That sounds like a quiet dance between code and waves, I’m curious what textures you’ll let the algorithm paint.
I’m thinking of a noise‑driven wavetable that morphs over time, maybe a simple LFO that tweaks filter resonance and a tiny random seed for each cycle—so the texture feels alive, not just static. Want to dive into a quick demo?
A gentle pulse already hums in my mind. Send me the code and let the quiet speak.
use std::f32::consts::PI;
use std::time::Instant;
use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
fn main() {
// setup audio host and default output device
let host = cpal::default_host();
let device = host.default_output_device().expect("No output device");
let config = device.default_output_config().expect("No default config");
// choose sample rate and channels
let sample_rate = config.sample_rate().0 as f32;
let channels = config.channels() as usize;
// synth state
let mut phase = 0.0f32;
let mut lfo_phase = 0.0f32;
let freq = 220.0f32; // base tone
let lfo_rate = 0.1f32; // slow pulse
let lfo_amp = 0.5f32; // depth of resonance change
let mut last_instant = Instant::now();
// build stream
let err_fn = |err| eprintln!("stream error: {}", err);
let stream = match config.sample_format() {
cpal::SampleFormat::F32 => device.build_output_stream(
&config.into(),
move |data: &mut [f32], _: &cpal::OutputCallbackInfo| {
write_data(data, channels, sample_rate, &mut phase, &mut lfo_phase, freq, lfo_rate, lfo_amp, last_instant);
},
err_fn,
),
cpal::SampleFormat::I16 => device.build_output_stream(
&config.into(),
move |data: &mut [i16], _: &cpal::OutputCallbackInfo| {
write_data_i16(data, channels, sample_rate, &mut phase, &mut lfo_phase, freq, lfo_rate, lfo_amp, last_instant);
},
err_fn,
),
cpal::SampleFormat::U16 => device.build_output_stream(
&config.into(),
move |data: &mut [u16], _: &cpal::OutputCallbackInfo| {
write_data_u16(data, channels, sample_rate, &mut phase, &mut lfo_phase, freq, lfo_rate, lfo_amp, last_instant);
},
err_fn,
),
}.expect("Failed to build stream");
stream.play().expect("Failed to play stream");
// keep the program running
std::thread::sleep(std::time::Duration::from_secs(30));
}
fn write_data(
output: &mut [f32],
channels: usize,
sample_rate: f32,
phase: &mut f32,
lfo_phase: &mut f32,
freq: f32,
lfo_rate: f32,
lfo_amp: f32,
last_instant: Instant,
) {
let dt = (last_instant.elapsed().as_secs_f32()) / output.len() as f32;
for frame in output.chunks_mut(channels) {
// LFO modulates filter resonance (here just a simple detune)
let lfo = (2.0 * PI * lfo_rate * (*lfo_phase)).sin() * lfo_amp;
let current_freq = freq + lfo * 50.0; // tweak frequency by up to ±50Hz
// generate a sine wave
let sample = (2.0 * PI * current_freq * *phase).sin() * 0.2;
for out in frame.iter_mut() {
*out = sample;
}
*phase += dt * current_freq;
if *phase > 1.0 { *phase -= 1.0; }
*lfo_phase += dt * lfo_rate;
if *lfo_phase > 1.0 { *lfo_phase -= 1.0; }
}
}
fn write_data_i16(
output: &mut [i16],
channels: usize,
sample_rate: f32,
phase: &mut f32,
lfo_phase: &mut f32,
freq: f32,
lfo_rate: f32,
lfo_amp: f32,
last_instant: Instant,
) {
let mut float_buf = vec![0.0f32; output.len()];
write_data(&mut float_buf, channels, sample_rate, phase, lfo_phase, freq, lfo_rate, lfo_amp, last_instant);
for (i, sample) in output.iter_mut().enumerate() {
*sample = (float_buf[i] * i16::MAX as f32) as i16;
}
}
fn write_data_u16(
output: &mut [u16],
channels: usize,
sample_rate: f32,
phase: &mut f32,
lfo_phase: &mut f32,
freq: f32,
lfo_rate: f32,
lfo_amp: f32,
last_instant: Instant,
) {
let mut float_buf = vec![0.0f32; output.len()];
write_data(&mut float_buf, channels, sample_rate, phase, lfo_phase, freq, lfo_rate, lfo_amp, last_instant);
for (i, sample) in output.iter_mut().enumerate() {
*sample = ((float_buf[i] + 1.0) * 0.5 * u16::MAX as f32) as u16;
}
}