Added errors to ui
ci/woodpecker/push/woodpecker Pipeline was successful
Details
ci/woodpecker/push/woodpecker Pipeline was successful
Details
This commit is contained in:
parent
a07a522cf3
commit
96a89f3091
|
@ -73,6 +73,7 @@ dependencies = [
|
|||
"hound",
|
||||
"image",
|
||||
"rfd",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
@ -8,3 +8,4 @@ hound = "*"
|
|||
image = "0.24.0"
|
||||
eframe = "0.16.0"
|
||||
rfd = "0.7.0"
|
||||
thiserror = "1.0.30"
|
||||
|
|
|
@ -2,6 +2,7 @@ use std::path::Path;
|
|||
|
||||
use amdemod::SquaringAMDemodulator;
|
||||
use aptsyncer::{APTSyncer, SyncedSample};
|
||||
use errors::DecoderError;
|
||||
use firfilter::FIRFilter;
|
||||
use resamplers::{Downsampler, Upsampler};
|
||||
use utils::float_sample_iterator;
|
||||
|
@ -75,12 +76,16 @@ const LOWPASS_COEFFS: [f32; 63] = [
|
|||
-7.383784e-03,
|
||||
];
|
||||
|
||||
pub fn decode<T>(input_file: &str, output_file: &str, progress_update: T) -> Result<(), String>
|
||||
pub fn decode<T>(
|
||||
input_file: &str,
|
||||
output_file: &str,
|
||||
progress_update: T,
|
||||
) -> Result<(), DecoderError>
|
||||
where
|
||||
T: Fn(f32, image::RgbaImage) -> (bool, u32),
|
||||
{
|
||||
let mut reader = hound::WavReader::open(input_file)
|
||||
.map_err(|err| format!("Could not open inputfile: {}", err))?;
|
||||
let mut reader =
|
||||
hound::WavReader::open(input_file).map_err(|err| DecoderError::InputFileError(err))?;
|
||||
|
||||
if reader.spec().channels != 1 {
|
||||
panic!("Expected a mono file");
|
||||
|
@ -88,7 +93,7 @@ where
|
|||
|
||||
let sample_rate = reader.spec().sample_rate;
|
||||
if sample_rate != 48000 {
|
||||
return Err("Expected a 48kHz sample rate".to_owned());
|
||||
return Err(DecoderError::UnexpectedSamplingRate(sample_rate));
|
||||
}
|
||||
|
||||
let sample_count = reader.len();
|
||||
|
@ -186,7 +191,7 @@ where
|
|||
progress_update(1.0, img.to_rgba8());
|
||||
|
||||
img.save_with_format(&Path::new(output_file), image::ImageFormat::Png)
|
||||
.map_err(|err| format!("Could not save outputfile: {}", err))?;
|
||||
.map_err(|err| DecoderError::OutputFileError(err))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
use hound;
|
||||
use image;
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum DecoderError {
|
||||
#[error("Unable to read input file: {0}")]
|
||||
InputFileError(#[from] hound::Error),
|
||||
|
||||
#[error("Expected a sampling rate of 48000Hz not {0}Hz")]
|
||||
UnexpectedSamplingRate(u32),
|
||||
|
||||
#[error("Unable to write output file: {0}")]
|
||||
OutputFileError(#[from] image::ImageError),
|
||||
|
||||
#[error("FIXME: Unknown decoder error")]
|
||||
Unknown,
|
||||
}
|
|
@ -4,10 +4,12 @@ extern crate eframe;
|
|||
extern crate hound;
|
||||
extern crate image;
|
||||
extern crate rfd;
|
||||
extern crate thiserror;
|
||||
|
||||
mod amdemod;
|
||||
mod aptsyncer;
|
||||
mod decoder;
|
||||
mod errors;
|
||||
mod firfilter;
|
||||
mod resamplers;
|
||||
mod ui;
|
||||
|
|
51
src/ui.rs
51
src/ui.rs
|
@ -6,6 +6,7 @@ use eframe::egui::{Color32, RichText};
|
|||
use eframe::{egui, epi};
|
||||
|
||||
use decoder;
|
||||
use errors::DecoderError;
|
||||
|
||||
#[derive(PartialEq)]
|
||||
enum DecoderRunState {
|
||||
|
@ -19,6 +20,7 @@ struct DecoderJobState {
|
|||
progress: f32,
|
||||
texture: Option<egui::TextureId>,
|
||||
run_state: DecoderRunState,
|
||||
error: Option<DecoderError>,
|
||||
}
|
||||
|
||||
impl DecoderJobState {
|
||||
|
@ -34,6 +36,7 @@ impl Default for DecoderJobState {
|
|||
progress: 0.0,
|
||||
texture: None,
|
||||
run_state: DecoderRunState::DONE,
|
||||
error: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -132,32 +135,43 @@ impl epi::App for DecoderApp {
|
|||
let decoding_state = decoding_state.clone();
|
||||
let input_path = input_path.clone();
|
||||
let output_path = output_path.clone();
|
||||
|
||||
state.error = None;
|
||||
state.run_state = DecoderRunState::RUNNING;
|
||||
if let Some(old_texture) = state.texture {
|
||||
frame.free_texture(old_texture);
|
||||
}
|
||||
state.texture = None;
|
||||
|
||||
std::thread::spawn(move || {
|
||||
decoder::decode(&input_path, &output_path, |progress, image| {
|
||||
let mut state = decoding_state.lock().unwrap();
|
||||
let decoder_res =
|
||||
decoder::decode(&input_path, &output_path, |progress, image| {
|
||||
let mut state = decoding_state.lock().unwrap();
|
||||
|
||||
state.progress = progress;
|
||||
state.progress = progress;
|
||||
|
||||
let size = [image.width() as _, image.height() as _];
|
||||
let epi_img = epi::Image::from_rgba_unmultiplied(
|
||||
size,
|
||||
image.as_flat_samples().as_slice(),
|
||||
);
|
||||
let size = [image.width() as _, image.height() as _];
|
||||
let epi_img = epi::Image::from_rgba_unmultiplied(
|
||||
size,
|
||||
image.as_flat_samples().as_slice(),
|
||||
);
|
||||
|
||||
if let Some(old_texture) = state.texture {
|
||||
frame.free_texture(old_texture);
|
||||
}
|
||||
state.texture = Some(frame.alloc_texture(epi_img));
|
||||
if let Some(old_texture) = state.texture {
|
||||
frame.free_texture(old_texture);
|
||||
}
|
||||
state.texture = Some(frame.alloc_texture(epi_img));
|
||||
|
||||
frame.request_repaint();
|
||||
frame.request_repaint();
|
||||
|
||||
return (state.is_running(), state.update_steps);
|
||||
})
|
||||
.unwrap();
|
||||
return (state.is_running(), state.update_steps);
|
||||
});
|
||||
|
||||
let mut state = decoding_state.lock().unwrap();
|
||||
state.run_state = DecoderRunState::DONE;
|
||||
state.error = match decoder_res {
|
||||
Err(err) => Some(err),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
frame.request_repaint();
|
||||
});
|
||||
|
@ -175,6 +189,11 @@ impl epi::App for DecoderApp {
|
|||
|
||||
let progressbar = ProgressBar::new(state.progress).show_percentage();
|
||||
ui.add(progressbar);
|
||||
ui.end_row();
|
||||
|
||||
if let Some(err) = &state.error {
|
||||
ui.label(RichText::new(err.to_string()).color(Color32::RED));
|
||||
};
|
||||
|
||||
ui.separator();
|
||||
|
||||
|
|
27
src/utils.rs
27
src/utils.rs
|
@ -4,15 +4,28 @@ extern crate hound;
|
|||
|
||||
type FileReader = std::io::BufReader<std::fs::File>;
|
||||
|
||||
pub fn float_sample_iterator<'a>(reader: &'a mut hound::WavReader<FileReader>)
|
||||
-> Box<Iterator<Item=f32> + 'a> {
|
||||
pub fn float_sample_iterator<'a>(
|
||||
reader: &'a mut hound::WavReader<FileReader>,
|
||||
) -> Box<Iterator<Item = f32> + 'a> {
|
||||
match reader.spec().sample_format {
|
||||
hound::SampleFormat::Float => Box::new(reader.samples::<f32>().map(|x| x.unwrap())),
|
||||
hound::SampleFormat::Int => match reader.spec().bits_per_sample {
|
||||
8 => Box::new(reader.samples::<i8>().map(|x| (x.unwrap() as f32) / (i16::max_value() as f32))),
|
||||
16 => Box::new(reader.samples::<i16>().map(|x| (x.unwrap() as f32) / (i16::max_value() as f32))),
|
||||
32 => Box::new(reader.samples::<i32>().map(|x| (x.unwrap() as f32) / (i32::max_value() as f32))),
|
||||
_ => panic!("Unsupported sample rate")
|
||||
}
|
||||
8 => Box::new(
|
||||
reader
|
||||
.samples::<i8>()
|
||||
.map(|x| (x.unwrap() as f32) / (i16::max_value() as f32)),
|
||||
),
|
||||
16 => Box::new(
|
||||
reader
|
||||
.samples::<i16>()
|
||||
.map(|x| (x.unwrap() as f32) / (i16::max_value() as f32)),
|
||||
),
|
||||
32 => Box::new(
|
||||
reader
|
||||
.samples::<i32>()
|
||||
.map(|x| (x.unwrap() as f32) / (i32::max_value() as f32)),
|
||||
),
|
||||
_ => panic!("Unsupported sample format"),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue