1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
|
use clap::{Parser, ValueEnum, Args};
use crate::outputers::{ColourScheme, Outputers, SimpleOutputer, LineLayout, TuiOutputer};
use derive_more::Display;
use crate::notes::Note;
use std::path::{PathBuf, Path};
use std::error::Error;
use std::fs::File;
use std::io::BufReader;
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum, Debug, Display)]
pub enum OutputerTypes {
#[display(fmt="simple")]
Simple,
#[display(fmt="line-layout")]
LineLayout,
#[display(fmt="tui")]
Tui,
}
// TODO: it might make sense to add a step and quanitize values (they're quanitized to 1/i16::MAX
// anyway because it's 16bit signed ints from alsa), but i think just scaling by
// max_threshold will work for now
#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
pub struct SimpleArgs {
/// outputter to use
#[arg(short, long, default_value_t = OutputerTypes::Simple)]
pub outputer: OutputerTypes,
/// threshold for displaying the value, the values have a range of
/// 0 - 1 for the most part, a square wave at the max volume
/// of a single note will be ~1 (pure sine will be ~sqrt(0.5) or ~0.707ish)
/// but in practice most sounds won't get close to that, normally being in
/// the range of 0.005-0.10 will give you something usable without being too noisy,
/// highly depending on your input though
#[arg(short, long, default_value_t = 0.00526532149076897)]
pub threshold: f32,
/// max (saturating) threshold, for colour output in LineLayout and maybe with
/// certain other outputers this is used as a value for which any values higher
/// then this is considered a max value and displayed at full brightness.
///
/// For LineLayout this contols the brightness of the colour output,
/// anything >= max_threshold will display at full brightness and anything below
/// will be scaled linearly, like brightness = min(1, note_val / max_threshold) and of course
/// r = r_max * brightness, g = g_max * brightness, b = b_max * brightness.
///
/// it's recommended to set this somewhat close to what you
/// expect your highest value is going to be (you can play with that by experimenting
/// with the Simple output, in Simple output each value is scaled by 10,000 so 2000 for
/// example would be 0.2)
///
/// because the max sine wave volume is sqrt(0.5) for now this defaults to sqrt(0.5), but
/// it's recommended to set it lower especially if the brightness of the bars seems too low for
/// your input.
///
/// 0.2 - 0.3 seems like an actual good value in practice, but it's worth playing with
#[arg(short, long, default_value_t = 0.7071067811865476)]
pub max_threshold: f32,
/// don't use colour to output for outputers that support it
/// (currently LineLayout)
#[arg(long, default_value_t = false)]
pub plain: bool,
/*/// max brightness colour for LineLayout and maybe other outputers,
/// this is the r/g/b colour at >= max_threshold, values
/// threshold > val > max_threshold will scale linearly from
/// brightness = threshold to brightness = 1, currently
/// threshold just determines if the value is displayed and not
/// its colour, that's purely from the max threshold
/// (though that could be something to change, make the calculation something like
/// diff = note_val - threshold
/// max_diff = max_threshold - threshold
/// brightness = diff / max_diff)
///
/// These should have a range of (0.0 - 255.0) because each value gets converted
/// to a u8 to determine the final rgb colour
#[arg(long, default_value_t = String::from("78ffdc"))]
pub colour: String,*/
/// File that contains the colourscheme as JSON, see the colourschemes/ directory for examples
/// we'll use adam neely's as the default for the moment, but this should be changed
/// TODO
/// NOTE (The default here is set at compile time, so you have to recompile if you change the
/// dir you're in)
#[arg(short, long)]
colours: Option<PathBuf>,
/// Output device
#[arg(long)]
pub outdev: Option<Option<String>>
}
impl SimpleArgs {
pub fn get_outputer(&self, notes: &[Note]) -> Outputers {
match self.outputer {
OutputerTypes::Simple => Outputers::Simple(SimpleOutputer),
// TODO: change this unwrap to a ? and a Result return value
OutputerTypes::LineLayout => Outputers::LineLayout(LineLayout::new(self.max_threshold, !self.plain, self.get_colours().unwrap(), ¬es)),
OutputerTypes::Tui => Outputers::Tui(TuiOutputer::new().unwrap()),
}
}
pub fn get_outdev(&self) -> Option<String> {
match &self.outdev {
Some(outdev) => outdev.clone(),
None => Some(String::from("default")),
}
}
pub fn get_colours(&self) -> Result<ColourScheme, Box<dyn Error>> {
match (self.plain, &self.colours) {
(true, _) => Ok(ColourScheme::default()),
(false, None) => Ok(ColourScheme::default()),
(false, Some(cf)) => {
// first check if the file exists either as an absolute path or in the current
// directory, if it does try to load it
let mut fres = File::open(&cf);
// otherwise try to load the colourscheme from colourschemes/ in the project directory
if fres.is_err() {
//let pth: PathBuf = [env!("CARGO_MANIFEST_DIR"), "colourschemes", cf.as_path()].iter().collect();
let mut pth: PathBuf = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
pth.push("colourschemes");
pth.push(&cf);
fres = File::open(pth);
}
let file = fres?;
let reader = BufReader::new(file);
let colours: ColourScheme = serde_json::from_reader(reader)?;
// if either loaded successfully, make sure all of the colours are Rgb for later
Ok(colours)
}
}
}
}
|