diff options
author | Graham Northup <grissess@nexusg.org> | 2017-10-01 07:04:21 -0400 |
---|---|---|
committer | Graham Northup <grissess@nexusg.org> | 2017-10-01 07:04:21 -0400 |
commit | 145e2771c0d1ad30748da6e6ef1fabbd4cc2478c (patch) | |
tree | b9e96a57df0d515383a7c09e3b2ea71edb31db96 | |
parent | 629d2fa754dcd4bbdbd1e84ea9f7598806abc840 (diff) |
It plays network noises now!
-rw-r--r-- | Cargo.toml | 1 | ||||
-rw-r--r-- | src/client.rs | 116 | ||||
-rw-r--r-- | src/main.rs | 56 | ||||
-rw-r--r-- | src/proto.rs | 17 | ||||
-rw-r--r-- | src/synth/mod.rs | 4 |
5 files changed, 142 insertions, 52 deletions
@@ -7,3 +7,4 @@ authors = ["Graham Northup <grissess@nexusg.org>"] byteorder = "1.1.0" rand = "0.3" unicode-xid = "0.1.0" +portaudio = "0.7.0" diff --git a/src/client.rs b/src/client.rs index 1a0c69f..4615edd 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1,4 +1,4 @@ -use std::net::{UdpSocket}; +use std::net::{UdpSocket, SocketAddr}; use std::{io, mem}; use synth::*; @@ -15,6 +15,7 @@ pub struct Client { pub env: Environment, pub frames: usize, pub buf: SampleBuffer, + norm: SampleBuffer } macro_rules! dprintln { @@ -23,7 +24,6 @@ macro_rules! dprintln { impl Client { pub fn new(socket: UdpSocket, gens: Vec<GenBox>, env: Environment) -> io::Result<Client> { - socket.set_nonblocking(true)?; let buf = SampleBuffer::new(env.default_buffer_size); let voices = gens.into_iter().map(|g| Voice { gen: g, params: Parameters { env: env.clone(), ..Default::default() } }).collect(); Ok(Client { @@ -32,10 +32,13 @@ impl Client { env: env, frames: 0, buf: buf, + norm: SampleBuffer::new(1), }) } - pub fn pump(&mut self, out_buffer: &mut Vec<u8>) -> bool { + // NB: Loops indefinitely (until timeout, quit, or error) iff self.socket blocks + /* + pub fn process_packets(&mut self) -> bool { if self.voices.len() == 0 { return false; } @@ -51,45 +54,8 @@ impl Client { } let cmd = Command::from(&buffer); - dprintln!("Packet {:?} from {:?}", (&buffer as &[u8]), sender); - match cmd { - Command::KeepAlive => {}, - Command::Ping{..} => { - self.socket.send_to(&buffer, sender); - }, - Command::Quit => { - return false; - }, - Command::Play{voice, freq, amp, ..} => { - if (voice as usize) >= self.voices.len() { - dprintln!("Dropping packet: tried to send to voice {} >= number of voices {}", voice, self.voices.len()); - continue; - } - let dur = cmd.duration().unwrap(); - let frac_secs = (dur.as_secs() as f32) + (dur.subsec_nanos() as f32) / 1.0e9; - let frames = frac_secs * (self.env.sample_rate as f32); - - dprintln!("Playing on voice {} freq {} amp {} from frame {} until frame {}", voice, freq, amp, self.frames, (self.frames as f32) + frames); - - let mut vars = &mut self.voices[voice as usize].params.vars; - *vars.entry("v_deadline".to_string()).or_insert_with(Default::default) = (self.frames as f32) + frames; - *vars.entry("v_freq".to_string()).or_insert_with(Default::default) = freq as f32; - *vars.entry("v_amp".to_string()).or_insert_with(Default::default) = amp; - }, - Command::Caps{..} => { - let reply = Command::Caps { - voices: self.voices.len() as u32, - tp: ['S' as u8, 'Y' as u8, 'N' as u8, 'F' as u8], - ident: [0u8; 24], - }; - let mut reply_buffer: [u8; Command::SIZE] = [0u8; Command::SIZE]; - reply.write_into(&mut reply_buffer); - self.socket.send_to(&reply_buffer, sender); - }, - Command::PCM{..} => { /* TODO */ }, - Command::Unknown{data} => { - dprintln!("Dropping packet: unknown data {:?}", (&data as &[u8])); - }, + if !self.handle_command(cmd, sender) { + return false; } }, Err(err) => { @@ -101,6 +67,60 @@ impl Client { } } + true + } + */ + + pub fn handle_command(&mut self, cmd: Command, sender: SocketAddr) -> bool { + dprintln!("Packet {:?} from {:?}", cmd, sender); + match cmd { + Command::KeepAlive => {}, + Command::Ping{..} => { + let mut reply_buffer: [u8; Command::SIZE] = [0u8; Command::SIZE]; + cmd.write_into(&mut reply_buffer); + self.socket.send_to(&reply_buffer, sender); + }, + Command::Quit => { + return false; + }, + Command::Play{voice, freq, amp, ..} => { + if (voice as usize) >= self.voices.len() { + dprintln!("Dropping packet: tried to send to voice {} >= number of voices {}", voice, self.voices.len()); + return true; + } + let dur = cmd.duration().unwrap(); + let frac_secs = (dur.as_secs() as f32) + (dur.subsec_nanos() as f32) / 1.0e9; + let frames = frac_secs * (self.env.sample_rate as f32); + + dprintln!("Playing on voice {} freq {} amp {} from frame {} until frame {}", voice, freq, amp, self.frames, (self.frames as f32) + frames); + + let mut vars = &mut self.voices[voice as usize].params.vars; + *vars.entry("v_deadline".to_string()).or_insert_with(Default::default) = (self.frames as f32) + frames; + *vars.entry("v_freq".to_string()).or_insert_with(Default::default) = freq as f32; + *vars.entry("v_amp".to_string()).or_insert_with(Default::default) = amp; + }, + Command::Caps{..} => { + let reply = Command::Caps { + voices: self.voices.len() as u32, + tp: ['S' as u8, 'Y' as u8, 'N' as u8, 'F' as u8], + ident: [0u8; 24], + }; + let mut reply_buffer: [u8; Command::SIZE] = [0u8; Command::SIZE]; + reply.write_into(&mut reply_buffer); + self.socket.send_to(&reply_buffer, sender); + }, + Command::PCM{..} => { /* TODO */ }, + Command::Unknown{data} => { + dprintln!("Dropping packet: unknown data {:?}", (&data as &[u8])); + }, + } + + true + } + + pub fn next_frames(&mut self) { + let len = self.voices.len(); + for voice in self.voices.iter_mut() { *voice.params.vars.entry("v_frame".to_string()).or_insert_with(Default::default) = self.frames as f32; } @@ -112,11 +132,19 @@ impl Client { self.buf.sum_into(voice.gen.eval(&voice.params)); } + self.norm.set(1.0 / (len as f32)); + self.buf.mul_into(&self.norm); + self.frames += self.buf.len(); + } + + pub fn buffer(&self) -> &SampleBuffer { + &self.buf + } + + pub fn write_frames_bytes(&self, out_buffer: &mut Vec<u8>) { let current = out_buffer.len(); out_buffer.reserve_exact(self.buf.size() - current); unsafe { out_buffer.set_len(self.buf.size()); } self.buf.write_bytes(out_buffer); - self.frames += self.buf.len(); - return true; } } diff --git a/src/main.rs b/src/main.rs index e06d2b1..9b78146 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,28 +1,70 @@ use std::io; use std::io::*; use std::net::*; +use std::sync::*; +use std::collections::VecDeque; extern crate synfone; +extern crate portaudio; +use portaudio as pa; +use synfone::*; use synfone::synth::*; use synfone::lang::*; +use synfone::proto::*; use synfone::client::*; -const GEN: &'static str = "mul(sine(param('v_freq', 500)), ifelse(rel(param('v_frame'), '<', param('v_deadline')), param('v_amp'), 0.0))"; +const GEN: &'static str = "mul(saw(param('v_freq', 500)), ifelse(rel(param('v_frame'), '<', param('v_deadline')), param('v_amp'), 0.0))"; fn main() { let env = Environment::default(); - let gen = Parser::new(Tokenizer::new(GEN.chars())).expect("Failed to get first token").parse().expect("Failed to compile generator"); + let mut gens = Vec::new(); + for _i in 0..25 { + let gen = Parser::new(Tokenizer::new(GEN.chars())).expect("Failed to get first token").parse().expect("Failed to compile generator"); + gens.push(gen); + } let sock = UdpSocket::bind("0.0.0.0:13676").expect("Failed to bind socket"); - let mut client = Client::new(sock, vec![gen], env).expect("Failed to create client"); - let mut buf: Vec<u8> = Vec::new(); - let mut out = io::stdout(); + let mut client = Arc::new(Mutex::new(Client::new(sock.try_clone().expect("Failed to clone socket"), gens, env.clone()).expect("Failed to create client"))); + + let pa_inst = pa::PortAudio::new().expect("Failed to create PortAudio interface"); + let settings = pa_inst.default_output_stream_settings(1, env.sample_rate as f64, env.default_buffer_size as u32).expect("Failed to instantiate stream settings"); + let mut stream; + { + let client = client.clone(); + let mut ring: VecDeque<Sample> = VecDeque::new(); + ring.reserve_exact(2 * env.default_buffer_size); + stream = pa_inst.open_non_blocking_stream(settings, move |pa::OutputStreamCallbackArgs { buffer, frames, .. }| { + while frames > ring.len() { + let mut cli = client.lock().unwrap(); + cli.next_frames(); + ring.append(&mut cli.buffer().iter().map(|&x| x).collect()); + } + let samps = ring.drain(..frames).collect::<Vec<f32>>(); + buffer.copy_from_slice(&samps); + pa::Continue + }).expect("Failed to create stream"); + } + eprintln!("Starting."); - while client.pump(&mut buf) { - out.write_all(&buf).expect("Failed to write samples"); + stream.start().expect("Failed to start stream"); + + let mut buffer: [u8; Command::SIZE] = [0u8; Command::SIZE]; + loop { + let (bytes, sender) = sock.recv_from(&mut buffer).unwrap(); + if bytes < Command::SIZE { + continue; + } + + let cmd = Command::from(&buffer); + { + let mut cli = client.lock().unwrap(); + if !cli.handle_command(cmd, sender) { + break; + } + } } eprintln!("Exiting."); diff --git a/src/proto.rs b/src/proto.rs index fe3d576..630e3e8 100644 --- a/src/proto.rs +++ b/src/proto.rs @@ -1,4 +1,4 @@ -use std::mem; +use std::{mem, fmt}; use std::time::Duration; use super::*; @@ -69,6 +69,21 @@ impl Command { } } +impl fmt::Debug for Command { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + write!(f, "Command::")?; + match *self { + Command::KeepAlive => write!(f, "KeepAlive"), + Command::Ping{data} => write!(f, "Ping {{ data: {:?} }}", &data), + Command::Quit => write!(f, "Quit"), + Command::Play{sec, usec, freq, amp, voice} => write!(f, "Play {{ sec: {:?}, usec: {:?}, freq: {:?}, amp: {:?}, voice: {:?} }}", sec, usec, freq, amp, voice), + Command::Caps{voices, tp, ident} => write!(f, "Caps {{ voices: {:?}, tp: {:?}, ident: {:?} }}", voices, &tp, &ident), + Command::PCM{samples} => write!(f, "PCM {{ samples: {:?} }}", &samples), + Command::Unknown{data} => write!(f, "Unknown {{ data: {:?} }}", &data as &[u8]), + } + } +} + impl<'a> From<&'a [u8; Command::SIZE]> for Command { fn from(packet: &'a [u8; Command::SIZE]) -> Command { let mut fields_u32: [u32; Command::SIZE / 4] = unsafe { mem::uninitialized() }; diff --git a/src/synth/mod.rs b/src/synth/mod.rs index 69523e2..60a7372 100644 --- a/src/synth/mod.rs +++ b/src/synth/mod.rs @@ -64,6 +64,10 @@ impl SampleBuffer { self.samples.len() } + pub fn iter(&self) -> slice::Iter<f32> { + self.samples.iter() + } + pub fn iter_mut(&mut self) -> slice::IterMut<f32> { self.samples.iter_mut() } |