2019-05-03 09:33:58 +00:00
|
|
|
use generational_arena::Arena;
|
|
|
|
use rodio::{source::Source, Sample, Sink};
|
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, Mutex};
|
|
|
|
|
|
|
|
pub struct RodioAudioBackend {
|
2019-05-05 22:55:27 +00:00
|
|
|
sounds: Arena<Sound>,
|
2019-05-10 00:43:53 +00:00
|
|
|
active_sounds: Arena<Sink>,
|
2019-05-03 09:33:58 +00:00
|
|
|
streams: Arena<AudioStream>,
|
|
|
|
device: rodio::Device,
|
|
|
|
}
|
|
|
|
|
|
|
|
struct AudioStream {
|
|
|
|
info: swf::SoundStreamInfo,
|
|
|
|
sink: rodio::Sink,
|
|
|
|
data: Arc<Mutex<Cursor<Vec<u8>>>>,
|
|
|
|
}
|
|
|
|
|
2019-05-05 22:55:27 +00:00
|
|
|
struct Sound {
|
|
|
|
format: swf::SoundFormat,
|
|
|
|
data: Vec<u8>,
|
|
|
|
}
|
|
|
|
|
2019-05-03 09:33:58 +00:00
|
|
|
impl RodioAudioBackend {
|
|
|
|
pub fn new() -> Result<Self, Box<std::error::Error>> {
|
|
|
|
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<std::error::Error>> {
|
|
|
|
let sound = Sound {
|
|
|
|
format: swf_sound.format.clone(),
|
|
|
|
data: swf_sound.data.clone(),
|
|
|
|
};
|
|
|
|
Ok(self.sounds.insert(sound))
|
|
|
|
}
|
|
|
|
|
2019-05-03 09:33:58 +00:00
|
|
|
fn register_stream(&mut self, stream_info: &swf::SoundStreamInfo) -> AudioStreamHandle {
|
|
|
|
let sink = Sink::new(&self.device);
|
|
|
|
let data = Arc::new(Mutex::new(Cursor::new(vec![])));
|
|
|
|
|
|
|
|
let format = &stream_info.stream_format;
|
|
|
|
let decoder = Mp3Decoder::new(
|
|
|
|
if format.is_stereo { 2 } else { 1 },
|
|
|
|
format.sample_rate as u32,
|
|
|
|
ThreadRead(Arc::clone(&data)),
|
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
let stream = AudioStream {
|
|
|
|
info: stream_info.clone(),
|
|
|
|
sink,
|
|
|
|
data,
|
|
|
|
};
|
|
|
|
stream.sink.append(decoder);
|
|
|
|
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() {
|
|
|
|
let val = sound.data[i] as i16 | ((sound.data[i + 1] as i16) << 8);
|
|
|
|
data.push(val);
|
|
|
|
}
|
|
|
|
let buffer = rodio::buffer::SamplesBuffer::new(
|
|
|
|
if sound.format.is_stereo { 2 } else { 1 },
|
|
|
|
sound.format.sample_rate.into(),
|
|
|
|
data,
|
|
|
|
);
|
|
|
|
let sink = Sink::new(&self.device);
|
|
|
|
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::Mp3 => {
|
|
|
|
let decoder = Mp3EventDecoder::new(Cursor::new(sound.data.clone())).unwrap();
|
|
|
|
let sink = Sink::new(&self.device);
|
|
|
|
sink.append(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-03 09:33:58 +00:00
|
|
|
fn queue_stream_samples(&mut self, handle: AudioStreamHandle, mut samples: &[u8]) {
|
|
|
|
if let Some(stream) = self.streams.get_mut(handle) {
|
|
|
|
let mut stream_channels = 0;
|
|
|
|
let mut n = 0;
|
|
|
|
let mut stream_sample_rate = 0;
|
|
|
|
|
|
|
|
let tag_samples = (samples[0] as u16) | ((samples[1] as u16) << 8);
|
|
|
|
samples = &samples[4..];
|
|
|
|
|
|
|
|
let mut buffer = stream.data.lock().unwrap();
|
|
|
|
buffer.get_mut().extend_from_slice(&samples);
|
|
|
|
}
|
|
|
|
}
|
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
|
|
|
}
|
|
|
|
|
|
|
|
use std::io::{self, Read, Seek};
|
|
|
|
use std::time::Duration;
|
|
|
|
|
|
|
|
use minimp3::{Decoder, Frame};
|
|
|
|
|
|
|
|
pub struct ThreadRead(Arc<Mutex<Cursor<Vec<u8>>>>);
|
|
|
|
|
|
|
|
impl Read for ThreadRead {
|
|
|
|
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
|
|
|
let mut buffer = self.0.lock().unwrap();
|
|
|
|
let result = buffer.read(buf);
|
2019-05-10 00:43:53 +00:00
|
|
|
let len_remaining = buffer.get_ref().len() - buffer.position() as usize;
|
|
|
|
let tmp = buffer.get_ref()[buffer.position() as usize..].to_vec();
|
|
|
|
buffer.get_mut().resize(len_remaining, 0);
|
|
|
|
*buffer.get_mut() = tmp;
|
|
|
|
buffer.set_position(0);
|
2019-05-03 09:33:58 +00:00
|
|
|
result
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Seek for ThreadRead {
|
|
|
|
fn seek(&mut self, pos: std::io::SeekFrom) -> io::Result<u64> {
|
|
|
|
self.0.lock().unwrap().seek(pos)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct Mp3Decoder {
|
|
|
|
decoder: Decoder<ThreadRead>,
|
|
|
|
sample_rate: u32,
|
|
|
|
num_channels: u16,
|
|
|
|
current_frame: Frame,
|
|
|
|
current_frame_offset: usize,
|
2019-05-10 00:43:53 +00:00
|
|
|
playing: bool,
|
2019-05-03 09:33:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Mp3Decoder {
|
|
|
|
pub fn new(num_channels: u16, sample_rate: u32, data: ThreadRead) -> Result<Self, ()> {
|
|
|
|
let decoder = Decoder::new(data);
|
|
|
|
let current_frame = Frame {
|
|
|
|
data: vec![],
|
|
|
|
sample_rate: sample_rate as _,
|
|
|
|
channels: num_channels as _,
|
|
|
|
layer: 3,
|
|
|
|
bitrate: 160,
|
|
|
|
};
|
|
|
|
|
|
|
|
Ok(Mp3Decoder {
|
|
|
|
decoder,
|
|
|
|
num_channels,
|
|
|
|
sample_rate,
|
|
|
|
current_frame,
|
|
|
|
current_frame_offset: 0,
|
2019-05-10 00:43:53 +00:00
|
|
|
playing: false,
|
2019-05-03 09:33:58 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Source for Mp3Decoder {
|
|
|
|
#[inline]
|
|
|
|
fn current_frame_len(&self) -> Option<usize> {
|
|
|
|
None //Some(self.current_frame.data.len())
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn channels(&self) -> u16 {
|
|
|
|
self.num_channels
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn sample_rate(&self) -> u32 {
|
|
|
|
self.sample_rate
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn total_duration(&self) -> Option<Duration> {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Iterator for Mp3Decoder {
|
|
|
|
type Item = i16;
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn next(&mut self) -> Option<i16> {
|
2019-05-10 00:43:53 +00:00
|
|
|
if !self.playing {
|
2019-05-03 09:33:58 +00:00
|
|
|
let buffer = self.decoder.reader().0.lock().unwrap();
|
2019-05-10 00:43:53 +00:00
|
|
|
if buffer.get_ref().len() < 44100 / 60 {
|
2019-05-03 09:33:58 +00:00
|
|
|
return Some(0);
|
|
|
|
}
|
2019-05-10 00:43:53 +00:00
|
|
|
self.playing = true;
|
2019-05-03 09:33:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if self.current_frame_offset == self.current_frame.data.len() {
|
|
|
|
match self.decoder.next_frame() {
|
|
|
|
Ok(frame) => self.current_frame = frame,
|
|
|
|
_ => return Some(0),
|
|
|
|
}
|
2019-05-10 00:43:53 +00:00
|
|
|
self.current_frame_offset = 0;
|
2019-05-03 09:33:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
let v = self.current_frame.data[self.current_frame_offset];
|
|
|
|
self.current_frame_offset += 1;
|
|
|
|
|
|
|
|
Some(v)
|
|
|
|
}
|
|
|
|
}
|
2019-05-05 22:55:27 +00:00
|
|
|
|
|
|
|
pub struct Mp3EventDecoder<R>
|
|
|
|
where
|
|
|
|
R: Read + Seek,
|
|
|
|
{
|
|
|
|
decoder: Decoder<R>,
|
|
|
|
current_frame: Frame,
|
|
|
|
current_frame_offset: usize,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<R> Mp3EventDecoder<R>
|
|
|
|
where
|
|
|
|
R: Read + Seek,
|
|
|
|
{
|
|
|
|
pub fn new(data: R) -> Result<Self, ()> {
|
|
|
|
let mut decoder = Decoder::new(data);
|
|
|
|
let current_frame = decoder.next_frame().map_err(|_| ())?;
|
|
|
|
|
|
|
|
Ok(Mp3EventDecoder {
|
|
|
|
decoder,
|
|
|
|
current_frame,
|
|
|
|
current_frame_offset: 0,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<R> Source for Mp3EventDecoder<R>
|
|
|
|
where
|
|
|
|
R: Read + Seek,
|
|
|
|
{
|
|
|
|
#[inline]
|
|
|
|
fn current_frame_len(&self) -> Option<usize> {
|
|
|
|
Some(self.current_frame.data.len())
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn channels(&self) -> u16 {
|
|
|
|
self.current_frame.channels as _
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn sample_rate(&self) -> u32 {
|
|
|
|
self.current_frame.sample_rate as _
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn total_duration(&self) -> Option<Duration> {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<R> Iterator for Mp3EventDecoder<R>
|
|
|
|
where
|
|
|
|
R: Read + Seek,
|
|
|
|
{
|
|
|
|
type Item = i16;
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn next(&mut self) -> Option<i16> {
|
|
|
|
if self.current_frame_offset == self.current_frame.data.len() {
|
|
|
|
self.current_frame_offset = 0;
|
|
|
|
match self.decoder.next_frame() {
|
|
|
|
Ok(frame) => self.current_frame = frame,
|
|
|
|
_ => return None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let v = self.current_frame.data[self.current_frame_offset];
|
|
|
|
self.current_frame_offset += 1;
|
|
|
|
|
|
|
|
return Some(v);
|
|
|
|
}
|
|
|
|
}
|