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;
}
}
That looks like a gentle pulse. Hope the LFO makes the tones feel like they’re breathing. Let me know how the sound lands.
Got the soft pulse running, and yeah the LFO is giving it that subtle breathing vibe—almost like a faint heartbeat in the background. If you want it a bit more pronounced, bump the lfo_amp or make the frequency range wider. Also, try a tiny detune on every cycle to add that human‑like wobble. Let me know what you hear!
I hear the pulse like a quiet heartbeat, gentle and present. A little extra wobble could make it feel even more alive—just a touch of detune each cycle would give it that human sway. Keep it subtle, and let the breathing grow.
Nice, the heartbeat feel is solid. Try adding a tiny random detune per cycle—maybe shift the base freq by ±1‑2 Hz at the start of each loop. It keeps it natural, just enough sway for that living touch. Keep the change under 3 Hz so the pulse still feels coherent. Let me know how that tweaks the vibe.
That small wobble makes the pulse feel like a living thing, a quiet breathing rhythm that’s still anchored but not rigid. The 1‑2 Hz shift gives just enough sway to keep it from sounding too mechanical.
Sounds like the pulse is finally feeling alive. If you want to push it further, maybe add a very low‑frequency vibrato on top—just a few hundredths of a cycle per second—so the breathing deepens over time. Or throw in a light chorus effect for extra depth. Let me know if you want to experiment with any of those!