ruffle/desktop/src/audio.rs

157 lines
4.7 KiB
Rust
Raw Normal View History

2019-05-03 09:33:58 +00:00
use generational_arena::Arena;
use ruffle_core::backend::audio::decoders::{stream_tag_reader, AdpcmDecoder, Decoder, Mp3Decoder};
2019-05-08 16:46:19 +00:00
use ruffle_core::backend::audio::{swf, AudioBackend, AudioStreamHandle, SoundHandle};
2019-05-03 09:33:58 +00:00
use std::io::Cursor;
use std::sync::Arc;
2019-05-03 09:33:58 +00:00
pub struct RodioAudioBackend {
2019-05-05 22:55:27 +00:00
sounds: Arena<Sound>,
active_sounds: Arena<rodio::Sink>,
2019-05-03 09:33:58 +00:00
streams: Arena<AudioStream>,
device: rodio::Device,
}
2019-05-24 17:25:03 +00:00
#[allow(dead_code)]
2019-05-03 09:33:58 +00:00
struct AudioStream {
clip_id: swf::CharacterId,
2019-07-19 08:32:41 +00:00
info: swf::SoundStreamHead,
2019-05-03 09:33:58 +00:00
sink: rodio::Sink,
}
#[allow(dead_code)]
2019-05-05 22:55:27 +00:00
struct Sound {
format: swf::SoundFormat,
data: Arc<Vec<u8>>,
2019-05-05 22:55:27 +00:00
}
2019-05-03 09:33:58 +00:00
impl RodioAudioBackend {
pub fn new() -> Result<Self, Box<dyn std::error::Error>> {
2019-05-03 09:33:58 +00:00
Ok(Self {
2019-05-05 22:55:27 +00:00
sounds: Arena::new(),
2019-05-03 09:33:58 +00:00
streams: Arena::new(),
2019-05-10 00:43:53 +00:00
active_sounds: Arena::new(),
2019-05-03 09:33:58 +00:00
device: rodio::default_output_device().ok_or("Unable to create output device")?,
})
}
}
impl AudioBackend for RodioAudioBackend {
2019-05-05 22:55:27 +00:00
fn register_sound(
&mut self,
swf_sound: &swf::Sound,
) -> Result<SoundHandle, Box<dyn std::error::Error>> {
2019-05-05 22:55:27 +00:00
let sound = Sound {
format: swf_sound.format.clone(),
data: Arc::new(swf_sound.data.clone()),
2019-05-05 22:55:27 +00:00
};
Ok(self.sounds.insert(sound))
}
fn start_stream(
&mut self,
clip_id: swf::CharacterId,
clip_data: ruffle_core::tag_utils::SwfSlice,
stream_info: &swf::SoundStreamHead,
) -> AudioStreamHandle {
let sink = rodio::Sink::new(&self.device);
2019-05-03 09:33:58 +00:00
let format = &stream_info.stream_format;
let decoder = Mp3Decoder::new(
if format.is_stereo { 2 } else { 1 },
2019-05-24 17:25:03 +00:00
format.sample_rate.into(),
stream_tag_reader(clip_data),
);
2019-05-03 09:33:58 +00:00
let stream = AudioStream {
clip_id,
2019-05-03 09:33:58 +00:00
info: stream_info.clone(),
sink,
};
stream.sink.append(DecoderSource(Box::new(decoder)));
2019-05-03 09:33:58 +00:00
self.streams.insert(stream)
}
2019-05-05 22:55:27 +00:00
fn play_sound(&mut self, sound: SoundHandle) {
let sound = &self.sounds[sound];
use swf::AudioCompression;
match sound.format.compression {
AudioCompression::Uncompressed => {
let mut data = Vec::with_capacity(sound.data.len() / 2);
let mut i = 0;
while i < sound.data.len() {
2019-05-24 17:25:03 +00:00
let val = i16::from(sound.data[i]) | (i16::from(sound.data[i + 1]) << 8);
2019-05-05 22:55:27 +00:00
data.push(val);
2019-05-24 17:25:03 +00:00
i += 2;
2019-05-05 22:55:27 +00:00
}
let buffer = rodio::buffer::SamplesBuffer::new(
if sound.format.is_stereo { 2 } else { 1 },
sound.format.sample_rate.into(),
data,
);
let sink = rodio::Sink::new(&self.device);
2019-05-05 22:55:27 +00:00
sink.append(buffer);
2019-05-10 00:43:53 +00:00
self.active_sounds.insert(sink);
2019-05-05 22:55:27 +00:00
}
AudioCompression::Adpcm => {
let decoder = AdpcmDecoder::new(
Cursor::new(sound.data.to_vec()),
sound.format.is_stereo,
sound.format.sample_rate,
)
.unwrap();
let sink = rodio::Sink::new(&self.device);
sink.append(DecoderSource(Box::new(decoder)));
self.active_sounds.insert(sink);
}
2019-05-05 22:55:27 +00:00
AudioCompression::Mp3 => {
let decoder = Mp3Decoder::new(
if sound.format.is_stereo { 2 } else { 1 },
sound.format.sample_rate.into(),
Cursor::new(sound.data.to_vec()),
);
let sink = rodio::Sink::new(&self.device);
sink.append(DecoderSource(Box::new(decoder)));
2019-05-10 00:43:53 +00:00
self.active_sounds.insert(sink);
2019-05-05 22:55:27 +00:00
}
_ => unimplemented!(),
}
}
2019-05-10 00:43:53 +00:00
fn tick(&mut self) {
self.active_sounds.retain(|_, sink| !sink.empty());
}
2019-05-03 09:33:58 +00:00
}
struct DecoderSource(Box<dyn Decoder + Send>);
2019-05-03 09:33:58 +00:00
impl Iterator for DecoderSource {
2019-05-03 09:33:58 +00:00
type Item = i16;
#[inline]
fn next(&mut self) -> Option<i16> {
self.0.next()
2019-05-05 22:55:27 +00:00
}
}
impl rodio::Source for DecoderSource {
2019-05-05 22:55:27 +00:00
#[inline]
fn current_frame_len(&self) -> Option<usize> {
None
2019-05-05 22:55:27 +00:00
}
#[inline]
fn channels(&self) -> u16 {
self.0.num_channels().into()
2019-05-05 22:55:27 +00:00
}
#[inline]
fn sample_rate(&self) -> u32 {
self.0.sample_rate().into()
2019-05-05 22:55:27 +00:00
}
#[inline]
fn total_duration(&self) -> Option<std::time::Duration> {
2019-05-05 22:55:27 +00:00
None
}
}