main.rs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. use std::{io, env, thread, iter, time, mem};
  2. use std::io::*;
  3. use std::fs::*;
  4. use std::net::*;
  5. use std::sync::*;
  6. use std::collections::VecDeque;
  7. extern crate synfone;
  8. extern crate portaudio;
  9. #[macro_use]
  10. extern crate glium;
  11. use glium::{glutin, Surface};
  12. use glium::index::PrimitiveType;
  13. extern crate palette;
  14. use palette::IntoColor;
  15. use portaudio as pa;
  16. use synfone::*;
  17. use synfone::synth::*;
  18. use synfone::lang::*;
  19. use synfone::proto::*;
  20. use synfone::client::*;
  21. fn main() {
  22. let env = Environment::default();
  23. let mut genfile = File::open(env::args_os().nth(1).expect("Need first argument to be a file with a generator vector")).expect("Failed to open file");
  24. let mut genstr = String::new();
  25. genfile.read_to_string(&mut genstr);
  26. let gens = Parser::new(Tokenizer::new(genstr.chars()), env.clone()).expect("Failed to get first token").parse_gen_vec().expect("Failed to compile generators");
  27. let sock = UdpSocket::bind("0.0.0.0:13676").expect("Failed to bind socket");
  28. eprintln!("Parsed {} generator definitions", gens.len());
  29. 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")));
  30. let mut last_buffer = Arc::new(Mutex::new(<VecDeque<Sample>>::with_capacity(env.default_buffer_size * 9)));
  31. let last_buffer_lim = env.default_buffer_size * 8;
  32. last_buffer.lock().expect("Failed to init shared buffer").append(&mut iter::repeat(0.0f32).take(last_buffer_lim).collect());
  33. let pa_inst = pa::PortAudio::new().expect("Failed to create PortAudio interface");
  34. 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");
  35. let mut stream;
  36. {
  37. let client = client.clone();
  38. let last_buffer = last_buffer.clone();
  39. let mut ring: VecDeque<Sample> = VecDeque::new();
  40. ring.reserve_exact(2 * env.default_buffer_size);
  41. stream = pa_inst.open_non_blocking_stream(settings, move |pa::OutputStreamCallbackArgs { buffer, frames, .. }| {
  42. while frames > ring.len() {
  43. let mut cli = client.lock().unwrap();
  44. cli.next_frames();
  45. {
  46. let mut buf = last_buffer.lock().expect("Failed to acquire shared buffer in audio callback");
  47. buf.append(&mut cli.buffer().samples.iter().map(|&x| x).collect());
  48. let len = buf.len();
  49. if len > last_buffer_lim {
  50. buf.drain(..(len - last_buffer_lim));
  51. }
  52. }
  53. ring.append(&mut cli.buffer().iter().map(|&x| x).collect());
  54. }
  55. let samps = ring.drain(..frames).collect::<Vec<f32>>();
  56. buffer.copy_from_slice(&samps);
  57. pa::Continue
  58. }).expect("Failed to create stream");
  59. }
  60. eprintln!("Starting.");
  61. stream.start().expect("Failed to start stream");
  62. eprintln!("Audio stream started.");
  63. {
  64. let client = client.clone();
  65. let net_thread = thread::spawn(move || {
  66. let mut buffer: [u8; Command::SIZE] = [0u8; Command::SIZE];
  67. loop {
  68. let (bytes, sender) = sock.recv_from(&mut buffer).unwrap();
  69. if bytes < Command::SIZE {
  70. continue;
  71. }
  72. let cmd = Command::from(&buffer);
  73. {
  74. let mut cli = client.lock().unwrap();
  75. if !cli.handle_command(cmd, sender) {
  76. break;
  77. }
  78. }
  79. }
  80. });
  81. }
  82. eprintln!("Network thread started.");
  83. //net_thread.join().expect("Network thread panicked");
  84. {
  85. let last_buffer = last_buffer.clone();
  86. let mut events_loop = glutin::EventsLoop::new();
  87. let window_bld = glutin::WindowBuilder::new().with_fullscreen(glutin::get_primary_monitor());
  88. let context_bld = glutin::ContextBuilder::new().with_gl_profile(glutin::GlProfile::Core);
  89. let display = glium::Display::new(window_bld, context_bld, &events_loop).expect("Failed to create display");
  90. eprintln!("OpenGL init, version {:?}", display.get_opengl_version());
  91. #[derive(Copy,Clone)]
  92. struct Vertex1dx {
  93. x: f32,
  94. }
  95. implement_vertex!(Vertex1dx, x);
  96. #[derive(Copy,Clone)]
  97. struct Vertex1dy {
  98. y: f32,
  99. }
  100. implement_vertex!(Vertex1dy, y);
  101. #[derive(Copy,Clone)]
  102. struct TexVertex2d {
  103. position: [f32; 2],
  104. uv: [f32; 2],
  105. }
  106. implement_vertex!(TexVertex2d, position, uv);
  107. let rect_vertices = glium::VertexBuffer::new(&display, &[
  108. TexVertex2d { position: [-1.0, -1.0], uv: [0.0, 0.0] },
  109. TexVertex2d { position: [1.0, -1.0], uv: [1.0, 0.0] },
  110. TexVertex2d { position: [1.0, 1.0], uv: [1.0, 1.0] },
  111. TexVertex2d { position: [-1.0, 1.0], uv: [0.0, 1.0] },
  112. ]).expect("Failed to create vertex buffer");
  113. let rect_indices = glium::IndexBuffer::new(&display, PrimitiveType::TrianglesList, &[0u16, 1, 2, 0, 2, 3]).expect("Failed to create index buffer");
  114. let graph_program = glium::program::Program::from_source(&display,
  115. "#version 430
  116. in vec2 position;
  117. in vec2 uv;
  118. out vec2 vUV;
  119. void main() {
  120. gl_Position = vec4(position, 0.0, 1.0);
  121. vUV = uv;
  122. }",
  123. "#version 430
  124. in vec2 vUV;
  125. out vec4 f_color;
  126. uniform sampler2D tex;
  127. void main() {
  128. f_color = texture(tex, vUV);
  129. }",
  130. None,
  131. ).expect("Failed to create graph program");
  132. let bg_program = glium::program::Program::from_source(&display,
  133. "#version 430
  134. in vec2 position;
  135. in vec2 uv;
  136. out vec2 vUV;
  137. void main() {
  138. gl_Position = vec4(position, 0.0, 1.0);
  139. vUV = uv;
  140. }",
  141. "#version 430
  142. layout (std430, binding = 1) buffer sbVoices {
  143. float voices[];
  144. };
  145. in vec2 vUV;
  146. out vec4 f_color;
  147. uniform float freq_low = 40.0, freq_high = 95.0;
  148. vec3 hsv2rgb(vec3 c)
  149. {
  150. vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
  151. vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
  152. return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
  153. }
  154. void main() {
  155. int n_voice = voices.length() / 2;
  156. int voice = clamp(int(vUV.x * n_voice), 0, n_voice - 1);
  157. float pitch = voices[voice * 2];
  158. float amp = voices[voice * 2 + 1];
  159. f_color = amp * vec4(hsv2rgb(vec3(clamp((pitch - freq_low) / (freq_high - freq_low), 0.0, 1.0), 1.0, amp)), 1.0);
  160. }",
  161. None,
  162. ).expect("Failed to create background program");
  163. let scope_program = glium::program::Program::from_source(&display,
  164. "#version 430
  165. in float x;
  166. in float y;
  167. void main() {
  168. gl_Position = vec4(x, y, 0.0, 1.0);
  169. }",
  170. "#version 430
  171. out vec4 f_color;
  172. void main() {
  173. f_color = vec4(0.0, 1.0, 0.0, 1.0);
  174. }",
  175. None,
  176. ).expect("Failed to create scope program");
  177. let params = glium::DrawParameters {
  178. blend: glium::draw_parameters::Blend::alpha_blending(),
  179. ..Default::default()
  180. };
  181. let (width, height) = display.get_framebuffer_dimensions();
  182. eprintln!("Allocating data with dimensionality {}, {}", width, height);
  183. let tex_data = glium::texture::RawImage2d::from_raw_rgba(iter::repeat(0u8).take((width * height * 4) as usize).collect(), (width, height));
  184. let tex_src = glium::texture::Texture2d::with_format(&display, tex_data, glium::texture::UncompressedFloatFormat::F32F32F32F32, glium::texture::MipmapsOption::NoMipmap).expect("Failed to create source texture");
  185. let tex_data = glium::texture::RawImage2d::from_raw_rgba(iter::repeat(0u8).take((width * height * 4) as usize).collect(), (width, height));
  186. let tex_dst = glium::texture::Texture2d::with_format(&display, tex_data, glium::texture::UncompressedFloatFormat::F32F32F32F32, glium::texture::MipmapsOption::NoMipmap).expect("Failed to create source texture");
  187. let mut fb_src = tex_src.as_surface();
  188. let mut fb_dst = tex_dst.as_surface();
  189. let bar_height = height / 128;
  190. let mut voice_ssbo = <glium::buffer::Buffer<[f32]>>::empty_unsized(&display,
  191. glium::buffer::BufferType::ShaderStorageBuffer,
  192. 2 * mem::size_of::<f32>() * client.lock().unwrap().voices.len(),
  193. glium::buffer::BufferMode::Persistent,
  194. ).expect("Failed to create voice buffer");
  195. let mut sample_vbo_x = glium::VertexBuffer::new(&display,
  196. &(0..last_buffer_lim).into_iter().map(|i| Vertex1dx { x: 2.0 * ((i as f32) / ((last_buffer_lim - 1) as f32)) - 1.0 }).collect::<Vec<_>>()[..],
  197. ).expect("Failed to create sample X buffer");
  198. let mut sample_vbo_y = glium::VertexBuffer::persistent(&display,
  199. &(0..last_buffer_lim).into_iter().map(|_| Vertex1dy { y: 0.0 }).collect::<Vec<_>>()[..],
  200. ).expect("Failed to create sample Y buffer");
  201. let mut should_break = false;
  202. loop {
  203. events_loop.poll_events(|event| {
  204. match event {
  205. glutin::Event::WindowEvent { event, .. } => match event {
  206. glutin::WindowEvent::Closed => should_break = true,
  207. glutin::WindowEvent::KeyboardInput {
  208. input: glutin::KeyboardInput {
  209. virtual_keycode: Some(glutin::VirtualKeyCode::Escape),
  210. ..
  211. },
  212. ..
  213. } => should_break = true,
  214. _ => (),
  215. },
  216. _ => (),
  217. }
  218. });
  219. if should_break { break; }
  220. fb_dst.fill(&fb_src, glium::uniforms::MagnifySamplerFilter::Nearest);
  221. fb_dst.clear_color(0.0, 0.0, 0.0, 0.0);
  222. fb_src.blit_color(
  223. &glium::Rect { left: 1, bottom: 0, width: (width - 1), height: height },
  224. &fb_dst,
  225. &glium::BlitTarget { left: 0, bottom: 0, width: (width - 1) as i32, height: height as i32 },
  226. glium::uniforms::MagnifySamplerFilter::Nearest,
  227. );
  228. let mut voice_params: Vec<(f32, f32)> = Vec::new();
  229. {
  230. let client = client.lock().unwrap();
  231. let len = client.voices.len();
  232. for (idx, voice) in client.voices.iter().enumerate() {
  233. let freq = *voice.params.vars.get("v_freq").unwrap_or(&0.0);
  234. let amp = *voice.params.vars.get("v_amp").unwrap_or(&0.0);
  235. let deadline = *voice.params.vars.get("v_deadline").unwrap_or(&std::f32::INFINITY);
  236. if deadline > (client.frames as f32) {
  237. if freq > 0.0 && amp > 0.0 {
  238. voice_params.push((Pitch::Freq(freq).to_midi(), amp));
  239. let col = palette::Hsl::new(
  240. palette::RgbHue::from_radians((idx as f64) * 2.0 * std::f64::consts::PI / (len as f64)),
  241. 1.0,
  242. 0.5 * (amp as f64),
  243. ).into_rgb();
  244. let bar_data = glium::texture::RawImage2d::from_raw_rgba(
  245. [
  246. (col.red * 255.0) as u8,
  247. (col.green * 255.0) as u8,
  248. (col.blue * 255.0) as u8,
  249. (amp * 255.0) as u8,
  250. ].into_iter().cycle().take((bar_height * 4) as usize).map(|&x| x).collect(),
  251. (1, bar_height),
  252. );
  253. tex_dst.write(glium::Rect {
  254. left: width - 1,
  255. bottom: ((height as f32) * (Pitch::Freq(freq).to_midi() / 127.0)) as u32,
  256. width: 1,
  257. height: bar_height
  258. }, bar_data);
  259. } else {
  260. voice_params.push((0.0, 0.0));
  261. }
  262. } else {
  263. voice_params.push((0.0, 0.0));
  264. }
  265. }
  266. }
  267. let flat_buffer: Vec<f32> = voice_params.into_iter().flat_map(|pair| vec![pair.0, pair.1]).collect();
  268. voice_ssbo.slice_mut(..flat_buffer.len()).expect("Failed to view into buffer slice").write(
  269. &flat_buffer[..],
  270. );
  271. sample_vbo_y.write(&last_buffer.lock().expect("Failed to read shared buffer in gfx").iter().map(|&y| Vertex1dy { y }).collect::<Vec<_>>()[..]);
  272. {
  273. let uniforms = uniform! {
  274. tex: &tex_dst,
  275. sbVoices: &voice_ssbo,
  276. };
  277. let mut target = display.draw();
  278. target.clear_color(0.0, 0.0, 0.0, 0.0);
  279. target.draw(&rect_vertices, &rect_indices, &bg_program, &uniforms, &params).expect("Failed to draw");
  280. target.draw(&rect_vertices, &rect_indices, &graph_program, &uniforms, &params).expect("Failed to draw");
  281. target.draw((&sample_vbo_x, &sample_vbo_y), glium::index::NoIndices(glium::index::PrimitiveType::LineStrip), &scope_program, &uniforms, &params).expect("Failed to draw");
  282. target.finish().expect("Failed to submit draw commands");
  283. }
  284. //display.swap_buffers().expect("Failed to swap buffers");
  285. }
  286. }
  287. eprintln!("Exiting.");
  288. }