Skip to content

Commit 03f2ebf

Browse files
committed
Merge pull request #75 from andelf/add-sdl-audio-support
Add sdl audio support.
2 parents 1baa319 + 13a0f8b commit 03f2ebf

File tree

3 files changed

+380
-5
lines changed

3 files changed

+380
-5
lines changed

src/sdl2/audio.rs

Lines changed: 372 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,372 @@
1+
use std::cast;
2+
use std::ptr;
3+
use std::mem;
4+
use std::c_str::CString;
5+
use std::c_vec::CVec;
6+
use libc;
7+
use libc::{c_int, size_t, c_void};
8+
use libc::{uint8_t, uint16_t, uint32_t};
9+
use std::raw::Slice;
10+
11+
use get_error;
12+
use rwops::RWops;
13+
14+
15+
#[allow(non_camel_case_types)]
16+
pub mod ll {
17+
use libc::{c_int, c_uint, c_void, uint8_t, uint32_t};
18+
use libc::{uint16_t, c_double, c_char};
19+
use rwops::ll::SDL_RWops;
20+
21+
// assume LSB
22+
pub type SDL_AudioFormat = uint16_t;
23+
pub static AUDIO_U8 : SDL_AudioFormat = 0x0008;
24+
pub static AUDIO_S8 : SDL_AudioFormat = 0x8008;
25+
pub static AUDIO_U16LSB : SDL_AudioFormat = 0x0010;
26+
pub static AUDIO_S16LSB : SDL_AudioFormat = 0x8010;
27+
pub static AUDIO_U16MSB : SDL_AudioFormat = 0x1010;
28+
pub static AUDIO_S16MSB : SDL_AudioFormat = 0x9010;
29+
pub static AUDIO_U16 : SDL_AudioFormat = AUDIO_U16LSB;
30+
pub static AUDIO_S16 : SDL_AudioFormat = AUDIO_S16LSB;
31+
pub static AUDIO_S32LSB : SDL_AudioFormat = 0x8020;
32+
pub static AUDIO_S32MSB : SDL_AudioFormat = 0x9020;
33+
pub static AUDIO_S32 : SDL_AudioFormat = AUDIO_S32LSB;
34+
pub static AUDIO_F32LSB : SDL_AudioFormat = 0x8120;
35+
pub static AUDIO_F32MSB : SDL_AudioFormat = 0x9120;
36+
pub static AUDIO_F32 : SDL_AudioFormat = AUDIO_F32LSB;
37+
pub static AUDIO_U16SYS : SDL_AudioFormat = AUDIO_U16LSB;
38+
pub static AUDIO_S16SYS : SDL_AudioFormat = AUDIO_S16LSB;
39+
pub static AUDIO_S32SYS : SDL_AudioFormat = AUDIO_S32LSB;
40+
pub static AUDIO_F32SYS : SDL_AudioFormat = AUDIO_F32LSB;
41+
42+
pub type SDL_AudioCallback =
43+
::std::option::Option<extern "C" fn
44+
(arg1: *c_void, arg2: *uint8_t,
45+
arg3: c_int)>;
46+
pub struct SDL_AudioSpec {
47+
pub freq: c_int,
48+
pub format: SDL_AudioFormat,
49+
pub channels: uint8_t,
50+
pub silence: uint8_t,
51+
pub samples: uint16_t,
52+
pub padding: uint16_t,
53+
pub size: uint32_t,
54+
pub callback: SDL_AudioCallback,
55+
pub userdata: *c_void,
56+
}
57+
pub type SDL_AudioFilter =
58+
::std::option::Option<extern "C" fn
59+
(arg1: *SDL_AudioCVT,
60+
arg2: SDL_AudioFormat)>;
61+
pub struct SDL_AudioCVT {
62+
pub needed: c_int,
63+
pub src_format: SDL_AudioFormat,
64+
pub dst_format: SDL_AudioFormat,
65+
pub rate_incr: c_double,
66+
pub buf: *mut uint8_t,
67+
pub len: c_int,
68+
pub len_cvt: c_int,
69+
pub len_mult: c_int,
70+
pub len_ratio: c_double,
71+
filters: [SDL_AudioFilter, ..10u],
72+
filter_index: c_int,
73+
}
74+
pub type SDL_AudioDeviceID = uint32_t;
75+
pub type SDL_AudioStatus = c_uint;
76+
pub static SDL_AUDIO_STOPPED: c_uint = 0;
77+
pub static SDL_AUDIO_PLAYING: c_uint = 1;
78+
pub static SDL_AUDIO_PAUSED: c_uint = 2;
79+
extern "C" {
80+
pub fn SDL_GetNumAudioDrivers() -> c_int;
81+
pub fn SDL_GetAudioDriver(index: c_int) -> *c_char;
82+
pub fn SDL_AudioInit(driver_name: *c_char) -> c_int;
83+
pub fn SDL_AudioQuit();
84+
pub fn SDL_GetCurrentAudioDriver() -> *c_char;
85+
pub fn SDL_OpenAudio(desired: *SDL_AudioSpec,
86+
obtained: *SDL_AudioSpec) -> c_int;
87+
pub fn SDL_GetNumAudioDevices(iscapture: c_int) -> c_int;
88+
pub fn SDL_GetAudioDeviceName(index: c_int, iscapture: c_int) -> *c_char;
89+
pub fn SDL_OpenAudioDevice(device: *c_char, iscapture: c_int,
90+
desired: *SDL_AudioSpec,
91+
obtained: *SDL_AudioSpec,
92+
allowed_changes: c_int) -> SDL_AudioDeviceID;
93+
pub fn SDL_GetAudioStatus() -> SDL_AudioStatus;
94+
pub fn SDL_GetAudioDeviceStatus(dev: SDL_AudioDeviceID) ->
95+
SDL_AudioStatus;
96+
pub fn SDL_PauseAudio(pause_on: c_int);
97+
pub fn SDL_PauseAudioDevice(dev: SDL_AudioDeviceID, pause_on: c_int);
98+
pub fn SDL_LoadWAV_RW(src: *SDL_RWops, freesrc: c_int,
99+
spec: *SDL_AudioSpec,
100+
audio_buf: **uint8_t, audio_len: *uint32_t) -> *SDL_AudioSpec;
101+
pub fn SDL_FreeWAV(audio_buf: *uint8_t);
102+
pub fn SDL_BuildAudioCVT(cvt: *mut SDL_AudioCVT,
103+
src_format: SDL_AudioFormat, src_channels: uint8_t,
104+
src_rate: c_int, dst_format: SDL_AudioFormat,
105+
dst_channels: uint8_t, dst_rate: c_int) -> c_int;
106+
pub fn SDL_ConvertAudio(cvt: *mut SDL_AudioCVT) -> c_int;
107+
pub fn SDL_MixAudio(dst: *uint8_t, src: *uint8_t, len: uint32_t,
108+
volume: c_int);
109+
pub fn SDL_MixAudioFormat(dst: *uint8_t, src: *uint8_t,
110+
format: SDL_AudioFormat, len: uint32_t,
111+
volume: c_int);
112+
pub fn SDL_LockAudio();
113+
pub fn SDL_LockAudioDevice(dev: SDL_AudioDeviceID);
114+
pub fn SDL_UnlockAudio();
115+
pub fn SDL_UnlockAudioDevice(dev: SDL_AudioDeviceID);
116+
pub fn SDL_CloseAudio();
117+
pub fn SDL_CloseAudioDevice(dev: SDL_AudioDeviceID);
118+
}
119+
120+
}
121+
122+
123+
pub type AudioFormat = ll::SDL_AudioFormat;
124+
125+
pub static AudioU8 : AudioFormat = ll::AUDIO_U8;
126+
pub static AudioS8 : AudioFormat = ll::AUDIO_S8;
127+
pub static AudioU16LSB : AudioFormat = ll::AUDIO_U16LSB;
128+
pub static AudioS16LSB : AudioFormat = ll::AUDIO_S16LSB;
129+
pub static AudioU16MSB : AudioFormat = ll::AUDIO_U16MSB;
130+
pub static AudioS16MSB : AudioFormat = ll::AUDIO_S16MSB;
131+
pub static AudioU16 : AudioFormat = ll::AUDIO_U16;
132+
pub static AudioS16 : AudioFormat = ll::AUDIO_S16;
133+
pub static AudioS32LSB : AudioFormat = ll::AUDIO_S32LSB;
134+
pub static AudioS32MSB : AudioFormat = ll::AUDIO_S32MSB;
135+
pub static AudioS32 : AudioFormat = ll::AUDIO_S32;
136+
pub static AudioF32LSB : AudioFormat = ll::AUDIO_F32LSB;
137+
pub static AudioF32MSB : AudioFormat = ll::AUDIO_F32MSB;
138+
pub static AudioF32 : AudioFormat = ll::AUDIO_F32;
139+
pub static AudioU16SYS : AudioFormat = ll::AUDIO_U16SYS;
140+
pub static AudioS16SYS : AudioFormat = ll::AUDIO_S16SYS;
141+
pub static AudioS32SYS : AudioFormat = ll::AUDIO_S32SYS;
142+
pub static AudioF32SYS : AudioFormat = ll::AUDIO_F32SYS;
143+
144+
#[repr(C)]
145+
#[deriving(Clone, Eq, Hash, Show, FromPrimitive)]
146+
pub enum AudioStatus {
147+
Stopped = ll::SDL_AUDIO_STOPPED as int,
148+
Playing = ll::SDL_AUDIO_PLAYING as int,
149+
Paused = ll::SDL_AUDIO_PAUSED as int,
150+
}
151+
152+
pub fn get_num_audio_drivers() -> int {
153+
unsafe { ll::SDL_GetNumAudioDrivers() as int }
154+
}
155+
156+
pub fn get_audio_driver(index: int) -> ~str {
157+
unsafe {
158+
let buf = ll::SDL_GetAudioDriver(index as c_int);
159+
CString::new(buf, false).as_str().unwrap().into_owned()
160+
}
161+
}
162+
163+
pub fn get_num_audio_devices(iscapture: int) -> int {
164+
unsafe { ll::SDL_GetNumAudioDevices(iscapture as c_int) as int }
165+
}
166+
167+
pub fn get_audio_device_name(index: int, iscapture: int) -> ~str {
168+
unsafe {
169+
let buf = ll::SDL_GetAudioDeviceName(index as c_int, iscapture as c_int);
170+
CString::new(buf, false).as_str().unwrap().into_owned()
171+
}
172+
}
173+
174+
pub fn audio_init(name: &str) -> Result<(), ~str> {
175+
let ret = name.with_c_str(|buf| {
176+
unsafe { ll::SDL_AudioInit(buf) }
177+
});
178+
if ret == 0 {
179+
Ok(())
180+
} else {
181+
Err(get_error())
182+
}
183+
}
184+
185+
pub fn audio_quit() {
186+
unsafe { ll::SDL_AudioQuit() }
187+
}
188+
189+
pub fn get_current_audio_driver() -> ~str {
190+
unsafe {
191+
let buf = ll::SDL_GetCurrentAudioDriver();
192+
CString::new(buf, false).as_str().unwrap().into_owned()
193+
}
194+
}
195+
196+
// make this same layout as in C
197+
#[repr(C)]
198+
pub struct AudioSpec<'a > {
199+
pub freq: c_int,
200+
pub format: AudioFormat,
201+
pub channels: uint8_t,
202+
pub silence: uint8_t,
203+
pub samples: uint16_t,
204+
pub padding: uint16_t,
205+
pub size: uint32_t,
206+
c_callback: ll::SDL_AudioCallback,
207+
pub callback: &'a |&mut [u8]|:'a, // same size as *c_void
208+
}
209+
210+
extern "C" fn c_audio_callback(userdata: *c_void, stream: *uint8_t, len: c_int) {
211+
unsafe {
212+
let f : &|&mut [u8]| = cast::transmute(userdata);
213+
214+
// FIXME: lifetime error in calling
215+
//slice::raw::mut_buf_as_slice(stream as *mut u8, len as uint, *f)
216+
(*f)(cast::transmute(Slice {
217+
data: stream,
218+
len: len as uint
219+
}))
220+
}
221+
}
222+
223+
224+
impl<'a> AudioSpec<'a> {
225+
pub fn load_wav(path: &Path) -> Result<(~AudioSpec, CVec<u8>), ~str> {
226+
AudioSpec::load_wav_rw(try!(RWops::from_file(path, "rb")))
227+
}
228+
229+
pub fn load_wav_rw(src: &RWops) -> Result<(~AudioSpec, CVec<u8>), ~str> {
230+
assert_eq!(mem::size_of::<AudioSpec>(), mem::size_of::<ll::SDL_AudioSpec>());
231+
let mut spec = unsafe { mem::uninit::<AudioSpec>() };
232+
let audio_buf = ptr::null::<u8>();
233+
let audio_len = 0u32;
234+
unsafe {
235+
let ret = ll::SDL_LoadWAV_RW(src.raw, 0, cast::transmute(&spec), &audio_buf, &audio_len);
236+
if ret.is_null() {
237+
Err(get_error())
238+
} else {
239+
let v = CVec::new_with_dtor(audio_buf as *mut u8, audio_len as uint, proc() {
240+
ll::SDL_FreeWAV(audio_buf)
241+
});
242+
spec.c_callback = Some(c_audio_callback);
243+
Ok((~spec, v))
244+
}
245+
}
246+
}
247+
}
248+
249+
pub type AudioDeviceID = ll::SDL_AudioDeviceID;
250+
251+
// use rust's type system to make it right.
252+
pub enum AudioDevice{
253+
PlaybackDevice(AudioDeviceID),
254+
RecordingDevice(AudioDeviceID),
255+
}
256+
257+
impl AudioDevice {
258+
fn to_id(self) -> AudioDeviceID {
259+
match self {
260+
PlaybackDevice(id) => id,
261+
RecordingDevice(id) => id
262+
}
263+
}
264+
265+
pub fn open(device: &str, iscapture: int, spec: &AudioSpec) -> Result<(AudioDevice, ~AudioSpec), ~str> {
266+
//! SDL_OpenAudioDevice
267+
let obtained = unsafe { mem::uninit::<AudioSpec>() };
268+
unsafe {
269+
let ret = ll::SDL_OpenAudioDevice(device.to_c_str().unwrap(),
270+
iscapture as c_int,
271+
cast::transmute(spec),
272+
cast::transmute(&obtained),
273+
0);
274+
if ret == 0 {
275+
Err(get_error())
276+
} else {
277+
if iscapture == 0 { // plaback device
278+
Ok((PlaybackDevice(ret as AudioDeviceID), ~obtained))
279+
} else {
280+
Ok((RecordingDevice(ret as AudioDeviceID), ~obtained))
281+
}
282+
}
283+
}
284+
}
285+
286+
pub fn get_status(self) -> AudioStatus {
287+
unsafe {
288+
let status = ll::SDL_GetAudioDeviceStatus(self.to_id());
289+
FromPrimitive::from_int(status as int).unwrap()
290+
}
291+
}
292+
293+
pub fn pause(self) {
294+
unsafe { ll::SDL_PauseAudioDevice(self.to_id(), 1) }
295+
}
296+
297+
pub fn resume(self) {
298+
unsafe { ll::SDL_PauseAudioDevice(self.to_id(), 0) }
299+
}
300+
301+
pub fn lock(self) {
302+
unsafe { ll::SDL_LockAudioDevice(self.to_id()) }
303+
}
304+
305+
pub fn unlock(self) {
306+
unsafe { ll::SDL_UnlockAudioDevice(self.to_id()) }
307+
}
308+
309+
pub fn close(self) {
310+
//! Shut down audio processing and close the audio device.
311+
unsafe { ll::SDL_CloseAudioDevice(self.to_id()) }
312+
}
313+
}
314+
315+
#[deriving(Eq)] #[allow(raw_pointer_deriving)]
316+
pub struct AudioCVT {
317+
pub raw: *mut ll::SDL_AudioCVT,
318+
pub owned: bool,
319+
}
320+
321+
impl Drop for AudioCVT {
322+
fn drop(&mut self) {
323+
if self.owned {
324+
unsafe { libc::free(self.raw as *mut c_void) }
325+
}
326+
}
327+
}
328+
329+
impl AudioCVT {
330+
pub fn new(src_format: AudioFormat, src_channels: u8, src_rate: int,
331+
dst_format: AudioFormat, dst_channels: u8, dst_rate: int) -> Result<~AudioCVT, ~str> {
332+
unsafe {
333+
let c_cvt_p = libc::malloc(mem::size_of::<ll::SDL_AudioCVT>() as size_t) as *mut ll::SDL_AudioCVT;
334+
let ret = ll::SDL_BuildAudioCVT(c_cvt_p,
335+
src_format, src_channels, src_rate as c_int,
336+
dst_format, dst_channels, dst_rate as c_int);
337+
if ret == 1 || ret == 0 {
338+
Ok(~AudioCVT { raw: c_cvt_p, owned: true })
339+
} else {
340+
Err(get_error())
341+
}
342+
}
343+
}
344+
345+
pub fn convert(&self, src: CVec<u8>) -> Result<CVec<u8>, ~str> {
346+
//! Convert audio data to a desired audio format.
347+
348+
unsafe {
349+
if (*self.raw).needed != 1 {
350+
return Err(~"no convertion needed!")
351+
}
352+
// set len
353+
(*self.raw).len = src.len() as c_int;
354+
// alloc buf
355+
let size = (*self.raw).len * (*self.raw).len_mult;
356+
(*self.raw).buf = libc::malloc(size as size_t) as *mut u8;
357+
// set buf
358+
ptr::copy_memory::<u8>((*self.raw).buf, src.as_slice().as_ptr(), src.len());
359+
// convert
360+
let ret = ll::SDL_ConvertAudio(self.raw);
361+
// return
362+
let p = (*self.raw).buf as *mut c_void; // send to proc()
363+
if ret == 0 {
364+
Ok( CVec::new_with_dtor((*self.raw).buf as *mut u8, (*self.raw).len_cvt as uint,
365+
proc() { libc::free(p) })
366+
)
367+
} else {
368+
Err(get_error())
369+
}
370+
}
371+
}
372+
}

src/sdl2/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,4 @@ pub mod timer;
3030
pub mod render;
3131
pub mod rwops;
3232
pub mod sdl;
33+
pub mod audio;

0 commit comments

Comments
 (0)