use crate::support::{
math::gcd,
SyncRawPtr,
};
use super::{
SampleTransform,
MonoTrack,
};
enum PlayType{
None,
PausedOnce,
PausedRepeat,
PausedForever,
Once,
Repeat,
Forever,
}
pub struct TrackIter{
data:SyncRawPtr<Vec<f32>>,
track_sample_rate:u32,
track_len:usize,
track_current_frame:usize,
play_type:PlayType,
repeats:u32,
volume:f32,
converter_enabled:bool,
from:u32,
to:u32,
current_frame:f32,
current_frame_pos_in_chunk:u32,
next_frame:f32,
next_output_frame_pos_in_chunk:u32,
}
impl TrackIter{
pub fn empty()->TrackIter{
Self{
data:SyncRawPtr::zero(),
track_sample_rate:0u32,
track_len:0usize,
track_current_frame:0usize,
play_type:PlayType::None, repeats:0u32,
volume:0f32,
converter_enabled:false, from:0u32,
to:0u32,
current_frame:0f32,
current_frame_pos_in_chunk:0u32,
next_frame:0f32,
next_output_frame_pos_in_chunk:0u32,
}
}
pub fn unpause(&mut self){
self.play_type=match self.play_type{
PlayType::PausedOnce=>PlayType::Once,
PlayType::PausedRepeat=>PlayType::Repeat,
PlayType::PausedForever=>PlayType::Forever,
_=>return
}
}
pub fn pause(&mut self){
self.play_type=match self.play_type{
PlayType::Once=>PlayType::PausedOnce,
PlayType::Repeat=>PlayType::PausedRepeat,
PlayType::Forever=>PlayType::PausedForever,
_=>return
}
}
pub fn stop(&mut self){
self.play_type=PlayType::None
}
}
impl TrackIter{
pub fn set_track(&mut self,track:&MonoTrack,system_sample_rate:u32,repeats:u32,volume:f32){
self.data=SyncRawPtr::new(&track.data);
self.track_sample_rate=track.sample_rate;
self.volume=volume;
self.track_current_frame=0;
self.track_len=track.len();
match repeats{
0=>self.play_type=PlayType::Forever,
1=>self.play_type=PlayType::Once,
_=>{
self.play_type=PlayType::Repeat;
self.repeats=repeats
}
}
if system_sample_rate!=self.track_sample_rate{
self.current_frame_pos_in_chunk=0;
self.next_output_frame_pos_in_chunk=0;
self.converter_enabled=true;
let gcd=gcd(self.track_sample_rate,system_sample_rate);
self.from=self.track_sample_rate/gcd;
self.to=system_sample_rate/gcd;
self.current_frame=self.next_track_sample();
self.next_frame=self.next_track_sample();
}
else{
self.converter_enabled=false;
}
}
pub fn set_system_sample_rate(&mut self,sample_rate:u32){
if sample_rate==self.track_sample_rate{
self.converter_enabled=false;
}
else{
self.converter_enabled=true;
let gcd=gcd(self.track_sample_rate,sample_rate);
self.from=self.track_sample_rate/gcd;
self.to=sample_rate/gcd;
}
}
pub fn set_volume(&mut self,volume:f32){
self.volume=volume
}
}
impl TrackIter{
pub fn next_track_sample(&mut self)->f32{
match self.play_type{
PlayType::Once=>{
if self.track_current_frame==self.track_len-1{
self.play_type=PlayType::None
}
}
PlayType::Repeat=>{
if self.track_current_frame==self.track_len{
self.repeats-=1;
if self.repeats==0{
self.play_type=PlayType::None
}
self.track_current_frame=0;
}
}
PlayType::Forever=>{
if self.track_current_frame==self.track_len{
self.track_current_frame=0
}
}
_=>return 0f32,
}
let sample=self.data.as_ref()[self.track_current_frame];
self.track_current_frame+=1;
sample*self.volume
}
fn next_input_frame(&mut self){
self.current_frame_pos_in_chunk+=1;
std::mem::swap(&mut self.current_frame,&mut self.next_frame);
self.next_frame=self.next_track_sample();
}
pub fn next_converter_sample(&mut self)->f32{
if self.next_output_frame_pos_in_chunk>=self.to{
self.next_output_frame_pos_in_chunk=0;
self.next_input_frame();
while self.current_frame_pos_in_chunk<self.from{
self.next_input_frame();
}
self.current_frame_pos_in_chunk=0;
}
else{
let req_left_sample=(
self.from*self.next_output_frame_pos_in_chunk/self.to
)%self.from;
while self.current_frame_pos_in_chunk<req_left_sample{
self.next_input_frame();
debug_assert!(self.current_frame_pos_in_chunk<self.from);
}
}
let numerator=(self.from*self.next_output_frame_pos_in_chunk)%self.to;
let sample=SampleTransform::lerp(self.current_frame,self.next_frame,numerator,self.to);
self.next_output_frame_pos_in_chunk+=1;
sample
}
pub fn next(&mut self)->Option<f32>{
if let PlayType::None=self.play_type{
None
}
else{
Some(if self.converter_enabled{
self.next_converter_sample()
}
else{
self.next_track_sample()
})
}
}
}