From e96faeb6d3f8d5cbe29669cdbe6f1be4882fd61e Mon Sep 17 00:00:00 2001 From: unspeaker Date: Fri, 27 Dec 2024 13:18:00 +0100 Subject: [PATCH] fix some lints, add FromEdn trait --- crates/tek/src/audio/sampler.rs | 16 +-- crates/tek/src/cli/cli_arranger.rs | 11 +- crates/tek/src/cli/cli_sequencer.rs | 19 +-- crates/tek/src/edn.rs | 158 +++++++++++++----------- crates/tek/src/midi.rs | 4 +- crates/tek/src/midi/midi_clip.rs | 3 +- crates/tek/src/midi/midi_in.rs | 2 +- crates/tek/src/midi/midi_launch.rs | 5 +- crates/tek/src/midi/midi_out.rs | 2 +- crates/tek/src/midi/midi_play.rs | 13 +- crates/tek/src/midi/midi_rec.rs | 7 +- crates/tek/src/space/coord.rs | 2 +- crates/tek/src/space/stack.rs | 6 +- crates/tek/src/tui/arranger_v/v_head.rs | 2 +- 14 files changed, 126 insertions(+), 124 deletions(-) diff --git a/crates/tek/src/audio/sampler.rs b/crates/tek/src/audio/sampler.rs index c81e28cc..c9052520 100644 --- a/crates/tek/src/audio/sampler.rs +++ b/crates/tek/src/audio/sampler.rs @@ -50,11 +50,11 @@ impl Sampler { pub fn process_midi_in (&mut self, scope: &ProcessScope) { let Sampler { midi_in, mapped, voices, .. } = self; for RawMidi { time, bytes } in midi_in.iter(scope) { - if let LiveEvent::Midi { message, .. } = LiveEvent::parse(bytes).unwrap() { - if let MidiMessage::NoteOn { ref key, ref vel } = message { - if let Some(sample) = mapped.get(key) { - voices.write().unwrap().push(Sample::play(sample, time as usize, vel)); - } + if let LiveEvent::Midi { + message: MidiMessage::NoteOn { ref key, ref vel }, .. + } = LiveEvent::parse(bytes).unwrap() { + if let Some(sample) = mapped.get(key) { + voices.write().unwrap().push(Sample::play(sample, time as usize, vel)); } } } @@ -85,7 +85,7 @@ impl Sampler { return false } } - return true + true }); } @@ -135,13 +135,13 @@ impl Iterator for Voice { type Item = [f32;2]; fn next (&mut self) -> Option { if self.after > 0 { - self.after = self.after - 1; + self.after -= 1; return Some([0.0, 0.0]) } let sample = self.sample.read().unwrap(); if self.position < sample.end { let position = self.position; - self.position = self.position + 1; + self.position += 1; return sample.channels[0].get(position).map(|_amplitude|[ sample.channels[0][position] * self.velocity, sample.channels[0][position] * self.velocity, diff --git a/crates/tek/src/cli/cli_arranger.rs b/crates/tek/src/cli/cli_arranger.rs index 796f3ad9..57697699 100644 --- a/crates/tek/src/cli/cli_arranger.rs +++ b/crates/tek/src/cli/cli_arranger.rs @@ -46,7 +46,7 @@ impl ArrangerCli { let mut app = ArrangerTui::try_from(jack)?; let jack = jack.read().unwrap(); app.color = ItemPalette::random(); - add_tracks(&jack, &mut app, &self)?; + add_tracks(&jack, &mut app, self)?; add_scenes(&mut app, self.scenes)?; Ok(app) })?)?; @@ -82,9 +82,8 @@ fn add_tracks (jack: &JackClient, app: &mut ArrangerTui, cli: &ArrangerCli) -> U panic!("Tried to connect track {track} or {n}. Pass -t {track} to increase number of tracks.") } if let Some(port) = split.next() { - if let Some(port) = jack.port_by_name(&port) { - jack.client().connect_ports(&port, &app.tracks[track-1].player.midi_ins[0])?; - //jack.client().connect_ports(&port, &app.tracks[track].player.midi_ins[0])?; + if let Some(port) = jack.port_by_name(port).as_ref() { + jack.client().connect_ports(port, &app.tracks[track-1].player.midi_ins[0])?; } else { panic!("Missing MIDI output: {port}. Use jack_lsp to list all port names."); } @@ -106,8 +105,8 @@ fn add_tracks (jack: &JackClient, app: &mut ArrangerTui, cli: &ArrangerCli) -> U panic!("Tried to connect track {track} or {n}. Pass -t {track} to increase number of tracks.") } if let Some(port) = split.next() { - if let Some(port) = jack.port_by_name(&port) { - jack.client().connect_ports(&app.tracks[track-1].player.midi_outs[0], &port)?; + if let Some(port) = jack.port_by_name(port).as_ref() { + jack.client().connect_ports(&app.tracks[track-1].player.midi_outs[0], port)?; } else { panic!("Missing MIDI input: {port}. Use jack_lsp to list all port names."); } diff --git a/crates/tek/src/cli/cli_sequencer.rs b/crates/tek/src/cli/cli_sequencer.rs index 16b9cfde..619f9381 100644 --- a/crates/tek/src/cli/cli_sequencer.rs +++ b/crates/tek/src/cli/cli_sequencer.rs @@ -24,15 +24,11 @@ pub struct SequencerCli { /// MIDI ins to connect to (multiple instances accepted) #[arg(short='o', long)] midi_to: Vec, - - /// Default phrase duration (in pulses; default: 4 * PPQ = 1 bar) - #[arg(short, long)] - length: Option, } impl SequencerCli { fn run (&self) -> Usually<()> { - let name = self.name.as_ref().map(|n|n.as_str()).unwrap_or("tek_sequencer"); + let name = self.name.as_deref().unwrap_or("tek_sequencer"); Tui::run(JackClient::new(name)?.activate_with(|jack|{ let mut app = SequencerTui::try_from(jack)?; let jack = jack.read().unwrap(); @@ -42,11 +38,6 @@ impl SequencerCli { connect_to(&jack, &midi_out, &self.midi_to)?; app.player.midi_ins.push(midi_in); app.player.midi_outs.push(midi_out); - if let Some(_) = self.length { - // TODO: if let Some(phrase) = sequencer.phrase.as_mut() { - //phrase.write().unwrap().length = length; - //} - } Ok(app) })?)?; Ok(()) @@ -55,8 +46,8 @@ impl SequencerCli { fn connect_from (jack: &JackClient, input: &Port, ports: &[String]) -> Usually<()> { for port in ports.iter() { - if let Some(port) = jack.port_by_name(&port) { - jack.client().connect_ports(&port, &input)?; + if let Some(port) = jack.port_by_name(port).as_ref() { + jack.client().connect_ports(port, input)?; } else { panic!("Missing MIDI output: {port}. Use jack_lsp to list all port names."); } @@ -66,8 +57,8 @@ fn connect_from (jack: &JackClient, input: &Port, ports: &[String]) -> U fn connect_to (jack: &JackClient, output: &Port, ports: &[String]) -> Usually<()> { for port in ports.iter() { - if let Some(port) = jack.port_by_name(&port) { - jack.client().connect_ports(&output, &port)?; + if let Some(port) = jack.port_by_name(port).as_ref() { + jack.client().connect_ports(output, port)?; } else { panic!("Missing MIDI input: {port}. Use jack_lsp to list all port names."); } diff --git a/crates/tek/src/edn.rs b/crates/tek/src/edn.rs index eb4992bb..a3a92fb2 100644 --- a/crates/tek/src/edn.rs +++ b/crates/tek/src/edn.rs @@ -4,6 +4,23 @@ use crate::*; pub use clojure_reader::edn::Edn; //pub use clojure_reader::{edn::{read, Edn}, error::Error as EdnError}; +pub trait FromEdn: Sized { + const ID: &'static str; + fn from_edn <'e> (context: C, expr: &[Edn<'e>]) -> Usually; +} + +/// Implements the [FromEdn] trait. +#[macro_export] macro_rules! from_edn { + (|$context:pat = $Context:ty, $id:expr, $args:ident| -> $T:ty $body:block) => { + impl FromEdn<$Context> for $T { + const ID: &'static str = $id; + fn from_edn <'e> ($context: $Context, $args: &[Edn<'e>]) -> Usually { + $body + } + } + } +} + /// EDN parsing helper. #[macro_export] macro_rules! edn { ($edn:ident { $($pat:pat => $expr:expr),* $(,)? }) => { @@ -16,82 +33,79 @@ pub use clojure_reader::edn::Edn; }; } -impl crate::Sampler { - pub fn from_edn <'e> (jack: &Arc>, args: &[Edn<'e>]) -> Usually { - let mut name = String::new(); - let mut dir = String::new(); - let mut samples = BTreeMap::new(); - edn!(edn in args { - Edn::Map(map) => { - if let Some(Edn::Str(n)) = map.get(&Edn::Key(":name")) { - name = String::from(*n); - } - if let Some(Edn::Str(n)) = map.get(&Edn::Key(":dir")) { - dir = String::from(*n); +from_edn!(|jack = &Arc>, "sampler", args| -> crate::Sampler { + let mut name = String::new(); + let mut dir = String::new(); + let mut samples = BTreeMap::new(); + edn!(edn in args { + Edn::Map(map) => { + if let Some(Edn::Str(n)) = map.get(&Edn::Key(":name")) { + name = String::from(*n); + } + if let Some(Edn::Str(n)) = map.get(&Edn::Key(":dir")) { + dir = String::from(*n); + } + }, + Edn::List(args) => match args.get(0) { + Some(Edn::Symbol("sample")) => { + let (midi, sample) = MidiSample::from_edn((jack, &dir), &args[1..])?; + if let Some(midi) = midi { + samples.insert(midi, sample); + } else { + panic!("sample without midi binding: {}", sample.read().unwrap().name); } }, - Edn::List(args) => match args.get(0) { - Some(Edn::Symbol("sample")) => { - let (midi, sample) = Sample::from_edn(jack, &dir, &args[1..])?; - if let Some(midi) = midi { - samples.insert(midi, sample); - } else { - panic!("sample without midi binding: {}", sample.read().unwrap().name); - } - }, - _ => panic!("unexpected in sampler {name}: {args:?}") - }, - _ => panic!("unexpected in sampler {name}: {edn:?}") - }); - let midi_in = jack.read().unwrap().client().register_port("in", MidiIn::default())?; - Ok(Sampler { - jack: jack.clone(), - name: name.into(), - mapped: samples, - unmapped: Default::default(), - voices: Default::default(), - buffer: Default::default(), - audio_outs: vec![], - output_gain: 0., - midi_in, - }) - } -} + _ => panic!("unexpected in sampler {name}: {args:?}") + }, + _ => panic!("unexpected in sampler {name}: {edn:?}") + }); + let midi_in = jack.read().unwrap().client().register_port("in", MidiIn::default())?; + Ok(Self { + jack: jack.clone(), + name: name.into(), + mapped: samples, + unmapped: Default::default(), + voices: Default::default(), + buffer: Default::default(), + audio_outs: vec![], + output_gain: 0., + midi_in, + }) +}); -impl crate::Sample { - pub fn from_edn <'e> (jack: &Arc>, dir: &str, args: &[Edn<'e>]) -> Usually<(Option, Arc>)> { - let mut name = String::new(); - let mut file = String::new(); - let mut midi = None; - let mut start = 0usize; - edn!(edn in args { - Edn::Map(map) => { - if let Some(Edn::Str(n)) = map.get(&Edn::Key(":name")) { - name = String::from(*n); - } - if let Some(Edn::Str(f)) = map.get(&Edn::Key(":file")) { - file = String::from(*f); - } - if let Some(Edn::Int(i)) = map.get(&Edn::Key(":start")) { - start = *i as usize; - } - if let Some(Edn::Int(m)) = map.get(&Edn::Key(":midi")) { - midi = Some(u7::from(*m as u8)); - } - }, - _ => panic!("unexpected in sample {name}"), - }); - let (end, data) = Sample::read_data(&format!("{dir}/{file}"))?; - Ok((midi, Arc::new(RwLock::new(Self { - name: name.into(), - start, - end, - channels: data, - rate: None - })))) - } -} +type MidiSample = (Option, Arc>); +from_edn!(|(jack, dir) = (&Arc>, &str), "sample", args| -> MidiSample { + let mut name = String::new(); + let mut file = String::new(); + let mut midi = None; + let mut start = 0usize; + edn!(edn in args { + Edn::Map(map) => { + if let Some(Edn::Str(n)) = map.get(&Edn::Key(":name")) { + name = String::from(*n); + } + if let Some(Edn::Str(f)) = map.get(&Edn::Key(":file")) { + file = String::from(*f); + } + if let Some(Edn::Int(i)) = map.get(&Edn::Key(":start")) { + start = *i as usize; + } + if let Some(Edn::Int(m)) = map.get(&Edn::Key(":midi")) { + midi = Some(u7::from(*m as u8)); + } + }, + _ => panic!("unexpected in sample {name}"), + }); + let (end, data) = Sample::read_data(&format!("{dir}/{file}"))?; + Ok((midi, Arc::new(RwLock::new(crate::Sample { + name, + start, + end, + channels: data, + rate: None + })))) +}); //impl ArrangerScene { diff --git a/crates/tek/src/midi.rs b/crates/tek/src/midi.rs index 4ca9200b..73379924 100644 --- a/crates/tek/src/midi.rs +++ b/crates/tek/src/midi.rs @@ -165,7 +165,7 @@ pub struct PlayerAudio<'a, T: MidiPlayerApi>( ); /// JACK process callback for a sequencer's phrase player/recorder. -impl<'a, T: MidiPlayerApi> Audio for PlayerAudio<'a, T> { +impl Audio for PlayerAudio<'_, T> { fn process (&mut self, _: &Client, scope: &ProcessScope) -> Control { let model = &mut self.0; let note_buf = &mut self.1; @@ -217,7 +217,7 @@ impl MidiRecordApi for MidiPlayer { impl MidiPlaybackApi for MidiPlayer { fn notes_out (&self) -> &Arc> { - &self.notes_in + &self.notes_out } } diff --git a/crates/tek/src/midi/midi_clip.rs b/crates/tek/src/midi/midi_clip.rs index 2ee1c863..3960dc0c 100644 --- a/crates/tek/src/midi/midi_clip.rs +++ b/crates/tek/src/midi/midi_clip.rs @@ -76,13 +76,12 @@ impl MidiClip { } /// Check if a range `start..end` contains MIDI Note On `k` pub fn contains_note_on (&self, k: u7, start: usize, end: usize) -> bool { - //panic!("{:?} {start} {end}", &self); for events in self.notes[start.max(0)..end.min(self.notes.len())].iter() { for event in events.iter() { if let MidiMessage::NoteOn {key,..} = event { if *key == k { return true } } } } - return false + false } } diff --git a/crates/tek/src/midi/midi_in.rs b/crates/tek/src/midi/midi_in.rs index 4750ca9e..29e16946 100644 --- a/crates/tek/src/midi/midi_in.rs +++ b/crates/tek/src/midi/midi_in.rs @@ -5,6 +5,6 @@ pub trait HasMidiIns { fn midi_ins (&self) -> &Vec>; fn midi_ins_mut (&mut self) -> &mut Vec>; fn has_midi_ins (&self) -> bool { - self.midi_ins().len() > 0 + !self.midi_ins().is_empty() } } diff --git a/crates/tek/src/midi/midi_launch.rs b/crates/tek/src/midi/midi_launch.rs index 2acabd4a..49ec833e 100644 --- a/crates/tek/src/midi/midi_launch.rs +++ b/crates/tek/src/midi/midi_launch.rs @@ -27,9 +27,8 @@ pub trait HasPlayPhrase: HasClock { } fn enqueue_next (&mut self, phrase: Option<&Arc>>) { let start = self.clock().next_launch_pulse() as f64; - let instant = Moment::from_pulse(&self.clock().timebase(), start); - let phrase = phrase.map(|p|p.clone()); - *self.next_phrase_mut() = Some((instant, phrase)); + let instant = Moment::from_pulse(self.clock().timebase(), start); + *self.next_phrase_mut() = Some((instant, phrase.cloned())); *self.reset_mut() = true; } } diff --git a/crates/tek/src/midi/midi_out.rs b/crates/tek/src/midi/midi_out.rs index 0010ef4d..ca9d34c8 100644 --- a/crates/tek/src/midi/midi_out.rs +++ b/crates/tek/src/midi/midi_out.rs @@ -5,7 +5,7 @@ pub trait HasMidiOuts { fn midi_outs (&self) -> &Vec>; fn midi_outs_mut (&mut self) -> &mut Vec>; fn has_midi_outs (&self) -> bool { - self.midi_outs().len() > 0 + !self.midi_outs().is_empty() } /// Buffer for serializing a MIDI event. FIXME rename fn midi_note (&mut self) -> &mut Vec; diff --git a/crates/tek/src/midi/midi_play.rs b/crates/tek/src/midi/midi_play.rs index 5452c7c0..caa71c38 100644 --- a/crates/tek/src/midi/midi_play.rs +++ b/crates/tek/src/midi/midi_play.rs @@ -49,7 +49,7 @@ pub trait MidiPlaybackApi: HasPlayPhrase + HasClock + HasMidiOuts { // Samples elapsed since phrase was supposed to start let skipped = sample0 - start; // Switch over to enqueued phrase - let started = Moment::from_sample(&self.clock().timebase(), start as f64); + let started = Moment::from_sample(self.clock().timebase(), start as f64); // Launch enqueued phrase *self.play_phrase_mut() = Some((started, phrase.clone())); // Unset enqueuement (TODO: where to implement looping?) @@ -123,7 +123,7 @@ pub trait MidiPlaybackApi: HasPlayPhrase + HasClock + HasMidiOuts { // Append serialized message to output buffer. out[sample].push(note_buf.clone()); // Update the list of currently held notes. - update_keys(&mut*notes, &message); + update_keys(&mut*notes, message); } } } @@ -138,10 +138,11 @@ pub trait MidiPlaybackApi: HasPlayPhrase + HasClock + HasMidiOuts { /// Write a chunk of MIDI data from the output buffer to an output port. fn write_port (writer: &mut MidiWriter, samples: usize, out: &[Vec>]) { - for time in 0..samples { - for event in out[time].iter() { - writer.write(&RawMidi { time: time as u32, bytes: &event }) - .expect(&format!("{event:?}")); + for (time, events) in out.iter().enumerate().take(samples) { + for bytes in events.iter() { + writer.write(&RawMidi { time: time as u32, bytes }).unwrap_or_else(|_|{ + panic!("Failed to write MIDI data: {bytes:?}"); + }); } } } diff --git a/crates/tek/src/midi/midi_rec.rs b/crates/tek/src/midi/midi_rec.rs index 22a58f74..6ae97d22 100644 --- a/crates/tek/src/midi/midi_rec.rs +++ b/crates/tek/src/midi/midi_rec.rs @@ -33,12 +33,11 @@ pub trait MidiRecordApi: HasClock + HasPlayPhrase + HasMidiIns { let sample = (sample0 + sample - start) as f64; let pulse = timebase.samples_to_pulse(sample); let quantized = (pulse / quant).round() * quant; - let looped = quantized as usize % length; - looped + quantized as usize % length }, message); } } - update_keys(&mut*notes_in.write().unwrap(), &message); + update_keys(&mut notes_in.write().unwrap(), &message); } } } @@ -61,7 +60,7 @@ pub trait MidiRecordApi: HasClock + HasPlayPhrase + HasMidiIns { for (sample, event, bytes) in parse_midi_input(input.iter(scope)) { if let LiveEvent::Midi { message, .. } = event { midi_buf[sample].push(bytes.to_vec()); - update_keys(&mut*notes_in.write().unwrap(), &message); + update_keys(&mut notes_in.write().unwrap(), &message); } } } diff --git a/crates/tek/src/space/coord.rs b/crates/tek/src/space/coord.rs index 7feac7dc..67c8ddcf 100644 --- a/crates/tek/src/space/coord.rs +++ b/crates/tek/src/space/coord.rs @@ -19,7 +19,7 @@ pub trait Coordinate: Send + Sync + Copy 0.into() } } - fn ZERO () -> Self { + fn zero () -> Self { 0.into() } } diff --git a/crates/tek/src/space/stack.rs b/crates/tek/src/space/stack.rs index 914217d9..79fb643d 100644 --- a/crates/tek/src/space/stack.rs +++ b/crates/tek/src/space/stack.rs @@ -80,7 +80,7 @@ where let mut h: E::Unit = 0.into(); (self.0)(&mut |component: &dyn Render| { let max = to.h().minus(h); - if max > E::Unit::ZERO() { + if max > E::Unit::zero() { let item = E::max_y(max, E::push_y(h, component)); let size = item.min_size(to)?.map(|size|size.wh()); if let Some([width, height]) = size { @@ -98,7 +98,7 @@ where let mut h: E::Unit = 0.into(); (self.0)(&mut |component: &dyn Render| { let max = to.w().minus(w); - if max > E::Unit::ZERO() { + if max > E::Unit::zero() { let item = E::max_x(max, E::push_x(h, component)); let size = item.min_size(to)?.map(|size|size.wh()); if let Some([width, height]) = size { @@ -116,7 +116,7 @@ where let mut h: E::Unit = 0.into(); (self.0)(&mut |component: &dyn Render| { let max = to.h().minus(h); - if max > E::Unit::ZERO() { + if max > E::Unit::zero() { let item = E::max_y(to.h() - h, component); let size = item.min_size(to)?.map(|size|size.wh()); if let Some([width, height]) = size { diff --git a/crates/tek/src/tui/arranger_v/v_head.rs b/crates/tek/src/tui/arranger_v/v_head.rs index d2e7e812..fba00caf 100644 --- a/crates/tek/src/tui/arranger_v/v_head.rs +++ b/crates/tek/src/tui/arranger_v/v_head.rs @@ -37,7 +37,7 @@ render!(|self: ArrangerVHead<'a>|Tui::push_x(self.scenes_w, row!( impl<'a> ArrangerVHead<'a> { /// name and width of track - fn format_name (track: &ArrangerTrack, w: usize) -> impl Render { + fn format_name (track: &ArrangerTrack, _w: usize) -> impl Render { let name = track.name().read().unwrap().clone(); Tui::bold(true, Tui::fg(track.color.lightest.rgb, name)) }