#![allow(unused_variables, reason = "asdf")]
use std::error::Error;
use std::f64::consts::TAU;
use std::ffi::{c_long, c_void};
use std::io::{self, Cursor, Write};
use std::sync::mpsc::TrySendError;
use std::{iter, slice};
use std::sync::mpsc;
use std::sync::OnceLock;
use azo::data::ChannelId;
use azo::ffi::*;
static SENDER: OnceLock<mpsc::SyncSender<c_long>> = OnceLock::new();
fn main() -> Result<(), Box<dyn Error>> {
let (sender, receiver) = mpsc::sync_channel::<c_long>(2);
SENDER.set(sender).unwrap();
let all = azo::discover_drivers()?;
let driver = all[3].create_instance()?;
driver.init(None)?;
let channel_id = ChannelId { input: false, index: 0 };
let sample_rate = driver.get_sample_rate()?;
let sample_type = driver.channel_info(channel_id)?.sample_type;
let buffer_size = driver.buffer_size()?.preferred;
let mut sine_wave_generator = create_sine_wave_generator(440.0, sample_rate);
let (sample_size, fn_write) = match_sample_type(sample_type);
let buf_ptrs =
unsafe {
driver.create_buffers([channel_id], buffer_size, &raw const CALLBACKS)
}?[0];
driver.start()?;
loop {
let buf_idx = receiver.recv().unwrap() as usize;
let buf_ptr = buf_ptrs[buf_idx].cast::<u8>();
let buf_len = buffer_size as usize * sample_size;
let buf_slice = unsafe { slice::from_raw_parts_mut(buf_ptr, buf_len) };
let mut cursor = Cursor::new(buf_slice);
for _ in 0..buffer_size {
fn_write(sine_wave_generator.next().unwrap(), &mut cursor)?;
}
_ = driver.output_ready();
}
}
fn create_sine_wave_generator(frequency: f64, sample_rate: f64) -> impl Iterator<Item=f64> {
let mut phase = 0.0;
iter::from_fn(move || {
let sample = (phase * TAU).sin();
phase += frequency / sample_rate;
phase %= 1.0;
Some(sample)
})
}
fn match_sample_type<W: Write>(sample_type: SampleType) -> (usize, fn(f64, &mut W) -> io::Result<()>) {
const I18_MAX: i32 = 0x00_01_FF_FF;
const I20_MAX: i32 = 0x00_07_FF_FF;
const I24_MAX: i32 = 0x00_7F_FF_FF;
match sample_type {
SampleType::PCM_I16_MSB => (size_of::<i16>(), |sample, dst| dst.write_all(&((i16::MAX as f64 * sample) as i16).to_be_bytes() )),
SampleType::PCM_I24_MSB => (3 , |sample, dst| dst.write_all(&(( I24_MAX as f64 * sample) as i32).to_be_bytes()[1..])),
SampleType::PCM_I32_MSB => (size_of::<i32>(), |sample, dst| dst.write_all(&((i32::MAX as f64 * sample) as i32).to_be_bytes() )),
SampleType::PCM_F32_MSB => (size_of::<f32>(), |sample, dst| dst.write_all(&( sample as f32).to_be_bytes() )),
SampleType::PCM_F64_MSB => (size_of::<f64>(), |sample, dst| dst.write_all(& sample .to_be_bytes() )),
SampleType::PCM_I32_MSB_16 => (size_of::<i32>(), |sample, dst| dst.write_all(&((i16::MAX as f64 * sample) as i32).to_be_bytes() )),
SampleType::PCM_I32_MSB_18 => (size_of::<i16>(), |sample, dst| dst.write_all(&(( I18_MAX as f64 * sample) as i16).to_be_bytes() )),
SampleType::PCM_I32_MSB_20 => (size_of::<i16>(), |sample, dst| dst.write_all(&(( I20_MAX as f64 * sample) as i16).to_be_bytes() )),
SampleType::PCM_I32_MSB_24 => (size_of::<i32>(), |sample, dst| dst.write_all(&(( I24_MAX as f64 * sample) as i32).to_be_bytes() )),
SampleType::PCM_I16_LSB => (size_of::<i16>(), |sample, dst| dst.write_all(&((i16::MAX as f64 * sample) as i16).to_le_bytes() )),
SampleType::PCM_I24_LSB => (3 , |sample, dst| dst.write_all(&(( I24_MAX as f64 * sample) as i32).to_le_bytes()[..3])),
SampleType::PCM_I32_LSB => (size_of::<i32>(), |sample, dst| dst.write_all(&((i32::MAX as f64 * sample) as i32).to_le_bytes() )),
SampleType::PCM_F32_LSB => (size_of::<f32>(), |sample, dst| dst.write_all(&( sample as f32).to_le_bytes() )),
SampleType::PCM_F64_LSB => (size_of::<f64>(), |sample, dst| dst.write_all(& sample .to_le_bytes() )),
SampleType::PCM_I32_LSB_16 => (size_of::<i32>(), |sample, dst| dst.write_all(&((i16::MAX as f64 * sample) as i32).to_le_bytes() )),
SampleType::PCM_I32_LSB_18 => (size_of::<i16>(), |sample, dst| dst.write_all(&(( I18_MAX as f64 * sample) as i16).to_le_bytes() )),
SampleType::PCM_I32_LSB_20 => (size_of::<i16>(), |sample, dst| dst.write_all(&(( I20_MAX as f64 * sample) as i16).to_le_bytes() )),
SampleType::PCM_I32_LSB_24 => (size_of::<i32>(), |sample, dst| dst.write_all(&(( I24_MAX as f64 * sample) as i32).to_le_bytes() )),
SampleType::DSD_I8_LSB_1 |
SampleType::DSD_I8_MSB_1 |
SampleType::DSD_I8_NER_8 => unimplemented!(),
_ => panic!("unknown sample type")
}
}
static CALLBACKS: Callbacks = Callbacks {
buffer_switch,
sample_rate_did_change,
asio_message,
buffer_switch_time_info
};
unsafe extern "system" fn buffer_switch(buffer_index: c_long, direct_process: Bool) {
let send_result = SENDER.get().unwrap().try_send(buffer_index);
use TrySendError::*;
match send_result {
Ok(()) => return,
Err(Full(_)) => return,
Err(Disconnected(_)) => panic!("mpsc channel disconnected")
}
}
unsafe extern "system" fn sample_rate_did_change(rate: SampleRate) {
unimplemented!()
}
unsafe extern "system" fn asio_message(
selector: MessageSelector,
value : c_long,
message : *const c_void,
opt : *const f64
) -> c_long {
Bool::FALSE.0
}
unsafe extern "system" fn buffer_switch_time_info(
params : *const Time,
double_buffer_index: c_long,
direct_process : Bool
) -> Time {
unimplemented!()
}