151 lines
4.1 KiB
Rust
151 lines
4.1 KiB
Rust
extern crate ether_dream;
|
|
|
|
use ether_dream::dac;
|
|
|
|
fn main() {
|
|
println!("Listening for an Ether Dream DAC...");
|
|
|
|
let (dac_broadcast, source_addr) = ether_dream::recv_dac_broadcasts()
|
|
.expect("failed to bind to UDP socket")
|
|
.filter_map(Result::ok)
|
|
.next()
|
|
.unwrap();
|
|
let mac_address = dac::MacAddress(dac_broadcast.mac_address);
|
|
|
|
println!(
|
|
"Discovered DAC \"{}\" at \"{}\"! Connecting...",
|
|
mac_address, source_addr
|
|
);
|
|
|
|
// Establish the TCP connection.
|
|
let mut stream = dac::stream::connect(&dac_broadcast, source_addr.ip().clone()).unwrap();
|
|
|
|
// If we want to create an animation (in our case a moving sine wave) we need a frame rate.
|
|
let frames_per_second = 60.0;
|
|
// Lets use the DAC at an eighth the maximum scan rate.
|
|
let points_per_second = stream.dac().max_point_rate / 32;
|
|
// Determine the number of points per frame given our target frame and point rates.
|
|
let points_per_frame = (points_per_second as f32 / frames_per_second) as u16;
|
|
|
|
println!(
|
|
"Preparing for playback:\n\tframe_hz: {}\n\tpoint_hz: {}\n\tpoints_per_frame: {}\n",
|
|
frames_per_second, points_per_second, points_per_frame
|
|
);
|
|
|
|
// Prepare the DAC's playback engine and await the repsonse.
|
|
stream
|
|
.queue_commands()
|
|
.prepare_stream()
|
|
.submit()
|
|
.err()
|
|
.map(|err| {
|
|
eprintln!(
|
|
"err occurred when submitting PREPARE_STREAM \
|
|
command and listening for response: {}",
|
|
err
|
|
);
|
|
});
|
|
|
|
println!("Beginning playback!");
|
|
|
|
// The sine wave used to generate points.
|
|
let mut sine_wave = SineWave {
|
|
point: 0,
|
|
points_per_frame,
|
|
frames_per_second,
|
|
};
|
|
|
|
// Queue the initial frame and tell the DAC to begin producing output.
|
|
let n_points = points_to_generate(stream.dac());
|
|
stream
|
|
.queue_commands()
|
|
.data(sine_wave.by_ref().take(n_points))
|
|
.begin(0, points_per_second)
|
|
.submit()
|
|
.err()
|
|
.map(|err| {
|
|
eprintln!(
|
|
"err occurred when submitting initial DATA and BEGIN \
|
|
commands and listening for response: {}",
|
|
err
|
|
);
|
|
});
|
|
eprintln!("Stream dac{:?}", stream.dac());
|
|
|
|
// Loop and continue to send points forever.
|
|
loop {
|
|
// Determine how many points the DAC can currently receive.
|
|
let n_points = points_to_generate(stream.dac());
|
|
if let Err(err) = stream
|
|
.queue_commands()
|
|
.data(sine_wave.by_ref().take(n_points))
|
|
.submit()
|
|
{
|
|
eprintln!(
|
|
"err occurred when submitting DATA command and listening \
|
|
for response: {}",
|
|
err
|
|
);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Tell the DAC to stop producing output and return to idle. Wait for the response.
|
|
//
|
|
// Note that the DAC is commanded to stop on `Drop` if this is not called and any errors
|
|
// produced are ignored.
|
|
stream
|
|
.queue_commands()
|
|
.stop()
|
|
.submit()
|
|
.expect("err occurred when submitting STOP command and listening for response");
|
|
}
|
|
|
|
// Determine the number of points needed to fill the DAC.
|
|
fn points_to_generate(dac: ðer_dream::dac::Dac) -> usize {
|
|
dac.buffer_capacity as usize - 1 - dac.status.buffer_fullness as usize
|
|
}
|
|
|
|
// An iterator that endlessly generates a sine wave of DAC points.
|
|
//
|
|
// The sine wave oscillates at a rate of once per second.
|
|
struct SineWave {
|
|
point: u32,
|
|
points_per_frame: u16,
|
|
frames_per_second: f32,
|
|
}
|
|
|
|
impl Iterator for SineWave {
|
|
type Item = ether_dream::protocol::DacPoint;
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
let coloured_points_per_frame = self.points_per_frame - 1;
|
|
let i = (self.point % self.points_per_frame as u32) as u16;
|
|
let hz = 1.0;
|
|
let fract = i as f32 / coloured_points_per_frame as f32;
|
|
let phase = (self.point as f32 / coloured_points_per_frame as f32) / self.frames_per_second;
|
|
let amp = (hz * (fract + phase) * 2.0 * std::f32::consts::PI).sin();
|
|
let (r, g, b) = match i {
|
|
i if i == coloured_points_per_frame || i < 13 => (0, 0, 0),
|
|
_ => (std::u16::MAX, std::u16::MAX, std::u16::MAX),
|
|
};
|
|
let x_min = std::i16::MIN;
|
|
let x_max = std::i8::MAX as i16;
|
|
let x = (x_min as f32 + fract * (x_max as f32 - x_min as f32)) as i16;
|
|
let y = (amp * x_max as f32) as i16;
|
|
let control = 0;
|
|
let (u1, u2) = (0, 0);
|
|
let p = ether_dream::protocol::DacPoint {
|
|
control,
|
|
x,
|
|
y,
|
|
i,
|
|
r,
|
|
g,
|
|
b,
|
|
u1,
|
|
u2,
|
|
};
|
|
self.point += 1;
|
|
Some(p)
|
|
}
|
|
} |