Selaa lähdekoodia

It makes networked noise! (Poorly, for now)

Graham Northup 8 vuotta sitten
vanhempi
commit
629d2fa754
5 muutettua tiedostoa jossa 177 lisäystä ja 51 poistoa
  1. 122 0
      src/client.rs
  2. 1 0
      src/lib.rs
  3. 16 22
      src/main.rs
  4. 36 28
      src/proto.rs
  5. 2 1
      src/synth/mod.rs

+ 122 - 0
src/client.rs

@@ -0,0 +1,122 @@
+use std::net::{UdpSocket};
+use std::{io, mem};
+
+use synth::*;
+use proto::*;
+
+pub struct Voice {
+    pub gen: GenBox,
+    pub params: Parameters,
+}
+
+pub struct Client {
+    pub socket: UdpSocket,
+    pub voices: Vec<Voice>,
+    pub env: Environment,
+    pub frames: usize,
+    pub buf: SampleBuffer,
+}
+
+macro_rules! dprintln {
+    ( $( $x:expr ),* ) => { eprintln!( $( $x ),* ) }
+}
+
+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 {
+            socket: socket,
+            voices: voices,
+            env: env,
+            frames: 0,
+            buf: buf,
+        })
+    }
+
+    pub fn pump(&mut self, out_buffer: &mut Vec<u8>) -> bool {
+        if self.voices.len() == 0 {
+            return false;
+        }
+
+        let mut buffer: [u8; Command::SIZE] = unsafe { mem::uninitialized() };
+
+        loop {
+            match self.socket.recv_from(&mut buffer) {
+                Ok((bytes, sender)) => {
+                    if bytes != Command::SIZE {
+                        dprintln!("Dropping packet: wrong number of bytes (got {}, expected {})", bytes, Command::SIZE);
+                        continue;
+                    }
+
+                    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]));
+                        },
+                    }
+                },
+                Err(err) => {
+                    if err.kind() == io::ErrorKind::WouldBlock {
+                        break;
+                    }
+                    return false;
+                },
+            }
+        }
+
+        for voice in self.voices.iter_mut() {
+            *voice.params.vars.entry("v_frame".to_string()).or_insert_with(Default::default) = self.frames as f32;
+        }
+
+        let (first, next) = self.voices.split_at_mut(1);
+        self.buf.update_from(first[0].gen.eval(&first[0].params));
+
+        for voice in next {
+            self.buf.sum_into(voice.gen.eval(&voice.params));
+        }
+
+        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;
+    }
+}

+ 1 - 0
src/lib.rs

@@ -10,6 +10,7 @@ pub use types::*;
 pub mod synth;
 pub mod proto;
 pub mod lang;
