Skip to content

Commit

Permalink
Make clippy happy
Browse files Browse the repository at this point in the history
  • Loading branch information
alisomay committed Nov 20, 2023
1 parent fe4adda commit 9eba7a9
Show file tree
Hide file tree
Showing 9 changed files with 237 additions and 94 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

77 changes: 77 additions & 0 deletions rustfmt.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# max_width = 100
# hard_tabs = false
# tab_spaces = 4
# newline_style = "Auto"
# indent_style = "Block"
# use_small_heuristics = "Default"
# fn_call_width = 60
# attr_fn_like_width = 70
# struct_lit_width = 18
# struct_variant_width = 35
# array_width = 60
# chain_width = 60
# single_line_if_else_max_width = 50
# wrap_comments = false
# format_code_in_doc_comments = false
# comment_width = 80
# normalize_comments = false
# normalize_doc_attributes = false
# license_template_path = ""
# format_strings = false
# format_macro_matchers = false
# format_macro_bodies = true
# hex_literal_case = "Preserve"
# empty_item_single_line = true
# struct_lit_single_line = true
# fn_single_line = false
# where_single_line = false
# imports_indent = "Block"
# imports_layout = "Mixed"
imports_granularity = "Crate"
group_imports = "One"
reorder_imports = true
reorder_modules = true
# reorder_impl_items = false
# type_punctuation_density = "Wide"
# space_before_colon = false
# space_after_colon = true
# spaces_around_ranges = false
# binop_separator = "Front"
# remove_nested_parens = true
# combine_control_expr = true
# overflow_delimited_expr = false
# struct_field_align_threshold = 0
# enum_discrim_align_threshold = 0
# match_arm_blocks = true
# match_arm_leading_pipes = "Never"
# force_multiline_blocks = false
# fn_args_layout = "Tall"
# brace_style = "SameLineWhere"
# control_brace_style = "AlwaysSameLine"
# trailing_semicolon = true
# trailing_comma = "Vertical"
# match_block_trailing_comma = false
# blank_lines_upper_bound = 1
# blank_lines_lower_bound = 0
edition = "2021"
# version = "One"
# inline_attribute_width = 0
# format_generated_files = true
# merge_derives = true
# use_try_shorthand = false
# use_field_init_shorthand = false
# force_explicit_abi = true
# condense_wildcard_suffixes = false
# color = "Auto"
# required_version = "1.4.38"
# unstable_features = false
# disable_all_formatting = false
# skip_children = false
# hide_parse_errors = false
# error_on_line_overflow = false
# error_on_unformatted = false
# report_todo = "Never"
# report_fixme = "Never"
# ignore = []
# emit_mode = "Files"
# make_backup = false
42 changes: 25 additions & 17 deletions src/config.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
use crate::wav::spec_from_config;
use crate::WriterHandles;
use crate::{wav::spec_from_config, WriterHandles};
use anyhow::{anyhow, bail, Result};
use camino::Utf8PathBuf;
use chrono::{Datelike, Timelike, Utc};
use cpal::traits::{DeviceTrait, HostTrait};
use cpal::SupportedStreamConfig;
use serde::de::{self, Deserializer, MapAccess, Visitor};
use serde::Deserialize;
use std::collections::HashMap;
use std::fmt;
use std::str::FromStr;
use std::sync::{Arc, Mutex};
use cpal::{
traits::{DeviceTrait, HostTrait},
SupportedStreamConfig,
};
use serde::{
de::{self, Deserializer, MapAccess, Visitor},
Deserialize,
};
use std::{
collections::HashMap,
fmt,
str::FromStr,
sync::{Arc, Mutex},
};

