Add vibrato

This commit is contained in:
Gwilym Inzani 2024-07-10 11:48:09 +01:00
parent f6e7625bb1
commit 31ca8f631f
4 changed files with 38 additions and 11 deletions

View file

@ -69,6 +69,7 @@ pub enum PatternEffect {
Portamento(Num<u16, 12>), Portamento(Num<u16, 12>),
/// Slide each tick the first amount to at most the second amount /// Slide each tick the first amount to at most the second amount
TonePortamento(Num<u16, 12>, Num<u16, 12>), TonePortamento(Num<u16, 12>, Num<u16, 12>),
Vibrato(Waveform, Num<u16, 12>, u8),
SetTicksPerStep(u32), SetTicksPerStep(u32),
SetFramesPerTick(Num<u32, 8>), SetFramesPerTick(Num<u32, 8>),
SetGlobalVolume(Num<i32, 8>), SetGlobalVolume(Num<i32, 8>),
@ -77,7 +78,7 @@ pub enum PatternEffect {
PitchBend(Num<u32, 8>), PitchBend(Num<u32, 8>),
} }
#[derive(Debug, Default, Clone, PartialEq, Eq)] #[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
pub enum Waveform { pub enum Waveform {
#[default] #[default]
Sine, Sine,
@ -334,6 +335,10 @@ impl quote::ToTokens for PatternEffect {
let amount = amount.to_raw(); let amount = amount.to_raw();
quote! { PitchBend(agb_tracker::__private::Num::from_raw(#amount)) } quote! { PitchBend(agb_tracker::__private::Num::from_raw(#amount)) }
} }
PatternEffect::Vibrato(waveform, amount, speed) => {
let amount = amount.to_raw();
quote! { Vibrato(#waveform, #amount, #speed) }
}
}; };
tokens.append_all(quote! { tokens.append_all(quote! {

View file

@ -5,17 +5,17 @@ use std::fs;
use std::path::Path; use std::path::Path;
fn main() { fn main() {
let sine = (0..64).map(|i| (Num::<i32, 8>::new(i) / 64).sin()); let sine = (0..64).map(|i| (Num::<i32, 12>::new(i) / 64).sin());
let square = (0..64).map(|i| { let square = (0..64).map(|i| {
if i < 32 { if i < 32 {
Num::<i32, 8>::new(-1) Num::<i32, 12>::new(-1)
} else { } else {
Num::<i32, 8>::new(1) Num::<i32, 12>::new(1)
} }
}); });
let saw = (0..64).map(|i| (Num::<i32, 8>::new(i) - 32) / 32); let saw = (0..64).map(|i| (Num::<i32, 12>::new(i) - 32) / 32);
let out_dir = env::var_os("OUT_DIR").unwrap(); let out_dir = env::var_os("OUT_DIR").unwrap();
let dest_path = Path::new(&out_dir).join("lookups.rs"); let dest_path = Path::new(&out_dir).join("lookups.rs");
@ -24,9 +24,9 @@ fn main() {
&dest_path, &dest_path,
format!( format!(
" "
pub(crate) static SINE_LOOKUP: [agb_fixnum::Num<i32, 8>; 64] = [{sine_lookup}]; pub(crate) static SINE_LOOKUP: [agb_fixnum::Num<i32, 12>; 64] = [{sine_lookup}];
pub(crate) static SQUARE_LOOKUP: [agb_fixnum::Num<i32, 8>; 64] = [{square_lookup}]; pub(crate) static SQUARE_LOOKUP: [agb_fixnum::Num<i32, 12>; 64] = [{square_lookup}];
pub(crate) static SAW_LOOKUP: [agb_fixnum::Num<i32, 8>; 64] = [{saw_lookup}]; pub(crate) static SAW_LOOKUP: [agb_fixnum::Num<i32, 12>; 64] = [{saw_lookup}];
", ",
sine_lookup = gen_lookup(sine), sine_lookup = gen_lookup(sine),
square_lookup = gen_lookup(square), square_lookup = gen_lookup(square),
@ -38,7 +38,7 @@ fn main() {
println!("cargo::rerun-if-changed=build.rs"); println!("cargo::rerun-if-changed=build.rs");
} }
fn gen_lookup(input: impl IntoIterator<Item = Num<i32, 8>>) -> String { fn gen_lookup(input: impl IntoIterator<Item = Num<i32, 12>>) -> String {
let output: Vec<_> = input let output: Vec<_> = input
.into_iter() .into_iter()
.map(|v| format!("agb_fixnum::Num::from_raw({})", v.to_raw())) .map(|v| format!("agb_fixnum::Num::from_raw({})", v.to_raw()))

View file

@ -132,7 +132,7 @@ struct Waves {
waveform: Waveform, waveform: Waveform,
frame: usize, frame: usize,
speed: usize, speed: usize,
amount: Num<i32, 8>, amount: Num<i32, 12>,
} }
impl Waves { impl Waves {
@ -281,6 +281,7 @@ impl<'track, TChannelId> TrackerInner<'track, TChannelId> {
.and_then(|channel_id| mixer.channel(channel_id)) .and_then(|channel_id| mixer.channel(channel_id))
{ {
let mut current_speed = tracker_channel.current_speed; let mut current_speed = tracker_channel.current_speed;
if tracker_channel.vibrato.speed != 0 { if tracker_channel.vibrato.speed != 0 {
current_speed *= tracker_channel.vibrato.value().change_base(); current_speed *= tracker_channel.vibrato.value().change_base();
} }
@ -498,6 +499,11 @@ impl TrackerChannel {
global_settings.volume = global_settings.volume =
(global_settings.volume + *volume_delta).clamp(0.into(), 1.into()); (global_settings.volume + *volume_delta).clamp(0.into(), 1.into());
} }
PatternEffect::Vibrato(waveform, amount, speed) => {
self.vibrato.waveform = *waveform;
self.vibrato.amount = amount.change_base();
self.vibrato.speed = *speed as usize;
}
} }
} }

View file

@ -1,7 +1,7 @@
use std::collections::HashMap; use std::collections::HashMap;
use agb_fixnum::Num; use agb_fixnum::Num;
use agb_tracker_interop::PatternEffect; use agb_tracker_interop::{PatternEffect, Waveform};
use xmrs::prelude::*; use xmrs::prelude::*;
@ -277,6 +277,22 @@ pub fn parse_module(module: &Module) -> agb_tracker_interop::Track {
PatternEffect::None PatternEffect::None
} }
} }
0x4 => {
let vibrato_speed = effect_parameter >> 4;
let depth = effect_parameter & 0xF;
let c4_speed = note_to_speed(Note::C4, 0.0, 0, module.frequency_type);
let speed =
note_to_speed(Note::C4, depth as f64 * 8.0, 0, module.frequency_type);
let amount = speed / c4_speed - 1;
PatternEffect::Vibrato(
Waveform::Sine,
amount.try_change_base().unwrap(),
vibrato_speed,
)
}
0x8 => { 0x8 => {
PatternEffect::Panning(Num::new(slot.effect_parameter as i16 - 128) / 128) PatternEffect::Panning(Num::new(slot.effect_parameter as i16 - 128) / 128)
} }