sdl/
audio.rs

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);   // Don't free the callback!
161    }
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}