Skip to content

Commit

Permalink
use Handler for command output
Browse files Browse the repository at this point in the history
  • Loading branch information
camshaft committed May 12, 2024
1 parent f0d26c2 commit ee693eb
Show file tree
Hide file tree
Showing 10 changed files with 168 additions and 73 deletions.
167 changes: 141 additions & 26 deletions euphony-command/src/api.rs
Original file line number Diff line number Diff line change
@@ -1,60 +1,175 @@
use crate::*;
use std::{fs, io, path::Path, time::Duration};

bach::scope::define!(scope, Box<dyn io::Write>);
bach::scope::define!(scope, Box<dyn super::Handler>);

struct WriterOut<O: io::Write>(O);

impl<O: io::Write> super::Handler for WriterOut<O> {
fn advance_time(&mut self, msg: AdvanceTime) -> io::Result<()> {
msg.encode(&mut self.0)
}

fn set_timing(&mut self, msg: SetTiming) -> io::Result<()> {
msg.encode(&mut self.0)
}

fn create_group(&mut self, msg: CreateGroup) -> io::Result<()> {
msg.encode(&mut self.0)
}

fn spawn_node(&mut self, msg: SpawnNode) -> io::Result<()> {
msg.encode(&mut self.0)
}

fn fork_node(&mut self, msg: ForkNode) -> io::Result<()> {
msg.encode(&mut self.0)
}

fn emit_midi(&mut self, msg: EmitMidi) -> io::Result<()> {
msg.encode(&mut self.0)
}

fn set_parameter(&mut self, msg: SetParameter) -> io::Result<()> {
msg.encode(&mut self.0)
}

fn pipe_parameter(&mut self, msg: PipeParameter) -> io::Result<()> {
msg.encode(&mut self.0)
}

fn finish_node(&mut self, msg: FinishNode) -> io::Result<()> {
msg.encode(&mut self.0)
}

fn init_buffer(&mut self, msg: InitBuffer) -> io::Result<()> {
msg.encode(&mut self.0)
}

fn load_buffer(&mut self, msg: LoadBuffer) -> io::Result<()> {
msg.encode(&mut self.0)
}

fn set_buffer(&mut self, msg: SetBuffer) -> io::Result<()> {
msg.encode(&mut self.0)
}

fn finish(&mut self) -> io::Result<()> {
self.0.flush()
}
}

pub fn set_file(path: &Path) {
let file = fs::File::create(path).unwrap();
let file = io::BufWriter::new(file);
let output = Box::new(file);
scope::set(Some(output));
set_writer(file)
}

pub fn set_stdout() {
let io = io::stdout();
let output = Box::new(io);
scope::set(Some(output));
set_writer(io::stdout())
}

pub fn emit<M: Codec + fmt::Display>(message: M) {
scope::try_borrow_mut_with(|output| {
if let Some(output) = output.as_mut() {
message.encode(output).unwrap();
} else {
println!("{message}");
}
});
pub fn set_writer<W: io::Write + 'static>(out: W) {
let out = WriterOut(out);
let out = Box::new(out);
scope::set(Some(out));
}

