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

[wip] Implement reverse file reading #17

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
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 core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::time;
pub mod read;
pub mod write;

pub use read::{DataBlock, Decoder, ReadDiskStream, ReadStreamOptions, SeekMode};
pub use read::{DataBlock, Decoder, DecoderReadDirection, ReadDiskStream, ReadStreamOptions, SeekMode};
pub use write::{Encoder, WriteBlock, WriteDiskStream, WriteStatus, WriteStreamOptions};

const SERVER_WAIT_TIME: time::Duration = time::Duration::from_millis(1);
Expand Down
8 changes: 8 additions & 0 deletions core/src/read/decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ use std::{error::Error, fmt::Debug};
use super::DataBlock;
use crate::FileInfo;

pub enum DecoderReadDirection {
Forward,
Backward
}

/// A type that decodes a file in a read stream.
pub trait Decoder: Sized + 'static {
/// The data type of a single sample. (i.e. `f32`)
Expand Down Expand Up @@ -48,6 +53,9 @@ pub trait Decoder: Sized + 'static {
additional_opts: Self::AdditionalOpts,
) -> Result<(Self, FileInfo<Self::FileParams>), Self::OpenError>;

/// Change the read direction. This allows reverse playback.
fn direction(&mut self, direction: DecoderReadDirection);

/// Seek to a frame in the file. If a frame lies outside of the end of the file,
/// set the read position the end of the file instead of returning an error.
fn seek(&mut self, frame: usize) -> Result<(), Self::FatalError>;
Expand Down
2 changes: 1 addition & 1 deletion core/src/read/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ mod server;
pub mod error;

pub use data::{DataBlock, ReadData};
pub use decoder::Decoder;
pub use decoder::{Decoder, DecoderReadDirection};
pub use error::{FatalReadError, ReadError};
pub use read_stream::{ReadDiskStream, SeekMode};

Expand Down
2 changes: 0 additions & 2 deletions core/src/read/read_stream.rs
Original file line number Diff line number Diff line change
Expand Up @@ -751,8 +751,6 @@ impl<D: Decoder> ReadDiskStream<D> {

// Check if the end of the file was reached.
if self.playhead() >= self.file_info.num_frames {
self.current_block_start_frame = 0;
self.current_frame_in_block = 0;
return Err(ReadError::EndOfFile);
}
let mut reached_end_of_file = false;
Expand Down
119 changes: 103 additions & 16 deletions decode_symphonia/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use symphonia::core::meta::MetadataOptions;
use symphonia::core::probe::Hint;
use symphonia::core::units::Duration;

use creek_core::{DataBlock, Decoder, FileInfo};
use creek_core::{DataBlock, Decoder, FileInfo, DecoderReadDirection};

mod error;
pub use error::OpenError;
Expand All @@ -29,6 +29,7 @@ pub struct SymphoniaDecoder {

current_frame: usize,
reset_smp_buffer: bool,
direction: DecoderReadDirection
}

impl Decoder for SymphoniaDecoder {
Expand Down Expand Up @@ -159,11 +160,17 @@ impl Decoder for SymphoniaDecoder {

current_frame: start_frame,
reset_smp_buffer: false,
direction: DecoderReadDirection::Forward,
},
file_info,
))
}


fn direction(&mut self, direction: DecoderReadDirection) {
self.direction = direction;
}

