Added errors to ui
ci/woodpecker/push/woodpecker Pipeline was successful Details

This commit is contained in:
Sebastian 2022-02-20 20:36:21 +01:00
parent a07a522cf3
commit 96a89f3091
7 changed files with 87 additions and 28 deletions

1
Cargo.lock generated
View File

@ -73,6 +73,7 @@ dependencies = [
"hound", "hound",
"image", "image",
"rfd", "rfd",
"thiserror",
] ]
[[package]] [[package]]

View File

@ -8,3 +8,4 @@ hound = "*"
image = "0.24.0" image = "0.24.0"
eframe = "0.16.0" eframe = "0.16.0"
rfd = "0.7.0" rfd = "0.7.0"
thiserror = "1.0.30"

View File

@ -2,6 +2,7 @@ use std::path::Path;
use amdemod::SquaringAMDemodulator; use amdemod::SquaringAMDemodulator;
use aptsyncer::{APTSyncer, SyncedSample}; use aptsyncer::{APTSyncer, SyncedSample};
use errors::DecoderError;
use firfilter::FIRFilter; use firfilter::FIRFilter;
use resamplers::{Downsampler, Upsampler}; use resamplers::{Downsampler, Upsampler};
use utils::float_sample_iterator; use utils::float_sample_iterator;
@ -75,12 +76,16 @@ const LOWPASS_COEFFS: [f32; 63] = [
-7.383784e-03, -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 where
T: Fn(f32, image::RgbaImage) -> (bool, u32), T: Fn(f32, image::RgbaImage) -> (bool, u32),
{ {
let mut reader = hound::WavReader::open(input_file) let mut reader =
.map_err(|err| format!("Could not open inputfile: {}", err))?; hound::WavReader::open(input_file).map_err(|err| DecoderError::InputFileError(err))?;
if reader.spec().channels != 1 { if reader.spec().channels != 1 {
panic!("Expected a mono file"); panic!("Expected a mono file");
@ -88,7 +93,7 @@ where
let sample_rate = reader.spec().sample_rate; let sample_rate = reader.spec().sample_rate;
if sample_rate != 48000 { if sample_rate != 48000 {
return Err("Expected a 48kHz sample rate".to_owned()); return Err(DecoderError::UnexpectedSamplingRate(sample_rate));
} }
let sample_count = reader.len(); let sample_count = reader.len();
@ -186,7 +191,7 @@ where
progress_update(1.0, img.to_rgba8()); progress_update(1.0, img.to_rgba8());
img.save_with_format(&Path::new(output_file), image::ImageFormat::Png) 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(()) Ok(())
} }

18
src/errors.rs Normal file
View File

@ -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,
}

View File

@ -4,10 +4,12 @@ extern crate eframe;
extern crate hound; extern crate hound;
extern crate image; extern crate image;
extern crate rfd; extern crate rfd;
extern crate thiserror;
mod amdemod; mod amdemod;
mod aptsyncer; mod aptsyncer;
mod decoder; mod decoder;
mod errors;
mod firfilter; mod firfilter;
mod resamplers; mod resamplers;
mod ui; mod ui;

View File

@ -6,6 +6,7 @@ use eframe::egui::{Color32, RichText};
use eframe::{egui, epi}; use eframe::{egui, epi};
use decoder; use decoder;
use errors::DecoderError;
#[derive(PartialEq)] #[derive(PartialEq)]
enum DecoderRunState { enum DecoderRunState {
@ -19,6 +20,7 @@ struct DecoderJobState {
progress: f32, progress: f32,
texture: Option<egui::TextureId>, texture: Option<egui::TextureId>,
run_state: DecoderRunState, run_state: DecoderRunState,
error: Option<DecoderError>,
} }
impl DecoderJobState { impl DecoderJobState {
@ -34,6 +36,7 @@ impl Default for DecoderJobState {
progress: 0.0, progress: 0.0,
texture: None, texture: None,
run_state: DecoderRunState::DONE, run_state: DecoderRunState::DONE,
error: None,
} }
} }
} }
@ -132,32 +135,43 @@ impl epi::App for DecoderApp {
let decoding_state = decoding_state.clone(); let decoding_state = decoding_state.clone();
let input_path = input_path.clone(); let input_path = input_path.clone();
let output_path = output_path.clone(); let output_path = output_path.clone();
state.error = None;
state.run_state = DecoderRunState::RUNNING; state.run_state = DecoderRunState::RUNNING;
if let Some(old_texture) = state.texture {
frame.free_texture(old_texture);
}
state.texture = None;
std::thread::spawn(move || { std::thread::spawn(move || {
decoder::decode(&input_path, &output_path, |progress, image| { let decoder_res =
let mut state = decoding_state.lock().unwrap(); 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 size = [image.width() as _, image.height() as _];
let epi_img = epi::Image::from_rgba_unmultiplied( let epi_img = epi::Image::from_rgba_unmultiplied(
size, size,
image.as_flat_samples().as_slice(), image.as_flat_samples().as_slice(),
); );
if let Some(old_texture) = state.texture { if let Some(old_texture) = state.texture {
frame.free_texture(old_texture); frame.free_texture(old_texture);
} }
state.texture = Some(frame.alloc_texture(epi_img)); state.texture = Some(frame.alloc_texture(epi_img));
frame.request_repaint(); frame.request_repaint();
return (state.is_running(), state.update_steps); return (state.is_running(), state.update_steps);
}) });
.unwrap();
let mut state = decoding_state.lock().unwrap(); let mut state = decoding_state.lock().unwrap();
state.run_state = DecoderRunState::DONE; state.run_state = DecoderRunState::DONE;
state.error = match decoder_res {
Err(err) => Some(err),
_ => None,
};
frame.request_repaint(); frame.request_repaint();
}); });
@ -175,6 +189,11 @@ impl epi::App for DecoderApp {
let progressbar = ProgressBar::new(state.progress).show_percentage(); let progressbar = ProgressBar::new(state.progress).show_percentage();
ui.add(progressbar); ui.add(progressbar);
ui.end_row();
if let Some(err) = &state.error {
ui.label(RichText::new(err.to_string()).color(Color32::RED));
};
ui.separator(); ui.separator();

View File

@ -4,15 +4,28 @@ extern crate hound;
type FileReader = std::io::BufReader<std::fs::File>; type FileReader = std::io::BufReader<std::fs::File>;
pub fn float_sample_iterator<'a>(reader: &'a mut hound::WavReader<FileReader>) pub fn float_sample_iterator<'a>(
-> Box<Iterator<Item=f32> + 'a> { reader: &'a mut hound::WavReader<FileReader>,
) -> Box<Iterator<Item = f32> + 'a> {
match reader.spec().sample_format { match reader.spec().sample_format {
hound::SampleFormat::Float => Box::new(reader.samples::<f32>().map(|x| x.unwrap())), hound::SampleFormat::Float => Box::new(reader.samples::<f32>().map(|x| x.unwrap())),
hound::SampleFormat::Int => match reader.spec().bits_per_sample { 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))), 8 => Box::new(
16 => Box::new(reader.samples::<i16>().map(|x| (x.unwrap() as f32) / (i16::max_value() as f32))), reader
32 => Box::new(reader.samples::<i32>().map(|x| (x.unwrap() as f32) / (i32::max_value() as f32))), .samples::<i8>()
_ => panic!("Unsupported sample rate") .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"),
},
} }
} }