Skip to content

Commit 54a595a

Browse files
committed
improve sample rate metadata for audio files
1 parent bb558b6 commit 54a595a

File tree

10 files changed

+85
-24
lines changed

10 files changed

+85
-24
lines changed

Cargo.toml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,16 @@ tracing = [
4545
"firewheel-graph/tracing",
4646
"firewheel-cpal?/tracing",
4747
"firewheel-rtaudio?/tracing",
48+
"firewheel-symphonium?/tracing",
4849
"std",
4950
]
5051
# Use the `log` crate for logging
51-
log = ["firewheel-graph/log", "firewheel-cpal?/log", "firewheel-rtaudio?/log"]
52+
log = [
53+
"firewheel-graph/log",
54+
"firewheel-cpal?/log",
55+
"firewheel-rtaudio?/log",
56+
"firewheel-symphonium?/log",
57+
]
5258
# Enables scheduling events for nodes
5359
scheduled_events = [
5460
"firewheel-core/scheduled_events",

crates/firewheel-core/src/sample_resource.rs

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
use core::{num::NonZeroUsize, ops::Range};
1+
use core::{
2+
num::{NonZeroU32, NonZeroUsize},
3+
ops::Range,
4+
};
25

36
#[cfg(not(feature = "std"))]
47
use bevy_platform::prelude::Vec;
@@ -12,6 +15,13 @@ pub trait SampleResourceInfo: Send + Sync + 'static {
1215
///
1316
/// Not to be confused with video frames.
1417
fn len_frames(&self) -> u64;
18+
19+
/// The sample rate of this resource.
20+
///
21+
/// Returns `None` if the sample rate is unknown.
22+
fn sample_rate(&self) -> Option<NonZeroU32> {
23+
None
24+
}
1525
}
1626

