use std::{convert::TryInto}; use crate::db_internal::{audio_alloc, audio_allocCompressed, audio_free, audio_getUsage, audio_queueSetParam_i, audio_queueSetParam_f, audio_queueStartVoice, audio_queueStopVoice, audio_getVoiceState, audio_getTime, audio_setReverbParams, audio_initSynth, audio_playMidi, audio_setMidiReverb, audio_setMidiVolume}; pub const VOICE_COUNT: usize = 32; #[repr(C)] #[derive(Clone)] pub struct AudioSample { pub handle: i32, pub samplerate: i32, } #[repr(C)] #[derive(Clone, Copy)] pub enum AudioVoiceParam { Volume, Pitch, Detune, Pan, SampleData, Samplerate, LoopEnabled, LoopStart, LoopEnd, Reverb, FadeInDuration, FadeOutDuration, Start, Stop, } impl AudioSample { /// Create a new signed 8-bit PCM audio sample pub fn create_s8(pcm_data: &[i8], samplerate: i32) -> Result { let handle = unsafe { audio_alloc(pcm_data.as_ptr().cast(), pcm_data.len().try_into().unwrap(), 0) }; if handle == -1 { return Err(()); } return Ok(AudioSample { handle: handle, samplerate: samplerate }); } /// Create a new signed 16-bit PCM audio sample pub fn create_s16(pcm_data: &[i16], samplerate: i32) -> Result { let handle = unsafe { audio_alloc(pcm_data.as_ptr().cast(), (pcm_data.len() * 2).try_into().unwrap(), 1) }; if handle == -1 { return Err(()); } return Ok(AudioSample { handle: handle, samplerate: samplerate }); } /// Create a new IMA ADPCM encoded audio sample pub fn create_adpcm(adpcm_data: &[u8], chunk_size: i32, samplerate: i32) -> Result { let handle = unsafe { audio_allocCompressed(adpcm_data.as_ptr().cast(), adpcm_data.len().try_into().unwrap(), chunk_size) }; if handle == -1 { return Err(()); } return Ok(AudioSample { handle: handle, samplerate: samplerate }); } } impl Drop for AudioSample { fn drop(&mut self) { unsafe { audio_free(self.handle); } } } /// Get the current sample memory usage in bytes pub fn get_usage() -> i32 { unsafe { return audio_getUsage(); } } /// Schedule an audio voice integer parameter change at some point in the future pub fn queue_set_voice_param_i(slot: i32, param: AudioVoiceParam, value: i32, time: f64) { assert!(slot >= 0 && slot < VOICE_COUNT.try_into().unwrap(), "Tried to set parameter for invalid voice handle"); unsafe { audio_queueSetParam_i(slot, param, value, time); } } /// Schedule an audio voice float parameter change at some point in the future pub fn queue_set_voice_param_f(slot: i32, param: AudioVoiceParam, value: f32, time: f64) { assert!(slot >= 0 && slot < VOICE_COUNT.try_into().unwrap(), "Tried to set parameter for invalid voice handle"); unsafe { audio_queueSetParam_f(slot, param, value, time); } } /// Schedule an audio voice to start playing at some point in the future pub fn queue_start_voice(slot: i32, time: f64) { assert!(slot >= 0 && slot < VOICE_COUNT.try_into().unwrap(), "Tried to start invalid voice handle"); unsafe { audio_queueStartVoice(slot, time) }; } /// Schedule an audio voice to stop playing at some point in the future pub fn queue_stop_voice(slot: i32, time: f64) { assert!(slot >= 0 && slot < VOICE_COUNT.try_into().unwrap(), "Tried to stop invalid voice handle"); unsafe { audio_queueStopVoice(slot, time) }; } /// Gets whether the given voice is currently playing pub fn get_voice_state(slot: i32) -> bool { assert!(slot >= 0 && slot < VOICE_COUNT.try_into().unwrap(), "Tried to get state of invalid voice handle"); unsafe { return audio_getVoiceState(slot) }; } /// Get the current audio timer value for scheduling pub fn get_time() -> f64 { unsafe { return audio_getTime(); } } /// Set the current reverb unit parameters pub fn set_reverb(room_size: f32, damping: f32, width: f32, wet: f32, dry: f32) { unsafe { audio_setReverbParams(room_size, damping, width, wet, dry); } } /// Initialize the MIDI synth using the given soundfont data pub fn init_synth(sf2_data: &[u8]) -> Result<(),()> { unsafe { let result = audio_initSynth(sf2_data.as_ptr(), sf2_data.len().try_into().unwrap()); if result { return Ok(()); } else { return Err(()); } } } /// Start playing a MIDI file using the initialized MIDI synth, optionally looping the file when it reaches the end pub fn play_midi(midi_data: &[u8], looping: bool) -> Result<(),()> { unsafe { let result = audio_playMidi(midi_data.as_ptr(), midi_data.len().try_into().unwrap(), looping); if result { return Ok(()); } else { return Err(()); } } } /// Set whether to route MIDI playback through the reverb unit pub fn set_midi_reverb(enabled: bool) { unsafe { audio_setMidiReverb(enabled); } } /// Set the volume of MIDI playback pub fn set_midi_volume(volume: f32) { unsafe { audio_setMidiVolume(volume); } }