Skip to content

Commit

Permalink
improve performance (#41)
Browse files Browse the repository at this point in the history
* improve performance

* fix oob error
  • Loading branch information
Billy Messenger authored Sep 13, 2023
1 parent e1c7aff commit 7a1a5e4
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 92 deletions.
135 changes: 60 additions & 75 deletions decode_symphonia/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
use std::fs::File;
use std::path::PathBuf;

use symphonia::core::audio::SampleBuffer;
use symphonia::core::audio::AudioBuffer;
use symphonia::core::codecs::{CodecParameters, Decoder as SymphDecoder, DecoderOptions};
use symphonia::core::errors::Error;
use symphonia::core::formats::{FormatOptions, FormatReader, SeekMode, SeekTo};
Expand All @@ -24,16 +24,16 @@ pub struct SymphoniaDecoder {
reader: Box<dyn FormatReader>,
decoder: Box<dyn SymphDecoder>,

smp_buf: SampleBuffer<f32>,
curr_smp_buf_i: usize,
decode_buffer: AudioBuffer<f32>,
decode_buffer_len: usize,
curr_decode_buffer_frame: usize,

num_frames: usize,
num_channels: usize,
sample_rate: Option<u32>,
block_size: usize,

current_frame: usize,
reset_smp_buffer: bool,
playhead_frame: usize,
reset_decode_buffer: bool,
}

impl Decoder for SymphoniaDecoder {
Expand Down Expand Up @@ -117,13 +117,13 @@ impl Decoder for SymphoniaDecoder {
let mut channels = params.channels;

// Decode the first packet to get the signal specification.
let smp_buf = loop {
let (decode_buffer, decode_buffer_len) = loop {
match decoder.decode(&reader.next_packet()?) {
Ok(decoded) => {
// Get the buffer spec.
let spec = *decoded.spec();
if let Some(channels) = channels {
debug_assert_eq!(channels, spec.channels);
assert_eq!(channels, spec.channels);
} else {
log::debug!(
"Assuming {num_channels} channel(s) according to the first decoded packet",
Expand All @@ -132,14 +132,15 @@ impl Decoder for SymphoniaDecoder {
channels = Some(spec.channels);
}

// Get the buffer capacity.
let capacity = decoded.capacity() as u64;
let len = decoded.frames();
let capacity = decoded.capacity();

let mut smp_buf = SampleBuffer::<f32>::new(capacity, spec);
let mut decode_buffer: AudioBuffer<f32> =
AudioBuffer::new(capacity as u64, spec);

smp_buf.copy_interleaved_ref(decoded);
decoded.convert(&mut decode_buffer);

break smp_buf;
break (decode_buffer, len);
}
Err(Error::DecodeError(err)) => {
// Decode errors are not fatal.
Expand Down Expand Up @@ -172,16 +173,16 @@ impl Decoder for SymphoniaDecoder {
reader,
decoder,

smp_buf,
curr_smp_buf_i: 0,
decode_buffer,
decode_buffer_len,
curr_decode_buffer_frame: 0,

num_frames,
num_channels,
sample_rate,
block_size,

current_frame: start_frame,
reset_smp_buffer: false,
playhead_frame: start_frame,
reset_decode_buffer: false,
},
file_info,
))
Expand All @@ -190,14 +191,14 @@ impl Decoder for SymphoniaDecoder {
fn seek(&mut self, frame: usize) -> Result<(), Self::FatalError> {
if frame >= self.num_frames {
// Do nothing if out of range.
self.current_frame = self.num_frames;
self.playhead_frame = self.num_frames;

return Ok(());
}

self.current_frame = frame;
self.playhead_frame = frame;

let seconds = self.current_frame as f64 / f64::from(self.sample_rate.unwrap_or(44100));
let seconds = self.playhead_frame as f64 / f64::from(self.sample_rate.unwrap_or(44100));

match self.reader.seek(
SeekMode::Accurate,
Expand All @@ -212,8 +213,8 @@ impl Decoder for SymphoniaDecoder {
}
}

self.reset_smp_buffer = true;
self.curr_smp_buf_i = 0;
self.reset_decode_buffer = true;
self.curr_decode_buffer_frame = 0;

/*
let decoder_opts = DecoderOptions {
Expand All @@ -233,77 +234,61 @@ impl Decoder for SymphoniaDecoder {
&mut self,
data_block: &mut DataBlock<Self::T>,
) -> Result<(), Self::FatalError> {
if self.current_frame >= self.num_frames {
if self.playhead_frame >= self.num_frames {
// Do nothing if reached the end of the file.
return Ok(());
}

let mut reached_end_of_file = false;

let mut block_start = 0;
while block_start < self.block_size {
let num_frames_to_cpy = if self.reset_smp_buffer {
// Get new data first.
self.reset_smp_buffer = false;
0
} else if self.smp_buf.len() < self.num_channels {
let mut block_start_frame = 0;
while block_start_frame < self.block_size {
let num_frames_to_cpy = if self.reset_decode_buffer {
// Get new data first.
self.reset_decode_buffer = false;
0
} else {
// Find the maximum amount of frames that can be copied.
(self.block_size - block_start)
.min((self.smp_buf.len() - self.curr_smp_buf_i) / self.num_channels)
(self.block_size - block_start_frame)
.min(self.decode_buffer_len - self.curr_decode_buffer_frame)
};

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 {
// Provide efficient stereo deinterleaving.

let smp_buf = &self.smp_buf.samples()
[self.curr_smp_buf_i..self.curr_smp_buf_i + (num_frames_to_cpy * 2)];

let (block1, block2) = data_block.block.split_at_mut(1);
let block1 = &mut block1[0][block_start..block_start + num_frames_to_cpy];
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];
}
} 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];
}
}
let src_planes = self.decode_buffer.planes();
let src_channels = src_planes.planes();

for (dst_ch, src_ch) in data_block.block.iter_mut().zip(src_channels) {
let src_ch_part = &src_ch[self.curr_decode_buffer_frame
..self.curr_decode_buffer_frame + num_frames_to_cpy];
dst_ch[block_start_frame..block_start_frame + num_frames_to_cpy]
.copy_from_slice(src_ch_part);
}

block_start += num_frames_to_cpy;
block_start_frame += 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_decode_buffer_frame += num_frames_to_cpy;
if self.curr_decode_buffer_frame >= self.decode_buffer_len {
self.reset_decode_buffer = true;
}
} else {
// Decode more packets.
// Decode the next packet.

loop {
match self.reader.next_packet() {
Ok(packet) => {
match self.decoder.decode(&packet) {
Ok(decoded) => {
self.smp_buf.copy_interleaved_ref(decoded);
self.curr_smp_buf_i = 0;
self.decode_buffer_len = decoded.frames();

let capacity = decoded.capacity();
if self.decode_buffer.capacity() < capacity {
self.decode_buffer =
AudioBuffer::new(capacity as u64, *decoded.spec());
}

decoded.convert(&mut self.decode_buffer);

self.curr_decode_buffer_frame = 0;
break;
}
Err(Error::DecodeError(err)) => {
Expand All @@ -323,7 +308,7 @@ impl Decoder for SymphoniaDecoder {
if io_error.kind() == std::io::ErrorKind::UnexpectedEof {
// End of file, stop decoding.
reached_end_of_file = true;
block_start = self.block_size;
block_start_frame = self.block_size;
break;
} else {
return Err(e);
Expand All @@ -338,16 +323,16 @@ impl Decoder for SymphoniaDecoder {
}

if reached_end_of_file {
self.current_frame = self.num_frames;
self.playhead_frame = self.num_frames;
} else {
self.current_frame += self.block_size;
self.playhead_frame += self.block_size;
}

Ok(())
}

fn current_frame(&self) -> usize {
self.current_frame
self.playhead_frame
}
}

Expand Down Expand Up @@ -474,6 +459,6 @@ mod tests {
assert_approx_eq!(f32, last_frame[i], samples[i], ulps = 2);
}

assert_eq!(decoder.current_frame, file_info.num_frames - 1);
assert_eq!(decoder.playhead_frame, file_info.num_frames - 1);
}
}
37 changes: 20 additions & 17 deletions encode_wav/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,25 +168,28 @@ impl<B: WavBitDepth + 'static> Encoder for WavEncoder<B> {
.write_to_disk(&write_block.block()[0][0..written_frames], &mut file)?;
} else {
if self.num_channels == 2 {
// Hint to compiler to optimize loop
assert!(written_frames <= write_block.block()[0].len());
assert!(written_frames <= write_block.block()[1].len());
assert!(written_frames * 2 <= self.interleave_buf.len());

for frame in 0..written_frames {
self.interleave_buf[frame * 2] = write_block.block()[0][frame];
self.interleave_buf[frame * 2 + 1] = write_block.block()[1][frame];
// Provide efficient stereo interleaving.
let ch1 = &write_block.block()[0][0..written_frames];
let ch2 = &write_block.block()[1][0..written_frames];
let interleave_buf_part = &mut self.interleave_buf[0..written_frames * 2];

for (i, frame) in interleave_buf_part.chunks_exact_mut(2).enumerate() {
frame[0] = ch1[i];
frame[1] = ch2[i];
}
} else {
// Hint to compiler to optimize loop
assert!(written_frames * self.num_channels <= self.interleave_buf.len());
for block in write_block.block() {
assert!(written_frames <= block.len());
}

for frame in 0..written_frames {
for (ch, block) in write_block.block().iter().enumerate() {
self.interleave_buf[frame * self.num_channels + ch] = block[frame];
let interleave_buf_part =
&mut self.interleave_buf[0..written_frames * self.num_channels];

for (ch_i, ch) in write_block.block().iter().enumerate() {
let ch_slice = &ch[0..written_frames];

for (dst, src) in interleave_buf_part[ch_i..]
.iter_mut()
.step_by(self.num_channels)
.zip(ch_slice)
{
*dst = *src;
}
}
}
Expand Down

0 comments on commit 7a1a5e4

Please sign in to comment.