1use crate::core::*;
4use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
5use crossbeam::channel::Sender;
6
7pub struct Engine<E: Clone + Copy + Send + 'static> {
8 pub tx: Sender<E>,
9 stream: cpal::platform::Stream,
10}
11
12impl<E> Engine<E>
13where
14 E: Clone + Copy + Send + 'static,
15{
16 pub fn new<F>(f: F) -> Self
17 where
18 F: for<'a> FnOnce(Builder<E>) -> Runtime<E>,
19 {
20 let (event_bus, builder) = new::<E>();
21 let EventBus{tx, rx} = event_bus;
22
23 let host = cpal::default_host();
25 let device = host.default_output_device()
26 .ok_or("no output device available").unwrap();
27 let config = device.default_output_config().unwrap();
28 let sample_rate = config.sample_rate().0 as f32;
29 let mut runtime = f(builder);
30
31 Engine {
32 tx,
33 stream: device.build_output_stream(
34 &config.into(),
35 move |data: &mut [f32], _: &cpal::OutputCallbackInfo| {
36
37 let input = vec![0.0; data.len()];
38
39 for (input_chunk, output_chunk) in input.chunks(256).zip(data.chunks_mut(256)) {
40 if let Ok(event) = rx.try_recv() {
41 runtime.tick(sample_rate, Some(event), &input_chunk, output_chunk);
42 } else {
43 runtime.tick(sample_rate, None, &input_chunk, output_chunk)
44 }
45 }
46 },
47 |err| eprintln!("Audio stream error: {}", err),
48 None,
49 ).unwrap(),
50 }
51 }
52
53 pub fn run(&self) {
54 self.stream.play().unwrap();
55 }
56}