Massive refactor ahead of waveforms

This commit is contained in:
Gwilym Inzani 2024-07-10 11:07:28 +01:00
parent 0daeba1876
commit f3cc62db6f
2 changed files with 170 additions and 204 deletions

View file

@ -80,7 +80,6 @@ pub enum PatternEffect {
#[derive(Debug, Default, Clone, PartialEq, Eq)] #[derive(Debug, Default, Clone, PartialEq, Eq)]
pub enum Waveform { pub enum Waveform {
#[default] #[default]
None,
Sine, Sine,
Saw, Saw,
Square, Square,
@ -349,7 +348,6 @@ impl quote::ToTokens for Waveform {
use quote::{quote, TokenStreamExt}; use quote::{quote, TokenStreamExt};
let name = match self { let name = match self {
Waveform::None => quote!(None),
Waveform::Sine => quote!(Sine), Waveform::Sine => quote!(Sine),
Waveform::Saw => quote!(Saw), Waveform::Saw => quote!(Saw),
Waveform::Square => quote!(Square), Waveform::Square => quote!(Square),

View file

@ -98,9 +98,11 @@ pub use agb_tracker_interop::Track;
/// Stores the required state in order to play tracker music. /// Stores the required state in order to play tracker music.
pub struct TrackerInner<'track, TChannelId> { pub struct TrackerInner<'track, TChannelId> {
track: &'track Track, track: &'track Track,
channels: Vec<TrackerChannel<TChannelId>>, channels: Vec<TrackerChannel>,
envelopes: Vec<Option<EnvelopeState>>, envelopes: Vec<Option<EnvelopeState>>,
mixer_channels: Vec<Option<TChannelId>>,
frame: Num<u32, 8>, frame: Num<u32, 8>,
tick: u32, tick: u32,
first: bool, first: bool,
@ -111,11 +113,16 @@ pub struct TrackerInner<'track, TChannelId> {
current_pattern: usize, current_pattern: usize,
} }
struct TrackerChannel<TChannelId> { #[derive(Default)]
channel_id: Option<TChannelId>, struct TrackerChannel {
original_speed: Num<u32, 16>, original_speed: Num<u32, 16>,
base_speed: Num<u32, 16>, base_speed: Num<u32, 16>,
volume: Num<i32, 8>, volume: Num<i32, 8>,
current_volume: Num<i32, 8>,
current_speed: Num<u32, 16>,
current_panning: Num<i32, 8>,
is_playing: bool,
} }
struct EnvelopeState { struct EnvelopeState {
@ -142,6 +149,9 @@ impl<'track, TChannelId> TrackerInner<'track, TChannelId> {
let mut envelopes = Vec::new(); let mut envelopes = Vec::new();
envelopes.resize_with(track.num_channels, || None); envelopes.resize_with(track.num_channels, || None);
let mut mixer_channels = Vec::new();
mixer_channels.resize_with(track.num_channels, || None);
let global_settings = GlobalSettings { let global_settings = GlobalSettings {
ticks_per_step: track.ticks_per_step, ticks_per_step: track.ticks_per_step,
frames_per_tick: track.frames_per_tick, frames_per_tick: track.frames_per_tick,
@ -150,6 +160,7 @@ impl<'track, TChannelId> TrackerInner<'track, TChannelId> {
Self { Self {
track, track,
mixer_channels,
channels, channels,
envelopes, envelopes,
@ -168,7 +179,9 @@ impl<'track, TChannelId> TrackerInner<'track, TChannelId> {
/// See the [example](crate#example) for how to use the tracker. /// See the [example](crate#example) for how to use the tracker.
pub fn step<M: Mixer<ChannelId = TChannelId>>(&mut self, mixer: &mut M) { pub fn step<M: Mixer<ChannelId = TChannelId>>(&mut self, mixer: &mut M) {
if !self.increment_frame() { if !self.increment_frame() {
self.update_envelopes(mixer); self.update_envelopes();
self.realise(mixer);
return; return;
} }
@ -184,7 +197,25 @@ impl<'track, TChannelId> TrackerInner<'track, TChannelId> {
{ {
if pattern_slot.sample != 0 && self.tick == 0 { if pattern_slot.sample != 0 && self.tick == 0 {
let sample = &self.track.samples[pattern_slot.sample as usize - 1]; let sample = &self.track.samples[pattern_slot.sample as usize - 1];
channel.play_sound(mixer, sample, &self.global_settings);
if let Some(channel) = self.mixer_channels[i]
.take()
.and_then(|channel_id| mixer.channel(&channel_id))
{
channel.stop();
}
let mut new_channel = M::SoundChannel::new(&sample.data);
if sample.should_loop {
new_channel
.should_loop()
.restart_point(sample.restart_point);
}
self.mixer_channels[i] = mixer.play_sound(new_channel);
channel.reset(sample);
self.envelopes[i] = sample.volume_envelope.map(|envelope_id| EnvelopeState { self.envelopes[i] = sample.volume_envelope.map(|envelope_id| EnvelopeState {
frame: 0, frame: 0,
envelope_id, envelope_id,
@ -194,18 +225,16 @@ impl<'track, TChannelId> TrackerInner<'track, TChannelId> {
} }
if self.tick == 0 { if self.tick == 0 {
channel.set_speed(mixer, pattern_slot.speed.change_base()); channel.set_speed(pattern_slot.speed.change_base());
} }
channel.apply_effect( channel.apply_effect(
mixer,
&pattern_slot.effect1, &pattern_slot.effect1,
self.tick, self.tick,
&mut self.global_settings, &mut self.global_settings,
&mut self.envelopes[i], &mut self.envelopes[i],
); );
channel.apply_effect( channel.apply_effect(
mixer,
&pattern_slot.effect2, &pattern_slot.effect2,
self.tick, self.tick,
&mut self.global_settings, &mut self.global_settings,
@ -213,20 +242,36 @@ impl<'track, TChannelId> TrackerInner<'track, TChannelId> {
); );
} }
self.update_envelopes(mixer); self.update_envelopes();
self.realise(mixer);
} }
fn update_envelopes<M: Mixer<ChannelId = TChannelId>>(&mut self, mixer: &mut M) { fn realise<M: Mixer<ChannelId = TChannelId>>(&mut self, mixer: &mut M) {
for (mixer_channel, tracker_channel) in self.mixer_channels.iter().zip(&self.channels) {
if let Some(channel) = mixer_channel
.as_ref()
.and_then(|channel_id| mixer.channel(channel_id))
{
channel.playback(tracker_channel.current_speed.change_base());
channel.volume(tracker_channel.current_volume.try_change_base().unwrap());
channel.panning(tracker_channel.current_panning.try_change_base().unwrap());
if tracker_channel.is_playing {
channel.resume();
} else {
channel.pause();
}
}
}
}
fn update_envelopes(&mut self) {
for (channel, envelope_state_option) in self.channels.iter_mut().zip(&mut self.envelopes) { for (channel, envelope_state_option) in self.channels.iter_mut().zip(&mut self.envelopes) {
if let Some(envelope_state) = envelope_state_option { if let Some(envelope_state) = envelope_state_option {
let envelope = &self.track.envelopes[envelope_state.envelope_id]; let envelope = &self.track.envelopes[envelope_state.envelope_id];
if !channel.update_volume_envelope( if !channel.update_volume_envelope(envelope_state, envelope, &self.global_settings)
mixer, {
envelope_state,
envelope,
&self.global_settings,
) {
envelope_state_option.take(); envelope_state_option.take();
} else { } else {
envelope_state.frame += 1; envelope_state.frame += 1;
@ -289,117 +334,76 @@ impl<'track, TChannelId> TrackerInner<'track, TChannelId> {
} }
} }
impl<TChannelId> TrackerChannel<TChannelId> { impl TrackerChannel {
fn play_sound<M: Mixer<ChannelId = TChannelId>>( fn reset(&mut self, sample: &Sample) {
&mut self,
mixer: &mut M,
sample: &Sample,
global_settings: &GlobalSettings,
) {
if let Some(channel) = self
.channel_id
.take()
.and_then(|channel_id| mixer.channel(&channel_id))
{
channel.stop();
}
let mut new_channel = M::SoundChannel::new(&sample.data);
new_channel.volume(
(sample.volume.change_base() * global_settings.volume)
.try_change_base()
.unwrap(),
);
if sample.should_loop {
new_channel
.should_loop()
.restart_point(sample.restart_point);
}
self.channel_id = mixer.play_sound(new_channel);
self.volume = sample.volume.change_base(); self.volume = sample.volume.change_base();
self.current_volume = self.volume;
self.current_panning = 0.into();
self.is_playing = true;
} }
fn set_speed<M: Mixer<ChannelId = TChannelId>>(&mut self, mixer: &mut M, speed: Num<u32, 8>) { fn set_speed(&mut self, speed: Num<u32, 8>) {
if let Some(channel) = self
.channel_id
.as_ref()
.and_then(|channel_id| mixer.channel(channel_id))
{
if speed != 0.into() { if speed != 0.into() {
self.base_speed = speed.change_base(); self.base_speed = speed.change_base();
self.original_speed = self.base_speed; self.original_speed = self.base_speed;
} }
channel.playback(self.base_speed.change_base()); self.current_speed = self.base_speed;
}
} }
fn apply_effect<M: Mixer<ChannelId = TChannelId>>( fn apply_effect(
&mut self, &mut self,
mixer: &mut M,
effect: &PatternEffect, effect: &PatternEffect,
tick: u32, tick: u32,
global_settings: &mut GlobalSettings, global_settings: &mut GlobalSettings,
envelope_state: &mut Option<EnvelopeState>, envelope_state: &mut Option<EnvelopeState>,
) { ) {
if let Some(channel) = self
.channel_id
.as_ref()
.and_then(|channel_id| mixer.channel(channel_id))
{
match effect { match effect {
PatternEffect::None => {} PatternEffect::None => {}
PatternEffect::Stop => { PatternEffect::Stop => {
channel.volume(0); self.current_volume = 0.into();
if let Some(envelope_state) = envelope_state { if let Some(envelope_state) = envelope_state {
envelope_state.finished = true; envelope_state.finished = true;
} }
} }
PatternEffect::Arpeggio(first, second) => { PatternEffect::Arpeggio(first, second) => {
match tick % 3 { match tick % 3 {
0 => channel.playback(self.base_speed.change_base()), 0 => self.current_speed = self.base_speed.change_base(),
1 => channel.playback(first.change_base()), 1 => self.current_speed = first.change_base(),
2 => channel.playback(second.change_base()), 2 => self.current_speed = second.change_base(),
_ => unreachable!(), _ => unreachable!(),
}; };
} }
PatternEffect::Panning(panning) => { PatternEffect::Panning(panning) => {
channel.panning(panning.change_base()); self.current_panning = panning.change_base();
} }
PatternEffect::Volume(volume) => { PatternEffect::Volume(volume) => {
channel.volume( self.current_volume = (volume.change_base() * global_settings.volume)
(volume.change_base() * global_settings.volume)
.try_change_base() .try_change_base()
.unwrap(), .unwrap();
);
self.volume = volume.change_base(); self.volume = volume.change_base();
} }
PatternEffect::VolumeSlide(amount) => { PatternEffect::VolumeSlide(amount) => {
if tick != 0 { if tick != 0 {
self.volume = (self.volume + amount.change_base()).max(0.into()); self.volume = (self.volume + amount.change_base()).max(0.into());
channel.volume( self.current_volume = (self.volume * global_settings.volume)
(self.volume * global_settings.volume)
.try_change_base() .try_change_base()
.unwrap(), .unwrap();
);
} }
} }
PatternEffect::FineVolumeSlide(amount) => { PatternEffect::FineVolumeSlide(amount) => {
if tick == 0 { if tick == 0 {
self.volume = (self.volume + amount.change_base()).max(0.into()); self.volume = (self.volume + amount.change_base()).max(0.into());
channel.volume( self.current_volume = (self.volume * global_settings.volume)
(self.volume * global_settings.volume)
.try_change_base() .try_change_base()
.unwrap(), .unwrap();
);
} }
} }
PatternEffect::NoteCut(wait) => { PatternEffect::NoteCut(wait) => {
if tick == *wait { if tick == *wait {
channel.volume(0); self.current_volume = 0.into();
if let Some(envelope_state) = envelope_state { if let Some(envelope_state) = envelope_state {
envelope_state.finished = true; envelope_state.finished = true;
@ -408,30 +412,26 @@ impl<TChannelId> TrackerChannel<TChannelId> {
} }
PatternEffect::NoteDelay(wait) => { PatternEffect::NoteDelay(wait) => {
if tick < *wait { if tick < *wait {
channel.pause(); self.is_playing = false;
} }
if tick == *wait { if tick == *wait {
channel.resume(); self.is_playing = true;
channel.volume( self.current_volume = (self.volume * global_settings.volume)
(self.volume * global_settings.volume)
.try_change_base() .try_change_base()
.unwrap(), .unwrap();
);
} }
} }
PatternEffect::Portamento(amount) => { PatternEffect::Portamento(amount) => {
if tick != 0 { if tick != 0 {
self.base_speed *= amount.change_base(); self.base_speed *= amount.change_base();
channel.playback(self.base_speed.change_base()); self.current_speed = self.base_speed.change_base();
} }
} }
PatternEffect::TonePortamento(amount, target) => { PatternEffect::TonePortamento(amount, target) => {
channel.volume( self.current_volume = (self.volume * global_settings.volume)
(self.volume * global_settings.volume)
.try_change_base() .try_change_base()
.unwrap(), .unwrap();
);
if tick != 0 { if tick != 0 {
if *amount < 1.into() { if *amount < 1.into() {
@ -443,24 +443,15 @@ impl<TChannelId> TrackerChannel<TChannelId> {
} }
} }
channel.playback(self.base_speed.change_base()); self.current_speed = self.base_speed.change_base();
} }
PatternEffect::PitchBend(amount) => { PatternEffect::PitchBend(amount) => {
if tick == 0 { if tick == 0 {
self.base_speed = self.original_speed * amount.change_base(); self.base_speed = self.original_speed * amount.change_base();
channel.playback(self.base_speed.change_base()); self.current_speed = self.base_speed.change_base();
}
}
// These are global effects handled below
PatternEffect::SetTicksPerStep(_)
| PatternEffect::SetFramesPerTick(_)
| PatternEffect::SetGlobalVolume(_)
| PatternEffect::GlobalVolumeSlide(_) => {}
} }
} }
// Some effects have to happen regardless of if we're actually playing anything
match effect {
PatternEffect::SetTicksPerStep(amount) => { PatternEffect::SetTicksPerStep(amount) => {
global_settings.ticks_per_step = *amount; global_settings.ticks_per_step = *amount;
} }
@ -474,50 +465,27 @@ impl<TChannelId> TrackerChannel<TChannelId> {
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());
} }
_ => {}
} }
} }
#[must_use] #[must_use]
fn update_volume_envelope<M: Mixer<ChannelId = TChannelId>>( fn update_volume_envelope(
&mut self, &mut self,
mixer: &mut M,
envelope_state: &EnvelopeState, envelope_state: &EnvelopeState,
envelope: &agb_tracker_interop::Envelope, envelope: &agb_tracker_interop::Envelope,
global_settings: &GlobalSettings, global_settings: &GlobalSettings,
) -> bool { ) -> bool {
if let Some(channel) = self
.channel_id
.as_ref()
.and_then(|channel_id| mixer.channel(channel_id))
{
let amount = envelope.amount[envelope_state.frame]; let amount = envelope.amount[envelope_state.frame];
if envelope_state.finished { if envelope_state.finished {
self.volume = (self.volume - envelope_state.fadeout).max(0.into()); self.volume = (self.volume - envelope_state.fadeout).max(0.into());
} }
channel.volume( self.current_volume = (self.volume * amount.change_base() * global_settings.volume)
(self.volume * amount.change_base() * global_settings.volume)
.try_change_base() .try_change_base()
.unwrap(), .unwrap();
);
self.volume != 0.into() self.volume != 0.into()
} else {
false
}
}
}
impl<TChannelId> Default for TrackerChannel<TChannelId> {
fn default() -> Self {
Self {
channel_id: None,
original_speed: Num::default(),
base_speed: Num::default(),
volume: Num::default(),
}
} }
} }