Skip to content

Instantly share code, notes, and snippets.

@routevegetable
Created March 8, 2025 01:53
Show Gist options
  • Save routevegetable/cf8dea9ee9a6a00ff64c2c49085fb6df to your computer and use it in GitHub Desktop.
Save routevegetable/cf8dea9ee9a6a00ff64c2c49085fb6df to your computer and use it in GitHub Desktop.
use std::{process::Output, time};
use timebase::{Event, Frame};
use tinyaudio::prelude::*;
mod timebase;
#[derive(Copy, Clone)]
struct Note {
khz: f32
}
impl Note {
const fn up_octave(self) -> Self {
Self{khz: self.khz * 2.0}
}
const fn down_octave(self) -> Self {
Self{khz: self.khz * 0.5}
}
const fn up_fifth(self) -> Self {
Self{khz: self.khz * 1.498307}
}
}
const C4: Note = Note{khz: 0.26163};
const D4: Note = Note{khz: 0.29366};
const E4: Note = Note{khz: 0.32963};
const F4: Note = Note{khz: 0.34923};
const G4: Note = Note{khz: 0.392};
const A4: Note = Note{khz: 0.44};
const B4: Note = Note{khz: 0.49388};
const MSEC: i32 = 10;
const SEC: i32 = 10000;
const HNDRDUSEC: i32 = 10;
const fn period(khz: f32) -> i32 {
(MSEC as f32 / khz) as i32
}
struct Piano<'a> {
frame: &'a Frame,
output: f32,
}
impl <'a> Piano<'a> {
fn new(frame: &'a Frame) -> Self {
Self {
frame,
output: 0.0,
}
}
fn key(&mut self, ev: Event, khz: f32) {
// Fundamental
let tone = self.frame.timebase(timebase::TimebaseMode::Repeat, period(khz), ev).circle().sin();
// Low harmonic
let tone2 = self.frame.timebase(timebase::TimebaseMode::Repeat, period(khz / 2.0), ev).circle().sin() / 3.0;
// Sustain
let ramp = self.frame.timebase(timebase::TimebaseMode::OneShot, SEC, ev);
self.output += (tone + tone2) * ramp.scale(0.15, 0.0);
}
fn out(&self) -> f32 {
self.output
}
}
fn audio(f: &Frame) -> f32 {
let mut piano = Piano::new(f);
let tune = f.timebase(timebase::TimebaseMode::Repeat, 8*SEC, Event::zero());
let notes = [
C4, E4, G4, C4, F4, E4, D4, C4.up_octave()
];
let long_notes = notes.repeat(4).into_iter().zip([
true, false, true, true, false, true, true, false, true, true, false, true, true, true, true, true, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true,
]).map(|(note, up)| if up {note.up_fifth()} else {note});
for (ev, note) in tune.seq::<32>().iter().zip(long_notes) {
piano.key(*ev, note.khz);
}
piano.out()
}
fn main() {
let _device = run_output_device(OutputDeviceParameters{
sample_rate:10000,
channels_count:1,
channel_sample_count:1000
}, {
let mut clock = 0i32;
move |data| {
for frame in data {
clock = clock + period(10.0);
*frame = audio(&Frame::new(clock));
}
}}).unwrap();
std::thread::sleep(std::time::Duration::from_secs(16));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment