use alloc::rc::Rc;
use core::ptr::NonNull;
use super::effects::sound_effect::SoundEffect;
use super::signals::synth_signal::{SynthSignal, SynthSignalSubclass};
use super::sources::sound_source::SoundSource;
use super::volume::Volume;
use super::Sound;
use crate::capi_state::CApiState;
use crate::clamped_float::ClampedFloatInclusive;
use crate::ctypes::*;
use crate::error::Error;
#[derive(Debug)]
pub struct SoundChannel {
ptr: Rc<NonNull<CSoundChannel>>,
owned: bool,
added: bool,
volume_modulator: Option<SynthSignal>,
pan_modulator: Option<SynthSignal>,
dry_level_signal: SynthSignal,
wet_level_signal: SynthSignal,
}
impl SoundChannel {
fn from_ptr(ptr: *mut CSoundChannel, owned: bool) -> SoundChannel {
let dry_level_signal = SynthSignal::new(
unsafe { Self::fns().getDryLevelSignal.unwrap()(ptr) },
Rc::new(LevelSignal {}),
);
let wet_level_signal = SynthSignal::new(
unsafe { Self::fns().getWetLevelSignal.unwrap()(ptr) },
Rc::new(LevelSignal {}),
);
SoundChannel {
ptr: Rc::new(NonNull::new(ptr).unwrap()),
owned,
added: false,
volume_modulator: None,
pan_modulator: None,
dry_level_signal,
wet_level_signal,
}
}
pub fn new() -> SoundChannel {
Self::from_ptr(unsafe { Self::fns().newChannel.unwrap()() }, true)
}
pub(crate) fn new_system_channel(ptr: *mut CSoundChannel) -> SoundChannel {
Self::from_ptr(ptr, false)
}
pub(crate) fn is_system_channel(&self) -> bool {
!self.owned
}
pub(crate) fn set_added(&mut self, added: bool) {
assert!(self.owned);
self.added = added
}
pub fn add_source<T: AsMut<SoundSource>>(&mut self, source: &mut T) -> Result<(), Error> {
source.as_mut().attach_to_channel(&self.ptr)
}
pub fn remove_source<T: AsMut<SoundSource>>(&mut self, source: &mut T) -> Result<(), Error> {
source.as_mut().detach_from_channel(&self.ptr)
}
pub fn add_sound_effect<T: AsMut<SoundEffect>>(
&mut self,
sound_effect: &mut T,
) -> Result<(), Error> {
sound_effect.as_mut().attach_to_channel(&self.ptr)
}
pub fn remove_sound_effect<T: AsMut<SoundEffect>>(
&mut self,
sound_effect: &mut T,
) -> Result<(), Error> {
sound_effect.as_mut().detach_from_channel(&self.ptr)
}
pub fn volume(&self) -> Volume {
unsafe { Self::fns().getVolume.unwrap()(self.cptr() as *mut _).into() }
}
pub fn set_volume(&mut self, volume: Volume) {
unsafe { Self::fns().setVolume.unwrap()(self.cptr_mut(), volume.into()) }
}
pub fn set_volume_modulator<T: AsRef<SynthSignal>>(&mut self, signal: Option<&T>) {
let modulator_ptr = signal.map_or_else(core::ptr::null_mut, |signal|
signal.as_ref().cptr() as *mut _);
unsafe { Self::fns().setVolumeModulator.unwrap()(self.cptr_mut(), modulator_ptr) }
self.volume_modulator = signal.map(|signal| signal.as_ref().clone());
}
pub fn volume_modulator(&mut self) -> Option<&SynthSignal> {
self.volume_modulator.as_ref()
}
pub fn set_pan(&mut self, pan: ClampedFloatInclusive<-1, 1>) {
unsafe { Self::fns().setPan.unwrap()(self.cptr_mut(), pan.into()) }
}
pub fn set_pan_modulator<T: AsRef<SynthSignal>>(&mut self, signal: Option<&T>) {
let modulator_ptr = signal.map_or_else(core::ptr::null_mut, |signal|
signal.as_ref().cptr() as *mut _);
unsafe { Self::fns().setPanModulator.unwrap()(self.cptr_mut(), modulator_ptr) }
self.pan_modulator = signal.map(|signal| signal.as_ref().clone());
}
pub fn pan_modulator(&mut self) -> Option<&SynthSignal> {
self.pan_modulator.as_ref()
}
pub fn dry_level_signal(&mut self) -> &SynthSignal {
&self.dry_level_signal
}
pub fn wet_level_signal(&mut self) -> &SynthSignal {
&self.wet_level_signal
}
pub(crate) fn cptr(&self) -> *const CSoundChannel {
self.ptr.as_ptr()
}
pub(crate) fn cptr_mut(&mut self) -> *mut CSoundChannel {
self.ptr.as_ptr()
}
pub(crate) fn fns() -> &'static craydate_sys::playdate_sound_channel {
unsafe { &*CApiState::get().csound.channel }
}
}
impl Drop for SoundChannel {
fn drop(&mut self) {
if self.added {
unsafe { Sound::fns().removeChannel.unwrap()(self.cptr_mut()) }
}
if self.owned {
unsafe { Self::fns().freeChannel.unwrap()(self.cptr_mut()) }
}
}
}
struct LevelSignal {}
impl SynthSignalSubclass for LevelSignal {}