Решил написать небольшую прогу на Харе для вывода синусоиды 440Гц. Чтобы все было как можно проще, я использовал фиксированный период времени в 10 секунд. Вот код:
use fs;
use fmt;
use io;
use os;
use math;
//use unix;
use unix::signal;
//use sndctl;
use rt;
// #include </usr/include/linux/soundcard.h>
// tested on Debian Stable
// manual for dsp:
// https://docs.oracle.com/cd/E88353_01/html/E37851/dsp-4i.html
def SNDCTL_DSP_GETBLKSIZE = 3221508100u64;
def SNDCTL_DSP_SETFRAGMENT = 3221508106u64;
def SNDCTL_DSP_GETOSPACE = 2148552716u64;
def SNDCTL_DSP_SPEED = 3221508098u64;
def SNDCTL_DSP_GETFMTS = 2147766283u64;
def SNDCTL_DSP_SETFMT = 3221508101u64;
def AFMT_MU_LAW = 1;
def AFMT_A_LAW = 2;
def AFMT_U8 = 8;
def AFMT_S16_LE = 16;
def AFMT_S16_BE = 32;
def AFMT_S16_NE = 16;
def AFMT_U16_LE = 128;
export fn main() void = {
const fw : f64 = 440.0; // frequency of sine wave
const pi : f64 = 3.14159;
defer fmt::printf("Bye\n")!;
fmt::printf("Type Ctrl-d to quit\n")!;
let fd = os::open("/dev/dsp", fs::flags::WRONLY, 0);
if (fd is fs::error) {
fmt::printf("Couldn't open OSS device\n")!;
os::exit(1);
};
let fd = fd:io::file;
defer io::close(fd)!;
let frag_size : int = 1;
rt::ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &frag_size)!;
fmt::printf("frag size = {}\n", frag_size)!;
const arg = 10; // double-buffering
rt::ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &arg)!;
// set sampling frequency
let fs : int = 22000; // sampling frequency
fmt::printf("Requested speed: {}, ", fs)!;
rt::ioctl(fd, SNDCTL_DSP_SPEED, &fs)!;
fmt::printf("actual speed: {}\n", fs)!;
// ensure we can set the right format
let fmt : int = 0;
rt::ioctl(fd, SNDCTL_DSP_GETFMTS, &fmt)!; // get a mask of the format types available
fmt::printf("Formats supported: {}\n", fmt)!;
let fmt_type : int = AFMT_U16_LE; // this is the type we want to use
assert((fmt & fmt_type) != 0); // make sure it is available
//fmt = fmt_type; // we want to use this format
rt::ioctl(fd, SNDCTL_DSP_SETFMT, &fmt_type)!; // set it
const dt : f64 = 2.0 * pi * fw / fs:f64;
let t : f64 = 0.0; // time
const els : size = 512;
let buf : [1024]u8 = [0...]; // low and high bytes
const secs : size = 10;
const rounds = secs * fs:size /els; // number of rounds to last given number of seconds
for (let i = 0z; i < rounds ; i+=1) {
for (let j = 0z; j < els; j+=1) {
const v : f64 = (math::sinf64(t) +1.0) * 4000.0; // fit it inside a u16
const v : u16 = v:u16;
buf[j*2] = v:u8;
buf[j*2+1] = (v/256):u8;
t += dt;
if (t > 2.0*pi) { t -= 2.0 * pi; };
};
io::write(fd, buf:[]u8)!;
};
};