Try composing my own theme (with some bug fixes)

This commit is contained in:
Gwilym Inzani 2023-08-02 16:48:41 +01:00
parent 70e763cc11
commit 4b145d3194
5 changed files with 51 additions and 28 deletions

View file

@ -4,7 +4,7 @@ use agb::{
};
use agb_tracker::{include_xm, Track, Tracker};
const MUSIC: Track = include_xm!("sfx/theme.xm");
const MUSIC: Track = include_xm!("sfx/gwilym-theme2.xm");
const BAD_SELECTION: &[u8] = include_wav!("sfx/bad.wav");
const SELECT: &[u8] = include_wav!("sfx/select.wav");

View file

@ -12,6 +12,7 @@ pub struct Track<'a> {
pub num_channels: usize,
pub frames_per_tick: Num<u32, 8>,
pub ticks_per_step: u32,
pub repeat: usize,
}
#[derive(Debug)]
@ -50,9 +51,9 @@ pub enum PatternEffect {
VolumeSlide(Num<i16, 8>),
FineVolumeSlide(Num<i16, 8>),
NoteCut(u32),
Portamento(Num<u16, 8>),
Portamento(Num<u16, 12>),
/// Slide each tick the first amount to at most the second amount
TonePortamento(Num<u16, 8>, Num<u16, 8>),
TonePortamento(Num<u16, 12>, Num<u16, 12>),
}
#[cfg(feature = "quote")]
@ -68,6 +69,7 @@ impl<'a> quote::ToTokens for Track<'a> {
num_channels,
patterns_to_play,
ticks_per_step,
repeat,
} = self;
let frames_per_tick = frames_per_tick.to_raw();
@ -88,6 +90,7 @@ impl<'a> quote::ToTokens for Track<'a> {
frames_per_tick: agb_tracker::__private::Num::from_raw(#frames_per_tick),
num_channels: #num_channels,
ticks_per_step: #ticks_per_step,
repeat: #repeat,
}
}
})

View file