+pub mod client;
 
 #[cfg(test)]
 mod tests {

+ 16 - 22
src/main.rs

@@ -1,35 +1,29 @@
 use std::io;
 use std::io::*;
+use std::net::*;
 
 extern crate synfone;
 use synfone::synth::*;
 use synfone::lang::*;
+use synfone::client::*;
 
-const FRAMES: usize = 44100 * 2;
-
-const GEN: &'static str = "add(mul(sine(param('freq', 440)), 0.5), mul(sine(param('freq2', 660)), 0.5))";
+const GEN: &'static str = "mul(sine(param('v_freq', 500)), ifelse(rel(param('v_frame'), '<', param('v_deadline')), param('v_amp'), 0.0))";
 
 fn main() {
-    let mut params = Parameters::default();
-    
-    let mut gen = Parser::new(Tokenizer::new(GEN.chars())).expect("Failed to get first token").parse().expect("Failed to compile generator");
+    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 sock = UdpSocket::bind("0.0.0.0:13676").expect("Failed to bind socket");
 
-    let mut counter = 0;
+    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 outbuf: Vec<u8> = Vec::new();
-    
-    params.vars.insert("freq".to_string(), 440.0);
-    params.vars.insert("freq2".to_string(), 660.0);
-
-    while counter < FRAMES {
-        *params.vars.get_mut("freq").unwrap() = 440.0 + 440.0 * ((counter as f32) / (FRAMES as f32));
-        *params.vars.get_mut("freq2").unwrap() = 660.0 + 220.0 * ((counter as f32) / (FRAMES as f32));
-        let buf = gen.eval(&params);
-        let curlen = outbuf.len();
-        outbuf.reserve_exact(buf.size() - curlen);
-        unsafe { outbuf.set_len(buf.size()); }
-        buf.bytes(&mut outbuf);
-        out.write_all(&outbuf).expect("failed to write to stdout");
-        counter += buf.len();
+
+    eprintln!("Starting.");
+
+    while client.pump(&mut buf) {
+        out.write_all(&buf).expect("Failed to write samples");
     }
+
+    eprintln!("Exiting.");
 }

+ 36 - 28
src/proto.rs

@@ -18,7 +18,7 @@ pub enum Command {
 }
 
 impl Command {
-    const SIZE: usize = 36;
+    pub const SIZE: usize = 36;
 
     pub fn duration(&self) -> Option<Duration> {
         match *self {
@@ -33,6 +33,40 @@ impl Command {
             _ => None,
         }
     }
+
+    pub fn write_into(&self, ret: &mut [u8]) -> bool {
+        if ret.len() < Command::SIZE {
+            return false;
+        }
+
+        match *self {
+            Command::KeepAlive => NetworkEndian::write_u32(&mut ret[..4], 0),
+            Command::Ping{data} => {
+                NetworkEndian::write_u32(&mut ret[..4], 1);
+                (&mut ret[4..]).copy_from_slice(&data);
+            },
+            Command::Quit => NetworkEndian::write_u32(&mut ret[..4], 2),
+            Command::Play{sec, usec, freq, amp, voice} => {
+                NetworkEndian::write_u32_into(&[3u32, sec, usec, freq], &mut ret[..16]);
+                NetworkEndian::write_f32(&mut ret[16..20], amp);
+                NetworkEndian::write_u32(&mut ret[20..24], voice);
+            },
+            Command::Caps{voices, tp, ident} => {
+                NetworkEndian::write_u32_into(&[4u32, voices], &mut ret[..8]);
+                (&mut ret[8..12]).copy_from_slice(&tp);
+                (&mut ret[12..]).copy_from_slice(&ident);
+            },
+            Command::PCM{samples} => {
+                NetworkEndian::write_u32(&mut ret[..4], 5);
+                NetworkEndian::write_i16_into(&samples, &mut ret[4..]);
+            },
+            Command::Unknown{data} => {
+                ret.copy_from_slice(&data);
+            },
+        };
+
+        true
+    }
 }
 
 impl<'a> From<&'a [u8; Command::SIZE]> for Command {
@@ -85,33 +119,7 @@ impl<'a> From<&'a [u8; Command::SIZE]> for Command {
 impl<'a> From<&'a Command> for [u8; Command::SIZE] {
     fn from(cmd: &'a Command) -> [u8; Command::SIZE] {
         let mut ret: [u8; Command::SIZE] = [0u8; Command::SIZE];
-
-        match *cmd {
-            Command::KeepAlive => NetworkEndian::write_u32(&mut ret[..4], 0),
-            Command::Ping{data} => {
-                NetworkEndian::write_u32(&mut ret[..4], 1);
-                (&mut ret[4..]).copy_from_slice(&data);
-            },
-            Command::Quit => NetworkEndian::write_u32(&mut ret[..4], 2),
-            Command::Play{sec, usec, freq, amp, voice} => {
-                NetworkEndian::write_u32_into(&[3u32, sec, usec, freq], &mut ret[..16]);
-                NetworkEndian::write_f32(&mut ret[16..20], amp);
-                NetworkEndian::write_u32(&mut ret[20..24], voice);
-            },
-            Command::Caps{voices, tp, ident} => {
-                NetworkEndian::write_u32_into(&[4u32, voices], &mut ret[..8]);
-                (&mut ret[8..12]).copy_from_slice(&tp);
-                (&mut ret[12..]).copy_from_slice(&ident);
-            },
-            Command::PCM{samples} => {
-                NetworkEndian::write_u32(&mut ret[..4], 5);
-                NetworkEndian::write_i16_into(&samples, &mut ret[4..]);
-            },
-            Command::Unknown{data} => {
-                ret.copy_from_slice(&data);
-            },
-        };
-
+        cmd.write_into(&mut ret);
         ret
     }
 }

+ 2 - 1
src/synth/mod.rs

@@ -21,6 +21,7 @@ pub struct SampleBuffer {
     pub rate: Rate,
 }
 
+#[derive(Debug,Clone)]
 pub struct Environment {
     pub sample_rate: f32,
     pub default_buffer_size: usize,
@@ -143,7 +144,7 @@ impl SampleBuffer {
         mem::size_of::<Sample>() * self.samples.len()
     }
 
-    pub fn bytes(&self, buf: &mut [u8]) {
+    pub fn write_bytes(&self, buf: &mut [u8]) {
         // FIXME: Depends on f32 instead of Sample alias
         ::byteorder::LittleEndian::write_f32_into(&self.samples, buf);
     }