Get rust annotator playing sound (if garbled)
This commit is contained in:
parent
775c039e03
commit
a644ad5b0b
2 changed files with 82 additions and 54 deletions
|
@ -5,4 +5,7 @@ edition = "2021"
|
|||
|
||||
[dependencies]
|
||||
clap = { version = "4.3.0", features = ["derive"] }
|
||||
cpal = "0.15.2"
|
||||
crossterm = "0.26.1"
|
||||
magic = "0.13.0"
|
||||
minimp3 = "0.5.1"
|
||||
|
|
133
src/main.rs
133
src/main.rs
|
@ -1,9 +1,14 @@
|
|||
use std::fs::File;
|
||||
use std::path::PathBuf;
|
||||
use std::process::exit;
|
||||
|
||||
use clap::{Parser, Subcommand};
|
||||
use clap::Parser;
|
||||
use cpal::traits::{DeviceTrait, StreamTrait};
|
||||
use cpal::{self, traits::HostTrait};
|
||||
use cpal::{OutputCallbackInfo, Stream, StreamConfig};
|
||||
use crossterm::event::{Event, KeyCode, KeyModifiers};
|
||||
use crossterm::terminal::{disable_raw_mode, enable_raw_mode};
|
||||
use minimp3::{Decoder, Frame};
|
||||
|
||||
use std::sync::mpsc;
|
||||
use std::sync::mpsc::{Receiver, Sender};
|
||||
|
@ -12,29 +17,7 @@ use std::thread;
|
|||
#[derive(Parser)]
|
||||
#[command(author, version, about, long_about = None)]
|
||||
struct Cli {
|
||||
/// Optional name to operate on
|
||||
name: Option<String>,
|
||||
|
||||
/// Sets a custom config file
|
||||
#[arg(short, long, value_name = "FILE")]
|
||||
config: Option<PathBuf>,
|
||||
|
||||
/// Turn debugging information on
|
||||
#[arg(short, long, action = clap::ArgAction::Count)]
|
||||
debug: u8,
|
||||
|
||||
#[command(subcommand)]
|
||||
command: Option<Commands>,
|
||||
}
|
||||
|
||||
#[derive(Subcommand)]
|
||||
enum Commands {
|
||||
/// does testing things
|
||||
Test {
|
||||
/// lists test values
|
||||
#[arg(short, long)]
|
||||
list: bool,
|
||||
},
|
||||
path: Vec<PathBuf>,
|
||||
}
|
||||
|
||||
/// Input thread commands sent to main thread
|
||||
|
@ -47,41 +30,19 @@ enum Command {
|
|||
NextFile,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
fn main() -> Result<(), magic::MagicError> {
|
||||
let cli = Cli::parse();
|
||||
|
||||
// You can check the value provided by positional arguments, or option arguments
|
||||
if let Some(name) = cli.name.as_deref() {
|
||||
println!("Value for name: {name}");
|
||||
}
|
||||
let cookie = magic::Cookie::open(magic::CookieFlags::MIME_TYPE)?;
|
||||
cookie.load(&vec!["/usr/share/misc/magic.mgc"])?;
|
||||
|
||||
if let Some(config_path) = cli.config.as_deref() {
|
||||
println!("Value for config: {}", config_path.display());
|
||||
}
|
||||
let host = cpal::default_host();
|
||||
|
||||
// You can see how many times a particular flag or argument occurred
|
||||
// Note, only flags can have multiple occurrences
|
||||
match cli.debug {
|
||||
0 => println!("Debug mode is off"),
|
||||
1 => println!("Debug mode is kind of on"),
|
||||
2 => println!("Debug mode is on"),
|
||||
_ => println!("Don't be crazy"),
|
||||
}
|
||||
let device = host
|
||||
.default_output_device()
|
||||
.expect("failed to find output device");
|
||||
|
||||
// You can check for the existence of subcommands, and if found use their
|
||||
// matches just as you would the top level cmd
|
||||
match &cli.command {
|
||||
Some(Commands::Test { list }) => {
|
||||
if *list {
|
||||
println!("Printing testing lists...");
|
||||
} else {
|
||||
println!("Not printing testing lists...");
|
||||
}
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
|
||||
// Continued program logic goes here...
|
||||
let config: StreamConfig = device.default_output_config().unwrap().into();
|
||||
|
||||
let (input_tx, input_rx): (Sender<Command>, Receiver<Command>) = mpsc::channel();
|
||||
|
||||
|
@ -105,7 +66,71 @@ fn main() {
|
|||
}
|
||||
});
|
||||
|
||||
let mut path_iter = cli.path.into_iter();
|
||||
|
||||
let mut stream: Option<Stream> = None;
|
||||
|
||||
loop {
|
||||
while stream.is_none() {
|
||||
let path = path_iter
|
||||
.find(|path| cookie.file(&path).unwrap() == "audio/mpeg")
|
||||
.unwrap();
|
||||
// let path = path_iter.next().unwrap();
|
||||
|
||||
// let mime_type = cookie.file(&path)?;
|
||||
// println!("Mime type: {}", mime_type);
|
||||
|
||||
println!("MP3 file: {}", path.display());
|
||||
|
||||
let file = File::open(path).unwrap();
|
||||
|
||||
let mut mp3dec = Decoder::new(file);
|
||||
|
||||
let mut mp3frame: Option<Frame> = None;
|
||||
|
||||
let mut mp3frame_idx: usize = 0;
|
||||
|
||||
let _stream = device
|
||||
.build_output_stream(
|
||||
&config,
|
||||
move |data: &mut [i16], _: &OutputCallbackInfo| {
|
||||
// write_data(data, channels, &mut next_value)
|
||||
|
||||
if mp3frame.is_none()
|
||||
|| mp3frame_idx >= mp3frame.as_ref().unwrap().data.len()
|
||||
{
|
||||
mp3frame = Some(mp3dec.next_frame().unwrap());
|
||||
mp3frame_idx = 0;
|
||||
}
|
||||
|
||||
for out_frame in data.chunks_mut(2) {
|
||||
out_frame[0] = mp3frame
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.data
|
||||
.get(mp3frame_idx)
|
||||
.copied()
|
||||
.unwrap_or(0);
|
||||
out_frame[1] = mp3frame
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.data
|
||||
.get(mp3frame_idx + 1)
|
||||
.copied()
|
||||
.unwrap_or(0);
|
||||
|
||||
mp3frame_idx += 2;
|
||||
}
|
||||
},
|
||||
|err| {},
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
_stream.play().unwrap();
|
||||
|
||||
stream = Some(_stream);
|
||||
}
|
||||
|
||||
// Block main thread and react to commands received
|
||||
let cmd = input_rx.recv();
|
||||
println!("{:?}", cmd);
|
||||
|
|
Loading…
Reference in a new issue