Created
June 7, 2018 20:49
-
-
Save 44100hertz/e4be786d3f770c25bda7999e7bf72bf9 to your computer and use it in GitHub Desktop.
mml -> fm synth
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
const SRATE: u16 = 48000; | |
use std::f64::consts::PI; | |
use std::io::{Read, Write, stdin, stdout}; | |
fn main() { | |
let sin_table: Vec<u8> = (0..256) | |
.map(|i| ((i as f64 / 512.0 / PI).sin() * 256.0) as u8) | |
.collect(); | |
let get_sin = |phase: u16| -> i16 { | |
let pos = (phase >> 6) as u8 as usize; | |
let samp = sin_table[if phase & 1<<14 == 0 { pos } else { 0xff - pos }]; | |
if phase & 1<<15 == 0 { samp as i16 } else { -(samp as i16) } | |
}; | |
let notes = { | |
let mut notes = [0_u8; 256]; | |
let note_vals: [(char, u8); 14] = [ | |
('a',0), ('A',1), ('b',2), ('B',3), ('c',3), ('C',4), ('d',5), | |
('D',6), ('e',7), ('E',8), ('f',8), ('F',9), ('g',10),('G',11)]; | |
for (c, i) in ¬e_vals { notes[*c as u8 as usize] = *i; } | |
notes | |
}; | |
let mut octave = 0i8; | |
let (mut phase, mut phase_inc, mut env) = (0u16, 0u16, 0u16); | |
let mut delay = 0; | |
let mut chars = { | |
let mut file = vec![]; | |
stdin().read_to_end(&mut file).unwrap(); | |
file.into_iter().peekable() | |
}; | |
let mut exit = false; | |
while !exit { | |
let c = chars.next().unwrap_or_else(|| { exit=true; b' '} ); | |
match c { | |
b'O' => { | |
let next = chars.next().expect("no octave specified"); | |
assert!(next <= b'9' && next >= b'0'); | |
octave = (next - b'0') as i8 - 4; | |
} | |
b'<' => if octave > -4 { octave -= 1 }, | |
b'>' => if octave < 5 { octave += 1 }, | |
b'a'..=b'g' | b'A'..=b'G' => { | |
env = SRATE/4; | |
let note = notes[c as usize] as f64; | |
phase_inc = (2.0_f64.powf(note/12.0 + octave as f64) * 440.0 * | |
std::u16::MAX as f64 / SRATE as f64) as u16; | |
let delays = [1, 2, 3, 4, 6, 8, 12, 16, 24, 32]; | |
delay = 8; | |
if let Some(&next) = chars.peek() { | |
if next <= b'9' && next >= b'0' { | |
chars.next().unwrap(); | |
delay = delays[(next - b'0') as usize]; | |
} | |
} | |
} | |
_ => {}, | |
} | |
for _ in 0..delay { | |
let mut out = [0u8; SRATE as usize/8]; | |
for i in 0..SRATE as usize/16 { | |
let phase2 = get_sin(phase).wrapping_mul(env as i16>>4) as u16; | |
let samp = get_sin(phase2) * 128; | |
phase = phase.wrapping_add(phase_inc); | |
if env > 0 { env -= 1 } | |
out[i*2] = samp as u8; | |
out[i*2+1] = (samp >> 8) as u8; | |
} | |
stdout().write_all(&out).unwrap(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment