use super::audiounit::*;
use super::buffer::*;
use super::math::*;
use super::sequencer::*;
use super::signal::*;
use super::*;
use funutd::dna::*;
use funutd::map3base::{Texture, TilingMode};
use funutd::*;
extern crate alloc;
use alloc::boxed::Box;
use alloc::vec;
use alloc::vec::Vec;
#[derive(Clone)]
struct Voice {
pub next_time: f64,
}
#[derive(Clone)]
pub struct Granular<
X: Fn(f64, f32, f32, f32, f32, f32) -> (f32, f32, Box<dyn AudioUnit>) + Sync + Send + Clone,
> {
voices: Vec<Voice>,
outputs: usize,
beat_length: f32,
beats_per_cycle: usize,
texture: Box<dyn Texture>,
jitter: f32,
texture_origin: Vec3a,
inner_radius: f32,
outer_radius: f32,
generator: X,
sequencer: Sequencer,
sample_rate: f64,
time: f64,
rnd_seed: u64,
rnd: Rnd,
}
impl<X: Fn(f64, f32, f32, f32, f32, f32) -> (f32, f32, Box<dyn AudioUnit>) + Sync + Send + Clone>
Granular<X>
{
pub fn new(
outputs: usize,
voices: usize,
beat_length: f32,
beats_per_cycle: usize,
texture_seed: u64,
inner_radius: f32,
outer_radius: f32,
jitter: f32,
generator: X,
) -> Self {
let voice_vector = vec![Voice { next_time: 0.0 }; voices];
let mut dna = Dna::new(texture_seed);
let texture = funutd::map3gen::genmap3(100.0, TilingMode::Z, &mut dna);
let mut granular = Self {
voices: voice_vector,
outputs,
beat_length,
beats_per_cycle,
texture,
jitter,
texture_origin: vec3a(0.0, 0.0, 0.0),
inner_radius,
outer_radius,
generator,
sequencer: Sequencer::new(0, outputs, ReplayMode::None),
sample_rate: DEFAULT_SR,
time: 0.0,
rnd_seed: texture_seed,
rnd: Rnd::from_u64(texture_seed),
};
granular.reset();
granular
}
fn helix_position(&mut self, voice: usize, time: f64) -> Vec3a {
let cycle_length = self.beat_length as f64 * self.beats_per_cycle as f64;
let cycle = (time / cycle_length).floor();
let cycle_start = cycle * cycle_length;
let z_depth = 1.0;
let cycle_d = (time - cycle_start) / cycle_length;
let z = cycle_d * z_depth;
let beat = cycle_d * self.beats_per_cycle as f64;
let voice_d = if self.voices.len() == 1 {
0.5
} else {
voice as f32 / (self.voices.len() - 1) as f32
};
let r = lerp(self.inner_radius, self.outer_radius, voice_d);
let x = cos(beat as f32 * f32::TAU) * r;
let y = sin(beat as f32 * f32::TAU) * r;
let random = vec3a(
self.rnd.f32() * 2.0 - 1.0,
self.rnd.f32() * 2.0 - 1.0,
self.rnd.f32() * 2.0 - 1.0,
) * self.jitter;
self.texture_origin + vec3a(x as f32, y as f32, z as f32) + random
}
fn instantiate(&mut self, voice: usize) {
let t = self.voices[voice].next_time;
let position = self.helix_position(voice, t);
let v = self.texture.at(position);
let voice_d = if self.voices.len() == 1 {
0.5
} else {
voice as f64 / (self.voices.len() - 1) as f64
};
let (grain_length, envelope_length, mut grain) = (self.generator)(
t,
(t / self.beat_length as f64) as f32,
(voice_d * 2.0 - 1.0) as f32,
v.x.clamp(-1.0, 1.0),
v.y.clamp(-1.0, 1.0),
v.z.clamp(-1.0, 1.0),
);
assert!(envelope_length >= 0.0);
assert!(envelope_length < grain_length);
if t == 0.0 {
assert_eq!(voice, 0);
for i in 1..self.voices.len() {
self.voices[i].next_time = (grain_length as f64 - envelope_length as f64)
* i as f64
/ self.voices.len() as f64;
}
}
self.voices[voice].next_time = t + grain_length as f64 - envelope_length as f64;
grain.ping(false, AttoHash::new(self.rnd.u64()));
self.sequencer.push_duration(
t,
grain_length as f64,
Fade::Power,
envelope_length as f64,
envelope_length as f64,
grain,
);
}
fn instantiate_voices(&mut self, before_time: f64) {
for voice in 0..self.voices.len() {
while self.voices[voice].next_time < before_time {
self.instantiate(voice);
}
}
}
}
impl<X: Fn(f64, f32, f32, f32, f32, f32) -> (f32, f32, Box<dyn AudioUnit>) + Sync + Send + Clone>
AudioUnit for Granular<X>
{
fn reset(&mut self) {
self.sequencer.reset();
for i in 0..self.voices.len() {
self.voices[i].next_time = 0.0;
}
self.time = 0.0;
self.rnd = Rnd::from_u64(self.rnd_seed);
}
fn set_sample_rate(&mut self, sample_rate: f64) {
self.sample_rate = sample_rate;
self.sequencer.set_sample_rate(sample_rate);
}
fn tick(&mut self, input: &[f32], output: &mut [f32]) {
self.time += 1.0 / self.sample_rate;
self.instantiate_voices(self.time);
self.sequencer.tick(input, output);
}
fn process(&mut self, size: usize, input: &BufferRef, output: &mut BufferMut) {
self.time += size as f64 / self.sample_rate;
self.instantiate_voices(self.time);
self.sequencer.process(size, input, output);
}
fn get_id(&self) -> u64 {
const ID: u64 = 72;
ID
}
fn set_hash(&mut self, hash: u64) {
self.rnd_seed = hash;
self.rnd = Rnd::from_u64(self.rnd_seed);
}
fn inputs(&self) -> usize {
0
}
fn outputs(&self) -> usize {
self.outputs
}
fn route(&mut self, input: &SignalFrame, frequency: f64) -> SignalFrame {
self.sequencer.route(input, frequency)
}
fn footprint(&self) -> usize {
core::mem::size_of::<Self>()
}
}