tons more lint fixes

This commit is contained in:
🪞👃🪞 2024-12-27 13:43:48 +01:00
parent e96faeb6d3
commit 96f360791b
23 changed files with 121 additions and 122 deletions

View file

@ -6,7 +6,7 @@ pub use clojure_reader::edn::Edn;
pub trait FromEdn<C>: Sized {
const ID: &'static str;
fn from_edn <'e> (context: C, expr: &[Edn<'e>]) -> Usually<Self>;
fn from_edn (context: C, expr: &[Edn<'_>]) -> Usually<Self>;
}
/// Implements the [FromEdn] trait.
@ -46,7 +46,7 @@ from_edn!(|jack = &Arc<RwLock<JackClient>>, "sampler", args| -> crate::Sampler {
dir = String::from(*n);
}
},
Edn::List(args) => match args.get(0) {
Edn::List(args) => match args.first() {
Some(Edn::Symbol("sample")) => {
let (midi, sample) = MidiSample::from_edn((jack, &dir), &args[1..])?;
if let Some(midi) = midi {
@ -62,7 +62,6 @@ from_edn!(|jack = &Arc<RwLock<JackClient>>, "sampler", args| -> crate::Sampler {
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(),
@ -70,6 +69,7 @@ from_edn!(|jack = &Arc<RwLock<JackClient>>, "sampler", args| -> crate::Sampler {
audio_outs: vec![],
output_gain: 0.,
midi_in,
name,
})
});

View file

@ -46,9 +46,9 @@ pub trait MidiView<E: Engine>: MidiRange + MidiPoint + HasSize<E> {
}
/// Make sure range is within display
fn autozoom (&self) {
let time_len = self.time_len().get();
let time_axis = self.time_axis().get();
let mut time_zoom = self.time_zoom().get();
let time_len = self.time_len().get();
let time_axis = self.time_axis().get();
let time_zoom = self.time_zoom().get();
//while time_len.div_ceil(time_zoom) > time_axis {
//println!("\r{time_len} {time_zoom} {time_axis}");
//time_zoom = Note::next(time_zoom);

View file

@ -47,7 +47,7 @@ pub trait MidiPlaybackApi: HasPlayPhrase + HasClock + HasMidiOuts {
// If it's time to switch to the next phrase:
if start <= sample0.saturating_sub(sample) {
// Samples elapsed since phrase was supposed to start
let skipped = sample0 - start;
let _skipped = sample0 - start;
// Switch over to enqueued phrase
let started = Moment::from_sample(self.clock().timebase(), start as f64);
// Launch enqueued phrase

View file

@ -42,7 +42,7 @@ pub trait MidiRecordApi: HasClock + HasPlayPhrase + HasMidiIns {
}
}
}
if let Some((start_at, phrase)) = &self.next_phrase() {
if let Some((start_at, _clip)) = &self.next_phrase() {
// TODO switch to next phrase and record into it
}
}

View file

@ -41,7 +41,7 @@ mod piano_h; pub(crate) use self::piano_h::*;
////////////////////////////////////////////////////////
pub fn render <F: Fn(&mut TuiOutput)->Usually<()>+Send+Sync> (render: F) -> impl Render<Tui> {
Widget::new(|_|Ok(Some([0u16,0u16].into())), render)
Widget::new(|_|Ok(Some([0u16,0u16])), render)
}
////////////////////////////////////////////////////////

View file

@ -37,13 +37,11 @@ pub enum GrooveboxCommand {
Sampler(SamplerCommand),
}
handle!(<Tui>|self:GrooveboxTui,input|GrooveboxCommand::execute_with_state(self, input));
input_to_command!(GrooveboxCommand: <Tui>|state:GrooveboxTui,input|match input.event() {
_ => match state.focus {
GrooveboxFocus::Sequencer => GrooveboxCommand::Sequencer(
SequencerCommand::input_to_command(&state.sequencer, input)?),
GrooveboxFocus::Sampler => GrooveboxCommand::Sampler(
SamplerCommand::input_to_command(&state.sampler, input)?),
}
input_to_command!(GrooveboxCommand: <Tui>|state:GrooveboxTui,input|match state.focus {
GrooveboxFocus::Sequencer => GrooveboxCommand::Sequencer(
SequencerCommand::input_to_command(&state.sequencer, input)?),
GrooveboxFocus::Sampler => GrooveboxCommand::Sampler(
SamplerCommand::input_to_command(&state.sampler, input)?),
});
command!(|self:GrooveboxCommand,state:GrooveboxTui|match self {
GrooveboxCommand::Sequencer(command) =>

View file

@ -2,12 +2,17 @@ use crate::*;
use super::*;
use KeyCode::Char;
use std::fs::File;
use symphonia::core::codecs::CODEC_TYPE_NULL;
use symphonia::core::errors::Error;
use symphonia::core::io::MediaSourceStream;
use symphonia::core::probe::Hint;
use symphonia::core::audio::SampleBuffer;
use symphonia::default::get_codecs;
use symphonia::{
core::{
formats::Packet,
codecs::{Decoder, CODEC_TYPE_NULL},
errors::Error,
io::MediaSourceStream,
probe::Hint,
audio::SampleBuffer,
},
default::get_codecs,
};
pub struct SamplerTui {
pub state: Sampler,
@ -305,8 +310,8 @@ fn scan (dir: &PathBuf) -> Usually<(Vec<OsString>, Vec<OsString>)> {
impl Sample {
fn from_file (path: &PathBuf) -> Usually<Self> {
let mut sample = Self::default();
sample.name = path.file_name().unwrap().to_string_lossy().into();
let name = path.file_name().unwrap().to_string_lossy().into();
let mut sample = Self { name, ..Default::default() };
// Use file extension if present
let mut hint = Hint::new();
if let Some(ext) = path.extension() {
@ -322,48 +327,14 @@ impl Sample {
&Default::default()
)?;
let mut format = probed.format;
let mut decoder = get_codecs().make(
&format.tracks().iter()
.find(|t| t.codec_params.codec != CODEC_TYPE_NULL)
.expect("no tracks found")
.codec_params,
&Default::default()
)?;
let params = &format.tracks().iter()
.find(|t| t.codec_params.codec != CODEC_TYPE_NULL)
.expect("no tracks found")
.codec_params;
let mut decoder = get_codecs().make(params, &Default::default())?;
loop {
match format.next_packet() {
Ok(packet) => {
// Decode a packet
let decoded = match decoder.decode(&packet) {
Ok(decoded) => decoded,
Err(err) => { return Err(err.into()); }
};
// Determine sample rate
let spec = *decoded.spec();
if let Some(rate) = sample.rate {
if rate != spec.rate as usize {
panic!("sample rate changed");
}
} else {
sample.rate = Some(spec.rate as usize);
}
// Determine channel count
while sample.channels.len() < spec.channels.count() {
sample.channels.push(vec![]);
}
// Load sample
let mut samples = SampleBuffer::new(
decoded.frames() as u64,
spec
);
if samples.capacity() > 0 {
samples.copy_interleaved_ref(decoded);
for frame in samples.samples().chunks(spec.channels.count()) {
for (chan, frame) in frame.iter().enumerate() {
sample.channels[chan].push(*frame)
}
}
}
},
Ok(packet) => sample.decode_packet(&mut decoder, packet)?,
Err(Error::IoError(_)) => break decoder.last_decoded(),
Err(err) => return Err(err.into()),
};
@ -371,6 +342,41 @@ impl Sample {
sample.end = sample.channels.iter().fold(0, |l, c|l + c.len());
Ok(sample)
}
fn decode_packet (
&mut self, decoder: &mut Box<dyn Decoder>, packet: Packet
) -> Usually<()> {
// Decode a packet
let decoded = decoder
.decode(&packet)
.map_err(|e|Box::<dyn crate::Error>::from(e))?;
// Determine sample rate
let spec = *decoded.spec();
if let Some(rate) = self.rate {
if rate != spec.rate as usize {
panic!("sample rate changed");
}
} else {
self.rate = Some(spec.rate as usize);
}
// Determine channel count
while self.channels.len() < spec.channels.count() {
self.channels.push(vec![]);
}
// Load sample
let mut samples = SampleBuffer::new(
decoded.frames() as u64,
spec
);
if samples.capacity() > 0 {
samples.copy_interleaved_ref(decoded);
for frame in samples.samples().chunks(spec.channels.count()) {
for (chan, frame) in frame.iter().enumerate() {
self.channels[chan].push(*frame)
}
}
}
Ok(())
}
}
fn draw_sample (

View file

@ -206,7 +206,7 @@ fn to_arrangement_command (state: &ArrangerTui, input: &TuiInput) -> Option<Arra
key_pat!(Down) => Some(
Cmd::Select(Selected::Scene((s + 1).min(s_len.saturating_sub(1))))),
key_pat!(Left) =>
return None,
None,
key_pat!(Right) => Some(
Cmd::Select(Selected::Clip(0, s))),
@ -221,7 +221,7 @@ fn to_arrangement_command (state: &ArrangerTui, input: &TuiInput) -> Option<Arra
key_pat!(Char('c')) => Some(Cmd::Track(Track::SetColor(t, ItemPalette::random()))),
key_pat!(Up) =>
return None,
None,
key_pat!(Down) => Some(
Cmd::Select(Selected::Clip(t, 0))),
key_pat!(Left) => Some(
@ -237,11 +237,11 @@ fn to_arrangement_command (state: &ArrangerTui, input: &TuiInput) -> Option<Arra
key_pat!(Char('c')) => Some(Cmd::Color(ItemPalette::random())),
key_pat!(Up) =>
return None,
None,
key_pat!(Down) => Some(
Cmd::Select(Selected::Scene(0))),
key_pat!(Left) =>
return None,
None,
key_pat!(Right) => Some(
Cmd::Select(Selected::Track(0))),

View file

@ -11,7 +11,7 @@ render!(<Tui>|self: ArrangerMode|{});
/// Arranger display mode can be cycled
impl ArrangerMode {
/// Cycle arranger display mode
pub fn to_next (&mut self) {
pub fn next (&mut self) {
*self = match self {
Self::H => Self::V(1),
Self::V(1) => Self::V(2),

View file

@ -7,7 +7,7 @@ impl ArrangerTui {
let scene = ArrangerScene {
name: Arc::new(name.into()),
clips: vec![None;self.tracks.len()],
color: color.unwrap_or_else(||ItemPalette::random()),
color: color.unwrap_or_else(ItemPalette::random),
};
self.scenes.push(scene);
let index = self.scenes.len() - 1;
@ -20,10 +20,10 @@ impl ArrangerTui {
format!("S{:3>}", self.scenes.len() + 1)
}
pub fn selected_scene (&self) -> Option<&ArrangerScene> {
self.selected.scene().map(|s|self.scenes.get(s)).flatten()
self.selected.scene().and_then(|s|self.scenes.get(s))
}
pub fn selected_scene_mut (&mut self) -> Option<&mut ArrangerScene> {
self.selected.scene().map(|s|self.scenes.get_mut(s)).flatten()
self.selected.scene().and_then(|s|self.scenes.get_mut(s))
}
}
#[derive(Default, Debug, Clone)] pub struct ArrangerScene {
@ -49,7 +49,7 @@ impl ArrangerScene {
if factor == 0 {
scenes.iter().map(|scene|{
let pulses = scene.pulses().max(PPQ);
total = total + pulses;
total += pulses;
(pulses, total - pulses)
}).collect()
} else {

View file

@ -13,13 +13,17 @@ pub enum ArrangerSelection {
}
/// Focus identification methods
impl ArrangerSelection {
pub fn description <E: Engine> (
pub fn is_mix (&self) -> bool { matches!(self, Self::Mix) }
pub fn is_track (&self) -> bool { matches!(self, Self::Track(_)) }
pub fn is_scene (&self) -> bool { matches!(self, Self::Scene(_)) }
pub fn is_clip (&self) -> bool { matches!(self, Self::Clip(_, _)) }
pub fn description (
&self,
tracks: &Vec<ArrangerTrack>,
scenes: &Vec<ArrangerScene>,
tracks: &[ArrangerTrack],
scenes: &[ArrangerScene],
) -> String {
format!("Selected: {}", match self {
Self::Mix => format!("Everything"),
Self::Mix => "Everything".to_string(),
Self::Track(t) => match tracks.get(*t) {
Some(track) => format!("T{t}: {}", &track.name.read().unwrap()),
None => "T??".into(),
@ -37,18 +41,6 @@ impl ArrangerSelection {
}
})
}
pub fn is_mix (&self) -> bool {
match self { Self::Mix => true, _ => false }
}
pub fn is_track (&self) -> bool {
match self { Self::Track(_) => true, _ => false }
}
pub fn is_scene (&self) -> bool {
match self { Self::Scene(_) => true, _ => false }
}
pub fn is_clip (&self) -> bool {
match self { Self::Clip(_, _) => true, _ => false }
}
pub fn track (&self) -> Option<usize> {
use ArrangerSelection::*;
match self {

View file

@ -10,7 +10,7 @@ impl ArrangerTui {
let track = ArrangerTrack {
width: name.len() + 2,
name: Arc::new(name.into()),
color: color.unwrap_or_else(||ItemPalette::random()),
color: color.unwrap_or_else(ItemPalette::random),
player: MidiPlayer::from(&self.clock),
};
self.tracks.push(track);
@ -96,7 +96,7 @@ pub struct TracksAudio<'a>(
/// Note chunk buffer
pub &'a mut Vec<Vec<Vec<u8>>>,
);
impl<'a> Audio for TracksAudio<'a> {
impl Audio for TracksAudio<'_> {
#[inline] fn process (&mut self, client: &Client, scope: &ProcessScope) -> Control {
let model = &mut self.0;
let note_buffer = &mut self.1;

View file

@ -17,7 +17,7 @@ from!(<'a>|args:(&'a ArrangerTui, usize)|ArrangerVClips<'a> = Self {
render!(<Tui>|self: ArrangerVClips<'a>|Fill::wh(
col!((scene, pulses) in self.scenes.iter().zip(self.rows.iter().map(|row|row.0)) => {
Self::format_scene(&self.tracks, scene, pulses)
Self::format_scene(self.tracks, scene, pulses)
})
));
@ -28,8 +28,10 @@ impl<'a> ArrangerVClips<'a> {
let height = 1.max((pulses / PPQ) as u16);
let playing = scene.is_playing(tracks);
Fixed::h(height, row!([
Tui::bg(scene.color.base.rgb, if playing { "" } else { " " }),
Tui::fg_bg(scene.color.lightest.rgb, scene.color.base.rgb, Tui::grow_x(1, Tui::bold(true, scene.name.read().unwrap().as_str()))),
Tui::bg(scene.color.base.rgb,
if playing { "" } else { " " }),
Tui::fg_bg(scene.color.lightest.rgb, scene.color.base.rgb,
Tui::grow_x(1, Tui::bold(true, scene.name.read().unwrap().as_str()))),
row!((index, track, x1, x2) in ArrangerTrack::with_widths(tracks) => {
Self::format_clip(scene, index, track, (x2 - x1) as u16, height)
})])
@ -41,8 +43,7 @@ impl<'a> ArrangerVClips<'a> {
Fixed::wh(w, h, Layers::new(move |add|{
if let Some(Some(phrase)) = scene.clips.get(index) {
let mut bg = TuiTheme::border_bg();
let name = &(phrase as &Arc<RwLock<MidiClip>>).read().unwrap().name;
let name = format!("{}", name);
let name = &(phrase as &Arc<RwLock<MidiClip>>).read().unwrap().name.to_string();
let max_w = name.len().min((w as usize).saturating_sub(2));
let color = phrase.read().unwrap().color;
bg = color.dark.rgb;
@ -52,7 +53,7 @@ impl<'a> ArrangerVClips<'a> {
}
};
add(&Tui::bg(bg,
Tui::push_x(1, Fixed::w(w as u16, &name.as_str()[0..max_w])))
Tui::push_x(1, Fixed::w(w, &name.as_str()[0..max_w])))
)?;
}
Ok(())

View file

@ -29,13 +29,13 @@ render!(<Tui>|self: ArrangerVHead<'a>|Tui::push_x(self.scenes_w, row!(
row(color, &Self::format_name(track, w)),
row(color, &Self::format_input(track)?),
row(color, &Self::format_output(track)?),
row(color, &Self::format_elapsed(track, &self.timebase)),
row(color, &Self::format_until_next(track, &self.current)),
row(color, &Self::format_elapsed(track, self.timebase)),
row(color, &Self::format_until_next(track, self.current)),
]))))
}
)));
impl<'a> ArrangerVHead<'a> {
impl ArrangerVHead<'_> {
/// name and width of track
fn format_name (track: &ArrangerTrack, _w: usize) -> impl Render<Tui> {
let name = track.name().read().unwrap().clone();
@ -43,12 +43,12 @@ impl<'a> ArrangerVHead<'a> {
}
/// input port
fn format_input (track: &ArrangerTrack) -> Usually<impl Render<Tui>> {
Ok(format!(">{}", track.player.midi_ins().get(0).map(|port|port.short_name())
Ok(format!(">{}", track.player.midi_ins().first().map(|port|port.short_name())
.transpose()?.unwrap_or("?".into())))
}
/// output port
fn format_output (track: &ArrangerTrack) -> Usually<impl Render<Tui>> {
Ok(format!("<{}", track.player.midi_outs().get(0).map(|port|port.short_name())
Ok(format!("<{}", track.player.midi_outs().first().map(|port|port.short_name())
.transpose()?.unwrap_or("?".into())))
}
/// beats elapsed

View file

@ -28,10 +28,10 @@ pub enum PhraseCommand {
SetTimeLock(bool),
Show(Option<Arc<RwLock<MidiClip>>>),
}
event_map_input_to_command!(Tui: MidiEditorModel: PhraseCommand: MidiEditorModel::KEYS);
event_map_input_to_command!(Tui: MidiEditorModel: PhraseCommand: MidiEditorModel::KEYS);
impl MidiEditorModel {
const KEYS: [(TuiEvent, &'static dyn Fn(&Self)->PhraseCommand);31] = [
const KEYS: KeyMapping<31, Self> = [
(kexp!(Ctrl-Alt-Up), &|s: &Self|SetNoteScroll(s.note_point() + 3)),
(kexp!(Ctrl-Alt-Down), &|s: &Self|SetNoteScroll(s.note_point().saturating_sub(3))),
(kexp!(Ctrl-Alt-Left), &|s: &Self|SetTimeScroll(s.time_point().saturating_sub(s.time_zoom().get()))),
@ -120,7 +120,7 @@ pub trait PhraseViewMode: Render<Tui> + HasSize<Tui> + MidiRange + MidiPoint + D
fn phrase (&self) -> &Option<Arc<RwLock<MidiClip>>>;
fn phrase_mut (&mut self) -> &mut Option<Arc<RwLock<MidiClip>>>;
fn set_phrase (&mut self, phrase: Option<&Arc<RwLock<MidiClip>>>) {
*self.phrase_mut() = phrase.map(|p|p.clone());
*self.phrase_mut() = phrase.cloned();
self.redraw();
}
}

View file

@ -37,19 +37,19 @@ impl PianoHorizontal {
Self {
buffer: Default::default(),
point: MidiPointModel::default(),
phrase: phrase.cloned(),
size,
range,
phrase: phrase.map(|p|p.clone()),
color
}
}
}
render!(<Tui>|self: PianoHorizontal|{
let keys = move||PianoHorizontalKeys(&self);
let timeline = move||PianoHorizontalTimeline(&self);
let notes = move||PianoHorizontalNotes(&self);
let cursor = move||PianoHorizontalCursor(&self);
let keys = move||PianoHorizontalKeys(self);
let timeline = move||PianoHorizontalTimeline(self);
let notes = move||PianoHorizontalNotes(self);
let cursor = move||PianoHorizontalCursor(self);
let keys_width = 5;
let border = Fill::wh(Outer(Style::default().fg(self.color.dark.rgb).bg(self.color.darkest.rgb)));
let with_border = |x|lay!([border, Tui::inset_xy(1, 1, &x)]);
@ -169,8 +169,8 @@ impl PhraseViewMode for PianoHorizontal {
self.buffer = buffer
}
fn set_phrase (&mut self, phrase: Option<&Arc<RwLock<MidiClip>>>) {
*self.phrase_mut() = phrase.map(|p|p.clone());
self.color = phrase.map(|p|p.read().unwrap().color.clone())
*self.phrase_mut() = phrase.cloned();
self.color = phrase.map(|p|p.read().unwrap().color)
.unwrap_or(ItemPalette::from(ItemColor::from(TuiTheme::g(64))));
self.redraw();
}

View file

@ -15,7 +15,7 @@ render!(<Tui>|self: PianoHorizontalCursor<'a>|render(|to|Ok({
for (area_y, screen_y, note) in note_y_iter(note_lo, note_hi, y0) {
if note == note_point {
for x in 0..w {
let screen_x = x0 + x as u16;
let screen_x = x0 + x;
let time_1 = time_start + x as usize * time_zoom;
let time_2 = time_1 + time_zoom;
if time_1 <= time_point && time_point < time_2 {

View file

@ -297,7 +297,7 @@ impl PhraseSelector {
} else if let Some((_, Some(phrase))) = state.play_phrase() {
let phrase = phrase.read().unwrap();
if phrase.looped {
(" ".into(), phrase.name.clone(), phrase.color.clone())
(" ".into(), phrase.name.clone(), phrase.color)
} else {
(" ".into(), " ".into(), TuiTheme::g(64).into())
}

View file

@ -15,7 +15,7 @@ impl Command<PoolModel> for PhraseRenameCommand {
match state.phrases_mode_mut().clone() {
Some(PoolMode::Rename(phrase, ref mut old_name)) => match self {
Set(s) => {
state.phrases()[phrase].write().unwrap().name = s.into();
state.phrases()[phrase].write().unwrap().name = s;
return Ok(Some(Self::Set(old_name.clone())))
},
Confirm => {

View file

@ -11,7 +11,7 @@ pub struct ArrangerStatus {
}
from!(|state:&ArrangerTui|ArrangerStatus = {
let samples = state.clock.chunk.load(Relaxed);
let rate = state.clock.timebase.sr.get() as f64;
let rate = state.clock.timebase.sr.get();
let buffer = samples as f64 / rate;
let width = state.size.w();
Self {
@ -48,7 +48,7 @@ impl ArrangerStatus {
double(("[]", "phrase"), ("{}", "order"),),
]))
}
fn stats <'a> (&'a self) -> impl Render<Tui> + use<'a> {
fn stats (&self) -> impl Render<Tui> + use<'_> {
row!([&self.cpu, &self.res, &self.size])
}
}

View file

@ -16,9 +16,9 @@ render!(<Tui>|self:MidiEditStatus<'a>|{
]);
Fill::w(Tui::fg_bg(fg, bg, row!([
Fixed::wh(26, 3, col!(![
field(" Edit", format!("{name}")),
field(" Length", format!("{length}")),
field(" Loop", format!("{looped}"))])),
field(" Edit", name.to_string()),
field(" Length", length.to_string()),
field(" Loop", looped.to_string())])),
Fixed::wh(30, 3, col!(![
field(" Time", format!("{}/{}-{} ({}*{}) {}",
self.0.time_point(), self.0.time_start().get(), self.0.time_end(),

View file

@ -11,7 +11,7 @@ pub struct SequencerStatus {
}
from!(|state:&SequencerTui|SequencerStatus = {
let samples = state.clock.chunk.load(Relaxed);
let rate = state.clock.timebase.sr.get() as f64;
let rate = state.clock.timebase.sr.get();
let buffer = samples as f64 / rate;
let width = state.size.w();
Self {
@ -46,7 +46,7 @@ impl SequencerStatus {
double(("c", "color"), ("", ""),),
]))
}
fn stats <'a> (&'a self) -> impl Render<Tui> + use<'a> {
fn stats (&self) -> impl Render<Tui> + use<'_> {
row!([&self.cpu, &self.res, &self.size])
}
}

View file

@ -92,6 +92,8 @@ impl<'a, const N: usize, E: PartialEq, T, U> EventMap<'a, N, E, T, U> {
}
}
pub(crate) type KeyMapping<const N: usize, T> = [(TuiEvent, &'static dyn Fn(&T)->PhraseCommand);N];
#[macro_export] macro_rules! kexp {
(Ctrl-Alt-$code:ident) => { key_event_expr!($code, KeyModifiers::from_bits(0b0000_0110).unwrap()) };
(Ctrl-$code:ident) => { key_event_expr!($code, KeyModifiers::CONTROL) };