fn seek(&mut self, frame: usize) -> Result<(), Self::FatalError> {
if frame >= self.num_frames {
// Do nothing if out of range.
Expand Down Expand Up @@ -235,12 +242,17 @@ impl Decoder for SymphoniaDecoder {
if num_frames_to_cpy != 0 {
if self.num_channels == 1 {
// Mono, no need to deinterleave.
data_block.block[0][block_start..block_start + num_frames_to_cpy]
.copy_from_slice(
&self.smp_buf.samples()
[self.curr_smp_buf_i..self.curr_smp_buf_i + num_frames_to_cpy],
);
} else if self.num_channels == 2 {
let smp_buf = &self.smp_buf.samples()
[self.curr_smp_buf_i..self.curr_smp_buf_i + num_frames_to_cpy];

let block = &mut data_block.block[0][block_start..block_start + num_frames_to_cpy];
for i in 0..num_frames_to_cpy {
block[i] = match self.direction {
DecoderReadDirection::Forward => smp_buf[i],
DecoderReadDirection::Backward => smp_buf[num_frames_to_cpy - 1 - i]
}
}
} else if self.num_channels == 2 {
// Provide efficient stereo deinterleaving.

let smp_buf = &self.smp_buf.samples()
Expand All @@ -251,26 +263,52 @@ impl Decoder for SymphoniaDecoder {
let block2 = &mut block2[0][block_start..block_start + num_frames_to_cpy];

for i in 0..num_frames_to_cpy {
block1[i] = smp_buf[i * 2];
block2[i] = smp_buf[(i * 2) + 1];
match self.direction {
DecoderReadDirection::Forward => {
block1[i] = smp_buf[i * 2];
block2[i] = smp_buf[(i * 2) + 1];
},
DecoderReadDirection::Backward => {
block1[i] = smp_buf[(num_frames_to_cpy - 1 - i) * 2];
block2[i] = smp_buf[((num_frames_to_cpy - 1 - i) * 2) + 1];
}
};
}
} else {
let smp_buf = &self.smp_buf.samples()[self.curr_smp_buf_i
..self.curr_smp_buf_i + (num_frames_to_cpy * self.num_channels)];

for i in 0..num_frames_to_cpy {
for (ch, block) in data_block.block.iter_mut().enumerate() {
block[block_start + i] = smp_buf[(i * self.num_channels) + ch];
match self.direction {
DecoderReadDirection::Forward => {
block[block_start + i] = smp_buf[(i * self.num_channels) + ch];
},
DecoderReadDirection::Backward => {
block[block_start + i] = smp_buf[((num_frames_to_cpy - 1 - i) * self.num_channels) + ch];
}
};
}
}
}

block_start += num_frames_to_cpy;

self.curr_smp_buf_i += num_frames_to_cpy * self.num_channels;
if self.curr_smp_buf_i >= self.smp_buf.len() {
self.reset_smp_buffer = true;
}
self.curr_smp_buf_i = match self.direction {
DecoderReadDirection::Forward => {
if self.curr_smp_buf_i >= self.smp_buf.len() {
self.reset_smp_buffer = true;
}
self.curr_smp_buf_i + num_frames_to_cpy * self.num_channels
},
DecoderReadDirection::Backward => {
if self.curr_smp_buf_i <= 0 {
self.reset_smp_buffer = true;
}
self.curr_smp_buf_i.checked_sub(1).unwrap_or(0).checked_sub(num_frames_to_cpy * self.num_channels).unwrap_or(0)
}
};

} else {
// Decode more packets.

Expand Down Expand Up @@ -319,9 +357,16 @@ impl Decoder for SymphoniaDecoder {
}

if reached_end_of_file {
self.current_frame = self.num_frames;
self.current_frame = match self.direction {
DecoderReadDirection::Forward => self.num_frames,
DecoderReadDirection::Backward => 0,
};
} else {
self.current_frame += self.block_size;
self.current_frame = match self.direction {
DecoderReadDirection::Forward => (self.current_frame + self.block_size).min(self.num_frames - 1),
DecoderReadDirection::Backward => self.current_frame.checked_sub(self.block_size).unwrap_or(0).max(0)

};
}

Ok(())
Expand Down Expand Up @@ -463,4 +508,46 @@ mod tests {

assert_eq!(decoder.current_frame, file_info.num_frames - 1);
}

#[test]
fn decode_first_frame_direction_backward() {
let block_size = 10;

let decoder =
SymphoniaDecoder::new("../test_files/wav_u8_mono.wav".into(), 0, block_size, ());


let (mut decoder, _) = decoder.unwrap();

decoder.direction(DecoderReadDirection::Backward);

let mut data_block = DataBlock::new(1, block_size);
unsafe {
decoder.decode(&mut data_block).unwrap();
}

let samples = &mut data_block.block[0];
assert_eq!(samples.len(), block_size);


let mut first_frame = [
0.0,
0.046875,
0.09375,
0.1484375,
0.1953125,
0.2421875,
0.2890625,
0.3359375,
0.3828125,
0.421875
];

first_frame.reverse();


for i in 0..samples.len() {
assert!(approx_eq!(f32, first_frame[i], samples[i], ulps = 2));
}
}
}