use core::fmt::Debug;
use alloc::boxed::Box;
pub use alloc::string::String;
pub use alloc::vec::Vec;
use dyn_clone::DynClone;
use crate::random::Random;
use crate::synth::{envelope, midi_to_hz, vibrato_sine};
use crate::{constants::PENTATONIC_MINOR, BassNote, DrumPattern, DrumStep, MelodyNote, StemSample};
pub mod chiptune;
pub mod koto;
pub mod lofi;
pub mod medieval;
pub mod metal;
pub mod persian;
pub mod rap;
pub mod rock;
pub mod samba;
pub mod toy;
pub mod trap;
#[derive(Debug)]
pub struct SampleStepConfig<'a> {
pub sample_rate: f64,
pub step_duration: f64,
pub pattern: usize,
pub color: u8,
pub random: &'a mut Box<dyn Random>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct StemMask {
pub voice: bool,
pub square: bool,
pub triangle: bool,
pub noise: bool,
pub sfx: bool,
}
impl StemMask {
pub const ALL: Self = Self {
voice: true,
square: true,
triangle: true,
noise: true,
sfx: true,
};
}
impl Default for StemMask {
fn default() -> Self {
Self::ALL
}
}
#[derive(Default, Debug, Clone, Copy, PartialEq)]
pub struct SectionDef {
pub beats: u64,
pub stems: StemMask,
pub silence_after: f64,
}
pub trait Plugin: Debug + DynClone + Send {
fn mode(&self) -> &'static str;
fn mode_string(&self) -> String;
fn scale(&self) -> &[u8] {
&PENTATONIC_MINOR
}
fn chord_progression_from_seed(&self, seed: u32) -> Vec<usize>;
fn tempo_from_seed(&self, seed: u32) -> i32;
fn sample_melody_note(&self, note: MelodyNote, sample_rate: u32) -> Vec<StemSample>;
fn sample_bass_note(&self, note: BassNote, sample_rate: u32) -> Vec<StemSample>;
fn has_sfx(&self) -> bool {
false
}
fn sample_sfx_note(&self, _note: MelodyNote, _sample_rate: u32) -> Vec<StemSample> {
Vec::new()
}
fn sample_voice_note(&self, note: MelodyNote, sample_rate: u32) -> Vec<StemSample> {
let sr = sample_rate as f64;
let total = (sr * note.duration).floor() as usize;
if total == 0 {
return Vec::new();
}
let dur = total as f64 / sr;
let raw = vibrato_sine(sr, midi_to_hz(note.midi), dur, 0.12, 5.5, 0.015);
let shaped = envelope(sr, &raw, 0.030, 0.080, 0.75, 0.10);
(0..total)
.map(|i| StemSample {
value: shaped.get(i).copied().unwrap_or(0.0),
byte_index: note.byte_index,
})
.collect()
}
fn sample_step<'a>(
&self,
step: &DrumStep,
config: SampleStepConfig<'a>,
samples: &mut Vec<f32>,
);
fn drum_pattern_from_seed(&self, seed: &[u8; 8]) -> DrumPattern {
DrumPattern::from_seed(seed)
}
fn section_defs(&self) -> &'static [SectionDef] {
&[]
}
fn section_defs_from_seed(&self, _seed: u32) -> Vec<SectionDef> {
self.section_defs().to_vec()
}
}
dyn_clone::clone_trait_object!(Plugin);
pub(crate) fn overlay_samples(src: &Vec<f32>, dst: &mut Vec<f32>) {
for i in 0..dst.len().min(src.len()) {
dst[i] += src[i];
}
}