summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Barksdale <amatus@amatus.name>2013-09-28 14:44:22 -0500
committerDavid Barksdale <amatus@amatus.name>2013-09-28 14:44:22 -0500
commit91f8e289c7ed3df1339848f2de9f07d33b35902a (patch)
tree572a70d2ce045aef68b6009b7bd278263435a4d6
Initial commit now that things are taking shape.
-rw-r--r--mp3lame.rs74
-rw-r--r--oss.rs139
-rw-r--r--per.rs49
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) };
+ }
+}
diff --git a/oss.rs b/oss.rs
new file mode 100644
index 0000000..b870c45
--- /dev/null
+++ b/oss.rs
@@ -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) };
+ }
+}
diff --git a/per.rs b/per.rs
new file mode 100644
index 0000000..6435978
--- /dev/null
+++ b/per.rs
@@ -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()));
+ }
+}