switch to AICA timing

This commit is contained in:
Zack Buhman 2025-06-25 15:47:15 -05:00
parent 01eaa32e37
commit 2066923f10
4 changed files with 78 additions and 29 deletions

View File

@ -113,12 +113,13 @@ void _play_note(int ch, const xm_pattern_format_t * pf)
wait(); aica_sound.channel[ch].PLFOS(0); wait(); aica_sound.channel[ch].PLFOS(0);
} }
wait(); aica_sound.channel[ch].KYONB(1); state.channel[ch].keyon = 1;
wait(); aica_sound.channel[ch].KYONB(0);
} }
void play_note_effect(int ch, const xm_pattern_format_t * pf) void play_note_effect(int ch, const xm_pattern_format_t * pf)
{ {
int effect_tick = (state.tick / 2) % state.ticks_per_line; int effect_tick = state.tick % state.ticks_per_line;
switch (pf->effect_type) { switch (pf->effect_type) {
case 0x04: // 4 vibrato case 0x04: // 4 vibrato
@ -207,51 +208,75 @@ void execute_line(int line_index)
void interrupt() void interrupt()
{ {
bool keyoff_tick = (state.tick + 1) % (state.ticks_per_line * 2) == 0; state.interrupt_clock += 1;
bool note_tick = state.tick % (state.ticks_per_line * 2) == 0; // execute keyons
bool effect_tick = (state.tick & 1) == 0; for (int ch = 0; ch < 64; ch++) {
bool pattern_break_tick = (state.tick % (state.ticks_per_line * 2)) == (state.ticks_per_line * 2 - 1); /*
if (state.channel[ch].keyon == 2) {
int sgc = aica_sound.common.SGC();
if (sgc == 3) {
wait(); aica_sound.channel[ch].KYONB(1);
state.channel[ch].keyon = 0;
}
break;
} else if (state.channel[ch].keyon == 1) {
wait(); aica_sound.common.afsel_mslc_mobuf
= aica::afsel_mslc_mobuf::AFSEL(0)
| aica::afsel_mslc_mobuf::MSLC(ch);
state.channel[ch].keyon = 2;
break;
}
*/
if (state.channel[ch].keyon != 0) {
wait(); aica_sound.channel[ch].KYONB(1);
state.channel[ch].keyon = 0;
}
}
wait(); aica_sound.channel[0].KYONEX(1);
if (keyoff_tick) { if ((state.interrupt_clock % state.tick_rate) != 0) {
// execute keyoffs return;
execute_line<rekey_note>(state.next_line_index);
}
if (state.pattern_break >= 0 && pattern_break_tick) {
printf("pattern_break\n");
next_pattern();
} }
int tick = state.tick % state.ticks_per_line;
bool note_tick = tick == 0;
if (note_tick) { if (note_tick) {
// execute notes // execute notes
state.line_index = state.next_line_index; state.line_index = state.next_line_index;
state.next_line_index += 1; state.next_line_index += 1;
execute_line<play_note>(state.line_index); execute_line<play_note>(state.line_index);
} else if (effect_tick) { } else {
// execute effects // execute effects
execute_line<play_note_effect>(state.line_index); execute_line<play_note_effect>(state.line_index);
} }
wait(); aica_sound.channel[0].KYONEX(1); wait(); aica_sound.channel[0].KYONEX(1);
int note_index = state.next_line_index * state.xm.number_of_channels; bool pattern_break_tick = tick == (state.ticks_per_line - 1);
bool end_of_pattern = note_index >= state.xm.pattern_note_count[state.pattern_index]; if (pattern_break_tick) {
if (end_of_pattern && pattern_break_tick) { if (state.pattern_break >= 0) {
printf("end_of_pattern\n"); printf("pattern_break\n");
next_pattern(); next_pattern();
}
int note_index = state.next_line_index * state.xm.number_of_channels;
bool end_of_pattern = note_index >= state.xm.pattern_note_count[state.pattern_index];
if (end_of_pattern) {
printf("end_of_pattern\n");
next_pattern();
}
} }
state.tick += 1; state.tick += 1;
} }
void init() void init(float clock_multiplier)
{ {
// 195 = 1ms // 195 = 1ms
// 2500 / bpm milliseconds // 2500 / bpm milliseconds
int default_bpm = s16(&state.xm.header->default_bpm); int default_bpm = s16(&state.xm.header->default_bpm);
int default_tempo = s16(&state.xm.header->default_tempo); int default_tempo = s16(&state.xm.header->default_tempo);
int tick_rate = 195.32 * 2500 / default_bpm; int tick_rate = clock_multiplier * 2500 / default_bpm;
printf("default_bpm %d\n", default_bpm); printf("default_bpm %d\n", default_bpm);
printf("default_tempo %d\n", default_tempo); printf("default_tempo %d\n", default_tempo);

View File

@ -7,10 +7,12 @@ namespace interpreter {
constexpr int max_channels = 64; constexpr int max_channels = 64;
struct channel_state { struct channel_state {
int instrument; uint8_t instrument;
uint8_t keyon;
}; };
struct interpreter_state { struct interpreter_state {
int interrupt_clock;
int tick_rate; int tick_rate;
int ticks_per_line; int ticks_per_line;
int tick; int tick;
@ -27,6 +29,6 @@ struct interpreter_state {
extern struct interpreter_state state; extern struct interpreter_state state;
void interrupt(); void interrupt();
void init(); void init(float clock_multiplier);
} }

View File

@ -6,6 +6,8 @@
#include "maple/maple_bus_commands.hpp" #include "maple/maple_bus_commands.hpp"
#include "maple/maple_bus_ft0.hpp" #include "maple/maple_bus_ft0.hpp"
#include "aica/aica.hpp"
#include "interrupt.hpp" #include "interrupt.hpp"
#include "graphics.hpp" #include "graphics.hpp"
#include "interpreter.hpp" #include "interpreter.hpp"
@ -43,6 +45,13 @@ void vbr600()
} }
graphics_interrupt(istnrm); graphics_interrupt(istnrm);
} else if (sh7091.CCN.EXPEVT == 0 && sh7091.CCN.INTEVT == 0x360) { // AICA
wait(); aica_sound.common.mcire = (1 << 6); // interrupt timer A
wait(); aica_sound.common.tactl_tima =
aica::tactl_tima::TACTL(0) // increment once every sample
| aica::tactl_tima::TIMA(0xffff) // interrupt after 1 counts
;
interpreter::interrupt();
} else if (sh7091.CCN.EXPEVT == 0 && sh7091.CCN.INTEVT == 0x400) { // TMU0 } else if (sh7091.CCN.EXPEVT == 0 && sh7091.CCN.INTEVT == 0x400) { // TMU0
sh7091.TMU.TCR0 sh7091.TMU.TCR0
= tmu::tcr0::UNIE = tmu::tcr0::UNIE
@ -174,7 +183,7 @@ void input_update()
last_b = b; last_b = b;
} }
void load_xm() void load_xm(float clock_multiplier)
{ {
using namespace interpreter; using namespace interpreter;
@ -187,8 +196,9 @@ void load_xm()
buf, buf,
sample_data, sample_data,
sample_data_length); sample_data_length);
interpreter::init(); interpreter::init(clock_multiplier);
sound_init(sample_data, sample_data_ix, state.tick_rate); sound_init(sample_data, sample_data_ix, state.tick_rate);
printf("tick_rate %d\n", state.tick_rate);
} }
#include "memorymap.hpp" #include "memorymap.hpp"
@ -225,7 +235,9 @@ void main()
{ {
serial::init(0); serial::init(0);
load_xm(); //const float tmu_clock_multiplier = 195.32;
const float aica_clock_multiplier = 44.1;
load_xm(aica_clock_multiplier);
graphics_init(); graphics_init();
test_pattern(); test_pattern();
@ -237,6 +249,8 @@ void main()
| istnrm::v_blank_in | istnrm::v_blank_in
| istnrm::end_of_transferring_opaque_list; | istnrm::end_of_transferring_opaque_list;
system.IML4EXT = istext::aica;
static uint8_t __attribute__((aligned(32))) ta_parameter_buf[1024 * 1024 * 1]; static uint8_t __attribute__((aligned(32))) ta_parameter_buf[1024 * 1024 * 1];
ta_parameter_writer writer = ta_parameter_writer(ta_parameter_buf, (sizeof (ta_parameter_buf))); ta_parameter_writer writer = ta_parameter_writer(ta_parameter_buf, (sizeof (ta_parameter_buf)));

View File

@ -17,8 +17,6 @@
#include "assert.h" #include "assert.h"
#include "interpreter.hpp"
void g2_aica_dma(uint32_t g2_address, uint32_t system_address, int length) void g2_aica_dma(uint32_t g2_address, uint32_t system_address, int length)
{ {
using namespace dmac; using namespace dmac;
@ -151,6 +149,7 @@ void sound_init(uint8_t * sample_data, int sample_data_ix, int tick_rate)
| aica::mono_mem8mb_dac18b_ver_mvol::MVOL(0xc) // volume | aica::mono_mem8mb_dac18b_ver_mvol::MVOL(0xc) // volume
; ;
/*
sh7091.TMU.TSTR = 0; // stop all timers sh7091.TMU.TSTR = 0; // stop all timers
sh7091.TMU.TCOR0 = tick_rate / 2; sh7091.TMU.TCOR0 = tick_rate / 2;
sh7091.TMU.TOCR = tmu::tocr::tcoe::tclk_is_external_clock_or_input_capture; sh7091.TMU.TOCR = tmu::tocr::tcoe::tclk_is_external_clock_or_input_capture;
@ -161,4 +160,13 @@ void sound_init(uint8_t * sample_data, int sample_data_ix, int tick_rate)
sh7091.TMU.TSTR = tmu::tstr::str0::counter_start; sh7091.TMU.TSTR = tmu::tstr::str0::counter_start;
sh7091.INTC.IPRA = intc::ipra::TMU0(1); sh7091.INTC.IPRA = intc::ipra::TMU0(1);
*/
wait(); aica_sound.common.tactl_tima =
aica::tactl_tima::TACTL(0) // increment once every sample
| aica::tactl_tima::TIMA(0xffff) // interrupt after 1 counts
;
wait(); aica_sound.common.mcieb = (1 << 6); // interrupt timer A
wait(); aica_sound.common.mcire = (1 << 6); // interrupt timer A
} }