use alloc::vec::Vec;
use core::marker::PhantomData;
use core::ptr::NonNull;
use super::super::sources::instrument::Instrument;
use super::sequence::Sequence;
use super::sequence_track_control::SequenceTrackControl;
use super::track_note::{ResolvedTrackNote, TrackNote};
use crate::capi_state::CApiState;
use crate::ctypes::*;
pub struct SequenceTrack<'a> {
ptr: NonNull<CSequenceTrack>,
index: u32,
instrument: NonNull<Instrument>,
_marker: PhantomData<&'a Sequence>,
}
impl<'a> SequenceTrack<'a> {
pub(crate) fn new<'b>(
ptr: *mut CSequenceTrack,
index: u32,
instrument: *const Instrument,
) -> Self {
SequenceTrack {
ptr: NonNull::new(ptr).unwrap(),
index,
instrument: NonNull::new(instrument as *mut _).unwrap(),
_marker: PhantomData,
}
}
pub fn index(&self) -> u32 {
self.index
}
pub fn instrument(&self) -> &'a Instrument {
unsafe { &*self.instrument.as_ptr() }
}
pub fn steps_count(&self) -> u32 {
unsafe { SequenceTrack::fns().getLength.unwrap()(self.cptr() as *mut _) }
}
pub fn polyphony(&self) -> i32 {
unsafe { SequenceTrack::fns().getPolyphony.unwrap()(self.cptr() as *mut _) }
}
pub fn active_notes_count(&self) -> i32 {
unsafe { SequenceTrack::fns().activeVoiceCount.unwrap()(self.cptr() as *mut _) }
}
pub fn notes_in_step_range(
&self,
start_step: u32,
end_step: u32,
) -> impl Iterator<Item = ResolvedTrackNote> {
let mut v = Vec::new();
let first_index =
unsafe { SequenceTrack::fns().getIndexForStep.unwrap()(self.cptr() as *mut _, start_step) };
for index in first_index.. {
let mut out_step = 0;
let mut length = 0;
let mut midi_note = 0.0;
let mut velocity = 0.0;
let r = unsafe {
SequenceTrack::fns().getNoteAtIndex.unwrap()(
self.cptr() as *mut _,
index,
&mut out_step,
&mut length,
&mut midi_note,
&mut velocity,
)
};
if r == 0 || out_step > end_step {
break;
}
v.push(ResolvedTrackNote {
length,
midi_note: midi_note as u8,
velocity: velocity.into(),
});
}
v.into_iter()
}
pub fn notes(&self) -> impl Iterator<Item = ResolvedTrackNote> {
let mut v = Vec::new();
for index in 0.. {
let mut out_step = 0;
let mut length = 0;
let mut midi_note = 0.0;
let mut velocity = 0.0;
let r = unsafe {
SequenceTrack::fns().getNoteAtIndex.unwrap()(
self.cptr() as *mut _,
index,
&mut out_step,
&mut length,
&mut midi_note,
&mut velocity,
)
};
if r == 0 {
break;
}
v.push(ResolvedTrackNote {
length,
midi_note: midi_note as u8,
velocity: velocity.into(),
});
}
v.into_iter()
}
pub fn signals_count(&self) -> usize {
unsafe { SequenceTrack::fns().getControlSignalCount.unwrap()(self.cptr() as *mut _) as usize }
}
pub fn signals(&self) -> impl Iterator<Item = SequenceTrackControl> {
let mut v = Vec::new();
let count =
unsafe { SequenceTrack::fns().getControlSignalCount.unwrap()(self.cptr() as *mut _) };
for i in 0..count {
let ptr = unsafe { SequenceTrack::fns().getControlSignal.unwrap()(self.cptr() as *mut _, i) };
v.push(SequenceTrackControl::from_ptr(NonNull::new(ptr).unwrap()));
}
v.into_iter()
}
pub fn signal_for_midi_controller(&self, midi_controller: i32) -> Option<SequenceTrackControl> {
let ptr = unsafe {
Self::fns().getSignalForController.unwrap()(
self.cptr() as *mut _,
midi_controller,
false as i32,
)
};
Some(SequenceTrackControl::from_ptr(NonNull::new(ptr)?))
}
pub(crate) fn cptr(&self) -> *const CSequenceTrack {
self.ptr.as_ptr()
}
pub(crate) fn fns() -> &'static craydate_sys::playdate_sound_track {
unsafe { &*CApiState::get().csound.track }
}
}
pub struct SequenceTrackMut<'a> {
track: SequenceTrack<'a>,
sequence_ptr: NonNull<Sequence>,
}
impl<'a> SequenceTrackMut<'a> {
pub(crate) fn new(
ptr: *mut CSequenceTrack,
index: u32,
sequence_ptr: *mut Sequence,
instrument: *mut Instrument,
) -> Self {
SequenceTrackMut {
track: SequenceTrack::new(ptr, index, instrument as *const _),
sequence_ptr: NonNull::new(sequence_ptr).unwrap(),
}
}
unsafe fn sequence(&mut self) -> &'a mut Sequence {
self.sequence_ptr.as_mut()
}
pub fn instrument_mut(&mut self) -> &'a mut Instrument {
unsafe { &mut *self.instrument.as_ptr() }
}
pub fn add_note(&mut self, step: u32, note: TrackNote, length: u32) {
unsafe {
SequenceTrack::fns().addNoteEvent.unwrap()(
self.cptr_mut(),
step,
length,
note.midi_note as f32,
note.velocity.into(),
)
}
}
pub fn remove_note_event(&mut self, step: u32, midi_note: f32) {
unsafe { SequenceTrack::fns().removeNoteEvent.unwrap()(self.cptr_mut(), step, midi_note) }
}
pub fn remove_all_notes(&mut self) {
unsafe { SequenceTrack::fns().clearNotes.unwrap()(self.cptr_mut()) }
}
pub fn set_instrument(&mut self, mut instrument: Instrument) {
unsafe { SequenceTrack::fns().setInstrument.unwrap()(self.cptr_mut(), instrument.cptr_mut()) };
let seq = unsafe { self.sequence() };
seq.set_track_instrument(self.index, instrument);
let instrument: &mut Instrument = seq.track_instrument_mut(self.index);
self.track.instrument = unsafe { NonNull::new_unchecked(instrument as *mut _) };
}
pub fn set_muted(&mut self) {
unsafe { SequenceTrack::fns().setMuted.unwrap()(self.cptr_mut(), true as i32) }
}
pub fn set_unmuted(&mut self) {
unsafe { SequenceTrack::fns().setMuted.unwrap()(self.cptr_mut(), false as i32) }
}
pub fn clear_control_signals(&mut self) {
unsafe { SequenceTrack::fns().clearControlEvents.unwrap()(self.cptr_mut()) }
}
pub fn create_signal_for_midi_controller(&mut self, midi_controller: i32) -> CreateSignalResult {
let ptr = unsafe {
SequenceTrack::fns().getSignalForController.unwrap()(
self.cptr_mut(),
midi_controller,
false as i32,
)
};
if !ptr.is_null() {
CreateSignalResult::AlreadyExists(SequenceTrackControl::from_ptr(NonNull::new(ptr).unwrap()))
} else {
let ptr = unsafe {
SequenceTrack::fns().getSignalForController.unwrap()(
self.cptr_mut(),
midi_controller,
true as i32,
)
};
CreateSignalResult::Created(SequenceTrackControl::from_ptr(NonNull::new(ptr).unwrap()))
}
}
pub(crate) fn cptr_mut(&mut self) -> *mut CSequenceTrack {
self.ptr.as_ptr()
}
}
pub enum CreateSignalResult<'a> {
Created(SequenceTrackControl<'a>),
AlreadyExists(SequenceTrackControl<'a>),
}
impl<'a> core::ops::Deref for SequenceTrackMut<'a> {
type Target = SequenceTrack<'a>;
fn deref(&self) -> &Self::Target {
&self.track
}
}
impl<'a> AsRef<SequenceTrack<'a>> for SequenceTrackMut<'a> {
fn as_ref(&self) -> &SequenceTrack<'a> {
self
}
}