Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

77 files are truncated to about an hour #79

Merged
merged 5 commits into from
Nov 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ edition = "2021"
[dependencies]
keepawake = "0.4.3"
rustfft = "6.0.1"
wave_stream = "0.3.0"
wave_stream = "0.5.0"
# Uncomment to test pre-release changes
# wave_stream = { git = "https://github.com/GWBasic/wave_stream.git", branch = "28-support-51-and-other-channel-layouts" }
120 changes: 100 additions & 20 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
use std::ffi::OsStr;
use std::path::Path;

use wave_stream::open_wav::OpenWav;
use wave_stream::wave_header::{Channels, SampleFormat, WavHeader};
use wave_stream::{read_wav_from_file_path, write_wav_to_file_path};
Expand Down Expand Up @@ -62,47 +65,124 @@ fn main() {
sample_rate: source_wav.sample_rate(),
};

let open_target_wav_result = write_wav_to_file_path(&options.target_wav_path, header);
// Wave files have a max size of 4GB. (Due to RIFF using 32 bits to track its size.) It's very easy to exceed this length
// when upmixing a file over (approximately) 58 minutes in length. 6 channels @ 32 bits / sample (float) adds up quickly

let target_wav = match open_target_wav_result {
Err(error) => {
println!(
"Can not open {}: {:?}",
&options.target_wav_path.display(),
error
let max_samples_in_file = header.max_samples();
let mut num_target_files = source_wav.len_samples() / max_samples_in_file;
if source_wav.len_samples() % max_samples_in_file > 0 {
num_target_files += 1;
}

let mut target_paths = Vec::with_capacity(num_target_files);
let mut target_open_wav_writers = Vec::with_capacity(num_target_files);

if num_target_files > 1 {
// Need to update the path if there are multiple targets
let file_stem = match options.target_wav_path.file_stem() {
Some(file_stem) => file_stem,
None => {
println!(
"Not a valid filename: {}",
options.target_wav_path.display()
);
return;
}
};
let extension = options
.target_wav_path
.extension()
.unwrap_or(OsStr::new("wav"));
let folder = options.target_wav_path.parent().unwrap_or(&Path::new("/"));

for file_ctr in 1..(num_target_files + 1) {
let target_wav_filename_string = format!(
"{} - {} of {}.{}",
file_stem.to_string_lossy(),
file_ctr,
num_target_files,
extension.to_string_lossy()
);
return;

let target_wav_path = folder.join(target_wav_filename_string);

let open_target_wav_result = write_wav_to_file_path(&target_wav_path, header);

let target_wav = match open_target_wav_result {
Err(error) => {
println!("Can not open {}: {:?}", &target_wav_path.display(), error);
return;
}
Ok(target_wav) => target_wav,
};

target_open_wav_writers.push(target_wav);
target_paths.push(target_wav_path);
}
Ok(target_wav) => target_wav,
};
} else {
let open_target_wav_result = write_wav_to_file_path(&options.target_wav_path, header);

let target_wav = match open_target_wav_result {
Err(error) => {
println!(
"Can not open {}: {:?}",
&options.target_wav_path.display(),
error
);
return;
}
Ok(target_wav) => target_wav,
};

target_open_wav_writers.push(target_wav);
target_paths.push(options.target_wav_path.to_path_buf());
}

let length_seconds = (source_wav.len_samples() as f64) / (source_wav.sample_rate() as f64);
println!(
"\tSource: {}, {} seconds long",
&options.source_wav_path.display(),
length_seconds
);
println!("\tTarget: {}", &options.target_wav_path.display());

if target_paths.len() == 1 {
println!("\tTarget: {}", target_paths[0].display());
} else {
println!("\tTargets:");
for target_path in target_paths {
println!("\t\t{}", target_path.display());
}
}

let mut _keepawake = if options.keep_awake {
let reason = format!(
"De-matrixing {} to {}",
&options.source_wav_path.display(),
&options.target_wav_path.display()
);
Some(
keepawake::Builder::new()
.display(false)
.idle(true)
.app_name("soft_matrix")
.reason(reason)
.app_reverse_domain("io.github.gwbasic.soft_matrix"),
)

let awake_handle = match keepawake::Builder::new()
.display(false)
.idle(true)
.sleep(true)
.app_name("soft_matrix")
.reason(reason)
.app_reverse_domain("io.github.gwbasic.soft_matrix")
.create()
{
Ok(awake_handle) => awake_handle,
Err(error) => {
println!("Cannot keep the computer awake: {}", error);
return;
}
};

Some(awake_handle)
} else {
None
};

match upmix(options, source_wav, target_wav) {
match upmix(options, source_wav, target_open_wav_writers) {
Err(error) => {
println!("Error upmixing: {:?}", error);
}
Expand Down
28 changes: 19 additions & 9 deletions src/panner_and_writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,13 @@ pub struct PannerAndWriter {
fft_inverse: Arc<dyn Fft<f32>>,

lfe_levels: Option<Vec<f32>>,

max_samples_in_file: usize,
}

// Wraps types used during writing so they can be within a mutex
struct WriterState {
pub target_wav_writer: RandomAccessWavWriter<f32>,
pub target_random_access_wav_writers: Vec<RandomAccessWavWriter<f32>>,
pub total_samples_written: usize,
}

Expand All @@ -41,8 +43,9 @@ impl PannerAndWriter {
options: &Options,
window_size: usize,
sample_rate: usize,
target_wav_writer: RandomAccessWavWriter<f32>,
target_random_access_wav_writers: Vec<RandomAccessWavWriter<f32>>,
fft_inverse: Arc<dyn Fft<f32>>,
max_samples_in_file: usize,
) -> PannerAndWriter {
let lfe_levels = if options.channels.low_frequency {
let mut lfe_levels = vec![0.0f32; window_size];
Expand Down Expand Up @@ -84,11 +87,12 @@ impl PannerAndWriter {
PannerAndWriter {
transformed_window_and_averaged_pans_queue: Mutex::new(VecDeque::new()),
writer_state: Mutex::new(WriterState {
target_wav_writer,
target_random_access_wav_writers,
total_samples_written: 0,
}),
fft_inverse,
lfe_levels,
max_samples_in_file,
}
}

Expand Down Expand Up @@ -411,9 +415,11 @@ impl PannerAndWriter {
None => {}
}

writer_state
.target_wav_writer
.write_samples(sample_ctr, samples_by_channel)?;
let out_file_index = sample_ctr / self.max_samples_in_file;
let sample_ctr_in_file = sample_ctr - (self.max_samples_in_file * out_file_index);

writer_state.target_random_access_wav_writers[out_file_index]
.write_samples(sample_ctr_in_file, samples_by_channel)?;

writer_state.total_samples_written += 1;

Expand All @@ -427,8 +433,12 @@ impl Drop for PannerAndWriter {
self.writer_state
.lock()
.expect("Cannot aquire lock because a thread panicked")
.target_wav_writer
.flush()
.expect("Can not flush writer");
.target_random_access_wav_writers
.iter_mut()
.for_each(|target_random_access_wav_writer| {
target_random_access_wav_writer
.flush()
.expect("Can not flush writer")
});
}
}
14 changes: 11 additions & 3 deletions src/upmixer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ unsafe impl Sync for Upmixer {}
pub fn upmix<TReader: 'static + Read + Seek>(
options: Options,
source_wav_reader: OpenWavReader<TReader>,
target_wav_writer: OpenWavWriter,
target_open_wav_writers: Vec<OpenWavWriter>,
) -> Result<()> {
let max_low_frequency = (source_wav_reader.sample_rate() / 8) as f32;
if options.low_frequency >= max_low_frequency {
Expand Down Expand Up @@ -83,7 +83,14 @@ pub fn upmix<TReader: 'static + Read + Seek>(
}

let source_wav_reader = source_wav_reader.get_stream_f32_reader()?;
let target_wav_writer = target_wav_writer.get_random_access_f32_writer()?;
let mut target_random_access_wav_writers = Vec::with_capacity(target_open_wav_writers.len());
for target_open_wav_writer in target_open_wav_writers {
target_random_access_wav_writers
.push(target_open_wav_writer.get_random_access_f32_writer()?);
}

let max_samples_in_file =
(source_wav_reader.info().len_samples() / target_random_access_wav_writers.len()) + 1;

// rustfft states that the scale is 1/len()
// See "noramlization": https://docs.rs/rustfft/latest/rustfft/#normalization
Expand All @@ -103,8 +110,9 @@ pub fn upmix<TReader: 'static + Read + Seek>(
&options,
window_size,
sample_rate,
target_wav_writer,
target_random_access_wav_writers,
fft_inverse,
max_samples_in_file,
);

let mut stdout = stdout();
Expand Down
Loading