Handle vibrato in the instrument too

This commit is contained in:
Gwilym Inzani 2024-07-10 14:47:59 +01:00
parent d15063373d
commit 3bd8b9019d
5 changed files with 93 additions and 13 deletions

View file

@ -358,6 +358,10 @@ pub fn parse_midi(midi_info: &MidiInfo) -> Track {
sustain: Some(envelope.amounts.len() - 1),
loop_start: None,
loop_end: None,
vib_waveform: Default::default(),
vib_amount: Default::default(),
vib_speed: Default::default(),
})
.collect();

View file

@ -49,6 +49,10 @@ pub struct Envelope {
pub sustain: Option<usize>,
pub loop_start: Option<usize>,
pub loop_end: Option<usize>,
pub vib_waveform: Waveform,
pub vib_amount: Num<u16, 12>,
pub vib_speed: u8,
}
#[derive(Debug, Default, Clone, PartialEq, Eq)]
@ -80,7 +84,7 @@ pub enum PatternEffect {
PitchBend(Num<u32, 8>),
}
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Waveform {
#[default]
Sine,
@ -146,6 +150,9 @@ impl quote::ToTokens for Envelope {
sustain,
loop_start,
loop_end,
vib_amount,
vib_speed,
vib_waveform,
} = self;
let amount = amount.iter().map(|value| {
@ -153,6 +160,11 @@ impl quote::ToTokens for Envelope {
quote! { agb_tracker::__private::Num::from_raw(#value) }
});
let vib_amount = {
let value = vib_amount.to_raw();
quote! { agb_tracker::__private::Num::from_raw(#value) }
};
let sustain = match sustain {
Some(value) => quote!(Some(#value)),
None => quote!(None),
@ -175,6 +187,10 @@ impl quote::ToTokens for Envelope {
sustain: #sustain,
loop_start: #loop_start,
loop_end: #loop_end,
vib_waveform: #vib_waveform,
vib_amount: #vib_amount,
vib_speed: #vib_speed,
}
}
});

View file

@ -141,23 +141,27 @@ impl Waves {
fn value(&self) -> Num<u32, 8> {
assert!(self.amount.abs() <= 1.into());
let lookup = match self.waveform {
Waveform::Sine => lookups::SINE_LOOKUP,
Waveform::Saw => lookups::SAW_LOOKUP,
Waveform::Square => lookups::SQUARE_LOOKUP,
};
(self.amount * lookup[self.frame] + 1)
.try_change_base()
.unwrap()
calculate_wave(self.waveform, self.amount, self.frame)
}
}
fn calculate_wave(waveform: Waveform, amount: Num<i32, 12>, frame: usize) -> Num<u32, 8> {
let lookup = match waveform {
Waveform::Sine => lookups::SINE_LOOKUP,
Waveform::Saw => lookups::SAW_LOOKUP,
Waveform::Square => lookups::SQUARE_LOOKUP,
};
(amount * lookup[frame] + 1).try_change_base().unwrap()
}
struct EnvelopeState {
frame: usize,
envelope_id: usize,
finished: bool,
fadeout: Num<i32, 8>,
vibrato_pos: usize,
}
#[derive(Clone)]
@ -249,6 +253,8 @@ impl<'track, TChannelId> TrackerInner<'track, TChannelId> {
envelope_id,
finished: false,
fadeout: sample.fadeout,
vibrato_pos: 0,
});
}
@ -277,7 +283,12 @@ impl<'track, TChannelId> TrackerInner<'track, TChannelId> {
}
fn realise<M: Mixer<ChannelId = TChannelId>>(&mut self, mixer: &mut M) {
for (mixer_channel, tracker_channel) in self.mixer_channels.iter().zip(&mut self.channels) {
for (i, (mixer_channel, tracker_channel)) in self
.mixer_channels
.iter()
.zip(&mut self.channels)
.enumerate()
{
tracker_channel.tick();
if let Some(channel) = mixer_channel
@ -288,6 +299,19 @@ impl<'track, TChannelId> TrackerInner<'track, TChannelId> {
if tracker_channel.vibrato.speed != 0 && tracker_channel.vibrato.enable {
current_speed *= tracker_channel.vibrato.value().change_base();
} else if let Some(envelope) = &mut self.envelopes[i] {
let track_envelope = &self.track.envelopes[envelope.envelope_id];
if track_envelope.vib_speed != 0 {
current_speed *= calculate_wave(
track_envelope.vib_waveform,
track_envelope.vib_amount.change_base(),
envelope.vibrato_pos,
)
.change_base();
envelope.vibrato_pos =
(envelope.vibrato_pos + track_envelope.vib_speed as usize) % 64;
}
}
channel.playback(current_speed.change_base());

View file

@ -31,7 +31,12 @@ pub fn parse_module(module: &Module) -> agb_tracker_interop::Track {
let envelope = &instrument.volume_envelope;
let envelope_id = if envelope.enabled {
let envelope = EnvelopeData::new(envelope, module.default_bpm as u32);
let envelope = EnvelopeData::new(
envelope,
instrument,
module.frequency_type,
module.default_bpm as u32,
);
let id = existing_envelopes
.entry(envelope)
.or_insert_with_key(|envelope| {
@ -461,6 +466,10 @@ pub fn parse_module(module: &Module) -> agb_tracker_interop::Track {
sustain: envelope.sustain,
loop_start: envelope.loop_start,
loop_end: envelope.loop_end,
vib_amount: envelope.vib_amount.try_change_base().unwrap(),
vib_waveform: envelope.vib_waveform,
vib_speed: envelope.vib_speed,
})
.collect::<Vec<_>>();
@ -541,10 +550,19 @@ struct EnvelopeData {
sustain: Option<usize>,
loop_start: Option<usize>,
loop_end: Option<usize>,
vib_waveform: Waveform,
vib_speed: u8,
vib_amount: Num<u32, 12>,
}
impl EnvelopeData {
fn new(e: &xmrs::envelope::Envelope, bpm: u32) -> Self {
fn new(
e: &xmrs::envelope::Envelope,
instrument: &xmrs::instr_default::InstrDefault,
frequency_type: FrequencyType,
bpm: u32,
) -> Self {
let mut amounts = vec![];
for frame in 0..=(Self::envelope_frame_to_gba_frame(e.point.last().unwrap().frame, bpm)) {
@ -587,11 +605,29 @@ impl EnvelopeData {
(None, None)
};
let vib_waveform = match instrument.vibrato.waveform {
xmrs::instr_vibrato::Waveform::Sine => Waveform::Sine,
xmrs::instr_vibrato::Waveform::Square => Waveform::Square,
xmrs::instr_vibrato::Waveform::RampUp => Waveform::Saw,
xmrs::instr_vibrato::Waveform::RampDown => Waveform::Saw,
};
let vib_speed = (instrument.vibrato.speed * 64.0) as u8;
let vib_depth = instrument.vibrato.depth * 16.0;
let c4_speed = note_to_speed(Note::C4, 0.0, 0, frequency_type);
let vib_amount =
note_to_speed(Note::C4, vib_depth.into(), 0, frequency_type) / c4_speed - 1;
EnvelopeData {
amounts,
sustain,
loop_start,
loop_end,
vib_waveform,
vib_speed,
vib_amount,
}
}