/// Chooses which channels to record.
pub fn choose_channels_to_record(
Expand Down Expand Up @@ -132,17 +137,20 @@ impl SmrecConfig {
config.channels_to_record = channels_to_record;

config.channels_to_record.iter().for_each(|channel| {
if !config.channel_names.contains_key(&(channel + 1)) {
config
.channel_names
.insert(*channel + 1, format!("chn_{}.wav", channel + 1));
} else {
if config.channel_names.contains_key(&(channel + 1)) {
let name = config.channel_names.get(&(channel + 1)).unwrap();
if !name.ends_with(".wav") {
if !std::path::Path::new(name)
.extension()
.map_or(false, |ext| ext.eq_ignore_ascii_case("wav"))
{
config
.channel_names
.insert(*channel + 1, format!("{}.wav", name));
.insert(*channel + 1, format!("{name}.wav"));
}
} else {
config
.channel_names
.insert(*channel + 1, format!("chn_{}.wav", channel + 1));
}
});
config.cpal_stream_config = Some(cpal_stream_config);
Expand Down
51 changes: 43 additions & 8 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,34 @@
// Most of the lints we deny here have a good chance to be relevant for our project.
#![deny(clippy::all)]
// We warn for all lints on the planet. Just to filter them later for customization.
// It is impossible to remember all the lints so a subtractive approach keeps us updated, in control and knowledgeable.
#![warn(clippy::pedantic, clippy::nursery, clippy::cargo)]
// Then in the end we allow ridiculous or too restrictive lints that are not relevant for our project.
// This list is dynamic and will grow in time which will define our style.
#![allow(
clippy::multiple_crate_versions,
clippy::blanket_clippy_restriction_lints,
clippy::missing_docs_in_private_items,
clippy::pub_use,
clippy::std_instead_of_alloc,
clippy::std_instead_of_core,
clippy::implicit_return,
clippy::missing_inline_in_public_items,
clippy::similar_names,
clippy::question_mark_used,
clippy::expect_used,
clippy::missing_errors_doc,
clippy::pattern_type_mismatch,
clippy::module_name_repetitions,
clippy::empty_structs_with_brackets,
clippy::as_conversions,
clippy::self_named_module_files,
clippy::cargo_common_metadata,
clippy::exhaustive_structs,
// It is a binary crate, panicing is usually fine.
clippy::missing_panics_doc
)]

mod config;
mod list;
mod midi;
Expand All @@ -6,22 +37,25 @@ mod stream;
mod types;
mod wav;

use crate::{
config::{choose_channels_to_record, SmrecConfig},
midi::Midi,
};
use anyhow::{bail, Result};
use clap::{Parser, Subcommand};
use config::{choose_device, choose_host};
use cpal::traits::{DeviceTrait, StreamTrait};
use hound::WavWriter;
use osc::Osc;
use std::cell::RefCell;
use std::fs::File;
use std::io::BufWriter;
use std::rc::Rc;
use std::sync::{Arc, Mutex};
use std::{
cell::RefCell,
fs::File,
io::BufWriter,
rc::Rc,
sync::{Arc, Mutex},
};
use types::Action;

use crate::config::{choose_channels_to_record, SmrecConfig};
use crate::midi::Midi;

#[derive(Parser)]
#[command(
author,
Expand Down Expand Up @@ -93,6 +127,7 @@ struct List {
pub type WriterHandle = Arc<Mutex<Option<WavWriter<BufWriter<File>>>>>;
pub type WriterHandles = Arc<Vec<WriterHandle>>;

#[allow(clippy::too_many_lines)]
fn main() -> Result<()> {
let cli = Cli::parse();

Expand Down
121 changes: 74 additions & 47 deletions src/midi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@ use anyhow::{bail, Result};
use midir::{
MidiInput, MidiInputConnection, MidiInputPort, MidiOutput, MidiOutputConnection, MidiOutputPort,
};
use std::collections::HashMap;
use std::ops::Deref;
use std::str::FromStr;
use std::sync::{Arc, Mutex};
use std::{
collections::HashMap,
ops::Deref,
str::FromStr,
sync::{Arc, Mutex},
};

enum MessageType {
NoteOff,
Expand Down Expand Up @@ -45,7 +47,7 @@ const fn make_cc_message(channel: u8, cc_num: u8, value: u8) -> [u8; 3] {
[0xB0 + channel, cc_num, value]
}

/// HashMap of port name to vector of (channel_num, cc_num[start], cc_num[stop])
/// `HashMap` of port name to vector of (`channel_num`, `cc_num`[start], `cc_num`[stop])
#[derive(Debug, Clone)]
pub struct MidiConfig(HashMap<String, Vec<(u8, u8, u8)>>);

Expand Down Expand Up @@ -160,9 +162,10 @@ impl Midi {
})
}

pub fn listen(&mut self) -> Result<()> {
let input_ports = self
.input_config
// These are going to be addressed in a later refactor.
#[allow(clippy::type_complexity)]
fn input_ports_from_configs(&self) -> Result<Vec<(String, MidiInputPort, Vec<(u8, u8, u8)>)>> {
self.input_config
.iter()
.filter_map(|(port_name, configs)| {
let input_ports = self.find_input_ports(port_name).ok()?;
Expand All @@ -175,7 +178,11 @@ impl Midi {
})
.flatten()
.map(Ok)
.collect::<Result<Vec<(String, MidiInputPort, Vec<(u8, u8, u8)>)>, anyhow::Error>>()?;
.collect::<Result<Vec<(String, MidiInputPort, Vec<(u8, u8, u8)>)>, anyhow::Error>>()
}

fn register_midi_input_hooks(&mut self) -> Result<()> {
let input_ports = self.input_ports_from_configs()?;

// Start listening for MIDI messages on all configured ports and channels.
for (port_name, port, configs) in input_ports {
Expand Down Expand Up @@ -254,46 +261,59 @@ impl Midi {
);
}

Ok(())
}

// These are going to be addressed in a later refactor.
#[allow(clippy::type_complexity)]
fn output_connections_from_config(
&self,
) -> Result<Option<Vec<(String, Arc<Mutex<MidiOutputConnection>>, Vec<(u8, u8, u8)>)>>> {
if let Some(ref output_config) = self.output_config {
let output_connections = {
let output_ports = output_config
.iter()
.filter_map(|(port_name, configs)| {
let output_ports = self.find_output_ports(port_name).ok()?;
Some(
output_ports
.into_iter()
.map(move |(name, port)| (name, port, configs.clone()))
.collect::<Vec<_>>(),
)
})
.flatten()
.map(Ok)
.collect::<Result<Vec<(String, MidiOutputPort, Vec<(u8, u8, u8)>)>, anyhow::Error>>()?;

output_ports
.iter()
.map(|(port_name, port, configs)| {
let output = MidiOutput::new("smrec")?;
Ok::<
(
std::string::String,
Arc<Mutex<MidiOutputConnection>>,
std::vec::Vec<(u8, u8, u8)>,
),
anyhow::Error,
>((
port_name.clone(),
Arc::new(Mutex::new(output.connect(port, port_name).expect("Could not bind to {port_name}"))),
configs.clone(),
))
})
.collect::<Result<Vec<(String, Arc<Mutex<MidiOutputConnection>>, Vec<(u8, u8, u8)>)>, _>>(
)?
};

let receiver_channel = self.receiver_channel.clone();
let output_ports = output_config
.iter()
.filter_map(|(port_name, configs)| {
let output_ports = self.find_output_ports(port_name).ok()?;
Some(
output_ports
.into_iter()
.map(move |(name, port)| (name, port, configs.clone()))
.collect::<Vec<_>>(),
)
})
.flatten()
.map(Ok)
.collect::<Result<Vec<(String, MidiOutputPort, Vec<(u8, u8, u8)>)>, anyhow::Error>>(
)?;

return output_ports
.iter()
.map(|(port_name, port, configs)| {
let output = MidiOutput::new("smrec")?;
Ok(Some((
port_name.clone(),
Arc::new(Mutex::new(
output
.connect(port, port_name)
.expect("Could not bind to {port_name}"),
)),
configs.clone(),
)))
})
.collect::<Result<
Option<Vec<(String, Arc<Mutex<MidiOutputConnection>>, Vec<(u8, u8, u8)>)>>,
_,
>>();
}

Ok(None)
}

fn spin_midi_output_thread_if_necessary(&mut self) -> Result<()> {
let output_connections = self.output_connections_from_config()?;
let receiver_channel = self.receiver_channel.clone();

if let Some(output_connections) = output_connections {
self.output_thread = Some(std::thread::spawn(move || {
loop {
if let Ok(action) = receiver_channel.recv() {
Expand Down Expand Up @@ -371,4 +391,11 @@ impl Midi {

Ok(())
}

pub fn listen(&mut self) -> Result<()> {
self.register_midi_input_hooks()?;
self.spin_midi_output_thread_if_necessary()?;

Ok(())
}
}
Loading

0 comments on commit 9eba7a9

Please sign in to comment.