1#![warn(missing_docs)]
74#![allow(clippy::tabs_in_doc_comments)]
75
76mod error;
77mod streaming;
78
79use std::{fs::File, io::Cursor, path::Path, sync::Arc};
80
81pub use error::*;
82use kira::{
83 dsp::Frame,
84 sound::static_sound::{StaticSoundData, StaticSoundSettings},
85};
86use streaming::decoder::symphonia::SymphoniaDecoder;
87pub use streaming::*;
88use symphonia::core::{
89 audio::{AudioBuffer, AudioBufferRef, Signal},
90 conv::{FromSample, IntoSample},
91 io::{MediaSource, MediaSourceStream},
92 sample::Sample,
93};
94
95fn load_from_media_source(
96 media_source: Box<dyn MediaSource>,
97 settings: StaticSoundSettings,
98) -> Result<StaticSoundData, Error> {
99 let codecs = symphonia::default::get_codecs();
100 let probe = symphonia::default::get_probe();
101 let mss = MediaSourceStream::new(media_source, Default::default());
102 let mut format_reader = probe
103 .format(
104 &Default::default(),
105 mss,
106 &Default::default(),
107 &Default::default(),
108 )?
109 .format;
110 let codec_params = &format_reader
111 .default_track()
112 .ok_or(Error::NoDefaultTrack)?
113 .codec_params;
114 let sample_rate = codec_params.sample_rate.ok_or(Error::UnknownSampleRate)?;
115 let mut decoder = codecs.make(codec_params, &Default::default())?;
116 let mut frames = vec![];
117 loop {
118 match format_reader.next_packet() {
119 Ok(packet) => {
120 let buffer = decoder.decode(&packet)?;
121 load_frames_from_buffer_ref(&mut frames, &buffer)?;
122 }
123 Err(error) => match error {
124 symphonia::core::errors::Error::IoError(error) => {
125 if error.kind() == std::io::ErrorKind::UnexpectedEof {
126 break;
127 }
128 return Err(symphonia::core::errors::Error::IoError(error).into());
129 }
130 error => return Err(error.into()),
131 },
132 }
133 }
134 Ok(StaticSoundData {
135 sample_rate,
136 frames: Arc::new(frames),
137 settings,
138 })
139}
140
141pub fn load(
143 path: impl AsRef<Path>,
144 settings: StaticSoundSettings,
145) -> Result<StaticSoundData, Error> {
146 load_from_media_source(Box::new(File::open(path)?), settings)
147}
148
149pub fn load_from_cursor<T: AsRef<[u8]> + Send + 'static>(
151 cursor: Cursor<T>,
152 settings: StaticSoundSettings,
153) -> Result<StaticSoundData, Error> {
154 load_from_media_source(Box::new(cursor), settings)
155}
156
157pub fn stream(
159 path: impl AsRef<Path>,
160 settings: StreamingSoundSettings,
161) -> Result<StreamingSoundData<Error>, Error> {
162 Ok(StreamingSoundData {
163 decoder: Box::new(SymphoniaDecoder::new(Box::new(File::open(path)?))?),
164 settings,
165 })
166}
167
168pub fn stream_from_cursor<T: AsRef<[u8]> + Send + 'static>(
170 cursor: Cursor<T>,
171 settings: StreamingSoundSettings,
172) -> Result<StreamingSoundData<Error>, Error> {
173 Ok(StreamingSoundData {
174 decoder: Box::new(SymphoniaDecoder::new(Box::new(cursor))?),
175 settings,
176 })
177}
178
179fn load_frames_from_buffer_ref(
180 frames: &mut Vec<Frame>,
181 buffer: &AudioBufferRef,
182) -> Result<(), Error> {
183 match buffer {
184 AudioBufferRef::U8(buffer) => load_frames_from_buffer(frames, buffer),
185 AudioBufferRef::U16(buffer) => load_frames_from_buffer(frames, buffer),
186 AudioBufferRef::U24(buffer) => load_frames_from_buffer(frames, buffer),
187 AudioBufferRef::U32(buffer) => load_frames_from_buffer(frames, buffer),
188 AudioBufferRef::S8(buffer) => load_frames_from_buffer(frames, buffer),
189 AudioBufferRef::S16(buffer) => load_frames_from_buffer(frames, buffer),
190 AudioBufferRef::S24(buffer) => load_frames_from_buffer(frames, buffer),
191 AudioBufferRef::S32(buffer) => load_frames_from_buffer(frames, buffer),
192 AudioBufferRef::F32(buffer) => load_frames_from_buffer(frames, buffer),
193 AudioBufferRef::F64(buffer) => load_frames_from_buffer(frames, buffer),
194 }
195}
196
197fn load_frames_from_buffer<S: Sample>(
198 frames: &mut Vec<Frame>,
199 buffer: &AudioBuffer<S>,
200) -> Result<(), Error>
201where
202 f32: FromSample<S>,
203{
204 match buffer.spec().channels.count() {
205 1 => {
206 for sample in buffer.chan(0) {
207 frames.push(Frame::from_mono((*sample).into_sample()));
208 }
209 }
210 2 => {
211 for (left, right) in buffer.chan(0).iter().zip(buffer.chan(1).iter()) {
212 frames.push(Frame::new((*left).into_sample(), (*right).into_sample()));
213 }
214 }
215 _ => return Err(Error::UnsupportedChannelConfiguration),
216 }
217 Ok(())
218}