2022-09-12 23:50:50 +01:00
|
|
|
use sdl2::audio::{AudioCallback, AudioDevice, AudioFormat, AudioSpec, AudioSpecDesired};
|
2019-12-09 20:53:11 +00:00
|
|
|
|
2022-09-12 23:50:50 +01:00
|
|
|
use rustboyadvance_core::prelude::SimpleAudioInterface;
|
|
|
|
use rustboyadvance_utils::audio::SampleConsumer;
|
2019-12-28 13:59:35 +00:00
|
|
|
|
2022-09-12 23:50:50 +01:00
|
|
|
pub struct GbaAudioCallback {
|
|
|
|
consumer: SampleConsumer,
|
|
|
|
#[allow(unused)]
|
2019-12-28 13:59:35 +00:00
|
|
|
spec: AudioSpec,
|
|
|
|
}
|
2019-12-09 20:53:11 +00:00
|
|
|
|
2019-12-28 13:59:35 +00:00
|
|
|
impl AudioCallback for GbaAudioCallback {
|
|
|
|
type Channel = i16;
|
|
|
|
|
|
|
|
fn callback(&mut self, out_samples: &mut [i16]) {
|
2022-09-12 23:50:50 +01:00
|
|
|
let written = self.consumer.pop_slice(out_samples);
|
|
|
|
for s in out_samples.iter_mut().skip(written) {
|
|
|
|
*s = self.spec.silence as i16;
|
2019-12-28 13:59:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-12 23:50:50 +01:00
|
|
|
pub fn create_audio_player(
|
|
|
|
sdl: &sdl2::Sdl,
|
|
|
|
) -> Result<(Box<SimpleAudioInterface>, AudioDevice<GbaAudioCallback>), String> {
|
2019-12-09 20:53:11 +00:00
|
|
|
let desired_spec = AudioSpecDesired {
|
2019-12-21 22:58:18 +00:00
|
|
|
freq: Some(44_100),
|
|
|
|
channels: Some(2), // stereo
|
2019-12-09 20:53:11 +00:00
|
|
|
samples: None,
|
|
|
|
};
|
|
|
|
|
2022-09-12 23:50:50 +01:00
|
|
|
let audio_subsystem = sdl.audio()?;
|
2019-12-28 13:59:35 +00:00
|
|
|
|
|
|
|
let mut freq = 0;
|
|
|
|
|
2022-09-12 23:50:50 +01:00
|
|
|
let mut gba_audio = None;
|
|
|
|
|
|
|
|
let device = audio_subsystem.open_playback(None, &desired_spec, |spec| {
|
|
|
|
info!("Found audio device: {:?}", spec);
|
|
|
|
freq = spec.freq;
|
2019-12-28 13:59:35 +00:00
|
|
|
|
2022-09-12 23:50:50 +01:00
|
|
|
if spec.format != AudioFormat::S16LSB {
|
|
|
|
panic!("Unsupported audio format {:?}", spec.format);
|
|
|
|
}
|
2019-12-09 20:53:11 +00:00
|
|
|
|
2022-09-12 23:50:50 +01:00
|
|
|
// Create a thread-safe SPSC fifo
|
|
|
|
let ringbuf_samples_per_channel = (spec.samples as usize) * 2; // we want the ringbuf to hold 2 frames worth of samples
|
|
|
|
let ringbuf_size = (spec.channels as usize) * ringbuf_samples_per_channel;
|
|
|
|
info!("ringbuffer size = {}", ringbuf_size);
|
2019-12-28 13:59:35 +00:00
|
|
|
|
2022-09-12 23:50:50 +01:00
|
|
|
let (audio_device, consumer) =
|
|
|
|
SimpleAudioInterface::create_channel(freq, Some(ringbuf_size));
|
|
|
|
// Move the audio to outer scope
|
|
|
|
gba_audio = Some(audio_device);
|
2019-12-28 13:59:35 +00:00
|
|
|
|
2022-09-12 23:50:50 +01:00
|
|
|
GbaAudioCallback { consumer, spec }
|
|
|
|
})?;
|
2019-12-21 22:58:18 +00:00
|
|
|
|
|
|
|
device.resume();
|
2019-12-22 23:30:36 +00:00
|
|
|
|
2022-09-12 23:50:50 +01:00
|
|
|
Ok((gba_audio.take().unwrap(), device))
|
2021-06-08 22:49:34 +01:00
|
|
|
}
|