mirror of
https://github.com/alemidev/scope-tui.git
synced 2024-11-14 02:39:20 +01:00
chore: separated lib from app code
so various display modes can be imported as deps, but by default it still compiles a binary target
This commit is contained in:
parent
f62586d1d1
commit
58a084e154
9 changed files with 72 additions and 61 deletions
18
Cargo.toml
18
Cargo.toml
|
@ -10,12 +10,22 @@ keywords = ["cli", "tui", "audio", "visualization", "scope"]
|
|||
repository = "https://git.alemi.dev/scope-tui.git"
|
||||
readme = "README.md"
|
||||
|
||||
[lib]
|
||||
name = "scope"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "scope-tui"
|
||||
path = "src/main.rs"
|
||||
required-features = ["app"]
|
||||
|
||||
|
||||
[dependencies]
|
||||
clap = { version = "4.0.32", features = ["derive"] }
|
||||
derive_more = "0.99.17"
|
||||
thiserror = "1.0.48"
|
||||
rustfft = "6.1.0"
|
||||
# for TUI app
|
||||
clap = { version = "4.0.32", features = ["derive"], optional = true }
|
||||
# cross platform audio library backend
|
||||
cpal = { version = "0.15.3", optional = true }
|
||||
# for TUI backend
|
||||
|
@ -26,9 +36,11 @@ libpulse-binding = { version = "2.0", optional = true }
|
|||
libpulse-simple-binding = { version = "2.25", optional = true }
|
||||
|
||||
[features]
|
||||
default = ["tui", "file", "cpal"]
|
||||
file = []
|
||||
default = ["tui"]
|
||||
#default = ["app", "file", "cpal"]
|
||||
app = ["dep:clap", "tui"]
|
||||
tui = ["dep:ratatui", "dep:crossterm"]
|
||||
file = []
|
||||
cpal = ["dep:cpal"]
|
||||
pulseaudio = ["dep:libpulse-binding", "dep:libpulse-simple-binding"]
|
||||
|
||||
|
|
32
src/app.rs
32
src/app.rs
|
@ -47,9 +47,9 @@ impl App {
|
|||
},
|
||||
};
|
||||
|
||||
let oscilloscope = Oscilloscope::from_args(source);
|
||||
let vectorscope = Vectorscope::from_args(source);
|
||||
let spectroscope = Spectroscope::from_args(source);
|
||||
let oscilloscope = Oscilloscope::default();
|
||||
let vectorscope = Vectorscope::default();
|
||||
let spectroscope = Spectroscope::from(source);
|
||||
|
||||
App {
|
||||
graph, oscilloscope, vectorscope, spectroscope,
|
||||
|
@ -175,32 +175,6 @@ impl App {
|
|||
|
||||
// TODO can these be removed or merged somewhere else?
|
||||
|
||||
pub fn update_value_f(val: &mut f64, base: f64, magnitude: f64, range: Range<f64>) {
|
||||
let delta = base * magnitude;
|
||||
if *val + delta > range.end {
|
||||
*val = range.end
|
||||
} else if *val + delta < range.start {
|
||||
*val = range.start
|
||||
} else {
|
||||
*val += delta;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_value_i(val: &mut u32, inc: bool, base: u32, magnitude: f64, range: Range<u32>) {
|
||||
let delta = (base as f64 * magnitude) as u32;
|
||||
if inc {
|
||||
if range.end - delta < *val {
|
||||
*val = range.end
|
||||
} else {
|
||||
*val += delta
|
||||
}
|
||||
} else if range.start + delta > *val {
|
||||
*val = range.start
|
||||
} else {
|
||||
*val -= delta
|
||||
}
|
||||
}
|
||||
|
||||
fn make_header<'a>(cfg: &GraphConfig, module_header: &'a str, kind_o_scope: &'static str, fps: usize, pause: bool) -> Table<'a> {
|
||||
Table::new(
|
||||
vec![
|
||||
|
|
|
@ -11,7 +11,7 @@ pub enum Dimension {
|
|||
X, Y
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct GraphConfig {
|
||||
pub pause: bool,
|
||||
pub samples: u32,
|
||||
|
@ -36,7 +36,6 @@ impl GraphConfig {
|
|||
#[allow(clippy::ptr_arg)] // TODO temporarily! it's a shitty solution
|
||||
pub trait DisplayMode {
|
||||
// MUST define
|
||||
fn from_args(args: &crate::cfg::SourceOptions) -> Self where Self : Sized;
|
||||
fn axis(&self, cfg: &GraphConfig, dimension: Dimension) -> Axis; // TODO simplify this
|
||||
fn process(&mut self, cfg: &GraphConfig, data: &Matrix<f64>) -> Vec<DataSet>;
|
||||
fn mode_str(&self) -> &'static str;
|
||||
|
@ -83,3 +82,29 @@ impl DataSet {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
pub(crate) fn update_value_f(val: &mut f64, base: f64, magnitude: f64, range: std::ops::Range<f64>) {
|
||||
let delta = base * magnitude;
|
||||
if *val + delta > range.end {
|
||||
*val = range.end
|
||||
} else if *val + delta < range.start {
|
||||
*val = range.start
|
||||
} else {
|
||||
*val += delta;
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn update_value_i(val: &mut u32, inc: bool, base: u32, magnitude: f64, range: std::ops::Range<u32>) {
|
||||
let delta = (base as f64 * magnitude) as u32;
|
||||
if inc {
|
||||
if range.end - delta < *val {
|
||||
*val = range.end
|
||||
} else {
|
||||
*val += delta
|
||||
}
|
||||
} else if range.start + delta > *val {
|
||||
*val = range.start
|
||||
} else {
|
||||
*val -= delta
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
use crossterm::event::{Event, KeyModifiers, KeyCode};
|
||||
use ratatui::{widgets::{Axis, GraphType}, style::Style, text::Span};
|
||||
|
||||
use crate::{app::{update_value_f, update_value_i}, input::Matrix};
|
||||
use crate::input::Matrix;
|
||||
|
||||
use super::{DisplayMode, GraphConfig, DataSet, Dimension};
|
||||
use super::{update_value_f, update_value_i, DataSet, Dimension, DisplayMode, GraphConfig};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Oscilloscope {
|
||||
|
@ -15,10 +15,6 @@ pub struct Oscilloscope {
|
|||
}
|
||||
|
||||
impl DisplayMode for Oscilloscope {
|
||||
fn from_args(_opts: &crate::cfg::SourceOptions) -> Self {
|
||||
Oscilloscope::default()
|
||||
}
|
||||
|
||||
fn mode_str(&self) -> &'static str {
|
||||
"oscillo"
|
||||
}
|
||||
|
|
|
@ -3,9 +3,9 @@ use std::collections::VecDeque;
|
|||
use crossterm::event::{Event, KeyCode};
|
||||
use ratatui::{widgets::{Axis, GraphType}, style::Style, text::Span};
|
||||
|
||||
use crate::{app::update_value_i, input::Matrix};
|
||||
use crate::input::Matrix;
|
||||
|
||||
use super::{DisplayMode, GraphConfig, DataSet, Dimension};
|
||||
use super::{update_value_i, DataSet, Dimension, DisplayMode, GraphConfig};
|
||||
|
||||
use rustfft::{FftPlanner, num_complex::Complex};
|
||||
|
||||
|
@ -37,17 +37,20 @@ pub fn hann_window(samples: &[f64]) -> Vec<f64> {
|
|||
windowed_samples
|
||||
}
|
||||
|
||||
impl DisplayMode for Spectroscope {
|
||||
fn from_args(opts: &crate::cfg::SourceOptions) -> Self {
|
||||
#[cfg(feature = "app")]
|
||||
impl From<&crate::cfg::SourceOptions> for Spectroscope {
|
||||
fn from(value: &crate::cfg::SourceOptions) -> Self {
|
||||
Spectroscope {
|
||||
sampling_rate: opts.sample_rate,
|
||||
buffer_size: opts.buffer,
|
||||
sampling_rate: value.sample_rate,
|
||||
buffer_size: value.buffer,
|
||||
average: 1, buf: Vec::new(),
|
||||
window: false,
|
||||
log_y: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DisplayMode for Spectroscope {
|
||||
fn mode_str(&self) -> &'static str {
|
||||
"spectro"
|
||||
}
|
||||
|
@ -80,7 +83,7 @@ impl DisplayMode for Spectroscope {
|
|||
Dimension::X => ("frequency -", [20.0f64.ln(), ((cfg.samples as f64 / cfg.width as f64) * 20000.0).ln()]),
|
||||
Dimension::Y => (
|
||||
if self.log_y { "| level" } else { "| amplitude" },
|
||||
[if self.log_y { 0. } else { 0.0 }, cfg.scale * 7.5] // very arbitrary but good default
|
||||
[0.0, cfg.scale * 7.5] // very arbitrary but good default
|
||||
),
|
||||
// TODO super arbitraty! wtf! also ugly inline ifs, get this thing together!
|
||||
};
|
||||
|
|
|
@ -8,10 +8,6 @@ use super::{DisplayMode, GraphConfig, DataSet, Dimension};
|
|||
pub struct Vectorscope {}
|
||||
|
||||
impl DisplayMode for Vectorscope {
|
||||
fn from_args(_opts: &crate::cfg::SourceOptions) -> Self {
|
||||
Vectorscope::default()
|
||||
}
|
||||
|
||||
fn mode_str(&self) -> &'static str {
|
||||
"vector"
|
||||
}
|
||||
|
|
|
@ -3,8 +3,10 @@ pub mod format;
|
|||
#[cfg(feature = "pulseaudio")]
|
||||
pub mod pulse;
|
||||
|
||||
#[cfg(feature = "file")]
|
||||
pub mod file;
|
||||
|
||||
#[cfg(feature = "cpal")]
|
||||
pub mod cpal;
|
||||
|
||||
pub type Matrix<T> = Vec<Vec<T>>;
|
||||
|
|
9
src/lib.rs
Normal file
9
src/lib.rs
Normal file
|
@ -0,0 +1,9 @@
|
|||
pub mod music;
|
||||
pub mod input;
|
||||
pub mod display;
|
||||
|
||||
#[cfg(feature = "app")]
|
||||
pub mod cfg;
|
||||
|
||||
#[cfg(feature = "app")]
|
||||
pub mod app;
|
14
src/main.rs
14
src/main.rs
|
@ -1,11 +1,5 @@
|
|||
mod app;
|
||||
mod cfg;
|
||||
mod music;
|
||||
mod input;
|
||||
mod display;
|
||||
|
||||
use app::App;
|
||||
use cfg::{ScopeArgs, ScopeSource};
|
||||
use scope::app::App;
|
||||
use scope::cfg::{ScopeArgs, ScopeSource};
|
||||
use clap::Parser;
|
||||
use ratatui::{backend::CrosstermBackend, Terminal};
|
||||
use crossterm::{execute, terminal::{
|
||||
|
@ -25,12 +19,12 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
|
||||
#[cfg(feature = "file")]
|
||||
ScopeSource::File { path, limit_rate } => {
|
||||
input::file::FileSource::new(&path, &args.opts, limit_rate)?
|
||||
scope::input::file::FileSource::new(&path, &args.opts, limit_rate)?
|
||||
},
|
||||
|
||||
#[cfg(feature = "cpal")]
|
||||
ScopeSource::Audio { device, timeout } => {
|
||||
input::cpal::DefaultAudioDeviceWithCPAL::new(device.as_deref(), &args.opts, timeout)?
|
||||
scope::input::cpal::DefaultAudioDeviceWithCPAL::new(device.as_deref(), &args.opts, timeout)?
|
||||
}
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue