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}; 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 BAD_SELECTION: &[u8] = include_wav!("sfx/bad.wav");
const SELECT: &[u8] = include_wav!("sfx/select.wav"); const SELECT: &[u8] = include_wav!("sfx/select.wav");

View file

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

View file

@ -101,7 +101,7 @@ pub struct Tracker {
struct TrackerChannel { struct TrackerChannel {
channel_id: Option<ChannelId>, channel_id: Option<ChannelId>,
base_speed: Num<u32, 8>, base_speed: Num<u32, 16>,
volume: Num<i32, 8>, volume: Num<i32, 8>,
} }
@ -182,7 +182,7 @@ impl Tracker {
self.current_row = 0; self.current_row = 0;
if self.current_pattern >= self.track.patterns_to_play.len() { 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)) .and_then(|channel_id| mixer.channel(channel_id))
{ {
if speed != 0.into() { 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 { match effect {
PatternEffect::None => {} PatternEffect::None => {}
PatternEffect::Stop => { PatternEffect::Stop => {
channel.stop(); channel.volume(0);
} }
PatternEffect::Arpeggio(first, second) => { PatternEffect::Arpeggio(first, second) => {
match tick % 3 { match tick % 3 {
0 => channel.playback(self.base_speed), 0 => channel.playback(self.base_speed.change_base()),
1 => channel.playback(first.change_base()), 1 => channel.playback(first.change_base()),
2 => channel.playback(second.change_base()), 2 => channel.playback(second.change_base()),
_ => unreachable!(), _ => unreachable!(),
@ -276,17 +276,18 @@ impl TrackerChannel {
} }
PatternEffect::NoteCut(wait) => { PatternEffect::NoteCut(wait) => {
if tick == *wait { if tick == *wait {
channel.stop(); channel.volume(0);
self.volume = 0.into();
} }
} }
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); channel.playback(self.base_speed.change_base());
} }
} }
PatternEffect::TonePortamento(amount, target) => { PatternEffect::TonePortamento(amount, target) => {
channel.volume(self.volume.try_change_base().unwrap());
if *amount < 1.into() { if *amount < 1.into() {
self.base_speed = self.base_speed =
(self.base_speed * amount.change_base()).max(target.change_base()); (self.base_speed * amount.change_base()).max(target.change_base());
@ -294,6 +295,8 @@ impl TrackerChannel {
self.base_speed = self.base_speed =
(self.base_speed * amount.change_base()).min(target.change_base()); (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 { for pattern in &module.pattern {
let start_pos = pattern_data.len(); let start_pos = pattern_data.len();
let mut effect_parameters: [u8; 255] = [0; u8::MAX as usize]; 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()]; let mut note_and_sample = vec![None; module.get_num_channels()];
for row in pattern.iter() { 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 previous_note_and_sample = note_and_sample[channel_number];
let maybe_note_and_sample = if matches!(slot.note, Note::KeyOff) { let maybe_note_and_sample = if matches!(slot.note, Note::KeyOff) {
effect1 = PatternEffect::Stop; effect1 = PatternEffect::Stop;
note_and_sample[channel_number] = None; // note_and_sample[channel_number] = None;
&None &note_and_sample[channel_number]
} else if !matches!(slot.note, Note::None) { } else if !matches!(slot.note, Note::None) {
if sample != 0 { if sample != 0 {
note_and_sample[channel_number] = Some((slot.note, &samples[sample - 1])); note_and_sample[channel_number] = Some((slot.note, &samples[sample - 1]));
@ -221,13 +221,15 @@ pub fn parse_module(module: &Module) -> TokenStream {
} }
} }
0x1 => { 0x1 => {
let c4_speed = note_to_speed(Note::C4, 0.0, 0, module.frequency_type); let c4_speed: Num<u32, 12> =
let speed = note_to_speed( note_to_speed(Note::C4, 0.0, 0, module.frequency_type).change_base();
let speed: Num<u32, 12> = note_to_speed(
Note::C4, Note::C4,
effect_parameter as f64, effect_parameter as f64 / 16.0,
0, 0,
module.frequency_type, module.frequency_type,
); )
.change_base();
let portamento_amount = speed / c4_speed; 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 c4_speed = note_to_speed(Note::C4, 0.0, 0, module.frequency_type);
let speed = note_to_speed( let speed = note_to_speed(
Note::C4, Note::C4,
-(effect_parameter as f64), effect_parameter as f64,
0, 0,
module.frequency_type, module.frequency_type,
); );
let portamento_amount = speed / c4_speed; let portamento_amount = c4_speed / speed;
PatternEffect::Portamento(portamento_amount.try_change_base().unwrap()) 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)) { 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 => { std::cmp::Ordering::Equal => {
tone_portamento_directions[channel_number] tone_portamento_directions[channel_number]
} }
std::cmp::Ordering::Greater => -1.0, std::cmp::Ordering::Greater => -1,
}; };
tone_portamento_directions[channel_number] = direction; 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 c4_speed = note_to_speed(Note::C4, 0.0, 0, module.frequency_type);
let speed = note_to_speed( let speed = note_to_speed(
Note::C4, Note::C4,
effect_parameter as f64 * direction, effect_parameter as f64 * 8.0,
0, 0,
module.frequency_type, 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( PatternEffect::TonePortamento(
portamento_amount.try_change_base().unwrap(), portamento_amount.try_change_base().unwrap(),
@ -320,7 +333,10 @@ pub fn parse_module(module: &Module) -> TokenStream {
_ => PatternEffect::None, _ => PatternEffect::None,
}; };
if sample == 0 { if sample == 0
|| matches!(effect2, PatternEffect::TonePortamento(_, _))
|| matches!(effect1, PatternEffect::Stop)
{
pattern_data.push(agb_tracker_interop::PatternSlot { pattern_data.push(agb_tracker_interop::PatternSlot {
speed: 0.into(), speed: 0.into(),
sample: 0, sample: 0,
@ -382,6 +398,7 @@ pub fn parse_module(module: &Module) -> TokenStream {
frames_per_tick, frames_per_tick,
ticks_per_step: ticks_per_step.into(), ticks_per_step: ticks_per_step.into(),
repeat: module.restart_position as usize,
}; };
quote!(#interop) quote!(#interop)
@ -392,7 +409,7 @@ fn note_to_speed(
fine_tune: f64, fine_tune: f64,
relative_note: i8, relative_note: i8,
frequency_type: FrequencyType, frequency_type: FrequencyType,
) -> Num<u32, 8> { ) -> Num<u32, 12> {
let frequency = match frequency_type { let frequency = match frequency_type {
FrequencyType::LinearFrequencies => { FrequencyType::LinearFrequencies => {
note_to_frequency_linear(note, fine_tune, relative_note) note_to_frequency_linear(note, fine_tune, relative_note)
@ -403,7 +420,7 @@ fn note_to_speed(
let gba_audio_frequency = 18157f64; let gba_audio_frequency = 18157f64;
let speed: f64 = frequency / gba_audio_frequency; 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 { fn note_to_frequency_linear(note: Note, fine_tune: f64, relative_note: i8) -> f64 {