use cpal::{
BufferSize, OutputCallbackInfo, SampleFormat, SampleRate, SupportedBufferSize,
SupportedStreamConfigRange,
};
use cpal::{
Stream,
traits::{DeviceTrait, HostTrait},
};
const SAMPLE_RATE: usize = 48000;
pub enum IT2Driver {
SB16, HQ,
}
pub fn load_bytes(mut mod_data: Vec<u8>, driver: IT2Driver) {
unsafe {
let driver = match driver {
IT2Driver::SB16 => it2play_sys::DRIVER_SB16MMX.try_into().unwrap(),
IT2Driver::HQ => it2play_sys::DRIVER_HQ.try_into().unwrap(),
};
it2play_sys::Music_Init(SAMPLE_RATE.try_into().unwrap(), 1024, driver);
it2play_sys::Music_LoadFromData(mod_data.as_mut_ptr(), mod_data.len().try_into().unwrap());
}
}
pub fn free() {
unsafe {
it2play_sys::Music_FreeSong();
it2play_sys::Music_Close();
}
}
pub fn play(order: u16) {
unsafe {
it2play_sys::Song.ProcessRow = 0;
it2play_sys::Music_PlaySong(order);
}
}
pub fn stop() {
unsafe {
it2play_sys::Music_Stop();
}
}
pub fn set_global_volume(vol: u16) {
unsafe {
it2play_sys::Song.GlobalVolume = vol;
}
}
pub fn generate_stream() -> Stream {
let host = cpal::default_host();
let device = host
.default_output_device()
.expect("it2play_rs::generate_stream: No output device available");
let mut supported_cfgs = device.supported_output_configs().unwrap();
let Some(config) = supported_cfgs.find(desired_config) else {
panic!(
"it2play_rs::generate_stream: Output device doesn't support desired parameters (f32 sample types/{}hz sample rate)",
SAMPLE_RATE
);
};
let config = config
.with_sample_rate(SampleRate(SAMPLE_RATE.try_into().unwrap()))
.config();
let mut buffer = vec![0i16; 1024];
return device
.build_output_stream(
&config,
move |data, _| read_f32(data, &mut buffer),
|err| {
dbg!(err);
},
None, )
.unwrap();
}
fn read_i16(stream: &mut [i16]) {
unsafe {
it2play_sys::Music_FillAudioBuffer(stream.as_mut_ptr(), (stream.len() / 2) as i32);
};
}
fn read_f32(stream: &mut [f32], buffer: &mut Vec<i16>) {
if buffer.len() != stream.len() {
buffer.resize(stream.len(), 0i16);
}
read_i16(buffer);
let converted_buffer: Vec<f32> = buffer
.into_iter()
.map(|x| (*x as f32) / (i16::MAX as f32))
.collect();
stream.copy_from_slice(&converted_buffer);
}
fn desired_config(cfg: &SupportedStreamConfigRange) -> bool {
cfg.channels() == 2
&& cfg.sample_format() == SampleFormat::F32
&& cfg.max_sample_rate() >= SampleRate(SAMPLE_RATE.try_into().unwrap())
}