mirror of
https://github.com/italicsjenga/agb.git
synced 2025-01-03 21:51:34 +11:00
Try composing my own theme (with some bug fixes)
This commit is contained in:
parent
70e763cc11
commit
4b145d3194
BIN
examples/the-dungeon-puzzlers-lament/sfx/gwilym-theme2.xm
Normal file
BIN
examples/the-dungeon-puzzlers-lament/sfx/gwilym-theme2.xm
Normal file
Binary file not shown.
|
@ -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");
|
||||||
|
|
|
@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
¬e_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 {
|
||||||
|
|
Loading…
Reference in a new issue