diff --git a/tracker/agb-midi-core/src/lib.rs b/tracker/agb-midi-core/src/lib.rs index 17280af2..833c8623 100644 --- a/tracker/agb-midi-core/src/lib.rs +++ b/tracker/agb-midi-core/src/lib.rs @@ -236,7 +236,25 @@ pub fn parse_midi(midi_info: &MidiInfo) -> TokenStream { }); } midly::MidiMessage::Aftertouch { .. } => {} - midly::MidiMessage::PitchBend { .. } => {} + midly::MidiMessage::PitchBend { bend } => { + // bend is between 0 and 8192 where 0 = -2 semitones and 8193 is +2 semitones (I think) + let amount = (bend.0.as_int() as f64 - (8192.0 / 2.0)) / (8192.0 / 2.0); + + // amount is now between -1 and 1 + let two_semitones_multiplier = 493.88 / 440.0; // B4 / A4 + let amount = if amount < 0.0 { + 1.0 / two_semitones_multiplier * (-amount) + } else { + two_semitones_multiplier * amount + }; + + pattern.push(PatternSlot { + speed: 0.into(), + sample: 0, + effect1: PatternEffect::PitchBend(Num::from_f64(amount)), + effect2: PatternEffect::None, + }); + } midly::MidiMessage::ProgramChange { program } => { let mut lookup_id = program.as_int().into(); if channel_id == 9 { diff --git a/tracker/agb-tracker-interop/src/lib.rs b/tracker/agb-tracker-interop/src/lib.rs index 1a2c05f3..13b7c3c5 100644 --- a/tracker/agb-tracker-interop/src/lib.rs +++ b/tracker/agb-tracker-interop/src/lib.rs @@ -69,6 +69,8 @@ pub enum PatternEffect { SetFramesPerTick(Num), SetGlobalVolume(Num), GlobalVolumeSlide(Num), + /// Increase / decrease the pitch by the specified amount immediately + PitchBend(Num), } #[cfg(feature = "quote")] @@ -311,6 +313,10 @@ impl quote::ToTokens for PatternEffect { let amount = amount.to_raw(); quote! { GlobalVolumeSlide(agb_tracker::__private::Num::from_raw(#amount)) } } + PatternEffect::PitchBend(amount) => { + let amount = amount.to_raw(); + quote! { PitchBend(agb_tracker::__private::Num::from_raw(#amount)) } + } }; tokens.append_all(quote! { diff --git a/tracker/agb-tracker/src/lib.rs b/tracker/agb-tracker/src/lib.rs index 27edc0b5..85254b90 100644 --- a/tracker/agb-tracker/src/lib.rs +++ b/tracker/agb-tracker/src/lib.rs @@ -428,6 +428,12 @@ impl TrackerChannel { channel.playback(self.base_speed.change_base()); } + PatternEffect::PitchBend(amount) => { + if tick == 0 { + self.base_speed *= amount.change_base(); + channel.playback(self.base_speed.change_base()); + } + } // These are global effects handled below PatternEffect::SetTicksPerStep(_) | PatternEffect::SetFramesPerTick(_)