diff options
author | David Barksdale <amatus@amatus.name> | 2013-09-28 14:44:22 -0500 |
---|---|---|
committer | David Barksdale <amatus@amatus.name> | 2013-09-28 14:44:22 -0500 |
commit | 91f8e289c7ed3df1339848f2de9f07d33b35902a (patch) | |
tree | 572a70d2ce045aef68b6009b7bd278263435a4d6 |
Initial commit now that things are taking shape.
-rw-r--r-- | mp3lame.rs | 74 | ||||
-rw-r--r-- | oss.rs | 139 | ||||
-rw-r--r-- | per.rs | 49 |
3 files changed, 262 insertions, 0 deletions
diff --git a/mp3lame.rs b/mp3lame.rs new file mode 100644 index 0000000..eb7d572 --- /dev/null +++ b/mp3lame.rs @@ -0,0 +1,74 @@ +use std::libc::{c_float, c_int, c_short, c_uchar, c_ulong, c_void}; + +type GlobalFlags_ = *c_void; + +enum MpegMode { + Stereo = 0, + JointStereo, + DualChannel, + Mono, + NotSet, + MaxIndicator +} + +#[link_args = "-lmp3lame"] + +extern { + fn lame_init() -> GlobalFlags_; + fn lame_set_num_samples(gfp: GlobalFlags_, samples: c_ulong) -> c_int; + fn lame_get_num_samples(gfp: GlobalFlags_) -> c_ulong; + fn lame_set_in_samplerate(gfp: GlobalFlags_, rate: c_int) -> c_int; + fn lame_get_in_samplerate(gfp: GlobalFlags_) -> c_int; + fn lame_set_num_channels(gfp: GlobalFlags_, channels: c_int) -> c_int; + fn lame_get_num_channels(gfp: GlobalFlags_) -> c_int; + fn lame_set_scale(gfp: GlobalFlags_, scale: c_float) -> c_int; + fn lame_get_scale(gfp: GlobalFlags_) -> c_float; + fn lame_set_scale_left(gfp: GlobalFlags_, scale: c_float) -> c_int; + fn lame_get_scale_left(gfp: GlobalFlags_) -> c_float; + fn lame_set_scale_right(gfp: GlobalFlags_, scale: c_float) -> c_int; + fn lame_get_scale_right(gfp: GlobalFlags_) -> c_float; + fn lame_set_out_samplerate(gfp: GlobalFlags_, rate: c_int) -> c_int; + fn lame_get_out_samplerate(gfp: GlobalFlags_) -> c_int; + fn lame_set_analysis(gfp: GlobalFlags_, analysis: c_int) -> c_int; + fn lame_get_analysis(gfp: GlobalFlags_) -> c_int; + fn lame_set_bWriteVbrTag(gfp: GlobalFlags_, write_tag: c_int) -> c_int; + fn lame_get_bWriteVbrTag(gfp: GlobalFlags_) -> c_int; + fn lame_set_decode_only(gfp: GlobalFlags_, decode: c_int) -> c_int; + fn lame_get_decode_only(gfp: GlobalFlags_) -> c_int; + fn lame_set_quality(gfp: GlobalFlags_, quality: c_int) -> c_int; + fn lame_get_quality(gfp: GlobalFlags_) -> c_int; + fn lame_set_mode(gfp: GlobalFlags_, mode: MpegMode) -> c_int; + fn lame_get_mode(gfp: GlobalFlags_) -> MpegMode; + fn lame_set_brate(gfp: GlobalFlags_, rate: c_int) -> c_int; + fn lame_get_brate(gfp: GlobalFlags_) -> c_int; + fn lame_set_disable_reservoir(gfp: GlobalFlags_, disable: c_int) -> c_int; + fn lame_get_disable_reservoir(gfp: GlobalFlags_) -> c_int; + fn lame_init_params(gfp: GlobalFlags_) -> c_int; + fn lame_close(gfp: GlobalFlags_) -> c_int; + fn lame_encode_buffer_interleaved(gfp: GlobalFlags_, + pcm: *c_short, + num_samples:c_int, + mp3buf: *c_uchar, + mp3buf_size: c_int) -> c_int; + fn lame_encode_flush_nogap(gfp: GlobalFlags_, + mp3buf: *c_uchar, + size: c_int) -> c_int; +} + +pub struct LameContext { + gfp: GlobalFlags_ +} + +impl LameContext { + #[fixed_stack_segment] + pub fn new() -> LameContext { + LameContext { gfp: unsafe { lame_init() }} + } +} + +impl Drop for LameContext { + #[fixed_stack_segment] + fn drop(&mut self) { + unsafe { lame_close(self.gfp) }; + } +} @@ -0,0 +1,139 @@ +use std::libc::{c_int, c_void, close, O_RDONLY, open, read}; +use std::rt::io::{io_error, IoError, OtherIoError}; +use std::vec; + +macro_rules! _SIO( + ($x: expr, $y: expr) => (($x << 8) | $y); +) + +/* rust doesn't have a sizeof you can use in constant expressions >.< +macro_rules! _SIOWR( + ($x: expr, $y: expr, $t: ty) => ( + 0xc0000000 as c_int | (size_of::<$t>() as c_int << 16) | ($x << 8) | $y); +) +*/ + +macro_rules! _SIOWR( + ($x: expr, $y: expr, $t: expr) => ( + 0xc0000000 as c_int | ($t << 16) | ($x << 8) | $y); +) + +static SNDCTL_DSP_RESET: c_int = _SIO!('P' as c_int, 0); +static SNDCTL_DSP_SYNC: c_int = _SIO!('P' as c_int, 1); +static SNDCTL_DSP_SPEED: c_int = _SIOWR!('P' as c_int, 2, 4); +static SNDCTL_DSP_STEREO: c_int = _SIOWR!('P' as c_int, 3, 4); +static SNDCTL_DSP_GETBLKSIZE: c_int = _SIOWR!('P' as c_int, 4, 4); +static SNDCTL_DSP_SETFMT: c_int = _SIOWR!('P' as c_int, 5, 4); +static AFMT_S16_LE: c_int = 0x00000010; + +extern { + fn ioctl(fd: c_int, ioctl: c_int, arg: *mut c_int) -> c_int; +} + +pub struct OssDevice { + fd: c_int, +} + +impl OssDevice { + #[fixed_stack_segment] + pub fn new(path: &Path) -> Option<OssDevice> { + let fd = do path.with_c_str |path| { + unsafe { open(path, O_RDONLY, 0777) } + }; + if fd != -1 { + Some(OssDevice { fd: fd }) + } else { + None + } + } + #[fixed_stack_segment] + pub fn reset(&self) { + unsafe { + if ioctl(self.fd, SNDCTL_DSP_RESET, 0 as *mut c_int) == -1 { + io_error::cond.raise(IoError { kind: OtherIoError, + desc: "Unable to reset dsp", + detail: None }); + } + }; + } + #[fixed_stack_segment] + pub fn set_format(&self) { + unsafe { + let mut i: c_int = AFMT_S16_LE; + if ioctl(self.fd, SNDCTL_DSP_SETFMT, &mut i) == -1 { + io_error::cond.raise(IoError { kind: OtherIoError, + desc: "Unable to set dsp format", + detail: None }); + } + }; + } + #[fixed_stack_segment] + pub fn set_stereo(&self) { + unsafe { + let mut i: c_int = 1; + if ioctl(self.fd, SNDCTL_DSP_STEREO, &mut i) == -1 { + io_error::cond.raise(IoError { kind: OtherIoError, + desc: "Unable to set dsp stereo", + detail: None }); + } + }; + } + #[fixed_stack_segment] + pub fn set_speed(&self, rate: int) { + unsafe { + let mut i: c_int = rate as c_int; + if ioctl(self.fd, SNDCTL_DSP_SPEED, &mut i) == -1 { + io_error::cond.raise(IoError { kind: OtherIoError, + desc: "Unable to set dsp speed", + detail: None }); + } + }; + } + #[fixed_stack_segment] + pub fn get_block_size(&self) -> uint { + unsafe { + let mut i: c_int = 0; + if ioctl(self.fd, SNDCTL_DSP_GETBLKSIZE, &mut i) == -1 { + io_error::cond.raise(IoError { kind: OtherIoError, + desc: "Unable to get dsp block size", + detail: None }); + }; + i as uint + } + } + #[fixed_stack_segment] + pub fn sync(&self) { + unsafe { + if ioctl(self.fd, SNDCTL_DSP_SYNC, 0 as *mut c_int) == -1 { + io_error::cond.raise(IoError { kind: OtherIoError, + desc: "Unable to get sync dsp", + detail: None }); + }; + } + } + #[fixed_stack_segment] + pub fn read_all(&self, chan: &Chan<~[u8]>) { + let block_size = self.get_block_size(); + self.sync(); + loop { + let mut buffer: ~[u8] = vec::with_capacity(block_size); + unsafe { + let length = read(self.fd, + vec::raw::to_mut_ptr(buffer) as *mut c_void, + block_size as u32); + if length == -1 { + break; + } + vec::raw::set_len(&mut buffer, length as uint); + } + chan.send(buffer); + } + } +} + +impl Drop for OssDevice { + #[fixed_stack_segment] + fn drop(&mut self) { + unsafe { close(self.fd) }; + } +} @@ -0,0 +1,49 @@ +use std::path::Path; +use std::rt::io::io_error; +use std::task::{SingleThreaded, spawn_sched}; + +use oss::*; +//use mp3lame::*; +mod oss; +//mod mp3lame; + +static DSP_FILES: &'static [&'static str] = &["/dev/dsp", "/dev/dsp1"]; +static DSP_SPEEDS: [int, ..2] = [44100i, 48000i]; + +#[fixed_stack_segment] +fn main() { + //let ctx = LameContext::new(); + let mut foo = None; + for file_name in DSP_FILES.iter() { + match OssDevice::new(&Path(file_name.as_slice())) { + Some(x) => { foo = Some(x); break } + None => {} + } + }; + let dsp = match foo { + Some(x) => x, + None => fail!("Unable to open dsp device") + }; + dsp.reset(); + dsp.set_format(); + dsp.set_stereo(); + let mut speed: int = 0; + for dsp_speed in DSP_SPEEDS.iter() { + do io_error::cond.trap(|_| {speed = 0}).inside { + dsp.set_speed(*dsp_speed); + speed = *dsp_speed; + } + if speed != 0 { + break; + } + } + println(fmt!("Sample rate: %d Hz", speed)); + let (port, chan) = stream::<~[u8]>(); + do spawn_sched(SingleThreaded) { + dsp.read_all(&chan); + } + loop { + let buffer = port.recv(); + println(fmt!("Read buffer of length %u", buffer.len())); + } +} |