mirror of
https://github.com/italicsjenga/agb.git
synced 2024-12-23 08:11:33 +11:00
Implement global volume
This commit is contained in:
parent
3976fd93ea
commit
f6ed1c484b
|
@ -66,6 +66,8 @@ pub enum PatternEffect {
|
||||||
TonePortamento(Num<u16, 12>, Num<u16, 12>),
|
TonePortamento(Num<u16, 12>, Num<u16, 12>),
|
||||||
SetTicksPerStep(u32),
|
SetTicksPerStep(u32),
|
||||||
SetFramesPerTick(Num<u32, 8>),
|
SetFramesPerTick(Num<u32, 8>),
|
||||||
|
SetGlobalVolume(Num<i32, 8>),
|
||||||
|
GlobalVolumeSlide(Num<i32, 8>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "quote")]
|
#[cfg(feature = "quote")]
|
||||||
|
@ -297,6 +299,14 @@ impl quote::ToTokens for PatternEffect {
|
||||||
let amount = new_frames_per_tick.to_raw();
|
let amount = new_frames_per_tick.to_raw();
|
||||||
quote! { SetFramesPerTick(agb_tracker::__private::Num::from_raw(#amount)) }
|
quote! { SetFramesPerTick(agb_tracker::__private::Num::from_raw(#amount)) }
|
||||||
}
|
}
|
||||||
|
PatternEffect::SetGlobalVolume(amount) => {
|
||||||
|
let amount = amount.to_raw();
|
||||||
|
quote! { SetGlobalVolume(agb_tracker::__private::Num::from_raw(#amount)) }
|
||||||
|
}
|
||||||
|
PatternEffect::GlobalVolumeSlide(amount) => {
|
||||||
|
let amount = amount.to_raw();
|
||||||
|
quote! { GlobalVolumeSlide(agb_tracker::__private::Num::from_raw(#amount)) }
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
tokens.append_all(quote! {
|
tokens.append_all(quote! {
|
||||||
|
|
|
@ -120,6 +120,7 @@ struct GlobalSettings {
|
||||||
ticks_per_step: u32,
|
ticks_per_step: u32,
|
||||||
|
|
||||||
frames_per_tick: Num<u32, 8>,
|
frames_per_tick: Num<u32, 8>,
|
||||||
|
volume: Num<i32, 8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Tracker {
|
impl Tracker {
|
||||||
|
@ -134,6 +135,7 @@ impl Tracker {
|
||||||
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,
|
||||||
|
volume: 1.into(),
|
||||||
};
|
};
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
|
@ -172,7 +174,7 @@ impl Tracker {
|
||||||
{
|
{
|
||||||
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);
|
channel.play_sound(mixer, sample, &self.global_settings);
|
||||||
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,
|
||||||
|
@ -208,7 +210,12 @@ impl Tracker {
|
||||||
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(mixer, envelope_state.frame, envelope) {
|
if !channel.update_volume_envelope(
|
||||||
|
mixer,
|
||||||
|
envelope_state.frame,
|
||||||
|
envelope,
|
||||||
|
&self.global_settings,
|
||||||
|
) {
|
||||||
envelope_state_option.take();
|
envelope_state_option.take();
|
||||||
} else {
|
} else {
|
||||||
envelope_state.frame += 1;
|
envelope_state.frame += 1;
|
||||||
|
@ -272,7 +279,12 @@ impl Tracker {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TrackerChannel {
|
impl TrackerChannel {
|
||||||
fn play_sound(&mut self, mixer: &mut Mixer<'_>, sample: &Sample<'static>) {
|
fn play_sound(
|
||||||
|
&mut self,
|
||||||
|
mixer: &mut Mixer<'_>,
|
||||||
|
sample: &Sample<'static>,
|
||||||
|
global_settings: &GlobalSettings,
|
||||||
|
) {
|
||||||
if let Some(channel) = self
|
if let Some(channel) = self
|
||||||
.channel_id
|
.channel_id
|
||||||
.take()
|
.take()
|
||||||
|
@ -283,7 +295,11 @@ impl TrackerChannel {
|
||||||
|
|
||||||
let mut new_channel = SoundChannel::new(sample.data);
|
let mut new_channel = SoundChannel::new(sample.data);
|
||||||
|
|
||||||
new_channel.volume(sample.volume.change_base());
|
new_channel.volume(
|
||||||
|
(sample.volume.change_base() * global_settings.volume)
|
||||||
|
.try_change_base()
|
||||||
|
.unwrap(),
|
||||||
|
);
|
||||||
|
|
||||||
if sample.should_loop {
|
if sample.should_loop {
|
||||||
new_channel
|
new_channel
|
||||||
|
@ -342,19 +358,31 @@ impl TrackerChannel {
|
||||||
channel.panning(panning.change_base());
|
channel.panning(panning.change_base());
|
||||||
}
|
}
|
||||||
PatternEffect::Volume(volume) => {
|
PatternEffect::Volume(volume) => {
|
||||||
channel.volume(volume.change_base());
|
channel.volume(
|
||||||
|
(volume.change_base() * global_settings.volume)
|
||||||
|
.try_change_base()
|
||||||
|
.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.volume.try_change_base().unwrap());
|
channel.volume(
|
||||||
|
(self.volume * global_settings.volume)
|
||||||
|
.try_change_base()
|
||||||
|
.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.volume.try_change_base().unwrap());
|
channel.volume(
|
||||||
|
(self.volume * global_settings.volume)
|
||||||
|
.try_change_base()
|
||||||
|
.unwrap(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PatternEffect::NoteCut(wait) => {
|
PatternEffect::NoteCut(wait) => {
|
||||||
|
@ -373,7 +401,11 @@ impl TrackerChannel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PatternEffect::TonePortamento(amount, target) => {
|
PatternEffect::TonePortamento(amount, target) => {
|
||||||
channel.volume(self.volume.try_change_base().unwrap());
|
channel.volume(
|
||||||
|
(self.volume * global_settings.volume)
|
||||||
|
.try_change_base()
|
||||||
|
.unwrap(),
|
||||||
|
);
|
||||||
|
|
||||||
if tick != 0 {
|
if tick != 0 {
|
||||||
if *amount < 1.into() {
|
if *amount < 1.into() {
|
||||||
|
@ -388,21 +420,27 @@ impl TrackerChannel {
|
||||||
channel.playback(self.base_speed.change_base());
|
channel.playback(self.base_speed.change_base());
|
||||||
}
|
}
|
||||||
// These are global effects handled below
|
// These are global effects handled below
|
||||||
PatternEffect::SetTicksPerStep(_) | PatternEffect::SetFramesPerTick(_) => {}
|
PatternEffect::SetTicksPerStep(_)
|
||||||
|
| PatternEffect::SetFramesPerTick(_)
|
||||||
|
| PatternEffect::SetGlobalVolume(_)
|
||||||
|
| PatternEffect::GlobalVolumeSlide(_) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Some effects have to happen regardless of if we're actually playing anything
|
// Some effects have to happen regardless of if we're actually playing anything
|
||||||
match effect {
|
match effect {
|
||||||
PatternEffect::SetTicksPerStep(amount) => {
|
PatternEffect::SetTicksPerStep(amount) => {
|
||||||
if tick == 0 {
|
global_settings.ticks_per_step = *amount;
|
||||||
global_settings.ticks_per_step = *amount;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
PatternEffect::SetFramesPerTick(new_frames_per_tick) => {
|
PatternEffect::SetFramesPerTick(new_frames_per_tick) => {
|
||||||
if tick == 0 {
|
global_settings.frames_per_tick = *new_frames_per_tick;
|
||||||
global_settings.frames_per_tick = *new_frames_per_tick;
|
}
|
||||||
}
|
PatternEffect::SetGlobalVolume(volume) => {
|
||||||
|
global_settings.volume = *volume;
|
||||||
|
}
|
||||||
|
PatternEffect::GlobalVolumeSlide(volume_delta) => {
|
||||||
|
global_settings.volume =
|
||||||
|
(global_settings.volume + *volume_delta).clamp(0.into(), 1.into());
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
@ -414,6 +452,7 @@ impl TrackerChannel {
|
||||||
mixer: &mut Mixer<'_>,
|
mixer: &mut Mixer<'_>,
|
||||||
frame: usize,
|
frame: usize,
|
||||||
envelope: &agb_tracker_interop::Envelope<'_>,
|
envelope: &agb_tracker_interop::Envelope<'_>,
|
||||||
|
global_settings: &GlobalSettings,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
if let Some(channel) = self
|
if let Some(channel) = self
|
||||||
.channel_id
|
.channel_id
|
||||||
|
@ -423,7 +462,7 @@ impl TrackerChannel {
|
||||||
let amount = envelope.amount[frame];
|
let amount = envelope.amount[frame];
|
||||||
|
|
||||||
channel.volume(
|
channel.volume(
|
||||||
(self.volume * amount.change_base())
|
(self.volume * amount.change_base() * global_settings.volume)
|
||||||
.try_change_base()
|
.try_change_base()
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
);
|
);
|
||||||
|
|
|
@ -350,6 +350,21 @@ pub fn parse_module(module: &Module) -> TokenStream {
|
||||||
slot.effect_parameter as u32,
|
slot.effect_parameter as u32,
|
||||||
)),
|
)),
|
||||||
},
|
},
|
||||||
|
// G
|
||||||
|
0x10 => PatternEffect::SetGlobalVolume(
|
||||||
|
Num::new(slot.effect_parameter as i32) / 0x40,
|
||||||
|
),
|
||||||
|
// H
|
||||||
|
0x11 => {
|
||||||
|
let first = effect_parameter >> 4;
|
||||||
|
let second = effect_parameter & 0xF;
|
||||||
|
|
||||||
|
if first == 0 {
|
||||||
|
PatternEffect::GlobalVolumeSlide(-Num::new(second as i32) / 0x40)
|
||||||
|
} else {
|
||||||
|
PatternEffect::GlobalVolumeSlide(Num::new(first as i32) / 0x40)
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => PatternEffect::None,
|
_ => PatternEffect::None,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue