Skip to content

Commit e5313f6

Browse files
committed
play: Update to Rubato 2.0.0.
Unfortunately, to implement audioadapter::Adapter/AdapterMut for Symphonia's AudioBuffer, unsafe code must be allowed. So this change also removes forbid(unsafe_code) for symphonia-play.
1 parent fdf6a8b commit e5313f6

File tree

3 files changed

+62
-21
lines changed

3 files changed

+62
-21
lines changed

symphonia-play/Cargo.toml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,5 +33,4 @@ libpulse-simple-binding = "2.5.0"
3333
[target.'cfg(not(target_os = "linux"))'.dependencies]
3434
cpal = "0.17.3"
3535
rb = "0.4.1"
36-
rubato = "0.14.1"
37-
smallvec = { workspace = true }
36+
rubato = "2.0.0"

symphonia-play/src/main.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
77

88
#![warn(rust_2018_idioms)]
9-
#![forbid(unsafe_code)]
109
// Justification: Fields on DecoderOptions and FormatOptions may change at any time, but
1110
// symphonia-play doesn't want to be updated every time those fields change, therefore always fill
1211
// in the remaining fields with default values.

symphonia-play/src/resampler.rs

Lines changed: 61 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,14 @@
77

88
use std::marker::PhantomData;
99

10-
use rubato::VecResampler;
1110
use symphonia::core::audio::conv::{FromSample, IntoSample};
1211
use symphonia::core::audio::sample::Sample;
13-
use symphonia::core::audio::{Audio, AudioBuffer, AudioMut, AudioSpec, GenericAudioBufferRef};
12+
use symphonia::core::audio::{Audio, AudioBuffer, AudioSpec, GenericAudioBufferRef};
13+
14+
use rubato::Resampler as _;
1415

1516
pub struct Resampler<T> {
16-
resampler: rubato::FftFixedIn<f32>,
17+
resampler: rubato::Fft<f32>,
1718
buf_in: AudioBuffer<f32>,
1819
buf_out: AudioBuffer<f32>,
1920
chunk_size: usize,
@@ -43,22 +44,11 @@ where
4344

4445
// Get slices to the required regions of the input and output buffers.
4546
let (read, _) = {
46-
let mut slices_in: smallvec::SmallVec<[&[f32]; 8]> = Default::default();
47-
let mut slices_out: smallvec::SmallVec<[&mut [f32]; 8]> = Default::default();
48-
49-
for plane in self.buf_in.iter_planes() {
50-
slices_in.push(&plane[..self.chunk_size]);
51-
}
52-
53-
for plane in self.buf_out.iter_planes_mut() {
54-
slices_out.push(&mut plane[begin..]);
55-
}
56-
5747
// Resample a chunk.
5848
rubato::Resampler::process_into_buffer(
5949
&mut self.resampler,
60-
&slices_in,
61-
&mut slices_out,
50+
&AudioBufferAdapter(&self.buf_in),
51+
&mut AudioBufferAdapterMut(&mut self.buf_out),
6252
None,
6353
)
6454
.unwrap()
@@ -80,12 +70,13 @@ where
8070
T: Sample + FromSample<f32> + IntoSample<f32>,
8171
{
8272
pub fn new(spec_in: &AudioSpec, out_sample_rate: u32, chunk_size: usize) -> Self {
83-
let resampler = rubato::FftFixedIn::<f32>::new(
73+
let resampler = rubato::Fft::<f32>::new(
8474
spec_in.rate() as usize,
8575
out_sample_rate as usize,
8676
chunk_size,
87-
2,
77+
1,
8878
spec_in.channels().count(),
79+
rubato::FixedSync::Input,
8980
)
9081
.unwrap();
9182

@@ -132,3 +123,55 @@ where
132123
self.resample_inner(dst)
133124
}
134125
}
126+
127+
// Implementing adapter interface for Symphonia's AudioBuffer. Since both the adapter traits and
128+
// audio buffers are foreign types, a new-type is used.
129+
130+
struct AudioBufferAdapter<'a, S: Sample>(&'a AudioBuffer<S>);
131+
132+
unsafe impl<'a, T> rubato::audioadapter::Adapter<'a, T> for AudioBufferAdapter<'a, T>
133+
where
134+
T: Sample,
135+
{
136+
unsafe fn read_sample_unchecked(&self, channel: usize, frame: usize) -> T {
137+
self.0[channel][frame]
138+
}
139+
140+
fn channels(&self) -> usize {
141+
self.0.num_planes()
142+
}
143+
144+
fn frames(&self) -> usize {
145+
self.0.frames()
146+
}
147+
}
148+
149+
struct AudioBufferAdapterMut<'a, S: Sample>(&'a mut AudioBuffer<S>);
150+
151+
unsafe impl<'a, T> rubato::audioadapter::Adapter<'a, T> for AudioBufferAdapterMut<'a, T>
152+
where
153+
T: Sample,
154+
{
155+
unsafe fn read_sample_unchecked(&self, channel: usize, frame: usize) -> T {
156+
self.0[channel][frame]
157+
}
158+
159+
fn channels(&self) -> usize {
160+
self.0.num_planes()
161+
}
162+
163+
fn frames(&self) -> usize {
164+
self.0.frames()
165+
}
166+
}
167+
168+
unsafe impl<'a, T> rubato::audioadapter::AdapterMut<'a, T> for AudioBufferAdapterMut<'a, T>
169+
where
170+
T: Sample,
171+
{
172+
unsafe fn write_sample_unchecked(&mut self, channel: usize, frame: usize, value: &T) -> bool {
173+
self.0[channel][frame] = *value;
174+
// No sample format conversion was performed.
175+
false
176+
}
177+
}

0 commit comments

Comments
 (0)