pub fn create_group(id: u64, name: String) {
emit(CreateGroup { id, name });
macro_rules! emit {
($method:ident($msg:expr)) => {
scope::try_borrow_mut_with(|output| {
let msg = $msg;
if let Some(output) = output.as_mut() {
output
.$method(msg)
.expect("failed to emit message to output");
} else {
println!("{msg}");
}
})
};
}

pub fn advance_time(ticks: u64) {
emit(AdvanceTime { ticks })
emit!(advance_time(AdvanceTime { ticks }))
}

pub fn set_timing(nanos_per_tick: Duration, ticks_per_beat: u64) {
emit(SetTiming {
emit!(set_timing(SetTiming {
nanos_per_tick: nanos_per_tick.as_nanos() as _,
ticks_per_beat,
})
}))
}

pub fn create_group(id: u64, name: String) {
emit!(create_group(CreateGroup { id, name }))
}

pub fn spawn_node(id: u64, processor: u64, group: Option<u64>) {
emit!(spawn_node(SpawnNode {
id,
group,
processor,
}))
}

pub fn fork_node(source: u64, target: u64) {
emit!(fork_node(ForkNode { source, target }))
}

pub fn emit_midi(data: [u8; 3], group: Option<u64>) {
emit!(emit_midi(EmitMidi { data, group }))
}

pub fn set_parameter(target_node: u64, target_parameter: u64, value: f64) {
emit!(set_parameter(SetParameter {
target_node,
target_parameter,
value: value.to_bits(),
}))
}

pub fn pipe_parameter(target_node: u64, target_parameter: u64, source_node: u64) {
emit!(pipe_parameter(PipeParameter {
source_node,
target_node,
target_parameter,
}))
}

pub fn finish_node(id: u64) {
emit!(finish_node(FinishNode { node: id }))
}

pub fn init_buffer(source: &Path, meta: &Path) {
let source = source.to_string_lossy().to_string();
let meta = meta.to_string_lossy().to_string();
emit!(init_buffer(InitBuffer { source, meta }))
}

pub fn load_buffer(id: u64, path: &Path, ext: &str) {
let path = path.to_string_lossy().to_string();
let ext = ext.to_string();
emit!(load_buffer(LoadBuffer { id, path, ext }))
}

pub fn set_buffer(target_node: u64, target_parameter: u64, buffer: u64, buffer_channel: u64) {
emit!(set_buffer(SetBuffer {
target_node,
target_parameter,
buffer,
buffer_channel,
}))
}

pub fn flush() {
scope::try_borrow_mut_with(|output| {
if let Some(output) = output.as_mut() {
output.flush().unwrap();
output.finish().unwrap();
}
});
}

pub fn finish() {
flush();
// TODO do we need anything else?
}

pub fn init_buffer(source: String, meta: &Path) {
let meta = meta.to_string_lossy().to_string();
emit(InitBuffer { source, meta });
}
5 changes: 5 additions & 0 deletions euphony-command/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ pub trait Handler {
fn init_buffer(&mut self, msg: InitBuffer) -> io::Result<()>;
fn load_buffer(&mut self, msg: LoadBuffer) -> io::Result<()>;
fn set_buffer(&mut self, msg: SetBuffer) -> io::Result<()>;
fn finish(&mut self) -> io::Result<()> {
Ok(())
}
}

fn push_msg<T: fmt::Display>(output: &mut String, v: T) -> io::Result<()> {
Expand Down Expand Up @@ -162,6 +165,7 @@ pub trait Codec: Sized {

trait WriteExt {
fn write_u8(&mut self, value: u8) -> io::Result<()>;
#[allow(dead_code)]
fn write_u16(&mut self, value: u16) -> io::Result<()>;
fn write_u32(&mut self, value: u32) -> io::Result<()>;
fn write_u64(&mut self, value: u64) -> io::Result<()>;
Expand Down Expand Up @@ -195,6 +199,7 @@ impl<W: io::Write> WriteExt for W {

trait ReadExt {
fn read_u8(&mut self) -> io::Result<u8>;
#[allow(dead_code)]
fn read_u16(&mut self) -> io::Result<u16>;
fn read_u32(&mut self) -> io::Result<u32>;
fn read_u64(&mut self) -> io::Result<u64>;
Expand Down
2 changes: 1 addition & 1 deletion euphony-dsp/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ euphony-graph = { version = "0.1", path = "../euphony-graph" }
euphony-node = { version = "0.1", path = "../euphony-node" }
euphony-units = { version = "0.1", path = "../euphony-units" }
fastapprox = "0.3"
fundsp = { version = "0.14", default-features = false }
fundsp = { version = "0.17", default-features = false }
noise = "0.8"

[dev-dependencies]
Expand Down
2 changes: 1 addition & 1 deletion euphony-tests/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ where
F: 'static + Future<Output = ()> + Send,
{
let list = List::default();
euphony_command::api::scope::set(Some(Box::new(list.clone())));
euphony_command::api::set_writer(list.clone());

euphony::runtime::Runtime::new(0).block_on(f);

Expand Down
3 changes: 1 addition & 2 deletions euphony/src/midi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,10 +209,9 @@ impl From<MidiMessage> for Message {

impl Message {
pub fn emit(&self) {
use crate::output::EmitMidi;
let data = self.as_bytes();
let group = crate::group::scope::try_borrow_with(|g| g.map(|g| g.as_u64()));
crate::output::emit(EmitMidi { data, group })
crate::output::emit_midi(data, group)
}

/// Write the data part of this message, including the channel
Expand Down
28 changes: 6 additions & 22 deletions euphony/src/node.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::{
output::*,
output,
processor::Definition,
sink::Sink,
value::{Parameter, ParameterValue},
Expand Down Expand Up @@ -39,7 +39,7 @@ struct OwnedNode {

impl Drop for OwnedNode {
fn drop(&mut self) {
emit(FinishNode { node: self.id })
output::finish_node(self.id);
}
}

Expand All @@ -55,11 +55,7 @@ impl Node {
pub(crate) fn new(definition: &Definition, group: Option<u64>) -> Self {
let id = NODE_ID.with(|v| v.next());

emit(SpawnNode {
id,
processor: definition.id,
group,
});
output::spawn_node(id, definition.id, group);

let node = OwnedNode {
id,
Expand All @@ -76,10 +72,7 @@ impl Node {
pub(crate) fn fork(&self) -> Self {
let id = NODE_ID.with(|v| v.next());

emit(ForkNode {
source: self.id(),
target: id,
});
output::fork_node(self.id(), id);

let parameters = self.0.parameters.lock().unwrap().len();

Expand All @@ -102,22 +95,13 @@ impl Node {
let buffer = channel.buffer(|path, ext| {
let id = BUFFER_ID.with(|v| v.next());
// load the buffer if needed
emit(LoadBuffer {
id,
path: path.display().to_string(),
ext: ext.to_owned(),
});
output::load_buffer(id, path, ext);
id
});
let buffer_channel = channel.channel();

// update the buffer for the node
emit(SetBuffer {
target_node: self.id(),
target_parameter: index,
buffer,
buffer_channel,
});
output::set_buffer(self.id(), index, buffer, buffer_channel);

assert!(self.0.buffers > index);
}
Expand Down
2 changes: 1 addition & 1 deletion euphony/src/output.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
pub use euphony_command::*;
use euphony_command::api;

pub(crate) use api::*;
pub use api::{set_file, set_stdout};
6 changes: 3 additions & 3 deletions euphony/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,17 @@ where
F: 'static + Future<Output = ()> + Send,
{
let list = List::default();
output::scope::set(Some(Box::new(list.clone())));
output::set_writer(list.clone());

euphony::runtime::Runtime::new(0).block_on(f);

let mut result = core::mem::take(&mut *list.0.lock().unwrap());
result.set_position(0);

let mut dump = String::new();
output::decode(&mut result, &mut dump).unwrap();
euphony_command::decode(&mut result, &mut dump).unwrap();

insta::assert_display_snapshot!(name, dump);
insta::assert_snapshot!(name, dump);
}

use euphony::prelude::*;
Expand Down
24 changes: 8 additions & 16 deletions euphony/src/value.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{node::Node, output::*};
use crate::{node::Node, output};
use euphony_units::{pitch::frequency::Frequency, ratio::Ratio};

#[derive(Clone, Debug)]
Expand All @@ -7,21 +7,13 @@ pub struct Parameter(pub(crate) ParameterValue);
impl Parameter {
pub(crate) fn set(&self, target_node: u64, target_parameter: u64) {
match &self.0 {
ParameterValue::Unset => emit(SetParameter {
target_node,
target_parameter,
value: 0.0f64.to_bits(),
}),
ParameterValue::Constant(value) => emit(SetParameter {
target_node,
target_parameter,
value: value.to_bits(),
}),
ParameterValue::Node(ref source) => emit(PipeParameter {
target_node,
target_parameter,
source_node: source.id(),
}),
ParameterValue::Unset => output::set_parameter(target_node, target_parameter, 0.0),
ParameterValue::Constant(value) => {
output::set_parameter(target_node, target_parameter, *value)
}
ParameterValue::Node(ref source) => {
output::pipe_parameter(target_node, target_parameter, source.id())
}
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion rust-toolchain
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.64.0
1.78.0

0 comments on commit ee693eb

Please sign in to comment.