2019-12-09 20:53:11 +00:00
|
|
|
use sdl2;
|
2019-12-28 13:59:35 +00:00
|
|
|
use sdl2::audio::{AudioCallback, AudioDevice, AudioSpec, AudioSpecDesired};
|
2019-12-09 20:53:11 +00:00
|
|
|
|
2019-12-28 13:59:35 +00:00
|
|
|
use rustboyadvance_ng::{AudioInterface, StereoSample};
|
|
|
|
|
|
|
|
extern crate ringbuf;
|
|
|
|
use ringbuf::{Consumer, Producer, RingBuffer};
|
|
|
|
|
|
|
|
struct GbaAudioCallback {
|
2020-01-20 23:18:47 +00:00
|
|
|
consumer: Consumer<StereoSample<i16>>,
|
2019-12-28 13:59:35 +00:00
|
|
|
spec: AudioSpec,
|
|
|
|
}
|
2019-12-09 20:53:11 +00:00
|
|
|
|
|
|
|
pub struct Sdl2AudioPlayer {
|
2019-12-28 13:59:35 +00:00
|
|
|
_device: AudioDevice<GbaAudioCallback>,
|
2020-01-20 23:18:47 +00:00
|
|
|
producer: Producer<StereoSample<i16>>,
|
2019-12-21 22:58:18 +00:00
|
|
|
freq: i32,
|
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]) {
|
|
|
|
let sample_count = out_samples.len() / 2;
|
|
|
|
|
|
|
|
for i in 0..sample_count {
|
|
|
|
if let Some((left, right)) = self.consumer.pop() {
|
2020-01-20 23:18:47 +00:00
|
|
|
out_samples[2 * i] = left;
|
|
|
|
out_samples[2 * i + 1] = right;
|
2019-12-28 13:59:35 +00:00
|
|
|
} else {
|
|
|
|
out_samples[2 * i] = self.spec.silence as i16;
|
|
|
|
out_samples[2 * i + 1] = self.spec.silence as i16;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-09 20:53:11 +00:00
|
|
|
impl AudioInterface for Sdl2AudioPlayer {
|
2019-12-21 22:58:18 +00:00
|
|
|
fn get_sample_rate(&self) -> i32 {
|
2019-12-09 20:53:11 +00:00
|
|
|
self.freq
|
|
|
|
}
|
|
|
|
|
2020-01-20 23:18:47 +00:00
|
|
|
fn push_sample(&mut self, sample: StereoSample<i16>) {
|
2019-12-28 13:59:35 +00:00
|
|
|
#![allow(unused_must_use)]
|
|
|
|
self.producer.push(sample);
|
2019-12-09 20:53:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn create_audio_player(sdl: &sdl2::Sdl) -> Sdl2AudioPlayer {
|
|
|
|
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,
|
|
|
|
};
|
|
|
|
|
2019-12-28 13:59:35 +00:00
|
|
|
let audio_subsystem = sdl.audio().unwrap();
|
|
|
|
|
|
|
|
let mut freq = 0;
|
|
|
|
|
2020-01-20 23:18:47 +00:00
|
|
|
let mut producer: Option<Producer<StereoSample<i16>>> = None;
|
2019-12-28 13:59:35 +00:00
|
|
|
|
2019-12-22 23:30:36 +00:00
|
|
|
let device = audio_subsystem
|
2019-12-28 13:59:35 +00:00
|
|
|
.open_playback(None, &desired_spec, |spec| {
|
|
|
|
println!("Found audio device: {:?}", spec);
|
|
|
|
freq = spec.freq;
|
2019-12-09 20:53:11 +00:00
|
|
|
|
2019-12-28 13:59:35 +00:00
|
|
|
// Create a thread-safe SPSC fifo
|
|
|
|
let ringbuf_size = (spec.samples as usize) * 2;
|
2020-01-20 23:18:47 +00:00
|
|
|
let rb = RingBuffer::<StereoSample<i16>>::new(ringbuf_size);
|
2019-12-28 13:59:35 +00:00
|
|
|
let (prod, cons) = rb.split();
|
|
|
|
|
|
|
|
// move producer to the outer scope
|
|
|
|
producer = Some(prod);
|
|
|
|
|
|
|
|
GbaAudioCallback {
|
|
|
|
consumer: cons,
|
|
|
|
spec,
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.unwrap();
|
2019-12-21 22:58:18 +00:00
|
|
|
|
|
|
|
device.resume();
|
2019-12-22 23:30:36 +00:00
|
|
|
|
2019-12-28 13:59:35 +00:00
|
|
|
Sdl2AudioPlayer {
|
|
|
|
_device: device,
|
|
|
|
freq,
|
|
|
|
producer: producer.unwrap(),
|
|
|
|
}
|
2019-12-09 20:53:11 +00:00
|
|
|
}
|