use alloc::boxed::Box;
use crate::species::Species;
use crate::stream::SynthStream;
use crate::vocalization::{CallIntent, Vocalization};
use crate::voice::CreatureVoice;
pub type PraniVoice = *mut CreatureVoice;
pub type PraniStream = *mut SynthStream;
#[unsafe(no_mangle)]
pub unsafe extern "C" fn prani_voice_create(species_index: u32) -> PraniVoice {
let species = match species_from_index(species_index) {
Some(s) => s,
None => return core::ptr::null_mut(),
};
Box::into_raw(Box::new(CreatureVoice::new(species)))
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn prani_voice_destroy(handle: PraniVoice) {
if !handle.is_null() {
drop(unsafe { Box::from_raw(handle) });
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn prani_voice_set_effort(handle: PraniVoice, effort: f32) {
if let Some(voice) = unsafe { handle.as_mut() } {
voice.set_vocal_effort(effort);
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn prani_voice_set_size(handle: PraniVoice, size: f32) {
if let Some(voice) = unsafe { handle.as_mut() } {
let species = voice.species();
let new = CreatureVoice::new(species).with_size(size);
*voice = new;
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn prani_voice_apply_lombard(handle: PraniVoice, ambient_spl_db: f32) {
if let Some(voice) = unsafe { handle.as_mut() } {
voice.apply_lombard_effect(ambient_spl_db);
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn prani_stream_start(
voice_handle: PraniVoice,
vocalization_index: u32,
intent_index: u32,
sample_rate: f32,
duration: f32,
) -> PraniStream {
let voice = match unsafe { voice_handle.as_ref() } {
Some(v) => v,
None => return core::ptr::null_mut(),
};
let vocalization = match vocalization_from_index(vocalization_index) {
Some(v) => v,
None => return core::ptr::null_mut(),
};
let intent = match intent_from_index(intent_index) {
Some(i) => i,
None => return core::ptr::null_mut(),
};
match SynthStream::new(voice.clone(), vocalization, intent, sample_rate, duration) {
Ok(stream) => Box::into_raw(Box::new(stream)),
Err(_) => core::ptr::null_mut(),
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn prani_stream_fill(
stream_handle: PraniStream,
buffer: *mut f32,
buffer_len: u32,
) -> u32 {
let stream = match unsafe { stream_handle.as_mut() } {
Some(s) => s,
None => return 0,
};
if buffer.is_null() || buffer_len == 0 {
return 0;
}
let slice = unsafe { core::slice::from_raw_parts_mut(buffer, buffer_len as usize) };
stream.fill_buffer(slice) as u32
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn prani_stream_is_finished(stream_handle: PraniStream) -> u32 {
match unsafe { stream_handle.as_ref() } {
Some(s) => u32::from(s.is_finished()),
None => 1,
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn prani_stream_destroy(stream_handle: PraniStream) {
if !stream_handle.is_null() {
drop(unsafe { Box::from_raw(stream_handle) });
}
}
fn species_from_index(index: u32) -> Option<Species> {
match index {
0 => Some(Species::Wolf),
1 => Some(Species::Dog),
2 => Some(Species::Cat),
3 => Some(Species::Lion),
4 => Some(Species::Songbird),
5 => Some(Species::Crow),
6 => Some(Species::Raptor),
7 => Some(Species::Snake),
8 => Some(Species::Crocodilian),
9 => Some(Species::Cricket),
10 => Some(Species::Bee),
11 => Some(Species::Dragon),
12 => Some(Species::Fantasy),
_ => None,
}
}
fn vocalization_from_index(index: u32) -> Option<Vocalization> {
match index {
0 => Some(Vocalization::Howl),
1 => Some(Vocalization::Bark),
2 => Some(Vocalization::Growl),
3 => Some(Vocalization::Roar),
4 => Some(Vocalization::Hiss),
5 => Some(Vocalization::Chirp),
6 => Some(Vocalization::Trill),
7 => Some(Vocalization::Whine),
8 => Some(Vocalization::Rumble),
9 => Some(Vocalization::Purr),
10 => Some(Vocalization::Yelp),
11 => Some(Vocalization::Screech),
12 => Some(Vocalization::Stridulate),
13 => Some(Vocalization::Buzz),
_ => None,
}
}
fn intent_from_index(index: u32) -> Option<CallIntent> {
match index {
0 => Some(CallIntent::Alarm),
1 => Some(CallIntent::Territorial),
2 => Some(CallIntent::Mating),
3 => Some(CallIntent::Distress),
4 => Some(CallIntent::Idle),
5 => Some(CallIntent::Threat),
6 => Some(CallIntent::Social),
_ => None,
}
}