1use self::ll::{AUDIO_S16LSB, AUDIO_S16MSB, AUDIO_S8, AUDIO_U16LSB, AUDIO_U16MSB, AUDIO_U8};
2use self::ll::{SDL_LockAudio, SDL_MixAudio, SDL_OpenAudio};
3use self::ll::{SDL_UnlockAudio};
4
5use std::mem::{forget, transmute};
6use libc::{c_int, c_void, uint16_t};
7use std::ptr::null_mut;
8
9pub mod ll {
10 #![allow(non_camel_case_types)]
11
12 use libc::{c_int, c_void, uint16_t};
13
14 pub const AUDIO_U8: uint16_t = 0x0008;
15 pub const AUDIO_S8: uint16_t = 0x8008;
16 pub const AUDIO_U16LSB: uint16_t = 0x0010;
17 pub const AUDIO_S16LSB: uint16_t = 0x8010;
18 pub const AUDIO_U16MSB: uint16_t = 0x1010;
19 pub const AUDIO_S16MSB: uint16_t = 0x9010;
20 pub const AUDIO_U16: uint16_t = AUDIO_U16LSB;
21 pub const AUDIO_S16: uint16_t = AUDIO_S16LSB;
22
23 #[repr(C)]
24 #[derive(Copy, Clone)]
25 pub struct SDL_AudioSpec {
26 pub freq: c_int,
27 pub format: u16,
28 pub channels: u8,
29 pub silence: u8,
30 pub samples: u16,
31 pub padding: u16,
32 pub size: u32,
33 pub callback: *mut u8,
34 pub userdata: *mut c_void,
35 }
36
37 extern "C" {
38 pub fn SDL_OpenAudio(desired: *mut SDL_AudioSpec, obtained: *mut SDL_AudioSpec) -> c_int;
39 pub fn SDL_PauseAudio(pause_on: c_int);
40 pub fn SDL_MixAudio(dst: *mut u8, src: *const u8, len: u32, volume: c_int);
41 pub fn SDL_LockAudio();
42 pub fn SDL_UnlockAudio();
43 pub fn SDL_CloseAudio();
44 }
45}
46
47#[derive(Copy, Clone)]
48pub enum AudioFormat {
49 U8 = AUDIO_U8 as isize,
50 S8 = AUDIO_S8 as isize,
51 U16Lsb = AUDIO_U16LSB as isize,
52 S16Lsb = AUDIO_S16LSB as isize,
53 U16Msb = AUDIO_U16MSB as isize,
54 S16Msb = AUDIO_S16MSB as isize
55}
56
57pub static U16_AUDIO_FORMAT: AudioFormat = AudioFormat::U16Lsb;
58pub static S16_AUDIO_FORMAT: AudioFormat = AudioFormat::S16Lsb;
59
60impl AudioFormat {
61 pub fn to_ll_format(self) -> uint16_t {
62 match self {
63 AudioFormat::U8 => AUDIO_U8,
64 AudioFormat::S8 => AUDIO_S8,
65 AudioFormat::U16Lsb => AUDIO_U16LSB,
66 AudioFormat::S16Lsb => AUDIO_S16LSB,
67 AudioFormat::U16Msb => AUDIO_U16MSB,
68 AudioFormat::S16Msb => AUDIO_S16MSB,
69 }
70 }
71
72 pub fn from_ll_format(x: uint16_t) -> AudioFormat {
73 match x {
74 AUDIO_U8 => AudioFormat::U8,
75 AUDIO_S8 => AudioFormat::S8,
76 AUDIO_U16LSB => AudioFormat::U16Lsb,
77 AUDIO_S16LSB => AudioFormat::S16Lsb,
78 AUDIO_U16MSB => AudioFormat::U16Msb,
79 AUDIO_S16MSB => AudioFormat::S16Msb,
80 _ => panic!("unexpected format")
81 }
82 }
83}
84
85#[derive(PartialEq, Eq, Copy, Clone)]
86pub enum Channels {
87 Mono,
88 Stereo,
89}
90
91impl Channels {
92 pub fn new(count: c_int) -> Channels { if count == 1 { Channels::Mono } else { Channels::Stereo } }
93 pub fn count(self) -> c_int { match self { Channels::Mono => 1, Channels::Stereo => 2 } }
94}
95
96pub type AudioCallback = fn(&mut [u8]);
97
98#[derive(Copy)]
99pub struct DesiredAudioSpec {
100 pub freq: c_int,
101 pub format: AudioFormat,
102 pub channels: Channels,
103 pub samples: u16,
104 pub callback: AudioCallback,
105}
106
107impl DesiredAudioSpec {
108 fn to_ll_spec(self) -> ll::SDL_AudioSpec {
109 unsafe {
110 let DesiredAudioSpec { freq, format, channels, samples, callback } = self;
111 ll::SDL_AudioSpec {
112 freq: freq,
113 format: format.to_ll_format(),
114 channels: channels.count() as u8,
115 silence: 0,
116 samples: samples,
117 padding: 0,
118 size: 0,
119 callback: native_callback as *mut u8,
120 userdata: transmute(Box::new(callback)),
121 }
122 }
123 }
124}
125
126impl Clone for DesiredAudioSpec {
127 fn clone(&self) -> DesiredAudioSpec {
128 *self
129 }
130}
131
132#[derive(Copy, Clone)]
133pub struct ObtainedAudioSpec {
134 pub freq: c_int,
135 pub format: AudioFormat,
136 pub channels: Channels,
137 pub silence: u8,
138 pub samples: u16,
139 pub size: u32,
140}
141
142impl ObtainedAudioSpec {
143 fn from_ll_spec(spec: &ll::SDL_AudioSpec) -> ObtainedAudioSpec {
144 ObtainedAudioSpec {
145 freq: spec.freq,
146 format: AudioFormat::from_ll_format(spec.format),
147 channels: Channels::new(spec.channels as c_int),
148 silence: spec.silence,
149 samples: spec.samples,
150 size: spec.size,
151 }
152 }
153}
154
155extern fn native_callback(userdata: *const c_void, stream: *mut u8, len: c_int) {
156 unsafe {
157 let callback: Box<AudioCallback> = transmute(userdata);
158 let buffer = transmute((stream, len as usize));
159 (*callback)(buffer);
160 forget(callback); }
162}
163
164pub fn open(desired: DesiredAudioSpec) -> Result<ObtainedAudioSpec,()> {
165 unsafe {
166 let mut ll_desired = desired.to_ll_spec();
167 let mut ll_obtained = ll::SDL_AudioSpec {
168 freq: 0,
169 format: 0,
170 channels: 0,
171 silence: 0,
172 samples: 0,
173 padding: 0,
174 size: 0,
175 callback: null_mut(),
176 userdata: null_mut(),
177 };
178
179 if SDL_OpenAudio(&mut ll_desired, &mut ll_obtained) < 0 {
180 Err(())
181 } else {
182 Ok(ObtainedAudioSpec::from_ll_spec(&ll_obtained))
183 }
184 }
185}
186
187pub fn pause(paused: bool) {
188 unsafe {
189 ll::SDL_PauseAudio(paused as c_int);
190 }
191}
192
193pub fn close() {
194 unsafe {
195 ll::SDL_CloseAudio();
196 }
197}
198
199pub fn mix(dest: &mut [u8], src: &[u8], volume: c_int) {
200 unsafe {
201 assert!(dest.len() == src.len());
202 SDL_MixAudio(&mut dest[0], &src[0], dest.len() as u32, volume);
203 }
204}
205
206pub fn with_lock<F: Fn() -> bool>(f: F) -> bool {
207 unsafe {
208 SDL_LockAudio();
209 let result = f();
210 SDL_UnlockAudio();
211 result
212 }
213}