@ -101,7 +101,7 @@ pub struct Tracker {
struct TrackerChannel {
channel_id: Option<ChannelId>,
base_speed: Num<u32, 8>,
base_speed: Num<u32, 16>,
volume: Num<i32, 8>,
}
@ -182,7 +182,7 @@ impl Tracker {
self.current_row = 0;
if self.current_pattern >= self.track.patterns_to_play.len() {
self.current_pattern = 0;
self.current_pattern = self.track.repeat;
}
}
@ -229,10 +229,10 @@ impl TrackerChannel {
.and_then(|channel_id| mixer.channel(channel_id))
{
if speed != 0.into() {
self.base_speed = speed;
self.base_speed = speed.change_base();
}
channel.playback(self.base_speed);
channel.playback(self.base_speed.change_base());
}
}
@ -245,11 +245,11 @@ impl TrackerChannel {
match effect {
PatternEffect::None => {}
PatternEffect::Stop => {
channel.stop();
channel.volume(0);
}
PatternEffect::Arpeggio(first, second) => {
match tick % 3 {
0 => channel.playback(self.base_speed),
0 => channel.playback(self.base_speed.change_base()),
1 => channel.playback(first.change_base()),
2 => channel.playback(second.change_base()),
_ => unreachable!(),
@ -276,17 +276,18 @@ impl TrackerChannel {
}
PatternEffect::NoteCut(wait) => {
if tick == *wait {
channel.stop();
self.volume = 0.into();
channel.volume(0);
}
}
PatternEffect::Portamento(amount) => {
if tick != 0 {
self.base_speed *= amount.change_base();
channel.playback(self.base_speed);
channel.playback(self.base_speed.change_base());
}
}
PatternEffect::TonePortamento(amount, target) => {
channel.volume(self.volume.try_change_base().unwrap());
if *amount < 1.into() {
self.base_speed =
(self.base_speed * amount.change_base()).max(target.change_base());
@ -294,6 +295,8 @@ impl TrackerChannel {
self.base_speed =
(self.base_speed * amount.change_base()).min(target.change_base());
}
channel.playback(self.base_speed.change_base());
}
}
}

View file

@ -109,7 +109,7 @@ pub fn parse_module(module: &Module) -> TokenStream {
for pattern in &module.pattern {
let start_pos = pattern_data.len();
let mut effect_parameters: [u8; 255] = [0; u8::MAX as usize];
let mut tone_portamento_directions = vec![0.0; module.get_num_channels()];
let mut tone_portamento_directions = vec![0; module.get_num_channels()];
let mut note_and_sample = vec![None; module.get_num_channels()];
for row in pattern.iter() {
@ -139,8 +139,8 @@ pub fn parse_module(module: &Module) -> TokenStream {
let previous_note_and_sample = note_and_sample[channel_number];
let maybe_note_and_sample = if matches!(slot.note, Note::KeyOff) {
effect1 = PatternEffect::Stop;
note_and_sample[channel_number] = None;
&None
// note_and_sample[channel_number] = None;
&note_and_sample[channel_number]
} else if !matches!(slot.note, Note::None) {
if sample != 0 {
note_and_sample[channel_number] = Some((slot.note, &samples[sample - 1]));
@ -221,13 +221,15 @@ pub fn parse_module(module: &Module) -> TokenStream {
}
}
0x1 => {
let c4_speed = note_to_speed(Note::C4, 0.0, 0, module.frequency_type);
let speed = note_to_speed(
let c4_speed: Num<u32, 12> =
note_to_speed(Note::C4, 0.0, 0, module.frequency_type).change_base();
let speed: Num<u32, 12> = note_to_speed(
Note::C4,
effect_parameter as f64,
effect_parameter as f64 / 16.0,
0,
module.frequency_type,
);
)
.change_base();
let portamento_amount = speed / c4_speed;
@ -237,12 +239,12 @@ pub fn parse_module(module: &Module) -> TokenStream {
let c4_speed = note_to_speed(Note::C4, 0.0, 0, module.frequency_type);
let speed = note_to_speed(
Note::C4,
-(effect_parameter as f64),
effect_parameter as f64,
0,
module.frequency_type,
);
let portamento_amount = speed / c4_speed;
let portamento_amount = c4_speed / speed;
PatternEffect::Portamento(portamento_amount.try_change_base().unwrap())
}
@ -258,11 +260,11 @@ pub fn parse_module(module: &Module) -> TokenStream {
);
let direction = match (prev_note as usize).cmp(&(*note as usize)) {
std::cmp::Ordering::Less => 1.0,
std::cmp::Ordering::Less => 1,
std::cmp::Ordering::Equal => {
tone_portamento_directions[channel_number]
}
std::cmp::Ordering::Greater => -1.0,
std::cmp::Ordering::Greater => -1,
};
tone_portamento_directions[channel_number] = direction;
@ -270,12 +272,23 @@ pub fn parse_module(module: &Module) -> TokenStream {
let c4_speed = note_to_speed(Note::C4, 0.0, 0, module.frequency_type);
let speed = note_to_speed(
Note::C4,
effect_parameter as f64 * direction,
effect_parameter as f64 * 8.0,
0,
module.frequency_type,
);
let portamento_amount = speed / c4_speed;
let portamento_amount = if direction > 0 {
speed / c4_speed
} else {
c4_speed / speed
};
dbg!(
speed,
c4_speed,
portamento_amount,
effect_parameter as f64 * 0.752941176470588
);
PatternEffect::TonePortamento(
portamento_amount.try_change_base().unwrap(),
@ -320,7 +333,10 @@ pub fn parse_module(module: &Module) -> TokenStream {
_ => PatternEffect::None,
};
if sample == 0 {
if sample == 0
|| matches!(effect2, PatternEffect::TonePortamento(_, _))
|| matches!(effect1, PatternEffect::Stop)
{
pattern_data.push(agb_tracker_interop::PatternSlot {
speed: 0.into(),
sample: 0,
@ -382,6 +398,7 @@ pub fn parse_module(module: &Module) -> TokenStream {
frames_per_tick,
ticks_per_step: ticks_per_step.into(),
repeat: module.restart_position as usize,
};
quote!(#interop)
@ -392,7 +409,7 @@ fn note_to_speed(
fine_tune: f64,
relative_note: i8,
frequency_type: FrequencyType,
) -> Num<u32, 8> {
) -> Num<u32, 12> {
let frequency = match frequency_type {
FrequencyType::LinearFrequencies => {
note_to_frequency_linear(note, fine_tune, relative_note)
@ -403,7 +420,7 @@ fn note_to_speed(
let gba_audio_frequency = 18157f64;
let speed: f64 = frequency / gba_audio_frequency;
Num::from_raw((speed * (1 << 8) as f64) as u32)
Num::from_raw((speed * (1 << 12) as f64) as u32)
}
fn note_to_frequency_linear(note: Note, fine_tune: f64, relative_note: i8) -> f64 {