Skip to content

Commit

Permalink
Merge pull request #69 from instaclustr/wavbrro-improvements
Browse files Browse the repository at this point in the history
Wavbrro improvements
  • Loading branch information
cjrolo authored Nov 14, 2023
2 parents 191fd84 + 3ccce65 commit a1dd95c
Show file tree
Hide file tree
Showing 5 changed files with 107 additions and 14 deletions.
6 changes: 3 additions & 3 deletions brro-compressor/src/compressor/fft.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use super::BinConfig;
use log::{error, debug, warn, info, trace};

const FFT_COMPRESSOR_ID: u8 = 15;
const DECIMAL_PRECISION: u8 = 5;

/// Struct to store frequencies, since bincode can't encode num_complex Complex format, this one is compatible
// This could be a Generic to support f64, integers, etc...
Expand Down Expand Up @@ -313,9 +314,8 @@ impl FFT {
// We need this for normalization
let len = frame_size as f32;
// We only need the real part
// TODO: Only 1 decimal place is sketchy!
let out_data = data.iter()
.map(|&f| self.round(f.re/len, 1))
.map(|&f| self.round(f.re/len, DECIMAL_PRECISION.into()))
.collect();
out_data
}
Expand Down Expand Up @@ -400,7 +400,7 @@ mod tests {
#[test]
fn test_to_lossy_data() {
let vector1 = vec![1.0, 1.0, 1.0, 1.0, 2.0, 1.0, 1.0, 1.0, 3.0, 1.0, 1.0, 5.0];
let lossy_vec = vec![1.0, 1.9, 2.3, 1.0, 1.8, 1.7, 1.8, 1.0, 2.8, 1.2, 1.0, 3.3];
let lossy_vec = vec![1.0, 1.87201, 2.25, 1.0, 1.82735, 1.689, 1.82735, 1.0, 2.75, 1.189, 1.0, 3.311];
let compressed_data = fft(&vector1);
let out = fft_to_data(vector1.len(), &compressed_data);
assert_eq!(lossy_vec, out);
Expand Down
10 changes: 9 additions & 1 deletion brro-compressor/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,14 @@ fn process_directory(arguments: &Args) -> Result<(), Box<dyn Error>> {
for entry in std::fs::read_dir(arguments.input.clone())? {
let path = entry?.path();
if path.is_file() {
match process_single_file(path.clone(), arguments) {
Ok (_) => continue,
//TODO: Files are created while this walks the dir, gives a funny output
//NOTE: Due to the way read_dir works, it seems we can't do much about this except collecting
// before and then iterating. But that might lead to a MASSIVE array. So it keeps a `funny` output
// output for the time beeing.
Err(err) => error!("{} File: {}", err, path.display()),
}
// We need to make sure we skip anything but BRO and WBRO, this can be done on single file processors
process_single_file(path, arguments)?;
}
Expand All @@ -60,7 +68,7 @@ fn process_single_file(mut file_path: PathBuf, arguments: &Args) -> Result<(), B
}
} else {
// Read an WavBRRO file and compress it
let data = WavBrro::from_file(&file_path);
let data = WavBrro::from_file(&file_path)?;
if arguments.verbose {
println!("Input={:?}", data);
}
Expand Down
6 changes: 6 additions & 0 deletions plot_data.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/bin/bash
filename=$1
target/debug/brro-compressor --compressor fft --error 1 --verbose ../../wbro-july/$filename.wbro > ../../$filename.m
target/debug/brro-compressor -u --verbose ../../wbro-july/$filename.bro >> ../../$filename.m
echo "plot(Input,'b', Output,'r')" >> ../../$filename.m
echo "print -dpng $filename.png" >> ../../$filename.m
8 changes: 4 additions & 4 deletions wavbrro/src/read.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ use std::fs::File;
use std::path::Path;

// Function to check if a file is a WAV file
pub fn is_wavbrro_file(file_path: &Path) -> bool {
pub fn is_wavbrro_file(file_path: &Path) -> io::Result<bool> {
// Open the file for reading and read the first 12 bytes (header) of the file
let mut file = fs::File::open(file_path).expect("Can't open file!");
let mut file = fs::File::open(file_path)?;
let mut header = [0u8; 12];
file.read_exact(&mut header).expect("File is too small!");
&header[0..4] == b"WBRO" && &header[8..12] == b"WBRO"
file.read_exact(&mut header)?;
Ok(&header[0..4] == b"WBRO" && &header[8..12] == b"WBRO")
}

pub fn read_wavbrro_file(file_path: &Path) -> io::Result<Vec<u8>> {
Expand Down
91 changes: 85 additions & 6 deletions wavbrro/src/wavbrro.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use rkyv::{Archive, Deserialize, Serialize};
use std::{io, fmt, result, error};
use std::path::Path;

use crate::read::{is_wavbrro_file, read_wavbrro_file};
Expand Down Expand Up @@ -83,12 +84,12 @@ impl WavBrro {

// This should be generic, but first implementation is going to be Vec f64
// TODO: This will panic left and right, make it right
pub fn from_file(file_path: &Path) -> Vec<f64> {
pub fn from_file(file_path: &Path) -> Result<Vec<f64>, Error> {
// Check if the header is correct
assert!(is_wavbrro_file(file_path));
let bytes = read_wavbrro_file(file_path).unwrap();
if !is_wavbrro_file(file_path)? {return Err(Error::FormatError);};
let bytes = read_wavbrro_file(file_path)?;
let obj = WavBrro::from_bytes(&bytes);
obj.get_samples()
Ok(obj.get_samples())
}

// TODO: This will panic left and right, make it right
Expand All @@ -114,6 +115,84 @@ impl WavBrro {

}

// Error class is based on https://codeberg.org/ruuda/hound/src/branch/master given the similarities
// between the formats (WAV and WAVBRRO).
#[derive(Debug)]
pub enum Error {
/// An IO error occured in the underlying reader or writer.
IoError(io::Error),
/// It's not WAVBRRO
FormatError,
/// The sample has more bits than the destination type.
///
/// When iterating using the `samples` iterator, this means that the
/// destination type (produced by the iterator) is not wide enough to hold
/// the sample. When writing, this means that the sample cannot be written,
/// because it requires more bits than the bits per sample specified.
TooWide,
/// The Sample format is not supported.
Unsupported,
/// The sample format is different than the destination format.
///
/// When iterating using the `samples` iterator, this means the destination
/// type (produced by the iterator) has a different sample format than the
/// samples in the wav file.
///
/// For example, this will occur if the user attempts to produce `i32`
/// samples (which have a `SampleFormat::Int`) from a wav file that
/// contains floating point data (`SampleFormat::Float`).
InvalidSampleFormat,
}

impl fmt::Display for Error {
fn fmt(&self, formatter: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
match *self {
Error::IoError(ref err) => err.fmt(formatter),
Error::FormatError => {
formatter.write_str("Wrong WAVBRRO file!")
}
Error::TooWide => {
formatter.write_str("The sample has more bits than the destination type.")
}
Error::Unsupported => {
formatter.write_str("The WAVBRRO format of the file is not supported.")
}
Error::InvalidSampleFormat => {
formatter.write_str("The sample format differs from the destination format.")
}
}
}
}

impl From<io::Error> for Error {
fn from(err: io::Error) -> Error {
Error::IoError(err)
}
}

impl error::Error for Error {
fn description(&self) -> &str {
match *self {
// TODO: I don't know if this is actually the right way to do!
Error::IoError(ref _err) => "IO Error",
Error::TooWide => "the sample has more bits than the destination type",
Error::Unsupported => "the wave format of the file is not supported",
Error::InvalidSampleFormat => "the sample format differs from the destination format",
Error::FormatError => "the file is not of the WAVBRRO format",
}
}

fn cause(&self) -> Option<&dyn error::Error> {
match *self {
Error::IoError(ref err) => Some(err),
Error::TooWide => None,
Error::Unsupported => None,
Error::InvalidSampleFormat => None,
Error::FormatError => None,
}
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down Expand Up @@ -152,7 +231,7 @@ mod tests {
wb.add_sample(3.0);
wb.to_file(path);
let result = is_wavbrro_file(path);
assert!(result);
assert!(result.unwrap());
std::fs::remove_file(path).expect("Failed to remove temporary file");
}

Expand All @@ -165,7 +244,7 @@ mod tests {
wb.add_sample(3.0);
wb.to_file(path);
let data = WavBrro::from_file(path);
assert_eq!(data, [1.0, 2.0, 3.0]);
assert_eq!(data.unwrap(), [1.0, 2.0, 3.0]);
std::fs::remove_file(path).expect("Failed to remove temporary file");
}
}

0 comments on commit a1dd95c

Please sign in to comment.