1
0
Fork 0
mirror of https://github.com/alemidev/scope-tui.git synced 2024-11-14 02:39:20 +01:00

fix: updated readme, catch errors

This commit is contained in:
əlemi 2022-12-24 06:57:56 +01:00
parent e2269ef6d6
commit 00f27b7f83
No known key found for this signature in database
GPG key ID: BBCBFE5D7244634E
5 changed files with 84 additions and 57 deletions

View file

@ -3,9 +3,7 @@ name = "scope-tui"
version = "0.1.1"
edition = "2021"
authors = [ "alemi <me@alemi.dev>" ]
description = """
A simple audio visualization tool for the terminal built with tui-rs and libpulse-simple-binding, inspired from cava
"""
description = "A simple audio visualization tool for the terminal built with tui-rs and libpulse-simple-binding, inspired from cava"
keywords = ["tui", "terminal", "audio", "visualization", "scope", "dashboard"]
repository = "https://github.com/alemidev/scope-tui"
readme = "README.md"

View file

@ -13,17 +13,17 @@ the first version of `scope-tui` was developed, with very minimal settings given
# Usage
```
$ scope-tui [OPTIONS] <WIDTH>
$ scope-tui [OPTIONS] [DEVICE]
Arguments:
<WIDTH> Size of audio buffer, and width of scope
[DEVICE] Audio device to attach to
Options:
-d, --device <DEVICE> Audio device to attach to
-s, --scale <SCALE> Max value on Amplitude scale [default: 20000]
-b, --buffer <BUFFER> Size of audio buffer, and width of scope [default: 8192]
-r, --range <RANGE> Max value, positive and negative, on amplitude scale [default: 20000]
--no-reference Don't draw reference line
--no-braille Don't use braille dots for drawing lines
--scatter Use vintage looking scatter mode
--scatter Use vintage looking scatter mode instead of line mode
--vectorscope Combine left and right channels into vectorscope view
-h, --help Print help information
-V, --version Print version information
@ -32,6 +32,9 @@ Options:
The audio buffer size directly impacts resource usage, latency and refresh rate and its limits are given by the audio refresh rate. Larger buffers are slower but less resource intensive. A good starting value might be `8192`
## Controls
* Use `q` or `CTRL+C` to exit. Not all keypresses are caught, so keep trying... (wip!)
* Use `q` or `CTRL+C` to exit
* Use `<SPACE>` to pause and resume display
* Use `-` and `=` to decrease or increase range (`_` and `+` for smaller steps)
* Use `v` to toggle vectorscope mode
* Use `s` to toggle scatter mode
* Decrease/increase terminal font size to increase/decrease scope resolution.

View file

@ -101,8 +101,10 @@ impl AppConfig {
}
pub fn update_scale(&mut self, increment: i32) {
self.scale = ((self.scale as i32) + increment) as u32;
self.update_values();
if increment > 0 || increment.abs() < self.scale as i32 {
self.scale = ((self.scale as i32) + increment) as u32;
self.update_values();
}
}
pub fn set_scatter(&mut self, scatter: bool) {
@ -111,8 +113,8 @@ impl AppConfig {
}
impl From::<crate::Args> for AppConfig {
fn from(args: crate::Args) -> Self {
impl From::<&crate::Args> for AppConfig {
fn from(args: &crate::Args) -> Self {
let marker_type = if args.no_braille { symbols::Marker::Dot } else { symbols::Marker::Braille };
let graph_type = if args.scatter { GraphType::Scatter } else { GraphType::Line };
@ -121,8 +123,8 @@ impl From::<crate::Args> for AppConfig {
primary_color: Color::Red,
secondary_color: Color::Yellow,
axis_color: Color::DarkGray,
scale: args.scale,
width: args.width / 4, // TODO It's 4 because 2 channels and 2 bytes per sample!
scale: args.range,
width: args.buffer / 4, // TODO It's 4 because 2 channels and 2 bytes per sample!
vectorscope: args.vectorscope,
references: !args.no_reference,
bounds: ChartBounds::default(),

View file

@ -1,9 +1,9 @@
mod parser;
mod app;
use std::{io, time::Duration};
use std::{io::{self, ErrorKind}, time::Duration};
use tui::{
backend::CrosstermBackend,
backend::{CrosstermBackend, Backend},
widgets::{Block, Chart, Axis, Dataset, GraphType},
// layout::{Layout, Constraint, Direction},
Terminal, text::Span, style::{Style, Color, Modifier}, symbols
@ -32,11 +32,11 @@ struct Args {
/// Size of audio buffer, and width of scope
#[arg(short, long, default_value_t = 8192)]
width: u32,
buffer: u32,
/// Max value on Amplitude scale
/// Max value, positive and negative, on amplitude scale
#[arg(short, long, default_value_t = 20000)]
scale: u32,
range: u32,
/// Don't draw reference line
#[arg(long, default_value_t = false)]
@ -46,7 +46,7 @@ struct Args {
#[arg(long, default_value_t = false)]
no_braille: bool,
/// Use vintage looking scatter mode
/// Use vintage looking scatter mode instead of line mode
#[arg(long, default_value_t = false)]
scatter: bool,
@ -78,10 +78,45 @@ fn data_set<'a>(
.data(&data)
}
fn main() -> Result<(), io::Error> {
let args = Args::parse();
// setup terminal
enable_raw_mode()?;
let mut stdout = io::stdout();
execute!(stdout, EnterAlternateScreen)?;
let backend = CrosstermBackend::new(stdout);
let mut terminal = Terminal::new(backend)?;
terminal.hide_cursor()?;
match run_app(args, &mut terminal) {
Ok(()) => {},
Err(e) => {
println!("[!] Error executing app: {:?}", e);
}
}
// restore terminal
disable_raw_mode()?;
execute!(
terminal.backend_mut(),
LeaveAlternateScreen,
DisableMouseCapture
)?;
terminal.show_cursor()?;
Ok(())
}
fn run_app<T : Backend>(args: Args, terminal: &mut Terminal<T>) -> Result<(), io::Error> {
// prepare globals
let mut buffer : Vec<u8> = vec![0; args.buffer as usize];
let mut cfg = AppConfig::from(&args);
let fmt = Signed16PCM{}; // TODO some way to choose this?
let mut pause = false;
// setup audio capture
let spec = Spec {
format: Format::S16NE,
@ -95,8 +130,7 @@ fn main() -> Result<(), io::Error> {
None => None,
};
let s = Simple::new(
let s = match Simple::new(
None, // Use the default server
"ScopeTUI", // Our applications name
Direction::Record, // We want a record stream
@ -105,29 +139,27 @@ fn main() -> Result<(), io::Error> {
&spec, // Our sample format
None, // Use default channel map
Some(&BufferAttr {
maxlength: 32 * args.width,
fragsize: args.width,
maxlength: 32 * args.buffer,
fragsize: args.buffer,
..Default::default()
}),
).unwrap();
) {
Ok(s) => s,
Err(e) => {
println!("[!] Could not connect to pulseaudio : {:?}", e);
return Err(io::Error::new(ErrorKind::Other, "could not connect to pulseaudio"));
},
};
// setup terminal
enable_raw_mode()?;
let mut stdout = io::stdout();
execute!(stdout, EnterAlternateScreen)?;
let backend = CrosstermBackend::new(stdout);
let mut terminal = Terminal::new(backend)?;
terminal.hide_cursor().unwrap();
// prepare globals
let mut buffer : Vec<u8> = vec![0; args.width as usize];
let mut cfg = AppConfig::from(args);
let fmt = Signed16PCM{}; // TODO some way to choose this?
let mut pause = false;
loop {
s.read(&mut buffer).unwrap();
match s.read(&mut buffer) {
Ok(()) => {},
Err(e) => {
println!("[!] Could not read data from pulseaudio : {:?}", e);
return Err(io::Error::new(ErrorKind::Other, "could not read from pulseaudio"));
},
}
if !pause {
let mut datasets = vec![];
@ -138,7 +170,7 @@ fn main() -> Result<(), io::Error> {
let mut ref_data_y = Vec::new();
if cfg.references {
// TODO find a proper way to put these references...
if cfg.vectorscope() {
for x in -(cfg.scale() as i64)..(cfg.scale() as i64) {
ref_data_x.push((x as f64, 0 as f64));
@ -182,7 +214,7 @@ fn main() -> Result<(), io::Error> {
.x_axis(Axis::default()
.title(Span::styled(cfg.name(app::Axis::X), Style::default().fg(Color::Cyan)))
.style(Style::default().fg(cfg.axis_color))
.bounds(cfg.bounds(app::Axis::X)))
.bounds(cfg.bounds(app::Axis::X))) // TODO allow to have axis sometimes?
.y_axis(Axis::default()
.title(Span::styled(cfg.name(app::Axis::Y), Style::default().fg(Color::Cyan)))
.style(Style::default().fg(cfg.axis_color))
@ -196,8 +228,6 @@ fn main() -> Result<(), io::Error> {
KeyModifiers::CONTROL => {
match key.code {
KeyCode::Char('c') => break,
KeyCode::Char('+') => cfg.update_scale(100),
KeyCode::Char('-') => cfg.update_scale(-100),
_ => {},
}
},
@ -205,8 +235,10 @@ fn main() -> Result<(), io::Error> {
match key.code {
KeyCode::Char('q') => break,
KeyCode::Char(' ') => pause = !pause,
KeyCode::Char('+') => cfg.update_scale(1000),
KeyCode::Char('-') => cfg.update_scale(-1000),
KeyCode::Char('=') => cfg.update_scale(-1000),
KeyCode::Char('-') => cfg.update_scale(1000),
KeyCode::Char('+') => cfg.update_scale(-100),
KeyCode::Char('_') => cfg.update_scale(100),
KeyCode::Char('v') => cfg.set_vectorscope(!cfg.vectorscope()),
KeyCode::Char('s') => cfg.set_scatter(!cfg.scatter()),
_ => {},
@ -216,14 +248,5 @@ fn main() -> Result<(), io::Error> {
}
}
// restore terminal
disable_raw_mode()?;
execute!(
terminal.backend_mut(),
LeaveAlternateScreen,
DisableMouseCapture
)?;
terminal.show_cursor()?;
Ok(())
}

View file

@ -14,6 +14,7 @@ pub trait SampleParser {
pub struct Signed16PCM {}
/// TODO these are kinda inefficient, can they be faster?
impl SampleParser for Signed16PCM {
fn oscilloscope(&self, data: &mut [u8]) -> (Vec<(f64, f64)>, Vec<(f64, f64)>) {
let mut left = Vec::new(); // TODO does left really come first?