use super::*;
use crate::audio;
use adhoc_audio::{AdhocCodec, SeekFrom, Streamable};
const MAX_CHANNELS_TO_MIX: usize = 8;
#[derive(Copy, Clone)]
pub enum ScaleMode {
Stretch,
Repeat,
}
impl Default for ScaleMode {
fn default() -> Self {
Self::Repeat
}
}
pub struct ExplicitWave {
state: StreamState,
explicit_wave: AdhocCodec,
explicit_wave_duration: SampleTime,
scale_mode: ScaleMode,
}
impl ExplicitWave {
pub fn new(explicit_wave: AdhocCodec, mode: ScaleMode) -> Self {
let info = explicit_wave.info();
let total_samples = explicit_wave.calculate_sample_count_per_channel();
let wave_duration = SampleTime::new()
.with_sample_count(total_samples)
.with_sample_rate(info.frequency() as u32);
Self {
state: StreamState {
local_time: SampleTime::new()
.with_sample_count(0)
.with_sample_rate(info.frequency() as u32),
global_interval: Interval::from_length(wave_duration.elapsed_in_ms_fp()),
attack_time: 2000,
release_time: 2000,
frequency: info.frequency() as u32,
channels: info.channels() as u32,
gain: 1.0,
pan: 0.5,
},
explicit_wave,
explicit_wave_duration: wave_duration,
scale_mode: mode,
}
}
fn pull_samples_repeat_non_repeat<'a>(
&mut self,
scratch_space: &mut [f32],
mut audio_pcm: PCMSlice<'a, f32>,
) -> PullInfo {
let mut sample_group = [0.0; MAX_CHANNELS_TO_MIX];
let mut local_time_in_ms = self.state.local_time.elapsed_in_ms_f32();
let track_delta_in_ms = 1000.0 / self.frequency() as f32;
let elapsed_track_time_in_ms = self.interval().distance().as_f64() as f32;
let local_attack_in_ms = self.state.attack_time as f32;
let local_release_in_ms = elapsed_track_time_in_ms - self.state.release_time as f32;
let num_channels_in_output = audio_pcm.channels() as usize;
let num_channels_in_explicit_wave = self.explicit_wave.info().channels() as usize;
let samples_writeable_per_channel = audio_pcm.samples_per_channel() as usize;
let samples_needed_to_read = num_channels_in_explicit_wave * samples_writeable_per_channel;
let samples_read = self
.explicit_wave
.decode(&mut scratch_space[0..samples_needed_to_read])
.unwrap_or_default();
let samples_read_per_channel = samples_read / num_channels_in_explicit_wave;
self.state
.local_time
.increment(samples_read_per_channel as u64);
let samples_decoded = &scratch_space[..samples_read];
for samp_idx in 0..samples_read_per_channel {
for channel_idx in 0..num_channels_in_explicit_wave {
let samp =
samples_decoded[(num_channels_in_explicit_wave * samp_idx) + channel_idx];
sample_group[channel_idx] = samp;
}
let last_sample = sample_group[num_channels_in_explicit_wave - 1];
for sample_element in &mut sample_group[num_channels_in_explicit_wave..] {
*sample_element = last_sample;
}
for aux_sample_idx in num_channels_in_output..num_channels_in_explicit_wave {
let aux_sample = sample_group[aux_sample_idx];
sample_group
.iter_mut()
.take(num_channels_in_output)
.for_each(|samp_group_samp| {
*samp_group_samp = (*samp_group_samp + aux_sample) * 0.5;
});
}
for channel_idx in 0..num_channels_in_output {
audio_pcm[num_channels_in_output * samp_idx + channel_idx] =
sample_group[channel_idx];
}
}
let gain = self.state.gain;
for samp_idx in 0..samples_read_per_channel {
let attack_t = 1.0 - linear_t_f32(local_time_in_ms, 0.0, local_attack_in_ms);
let release_t = linear_t_f32(
local_time_in_ms,
elapsed_track_time_in_ms,
local_release_in_ms,
);
let attack_coef = 1.0 - attack_t * attack_t;
let relase_coef = release_t * release_t;
let attack_release_gain = attack_coef * relase_coef * gain;
for channel_idx in 0..num_channels_in_output {
audio_pcm[samp_idx * num_channels_in_output + channel_idx] *= attack_release_gain;
}
local_time_in_ms += track_delta_in_ms;
}
let mixed_samples_written = samples_read_per_channel * num_channels_in_output;
PullInfo {
samples_read: mixed_samples_written,
samples_read_per_channel,
elapsed_audio_in_ms: audio::calculate_elapsed_time_in_ms_fp(
self.frequency(),
samples_read_per_channel,
),
}
}
fn pull_samples_repeat_repeat<'a>(
&mut self,
scratch_space: &mut [f32],
mut audio_pcm: PCMSlice<'a, f32>,
) -> PullInfo {
let samples_needed_per_channel = audio_pcm.samples_per_channel() as usize;
let first_pull_info = self.pull_samples_repeat_non_repeat(scratch_space, audio_pcm);
let has_reached_the_end_of_explicit_wave =
first_pull_info.samples_read_per_channel < samples_needed_per_channel;
let audio_pcm_len = audio_pcm.len();
if has_reached_the_end_of_explicit_wave {
let previous_pull_audio_start = scratch_space.len() - first_pull_info.samples_read - 1;
for idx in 0..first_pull_info.samples_read {
scratch_space[previous_pull_audio_start + idx] = audio_pcm[idx];
}
self.explicit_wave.seek(SeekFrom::Start(0));
let second_pull_info = self.pull_samples_repeat_non_repeat(scratch_space, audio_pcm);
let offset_needed_to_shift_to_end_of_pcm_buffer =
audio_pcm_len - second_pull_info.samples_read;
for idx in (0..second_pull_info.samples_read).rev() {
audio_pcm[idx + offset_needed_to_shift_to_end_of_pcm_buffer] = audio_pcm[idx];
}
let previous_pull_audio_slice = &mut scratch_space[previous_pull_audio_start..];
for (idx, &e) in previous_pull_audio_slice.iter().enumerate() {
audio_pcm[idx] = e;
}
PullInfo {
samples_read: audio_pcm.len(),
samples_read_per_channel: samples_needed_per_channel,
elapsed_audio_in_ms: audio::calculate_elapsed_time_in_ms_fp(
audio_pcm.frequency(),
audio_pcm.len(),
),
}
} else {
first_pull_info
}
}
pub fn pull_samples_stretch<'a>(
&mut self,
_scratch_space: &mut [f32],
_audio_pcm: PCMSlice<'a, f32>,
) -> PullInfo {
unimplemented!("stretch not implemented");
}
}
impl Debug for ExplicitWave {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{:?} duration={}ms",
self.state,
self.explicit_wave_duration.elapsed_in_ms_f32()
)
}
}
impl HasAudioStream for ExplicitWave {
fn stream_state(&self) -> &StreamState {
&self.state
}
fn stream_state_mut(&mut self) -> &mut StreamState {
&mut self.state
}
fn pull_samples<'a>(
&mut self,
scratch_space: &mut [f32],
audio_pcm: PCMSlice<'a, f32>,
) -> PullInfo {
match self.scale_mode {
ScaleMode::Repeat => self.pull_samples_repeat_repeat(scratch_space, audio_pcm),
ScaleMode::Stretch => self.pull_samples_stretch(scratch_space, audio_pcm),
}
}
fn seek(&mut self, global_time: SampleTime) {
let global_interval = self.state.global_interval;
let elapsed_time_in_ms = global_interval.distance();
let frequency = self.frequency();
match self.scale_mode {
ScaleMode::Repeat => {
let explicit_wave_duration_ms = self.explicit_wave_duration.elapsed_in_ms_u64();
let new_local_time_in_ms = (global_time.elapsed_in_ms_fp() - global_interval.lo)
.clamp(FP64::zero(), elapsed_time_in_ms)
.as_i64();
let new_local_time_in_ms_circular =
new_local_time_in_ms as u64 % explicit_wave_duration_ms;
self.explicit_wave
.seek(SeekFrom::Start(new_local_time_in_ms_circular));
self.state.local_time = audio::calculate_samples_needed_per_channel_st(
frequency,
FP64::from(new_local_time_in_ms),
);
}
ScaleMode::Stretch => {
let new_local_time_in_ms = (global_time.elapsed_in_ms_fp() - global_interval.lo)
.clamp(FP64::zero(), elapsed_time_in_ms)
.as_i64();
self.explicit_wave
.seek(SeekFrom::Start(new_local_time_in_ms as u64))
}
};
}
}