Skip to content

Instantly share code, notes, and snippets.

@HybridEidolon
Last active August 29, 2015 14:23
Show Gist options
  • Save HybridEidolon/8aae90086a65a03d9d7b to your computer and use it in GitHub Desktop.
Save HybridEidolon/8aae90086a65a03d9d7b to your computer and use it in GitHub Desktop.
sine keyboard
extern crate sdl2;
use sdl2::audio;
use std::f32::consts::PI;
use std::sync::Arc;
use std::sync::Mutex;
fn note_frequency(tone: i32) -> f32 {
440.0 * (1.059463 as f32).powi(tone)
}
fn scancode_to_halfstep(code: sdl2::keyboard::Scancode) -> Option<i32> {
use sdl2::keyboard::Scancode::*;
match code {
Z => Some(3),
S => Some(4),
X => Some(5),
D => Some(6),
C => Some(7),
V => Some(8),
G => Some(9),
B => Some(10),
H => Some(11),
N => Some(12),
J => Some(13),
M => Some(14),
Comma => Some(15),
L => Some(16),
Period => Some(17),
_ => None
}
}
struct Generator {
freq: i32,
phase: u32,
volume: f32,
note: Vec<i32>,
spectro_buffer: Arc<Mutex<Vec<i16>>>
}
impl audio::AudioCallback for Generator {
type Channel = i16;
fn callback(&mut self, out: &mut [i16]) {
// Clear the buffer.
for x in out.iter_mut() {
*x = 0;
}
for note in self.note.iter() {
let note_freq = note_frequency(*note);
let mut phase_counter = self.phase;
for x in out.iter_mut() {
let phase_f = (phase_counter as f32 / self.freq as f32) * note_freq * PI;
let sine_sample = (phase_f).sin() * self.volume;
let sample = (sine_sample * 32768.0).round() as i16;
*x = x.saturating_add(sample);
phase_counter = phase_counter.wrapping_add(1);
}
}
self.phase = self.phase.wrapping_add(out.len() as u32);
// replace the spectro buffer
{
let mut specbuf = self.spectro_buffer.lock().unwrap();
specbuf.clear();
for x in out.iter() {
specbuf.push(*x);
}
}
}
}
fn main() {
let mut sdl_context = sdl2::init().video().audio().unwrap();
let display = sdl_context.window("Hello", 800, 600).build().unwrap();
let mut running = true;
let desired_spec = audio::AudioSpecDesired {
freq: Some(44100),
channels: Some(1),
samples: Some(512)
};
let spectrobuf = Arc::new(Mutex::new(Vec::with_capacity(512)));
let mut device = audio::AudioDevice::open_playback(None, desired_spec, |spec| {
// Initialize audio callback
Generator {
freq: spec.freq,
phase: 0,
volume: 0.30,
note: Vec::with_capacity(8),
spectro_buffer: spectrobuf.clone()
}
}).unwrap();
device.resume();
while running {
for event in sdl_context.event_pump().poll_iter() {
use sdl2::event::Event;
match event {
Event::Quit { .. } => {
running = false;
},
Event::KeyDown { scancode, repeat, .. } => {
if !repeat {
let mut d = device.lock();
let halfstep = scancode.map(scancode_to_halfstep);
halfstep.map(|n| n.map(|nn| d.note.push(nn)));
}
},
Event::KeyUp { scancode, .. } => {
let mut d = device.lock();
scancode
.map(scancode_to_halfstep)
.map(|n| n.map(|nn| {
let loc = d.note.iter().position(|&v| v == nn);
loc.map(|l| d.note.remove(l));
}));
}
_ => ()
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment