use crate::core::fixed::fixed::Q15;
use crate::core::fixed::units::{ChannelVolume, Finetune, Panning, RetrigMul, Volume};
use crate::prelude::NewNoteAction;
use serde::{Deserialize, Serialize};
#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum NoteRetrigOperator {
#[default]
None,
Sum(Q15),
Mul(RetrigMul),
}
#[repr(u8)]
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum TrackEffect {
Arpeggio {
half1: usize,
half2: usize,
},
ChannelVolume(ChannelVolume),
Glissando(bool),
InstrumentFineTune(Finetune),
InstrumentNewNoteAction(NewNoteAction),
InstrumentPanningEnvelopePosition(usize),
InstrumentPanningEnvelope(bool),
InstrumentPitchEnvelope(bool),
InstrumentSampleOffset(usize),
InstrumentSurround(bool),
InstrumentVolumeEnvelopePosition(usize),
InstrumentVolumeEnvelope(bool),
NoteCut {
tick: usize,
past: bool,
},
NoteDelay(usize),
NoteFadeOut {
tick: usize,
past: bool,
},
NoteOff {
tick: usize,
past: bool,
},
NoteRetrig {
speed: usize,
volume_modifier: NoteRetrigOperator,
},
Panning(Panning),
Tremor {
on_time: usize,
off_time: usize,
},
Volume {
value: Volume,
tick: usize,
},
MidiMacro(MidiMacroType),
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum MidiMacroType {
SelectParametric(usize),
Parametric(u8),
Fixed { idx: usize, z: u8 },
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum NavigationEffect {
PatternBreak(usize),
PatternDelay {
quantity: usize,
tempo: bool,
},
PatternLoop(usize),
PositionJump(usize),
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum SongLevelEffect {
Bpm(usize),
BpmSlide(isize),
Speed(usize),
Volume(Volume),
VolumeSlide { speed: Q15, fine: bool },
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum GlobalEffect {
Navigation(NavigationEffect),
SongLevel(SongLevelEffect),
MidiMacro(MidiMacroType),
}
impl From<NavigationEffect> for GlobalEffect {
fn from(n: NavigationEffect) -> Self {
GlobalEffect::Navigation(n)
}
}
impl From<SongLevelEffect> for GlobalEffect {
fn from(s: SongLevelEffect) -> Self {
GlobalEffect::SongLevel(s)
}
}
impl From<MidiMacroType> for GlobalEffect {
fn from(m: MidiMacroType) -> Self {
GlobalEffect::MidiMacro(m)
}
}
impl TrackEffect {
pub fn merge(&self, other: &Self) -> Option<Self> {
match (self, other) {
(
TrackEffect::Arpeggio {
half1: h1,
half2: h2,
},
TrackEffect::Arpeggio {
half1: o1,
half2: o2,
},
) => Some(TrackEffect::Arpeggio {
half1: h1 + o1,
half2: h2 + o2,
}),
(TrackEffect::ChannelVolume(value1), TrackEffect::ChannelVolume(value2)) => {
let sum = (*value1 + *value2).clamp(ChannelVolume::SILENT, ChannelVolume::FULL);
Some(TrackEffect::ChannelVolume(sum))
}
(TrackEffect::Glissando(_h1), TrackEffect::Glissando(o1)) => {
Some(TrackEffect::Glissando(*o1)) }
(TrackEffect::InstrumentFineTune(h1), TrackEffect::InstrumentFineTune(o1)) => {
Some(TrackEffect::InstrumentFineTune(*h1 + *o1))
}
(
TrackEffect::InstrumentPanningEnvelopePosition(h1),
TrackEffect::InstrumentPanningEnvelopePosition(o1),
) => Some(TrackEffect::InstrumentPanningEnvelopePosition(h1 + o1)),
(TrackEffect::InstrumentSampleOffset(h1), TrackEffect::InstrumentSampleOffset(o1)) => {
Some(TrackEffect::InstrumentSampleOffset(h1 + o1))
}
(
TrackEffect::InstrumentVolumeEnvelopePosition(h1),
TrackEffect::InstrumentVolumeEnvelopePosition(o1),
) => Some(TrackEffect::InstrumentVolumeEnvelopePosition(h1 + o1)),
(
TrackEffect::NoteCut { tick: h1, past: h2 },
TrackEffect::NoteCut { tick: o1, past: o2 },
) => Some(TrackEffect::NoteCut {
tick: h1 + o1,
past: *h2 || *o2,
}),
(
TrackEffect::NoteFadeOut { tick: h1, past: h2 },
TrackEffect::NoteFadeOut { tick: o1, past: o2 },
) => Some(TrackEffect::NoteFadeOut {
tick: h1 + o1,
past: *h2 || *o2,
}),
(
TrackEffect::NoteOff { tick: h1, past: h2 },
TrackEffect::NoteOff { tick: o1, past: o2 },
) => Some(TrackEffect::NoteOff {
tick: h1 + o1,
past: *h2 || *o2,
}),
(TrackEffect::NoteDelay(h1), TrackEffect::NoteDelay(o1)) => {
Some(TrackEffect::NoteDelay(h1 + o1))
}
(
TrackEffect::NoteRetrig {
speed: h1,
volume_modifier: h2,
},
TrackEffect::NoteRetrig {
speed: o1,
volume_modifier: o2,
},
) => Some(TrackEffect::NoteRetrig {
speed: h1 + o1,
volume_modifier: match o2 {
NoteRetrigOperator::None => h2.clone(),
_ => o2.clone(),
},
}),
(TrackEffect::Panning(h1), TrackEffect::Panning(o1)) => {
Some(TrackEffect::Panning(*h1 + *o1))
}
(
TrackEffect::Tremor {
on_time: h1,
off_time: h2,
},
TrackEffect::Tremor {
on_time: o1,
off_time: o2,
},
) => Some(TrackEffect::Tremor {
on_time: h1 + o1,
off_time: h2 + o2,
}),
(
TrackEffect::Volume {
value: value1,
tick: tick1,
},
TrackEffect::Volume {
value: value2,
tick: tick2,
},
) => {
let sum = (*value1 + *value2).clamp(Volume::SILENT, Volume::FULL);
Some(TrackEffect::Volume {
value: sum,
tick: tick1 + tick2,
})
}
_ => None,
}
}
}