add global volume control
This commit is contained in:
parent
cb438c1887
commit
39eedfc5f4
1 changed files with 52 additions and 21 deletions
73
src/main.rs
73
src/main.rs
|
@ -1,8 +1,9 @@
|
||||||
use crossterm::cursor::MoveTo;
|
use crossterm::cursor::{self, MoveTo};
|
||||||
use crossterm::event::{self, Event, KeyCode};
|
use crossterm::event::{self, Event, KeyCode};
|
||||||
use crossterm::terminal::{self, Clear, ClearType};
|
use crossterm::terminal::{self, Clear, ClearType};
|
||||||
use crossterm::ExecutableCommand;
|
use crossterm::ExecutableCommand;
|
||||||
use rodio::{source::Source, OutputStream, OutputStreamHandle};
|
use rodio::Sink;
|
||||||
|
use rodio::{OutputStream, OutputStreamHandle};
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::io::stdout;
|
use std::io::stdout;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
@ -18,7 +19,7 @@ fn main() {
|
||||||
struct UIChannel {
|
struct UIChannel {
|
||||||
name: String,
|
name: String,
|
||||||
volume: i32,
|
volume: i32,
|
||||||
internal_volume: Arc<Mutex<f32>>,
|
volume_sync: Arc<Mutex<f32>>,
|
||||||
muted: bool,
|
muted: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,7 +28,7 @@ impl UIChannel {
|
||||||
if self.muted {
|
if self.muted {
|
||||||
self.sync();
|
self.sync();
|
||||||
} else {
|
} else {
|
||||||
*self.internal_volume.lock().unwrap() = 0.0;
|
*self.volume_sync.lock().unwrap() = 0.0;
|
||||||
}
|
}
|
||||||
self.muted = !self.muted;
|
self.muted = !self.muted;
|
||||||
}
|
}
|
||||||
|
@ -43,27 +44,33 @@ impl UIChannel {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sync(&mut self) {
|
fn sync(&mut self) {
|
||||||
*self.internal_volume.lock().unwrap() = self.get_vol();
|
*self.volume_sync.lock().unwrap() = self.get_vol();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct App {
|
struct App {
|
||||||
channels: Vec<UIChannel>,
|
channels: Vec<UIChannel>,
|
||||||
selected: usize,
|
selected: usize,
|
||||||
_stream: OutputStream,
|
_stream: (OutputStream, OutputStreamHandle),
|
||||||
stream_handle: OutputStreamHandle,
|
sink: Sink,
|
||||||
|
volume: i32,
|
||||||
|
playing: bool,
|
||||||
quit: bool,
|
quit: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl App {
|
impl App {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
let (_stream, stream_handle) = OutputStream::try_default() //
|
let (stream, stream_handle) = OutputStream::try_default() //
|
||||||
.expect("Failed to create output stream");
|
.expect("Failed to create output stream");
|
||||||
|
let sink = Sink::try_new(&stream_handle).unwrap();
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
channels: Vec::new(),
|
channels: Vec::new(),
|
||||||
selected: 0,
|
selected: 0,
|
||||||
_stream,
|
_stream: (stream, stream_handle),
|
||||||
stream_handle,
|
sink,
|
||||||
|
playing: true,
|
||||||
|
volume: 20,
|
||||||
quit: false,
|
quit: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -81,23 +88,25 @@ impl App {
|
||||||
let ui_channel = UIChannel {
|
let ui_channel = UIChannel {
|
||||||
name: file.file_name().to_string_lossy().into(),
|
name: file.file_name().to_string_lossy().into(),
|
||||||
volume: 100,
|
volume: 100,
|
||||||
internal_volume,
|
volume_sync: internal_volume,
|
||||||
muted: false,
|
muted: false,
|
||||||
};
|
};
|
||||||
self.channels.push(ui_channel);
|
self.channels.push(ui_channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.stream_handle
|
self.sink.append(snoud);
|
||||||
.play_raw(snoud.convert_samples())
|
self.sink.play();
|
||||||
.unwrap();
|
self.change_vol(0);
|
||||||
|
|
||||||
terminal::enable_raw_mode().unwrap();
|
terminal::enable_raw_mode().unwrap();
|
||||||
stdout().execute(Clear(ClearType::All)).unwrap();
|
stdout().execute(Clear(ClearType::All)).unwrap();
|
||||||
|
stdout().execute(cursor::Hide).unwrap();
|
||||||
|
|
||||||
while !self.quit {
|
while !self.quit {
|
||||||
self.render();
|
self.render();
|
||||||
self.input();
|
self.input();
|
||||||
}
|
}
|
||||||
|
stdout().execute(cursor::Show).unwrap();
|
||||||
terminal::disable_raw_mode().unwrap();
|
terminal::disable_raw_mode().unwrap();
|
||||||
println!("Exiting");
|
println!("Exiting");
|
||||||
}
|
}
|
||||||
|
@ -105,7 +114,16 @@ impl App {
|
||||||
fn render(&mut self) {
|
fn render(&mut self) {
|
||||||
stdout().execute(MoveTo(0, 0)).unwrap();
|
stdout().execute(MoveTo(0, 0)).unwrap();
|
||||||
|
|
||||||
println!("Snoud - ambient sound player\n\r");
|
println!("Snoud - ambient sound player\r");
|
||||||
|
println!(
|
||||||
|
"Master volume: {:3}%, {:10}\n\r",
|
||||||
|
self.volume,
|
||||||
|
if self.playing {
|
||||||
|
"[Playing]"
|
||||||
|
} else {
|
||||||
|
"[Paused]"
|
||||||
|
}
|
||||||
|
);
|
||||||
for (i, channel) in self.channels.iter().enumerate() {
|
for (i, channel) in self.channels.iter().enumerate() {
|
||||||
println!(
|
println!(
|
||||||
"{selection} {name}:\r\n {volume:3.0}% {status:-<21}\r\n",
|
"{selection} {name}:\r\n {volume:3.0}% {status:-<21}\r\n",
|
||||||
|
@ -130,11 +148,7 @@ impl App {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let event = if let Ok(Event::Key(keyevent)) = event::read() {
|
let Ok(Event::Key(event)) = event::read() else { return };
|
||||||
keyevent
|
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
match event.code {
|
match event.code {
|
||||||
KeyCode::Char('q') => self.quit = true,
|
KeyCode::Char('q') => self.quit = true,
|
||||||
|
@ -142,7 +156,10 @@ impl App {
|
||||||
KeyCode::Down => self.select_next(),
|
KeyCode::Down => self.select_next(),
|
||||||
KeyCode::Right => self.channels[self.selected].change_vol(10),
|
KeyCode::Right => self.channels[self.selected].change_vol(10),
|
||||||
KeyCode::Left => self.channels[self.selected].change_vol(-10),
|
KeyCode::Left => self.channels[self.selected].change_vol(-10),
|
||||||
KeyCode::Char(' ' | 'm') => self.channels[self.selected].mute(),
|
KeyCode::Char('m') => self.channels[self.selected].mute(),
|
||||||
|
KeyCode::Char(' ') => self.mute(),
|
||||||
|
KeyCode::Char('.') => self.change_vol(5),
|
||||||
|
KeyCode::Char(',') => self.change_vol(-5),
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -157,4 +174,18 @@ impl App {
|
||||||
fn select_next(&mut self) {
|
fn select_next(&mut self) {
|
||||||
self.selected = (self.selected + 1) % self.channels.len();
|
self.selected = (self.selected + 1) % self.channels.len();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn change_vol(&mut self, amount: i32) {
|
||||||
|
self.volume += amount;
|
||||||
|
self.sink.set_volume(self.volume as f32 / 100.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mute(&mut self) {
|
||||||
|
self.playing = !self.playing;
|
||||||
|
if self.playing {
|
||||||
|
self.sink.play();
|
||||||
|
} else {
|
||||||
|
self.sink.pause();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue