diff --git a/examples/audio-queue-squarewave.rs b/examples/audio-queue-squarewave.rs new file mode 100644 index 00000000..cf23344a --- /dev/null +++ b/examples/audio-queue-squarewave.rs @@ -0,0 +1,49 @@ +extern crate sdl2; + +use sdl2::audio::{AudioCallback, AudioSpecDesired}; +use std::time::Duration; + +fn gen_wave(bytes_to_write: i32) -> Vec { + // Generate a square wave + let tone_volume = 1000i16; + let period = 48000 / 256; + let sample_count = bytes_to_write / 4; + let mut result = Vec::new(); + + for x in 0..sample_count { + result.push( + if (x / period) % 2 == 0 { + tone_volume + } + else { + -tone_volume + } + ); + } + result +} + +fn main() { + let sdl_context = sdl2::init().unwrap(); + let audio_subsystem = sdl_context.audio().unwrap(); + + let desired_spec = AudioSpecDesired { + freq: Some(48000), + channels: Some(2), // mono + samples: Some(4) // default sample size + }; + + let device = audio_subsystem.open_queue::(None, &desired_spec).unwrap(); + + let target_bytes = 48000 * 4; + let wave = gen_wave(target_bytes); + device.queue(&wave); + + // Start playback + device.resume(); + + // Play for 2 seconds + std::thread::sleep(Duration::from_millis(2000)); + + // Device is automatically closed when dropped +} diff --git a/src/sdl2/audio.rs b/src/sdl2/audio.rs index 3f694310..fdfb9ef1 100644 --- a/src/sdl2/audio.rs +++ b/src/sdl2/audio.rs @@ -76,10 +76,9 @@ impl AudioSubsystem { /// Opens a new audio device which uses queueing rather than older callback method. #[inline] - pub fn open_queue(&self, device: Option<&str>, spec: &AudioSpecDesired) -> Result - where CB: AudioCallback + pub fn open_queue(&self, device: Option<&str>, spec: &AudioSpecDesired) -> Result, String> where Channel: AudioFormatNum { - AudioQueue::open_queue::(self, device, spec) + AudioQueue::open_queue(self, device, spec) } pub fn current_audio_driver(&self) -> &'static str { @@ -381,7 +380,7 @@ pub struct AudioSpecDesired { } impl AudioSpecDesired { - fn convert_to_ll(freq: Option, channels: Option, samples: Option, userdata: Option<*mut CB>) -> ll::SDL_AudioSpec { + fn convert_to_ll(freq: Option, channels: Option, samples: Option, userdata: *mut CB) -> ll::SDL_AudioSpec { use std::mem::transmute; if let Some(freq) = freq { assert!(freq > 0); } @@ -390,8 +389,6 @@ impl AudioSpecDesired { // A value of 0 means "fallback" or "default". - - unsafe { ll::SDL_AudioSpec { freq: freq.unwrap_or(0), @@ -401,25 +398,35 @@ impl AudioSpecDesired { samples: samples.unwrap_or(0), padding: 0, size: 0, - callback: if userdata.is_some() { - Some(audio_callback_marshall:: + callback: Some(audio_callback_marshall:: as extern "C" fn (arg1: *mut c_void, arg2: *mut uint8_t, - arg3: c_int)) - } - else { - None - }, - userdata: if userdata.is_some() { - transmute(userdata.expect("userdata error in AudioSpecDesired::convert_to_ll")) - } - else { - 0 as *mut c_void - } + arg3: c_int)), + userdata: transmute(userdata) } } } + + fn convert_queue_to_ll(freq: Option, channels: Option, samples: Option) -> ll::SDL_AudioSpec { + if let Some(freq) = freq { assert!(freq > 0); } + if let Some(channels) = channels { assert!(channels > 0); } + if let Some(samples) = samples { assert!(samples > 0); } + + // A value of 0 means "fallback" or "default". + + ll::SDL_AudioSpec { + freq: freq.unwrap_or(0), + format: ::audio_format().to_ll(), + channels: channels.unwrap_or(0), + silence: 0, + samples: samples.unwrap_or(0), + padding: 0, + size: 0, + callback: None, + userdata: 0 as *mut c_void + } + } } #[allow(missing_copy_implementations)] @@ -466,15 +473,16 @@ impl Drop for AudioDeviceID { } /// Wraps SDL_AudioDeviceID and owns the callback data used by the audio device. -pub struct AudioQueue { +pub struct AudioQueue { subsystem: AudioSubsystem, device_id: AudioDeviceID, + phantom: PhantomData } -impl AudioQueue { +impl AudioQueue { /// Opens a new audio device given the desired parameters and callback. - pub fn open_queue (a: &AudioSubsystem, device: Option<&str>, spec: &AudioSpecDesired) -> Result where CB: AudioCallback { - let desired = AudioSpecDesired::convert_to_ll::(spec.freq, spec.channels, spec.samples, None); + pub fn open_queue(a: &AudioSubsystem, device: Option<&str>, spec: &AudioSpecDesired) -> Result, String> { + let desired = AudioSpecDesired::convert_queue_to_ll::(spec.freq, spec.channels, spec.samples); let mut obtained = unsafe { mem::uninitialized::() }; unsafe { @@ -499,6 +507,7 @@ impl AudioQueue { Ok(AudioQueue { subsystem: a.clone(), device_id: device_id, + phantom: PhantomData::default() }) } } @@ -526,7 +535,7 @@ impl AudioQueue { } /// Adds data to the audio queue. - pub fn queue(&self, data: &[Channel]) -> bool { + pub fn queue(&self, data: &[Channel]) -> bool { let result = unsafe {ll::SDL_QueueAudio(self.device_id.id(), data.as_ptr() as *const c_void, data.len() as u32)}; result == 0 } @@ -562,7 +571,7 @@ impl AudioDevice { let b: Box = Box::new(mem::uninitialized()); mem::transmute(b) }; - let desired = AudioSpecDesired::convert_to_ll(spec.freq, spec.channels, spec.samples, Some(userdata)); + let desired = AudioSpecDesired::convert_to_ll(spec.freq, spec.channels, spec.samples, userdata); let mut obtained = unsafe { mem::uninitialized::() }; unsafe {