use crate::{
ReadResult, SampleRate, SamplesPerTick, Timing, delay::Delay, event::EveList, master::Master,
noise_builder::NoiseTable, overdrive::Overdrive, result::WriteResult, timing::SampleT,
unit::Unit, voice::Voice,
};
mod io;
pub use io::Tag;
pub mod moo;
const MAX_UNITS: u16 = 50;
const MAX_TUNE_VOICE_NAME: u32 = 16;
pub const MAX_TUNE_UNIT_NAME: usize = 16;
#[derive(Default)]
pub struct Text {
pub name: String,
pub comment: String,
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
pub enum FmtVer {
V1,
V2,
V3,
V4,
V5,
}
#[derive(Clone, Copy, Debug)]
pub enum FmtKind {
Collage,
Tune,
}
#[derive(Clone, Copy, Debug)]
pub struct FmtInfo {
pub ver: FmtVer,
pub kind: FmtKind,
pub(crate) exe_ver: u16,
pub(crate) dummy: u16,
}
impl Default for FmtInfo {
fn default() -> Self {
Self {
ver: FmtVer::V5,
kind: FmtKind::Collage,
exe_ver: 0,
dummy: 0,
}
}
}
#[derive(Default)]
pub struct Song {
pub text: Text,
pub master: Master,
pub events: EveList,
pub fmt: FmtInfo,
}
pub struct MooInstructions {
pub out_sample_rate: SampleRate,
pub voices: Vec<Voice>,
pub samples_per_tick: SamplesPerTick,
}
impl MooInstructions {
#[must_use]
pub const fn new(out_sample_rate: SampleRate) -> Self {
Self {
out_sample_rate,
voices: Vec::new(),
samples_per_tick: 1.0,
}
}
}
pub fn rebuild_tones(
ins: &mut MooInstructions,
out_sample_rate: SampleRate,
delays: &mut [Delay],
overdrives: &mut [Overdrive],
master: &Master,
) {
for delay in delays {
delay.rebuild(
master.timing.beats_per_meas,
master.timing.bpm,
ins.out_sample_rate,
);
}
for ovr in overdrives {
ovr.rebuild();
}
let builder = NoiseTable::generate();
for voice in &mut ins.voices {
voice.tone_ready(&builder, out_sample_rate);
}
}
#[derive(Default)]
pub struct Herd {
end: bool,
loop_: bool,
smp_smooth: SampleRate,
pub smp_count: SampleT,
smp_start: SampleT,
pub smp_end: SampleT,
pub smp_repeat: SampleT,
smp_stride: f32,
time_pan_index: usize,
pub evt_idx: usize,
pub units: Vec<Unit>,
pub delays: Vec<Delay>,
pub overdrives: Vec<Overdrive>,
}
impl Herd {
pub const fn seek_to_sample(&mut self, sample: SampleT) {
self.smp_count = sample;
self.evt_idx = 0;
}
pub fn tune_cow_voices(&mut self, ins: &MooInstructions, timing: Timing) {
for unit in &mut self.units {
unit.tone_init();
unit.reset_voice(ins, 0, timing);
}
}
}
#[expect(clippy::missing_errors_doc)]
pub fn read_song(
data: &[u8],
out_sample_rate: SampleRate,
) -> ReadResult<(Song, Herd, MooInstructions)> {
let mut song = Song {
text: Text::default(),
master: Master::default(),
events: EveList::default(),
fmt: FmtInfo {
ver: FmtVer::V5,
kind: FmtKind::Collage,
exe_ver: 0,
dummy: 0,
},
};
let mut ins = MooInstructions {
out_sample_rate,
voices: Vec::new(),
samples_per_tick: 0.0,
};
let mut herd = Herd::default();
io::read(&mut song, &mut herd, &mut ins, data)?;
song.master.adjust_meas_num(std::cmp::max(
song.master.get_last_tick(),
song.events.get_max_tick(),
));
rebuild_tones(
&mut ins,
out_sample_rate,
&mut herd.delays,
&mut herd.overdrives,
&song.master,
);
Ok((song, herd, ins))
}
pub fn serialize_project(song: &Song, herd: &Herd, ins: &MooInstructions) -> WriteResult<Vec<u8>> {
io::write(song, herd, ins)
}