diff --git a/agb/src/sound/mixer/mod.rs b/agb/src/sound/mixer/mod.rs index 0bff6c50..1a7fe1c4 100644 --- a/agb/src/sound/mixer/mod.rs +++ b/agb/src/sound/mixer/mod.rs @@ -226,6 +226,7 @@ pub struct SoundChannel { data: &'static [u8], pos: Num, should_loop: bool, + restart_point: Num, playback_speed: Num, volume: Num, // between 0 and 1 @@ -276,6 +277,7 @@ impl SoundChannel { priority: SoundPriority::Low, volume: 1.into(), is_stereo: false, + restart_point: 0.into(), } } @@ -319,6 +321,7 @@ impl SoundChannel { priority: SoundPriority::High, volume: 1.into(), is_stereo: false, + restart_point: 0.into(), } } @@ -330,6 +333,20 @@ impl SoundChannel { self } + /// Sets the point at which the sample should restart once it loops. Does nothing + /// unless you also call [`should_loop()`]. + /// + /// Useful if your song has an introduction or similar. + #[inline(always)] + pub fn restart_point(&mut self, restart_point: impl Into>) -> &mut Self { + self.restart_point = restart_point.into(); + assert!( + self.restart_point.floor() as usize <= self.data.len(), + "restart point must be shorter than the length of the sample" + ); + self + } + /// Sets the speed at which this should channel should be played. Defaults /// to 1 with values between 0 and 1 being slower above 1 being faster. /// diff --git a/agb/src/sound/mixer/sw_mixer.rs b/agb/src/sound/mixer/sw_mixer.rs index 6a14b5b3..55617aac 100644 --- a/agb/src/sound/mixer/sw_mixer.rs +++ b/agb/src/sound/mixer/sw_mixer.rs @@ -441,7 +441,7 @@ impl MixerBuffer { >= channel.data.len() as u32 { if channel.should_loop { - channel.pos = 0.into(); + channel.pos = channel.restart_point * 2; } else { channel.is_done = true; return; @@ -466,7 +466,7 @@ impl MixerBuffer { let channel_len = Num::::new(channel.data.len() as u32); let mut playback_speed = channel.playback_speed; - while playback_speed >= channel_len { + while playback_speed >= channel_len - channel.restart_point { playback_speed -= channel_len; } @@ -484,7 +484,7 @@ impl MixerBuffer { for i in 0..self.frequency.buffer_size() { if channel.pos >= channel_len { if channel.should_loop { - channel.pos -= channel_len; + channel.pos -= channel_len + channel.restart_point; } else { channel.is_done = true; break;