1727
/// A resource of audio samples.
@@ -45,6 +55,7 @@ pub trait SampleResourceF32: SampleResourceInfo {
4555
pub struct InterleavedResourceI16 {
4656
pub data: Vec<i16>,
4757
pub channels: NonZeroUsize,
58+
pub sample_rate: Option<NonZeroU32>,
4859
}
4960

5061
impl SampleResourceInfo for InterleavedResourceI16 {
@@ -55,6 +66,10 @@ impl SampleResourceInfo for InterleavedResourceI16 {
5566
fn len_frames(&self) -> u64 {
5667
(self.data.len() / self.channels.get()) as u64
5768
}
69+
70+
fn sample_rate(&self) -> Option<NonZeroU32> {
71+
self.sample_rate
72+
}
5873
}
5974

6075
impl SampleResource for InterleavedResourceI16 {
@@ -90,6 +105,7 @@ impl core::fmt::Debug for InterleavedResourceI16 {
90105
pub struct InterleavedResourceU16 {
91106
pub data: Vec<u16>,
92107
pub channels: NonZeroUsize,
108+
pub sample_rate: Option<NonZeroU32>,
93109
}
94110

95111
impl SampleResourceInfo for InterleavedResourceU16 {
@@ -100,6 +116,10 @@ impl SampleResourceInfo for InterleavedResourceU16 {
100116
fn len_frames(&self) -> u64 {
101117
(self.data.len() / self.channels.get()) as u64
102118
}
119+
120+
fn sample_rate(&self) -> Option<NonZeroU32> {
121+
self.sample_rate
122+
}
103123
}
104124

105125
impl SampleResource for InterleavedResourceU16 {
@@ -135,6 +155,7 @@ impl core::fmt::Debug for InterleavedResourceU16 {
135155
pub struct InterleavedResourceF32 {
136156
pub data: Vec<f32>,
137157
pub channels: NonZeroUsize,
158+
pub sample_rate: Option<NonZeroU32>,
138159
}
139160

140161
impl SampleResourceInfo for InterleavedResourceF32 {
@@ -145,6 +166,10 @@ impl SampleResourceInfo for InterleavedResourceF32 {
145166
fn len_frames(&self) -> u64 {
146167
(self.data.len() / self.channels.get()) as u64
147168
}
169+
170+
fn sample_rate(&self) -> Option<NonZeroU32> {
171+
self.sample_rate
172+
}
148173
}
149174

150175
impl SampleResource for InterleavedResourceF32 {

crates/firewheel-symphonium/Cargo.toml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ exclude.workspace = true
1010
repository.workspace = true
1111

1212
[features]
13+
default = ["tracing"]
1314
resample = [
1415
"dep:fixed-resample",
1516
"symphonium/resampler",
@@ -20,10 +21,14 @@ stretch = [
2021
"resample",
2122
"symphonium/stretch-sinc-resampler",
2223
]
24+
# Use the `tracing` crate for logging. Currently requires `std`.
25+
tracing = ["symphonium/tracing"]
26+
# Use the `log` crate for logging
27+
log = ["symphonium/log"]
2328

2429
[dependencies]
2530
firewheel-core = { path = "../firewheel-core", version = "0.10.0", default-features = false }
26-
symphonium = { version = "0.6.5", default-features = false }
31+
symphonium = { version = "0.7.0", default-features = false }
2732
fixed-resample = { version = "0.9.2", default-features = false, features = [
2833
"resampler",
2934
"fft-resampler",

crates/firewheel-symphonium/src/lib.rs

Lines changed: 39 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
use std::{num::NonZeroUsize, ops::Range};
1+
use std::{
2+
num::{NonZeroU32, NonZeroUsize},
3+
ops::Range,
4+
};
25

36
use firewheel_core::{
47
collector::ArcGc,
@@ -12,14 +15,24 @@ pub struct DecodedAudio(pub symphonium::DecodedAudio);
1215

1316
impl DecodedAudio {
1417
pub fn duration_seconds(&self) -> f64 {
15-
self.0.frames() as f64 / self.0.sample_rate() as f64
18+
self.0.frames() as f64 / self.0.sample_rate().get() as f64
1619
}
1720

1821
pub fn into_dyn_resource(self) -> ArcGc<dyn SampleResource> {
1922
ArcGc::new_unsized(|| {
2023
bevy_platform::sync::Arc::new(self) as bevy_platform::sync::Arc<dyn SampleResource>
2124
})
2225
}
26+
27+
/// The sample rate of this resource.
28+
pub fn sample_rate(&self) -> NonZeroU32 {
29+
self.0.sample_rate()
30+
}
31+
32+
/// The sample rate of the audio resource before it was resampled (if it was resampled).
33+
pub fn original_sample_rate(&self) -> NonZeroU32 {
34+
self.0.original_sample_rate()
35+
}
2336
}
2437

2538
impl From<DecodedAudio> for ArcGc<dyn SampleResource> {
@@ -36,6 +49,10 @@ impl SampleResourceInfo for DecodedAudio {
3649
fn len_frames(&self) -> u64 {
3750
self.0.frames() as u64
3851
}
52+
53+
fn sample_rate(&self) -> Option<NonZeroU32> {
54+
Some(self.0.sample_rate())
55+
}
3956
}
4057

4158
impl SampleResource for DecodedAudio {
@@ -77,8 +94,18 @@ impl From<symphonium::DecodedAudio> for DecodedAudio {
7794
pub struct DecodedAudioF32(pub symphonium::DecodedAudioF32);
7895

7996
impl DecodedAudioF32 {
80-
pub fn duration_seconds(&self, sample_rate: u32) -> f64 {
81-
self.0.frames() as f64 / sample_rate as f64
97+
pub fn duration_seconds(&self, sample_rate: NonZeroU32) -> f64 {
98+
self.0.frames() as f64 / sample_rate.get() as f64
99+
}
100+
101+
/// The sample rate of this resource.
102+
pub fn sample_rate(&self) -> NonZeroU32 {
103+
self.0.sample_rate
104+
}
105+
106+
/// The sample rate of the audio resource before it was resampled (if it was resampled).
107+
pub fn original_sample_rate(&self) -> NonZeroU32 {
108+
self.0.original_sample_rate
82109
}
83110
}
84111

@@ -90,6 +117,10 @@ impl SampleResourceInfo for DecodedAudioF32 {
90117
fn len_frames(&self) -> u64 {
91118
self.0.frames() as u64
92119
}
120+
121+
fn sample_rate(&self) -> Option<NonZeroU32> {
122+
Some(self.0.sample_rate)
123+
}
93124
}
94125

95126
impl SampleResource for DecodedAudioF32 {
@@ -135,7 +166,7 @@ pub fn load_audio_file<P: AsRef<std::path::Path>>(
135166
.load(
136167
path,
137168
#[cfg(feature = "resample")]
138-
target_sample_rate.map(|s| s.get()),
169+
target_sample_rate,
139170
#[cfg(feature = "resample")]
140171
resample_quality,
141172
None,
@@ -169,7 +200,7 @@ pub fn load_audio_file_from_source(
169200
source,
170201
hint,
171202
#[cfg(feature = "resample")]
172-
target_sample_rate.map(|s| s.get()),
203+
target_sample_rate,
173204
#[cfg(feature = "resample")]
174205
resample_quality,
175206
None,
@@ -197,7 +228,7 @@ pub fn load_audio_file_stretched<P: AsRef<std::path::Path>>(
197228
stretch: f64,
198229
) -> Result<DecodedAudio, symphonium::error::LoadError> {
199230
loader
200-
.load_f32_stretched(path, stretch, target_sample_rate.map(|s| s.get()), None)
231+
.load_stretched(path, stretch, target_sample_rate, None)
201232
.map(|d| DecodedAudio(d.into()))
202233
}
203234

@@ -224,13 +255,7 @@ pub fn load_audio_file_from_source_stretched(
224255
stretch: f64,
225256
) -> Result<DecodedAudio, symphonium::error::LoadError> {
226257
loader
227-
.load_f32_from_source_stretched(
228-
source,
229-
hint,
230-
stretch,
231-
target_sample_rate.map(|s| s.get()),
232-
None,
233-
)
258+
.load_from_source_stretched(source, hint, stretch, target_sample_rate, None)
234259
.map(|d| DecodedAudio(d.into()))
235260
}
236261

examples/play_sample/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,5 @@ publish = false
88
firewheel = { path = "../../" }
99
tracing.workspace = true
1010
tracing-subscriber.workspace = true
11-
symphonium = { version = "0.6.5", features = ["mp3", "flac"] }
11+
symphonium = { version = "0.7.0", features = ["mp3", "flac"] }
1212
clap = { version = "4", features = ["derive"] }

examples/sampler_pool/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ tracing.workspace = true
1212
tracing-subscriber.workspace = true
1313
egui.workspace = true
1414
eframe.workspace = true
15-
symphonium = { version = "0.6.5", features = ["mp3", "flac"] }
15+
symphonium = { version = "0.7.0", features = ["mp3", "flac"] }
1616

1717
[target.'cfg(target_arch = "wasm32")'.dependencies]
1818
wasm-bindgen-futures = "0.4"

examples/sampler_test/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ tracing.workspace = true
1010
tracing-subscriber.workspace = true
1111
egui.workspace = true
1212
eframe.workspace = true
13-
symphonium = { version = "0.6.5", features = ["mp3", "flac"] }
13+
symphonium = { version = "0.7.0", features = ["mp3", "flac"] }
1414

1515
[target.'cfg(target_arch = "wasm32")'.dependencies]
1616
wasm-bindgen-futures = "0.4"

examples/spatial_basic/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ tracing.workspace = true
1010
tracing-subscriber.workspace = true
1111
egui.workspace = true
1212
eframe.workspace = true
13-
symphonium = { version = "0.6.5", features = ["mp3", "flac"] }
13+
symphonium = { version = "0.7.0", features = ["mp3", "flac"] }
1414

1515
[target.'cfg(target_arch = "wasm32")'.dependencies]
1616
wasm-bindgen-futures = "0.4"

examples/visual_node_graph/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ tracing-subscriber.workspace = true
1111
egui.workspace = true
1212
eframe.workspace = true
1313
egui-snarl = "0.9.0"
14-
symphonium = { version = "0.6.4", features = ["mp3", "flac"] }
14+
symphonium = { version = "0.7.0", features = ["mp3", "flac"] }
1515

1616
[target.'cfg(target_arch = "wasm32")'.dependencies]
1717
wasm-bindgen-futures = "0.4"

examples/visualizer/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ tracing.workspace = true
1010
tracing-subscriber.workspace = true
1111
egui.workspace = true
1212
eframe.workspace = true
13-
symphonium = { version = "0.6.5", features = ["mp3", "flac"] }
13+
symphonium = { version = "0.7.0", features = ["mp3", "flac"] }
1414

1515
[target.'cfg(target_arch = "wasm32")'.dependencies]
16-
wasm-bindgen-futures = "0.4"
16+
wasm-bindgen-futures = "0.4"

0 commit comments

Comments
 (0)