mirror of
https://github.com/encounter/rust-sdl2.git
synced 2026-07-10 21:18:41 -07:00
Merge pull request #527 from hectorgrey/master
Added Audio Queue functions to sdl2-sys
This commit is contained in:
+3
-3
@@ -5,9 +5,9 @@ rust:
|
||||
- nightly
|
||||
- stable
|
||||
install:
|
||||
- sudo add-apt-repository ppa:team-xbmc/ppa -y
|
||||
- sudo apt-get update -q
|
||||
- sudo apt-get install libsdl2-dev
|
||||
- wget https://www.libsdl.org/release/SDL2-2.0.4.tar.gz -O sdl2.tar.gz
|
||||
- tar xzf sdl2.tar.gz
|
||||
- pushd SDL2-2.0.4 && ./configure && make && sudo make install && popd
|
||||
before_script:
|
||||
- |
|
||||
pip install 'travis-cargo<0.2' --user &&
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
extern crate sdl2;
|
||||
|
||||
use sdl2::audio::{AudioCallback, AudioSpecDesired};
|
||||
|
||||
use std::time::Duration;
|
||||
|
||||
fn gen_wave(bytes_to_write: i32) -> Vec<i16> {
|
||||
// Generate a square wave
|
||||
let tone_volume = 1000i16;
|
||||
let period = 48000 / 256;
|
||||
let sample_count = bytes_to_write;
|
||||
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::<i16>(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
|
||||
}
|
||||
@@ -96,6 +96,9 @@ extern "C" {
|
||||
pub fn SDL_MixAudioFormat(dst: *mut uint8_t, src: *const uint8_t,
|
||||
format: SDL_AudioFormat, len: uint32_t,
|
||||
volume: c_int);
|
||||
pub fn SDL_QueueAudio(dev: SDL_AudioDeviceID, data: *const c_void, len: uint32_t) -> c_int;
|
||||
pub fn SDL_GetQueuedAudioSize(dev: SDL_AudioDeviceID) -> uint32_t;
|
||||
pub fn SDL_ClearQueuedAudio(dev: SDL_AudioDeviceID);
|
||||
pub fn SDL_LockAudio();
|
||||
pub fn SDL_LockAudioDevice(dev: SDL_AudioDeviceID);
|
||||
pub fn SDL_UnlockAudio();
|
||||
|
||||
+109
-4
@@ -74,6 +74,13 @@ impl AudioSubsystem {
|
||||
AudioDevice::open_playback(self, device, spec, get_callback)
|
||||
}
|
||||
|
||||
/// Opens a new audio device which uses queueing rather than older callback method.
|
||||
#[inline]
|
||||
pub fn open_queue<Channel>(&self, device: Option<&str>, spec: &AudioSpecDesired) -> Result<AudioQueue<Channel>, String> where Channel: AudioFormatNum
|
||||
{
|
||||
AudioQueue::open_queue(self, device, spec)
|
||||
}
|
||||
|
||||
pub fn current_audio_driver(&self) -> &'static str {
|
||||
unsafe {
|
||||
let buf = ll::SDL_GetCurrentAudioDriver();
|
||||
@@ -392,14 +399,34 @@ impl AudioSpecDesired {
|
||||
padding: 0,
|
||||
size: 0,
|
||||
callback: Some(audio_callback_marshall::<CB>
|
||||
as extern "C" fn
|
||||
(arg1: *mut c_void,
|
||||
arg2: *mut uint8_t,
|
||||
arg3: c_int)),
|
||||
as extern "C" fn
|
||||
(arg1: *mut c_void,
|
||||
arg2: *mut uint8_t,
|
||||
arg3: c_int)),
|
||||
userdata: transmute(userdata)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn convert_queue_to_ll<Channel: AudioFormatNum>(freq: Option<i32>, channels: Option<u8>, samples: Option<u16>) -> 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: <Channel as AudioFormatNum>::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)]
|
||||
@@ -445,6 +472,84 @@ impl Drop for AudioDeviceID {
|
||||
}
|
||||
}
|
||||
|
||||
/// Wraps SDL_AudioDeviceID and owns the callback data used by the audio device.
|
||||
pub struct AudioQueue<Channel: AudioFormatNum> {
|
||||
subsystem: AudioSubsystem,
|
||||
device_id: AudioDeviceID,
|
||||
phantom: PhantomData<Channel>
|
||||
}
|
||||
|
||||
impl<Channel: AudioFormatNum> AudioQueue<Channel> {
|
||||
/// Opens a new audio device given the desired parameters and callback.
|
||||
pub fn open_queue(a: &AudioSubsystem, device: Option<&str>, spec: &AudioSpecDesired) -> Result<AudioQueue<Channel>, String> {
|
||||
let desired = AudioSpecDesired::convert_queue_to_ll::<Channel>(spec.freq, spec.channels, spec.samples);
|
||||
|
||||
let mut obtained = unsafe { mem::uninitialized::<ll::SDL_AudioSpec>() };
|
||||
unsafe {
|
||||
let device = match device {
|
||||
Some(device) => Some(CString::new(device).unwrap()),
|
||||
None => None
|
||||
};
|
||||
let device_ptr = device.map_or(ptr::null(), |s| s.as_ptr());
|
||||
|
||||
let iscapture_flag = 0;
|
||||
let device_id = ll::SDL_OpenAudioDevice(
|
||||
device_ptr as *const c_char, iscapture_flag, &desired,
|
||||
&mut obtained, 0
|
||||
);
|
||||
match device_id {
|
||||
0 => {
|
||||
Err(get_error())
|
||||
},
|
||||
id => {
|
||||
let device_id = AudioDeviceID::PlaybackDevice(id);
|
||||
|
||||
Ok(AudioQueue {
|
||||
subsystem: a.clone(),
|
||||
device_id: device_id,
|
||||
phantom: PhantomData::default()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn subsystem(&self) -> &AudioSubsystem { &self.subsystem }
|
||||
|
||||
pub fn status(&self) -> AudioStatus {
|
||||
unsafe {
|
||||
let status = ll::SDL_GetAudioDeviceStatus(self.device_id.id());
|
||||
FromPrimitive::from_i32(status as i32).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
/// Pauses playback of the audio device.
|
||||
pub fn pause(&self) {
|
||||
unsafe { ll::SDL_PauseAudioDevice(self.device_id.id(), 1) }
|
||||
}
|
||||
|
||||
/// Starts playback of the audio device.
|
||||
pub fn resume(&self) {
|
||||
unsafe { ll::SDL_PauseAudioDevice(self.device_id.id(), 0) }
|
||||
}
|
||||
|
||||
/// Adds data to the audio queue.
|
||||
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
|
||||
}
|
||||
|
||||
pub fn size(&self) -> u32 {
|
||||
unsafe {ll::SDL_GetQueuedAudioSize(self.device_id.id())}
|
||||
}
|
||||
|
||||
/// Clears all data from the current audio queue.
|
||||
pub fn clear(&self) {
|
||||
unsafe {ll::SDL_ClearQueuedAudio(self.device_id.id());}
|
||||
}
|
||||
}
|
||||
|
||||
/// Wraps SDL_AudioDeviceID and owns the callback data used by the audio device.
|
||||
pub struct AudioDevice<CB: AudioCallback> {
|
||||
subsystem: AudioSubsystem,
|
||||
|
||||
Reference in New Issue
Block a user