Created
July 3, 2022 19:57
-
-
Save euwbah/4c1221cb361ce3ee1c48ee3de3c714ff to your computer and use it in GitHub Desktop.
rip ears
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::{fs::File, io::BufWriter}; | |
use cpal::traits::{DeviceTrait, HostTrait, StreamTrait}; | |
use hound::WavWriter; | |
fn main() -> anyhow::Result<()> { | |
println!("Hello, world!"); | |
let host = cpal::host_from_id(cpal::HostId::Wasapi).expect("Failed to initialize wasapi host"); | |
let out_device = host.default_output_device().expect("No output device"); | |
let def_out_conf = out_device | |
.default_output_config() | |
.expect("No output config"); | |
dbg!(out_device.name()); | |
let spec = hound::WavSpec { | |
channels: 1, | |
sample_rate: 48000, | |
bits_per_sample: 24, | |
sample_format: hound::SampleFormat::Int, | |
}; | |
let mut writer = hound::WavWriter::create("rip ears poly.wav", spec)?; | |
match def_out_conf.sample_format() { | |
cpal::SampleFormat::F32 => run::<f32>(&out_device, &def_out_conf.into(), writer), | |
cpal::SampleFormat::I16 => run::<i16>(&out_device, &def_out_conf.into(), writer), | |
cpal::SampleFormat::U16 => run::<u16>(&out_device, &def_out_conf.into(), writer), | |
} | |
} | |
pub fn run<T>( | |
device: &cpal::Device, | |
config: &cpal::StreamConfig, | |
mut writer: WavWriter<BufWriter<File>>, | |
) -> Result<(), anyhow::Error> | |
where | |
T: cpal::Sample, | |
{ | |
let sample_rate = config.sample_rate.0 as f32; | |
let channels = config.channels as usize; | |
// Produce a sinusoid of maximum amplitude. | |
let mut sample_clock = 0f32; | |
let mut next_value = move || { | |
sample_clock += 1.0; | |
let mut sample_amp = 0.0; | |
let _2xhz_amp = 0.4; | |
let _3xhz_amp = 0.4; | |
// Add 2x hz where x = 110 hz (A2) | |
sample_amp += _2xhz_amp * (sample_clock * 220.0 * 2.0 * std::f32::consts::PI / sample_rate).sin(); | |
// Add 3x hz with 2/3rd pulse wave convolution | |
// period = 1/110 | |
let phase = sample_clock % (sample_rate / 110.0) / (sample_rate / 110.0); // % phase of a 1x hz freq wave. | |
if phase < 2.0/3.0 { | |
// Add 3x hz oscillations only if less than 2/3rd of the period is elapsed. | |
sample_amp += _3xhz_amp * (sample_clock * 330.0 * 2.0 * std::f32::consts::PI / sample_rate).sin(); | |
} | |
writer.write_sample((sample_amp * 2.0f32.powi(22)) as i32).unwrap(); | |
sample_amp | |
}; | |
let err_fn = |err| eprintln!("an error occurred on stream: {}", err); | |
let stream = device.build_output_stream( | |
config, | |
move |data: &mut [T], _: &cpal::OutputCallbackInfo| { | |
write_data(data, channels, &mut next_value) | |
}, | |
err_fn, | |
)?; | |
stream.play()?; | |
std::thread::sleep(std::time::Duration::from_millis(2000)); | |
Ok(()) | |
} | |
fn write_data<T>(output: &mut [T], channels: usize, next_sample: &mut dyn FnMut() -> f32) | |
where | |
T: cpal::Sample, | |
{ | |
for frame in output.chunks_mut(channels) { | |
let value: T = cpal::Sample::from::<f32>(&next_sample()); | |
for sample in frame.iter_mut() { | |
*sample = value; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment