mirror of
https://github.com/RaySollium99/picodrive.git
synced 2025-09-05 07:17:45 -04:00
audio: added SSG-EG to YM2612, plus some timing changes for SN76496+YM2612
This commit is contained in:
parent
2a942f0d41
commit
8ac9ab7fcb
13 changed files with 571 additions and 455 deletions
2
Makefile
2
Makefile
|
@ -36,7 +36,7 @@ endif
|
||||||
|
|
||||||
ifeq ("$(PLATFORM)",$(filter "$(PLATFORM)","gp2x" "opendingux" "rpi1"))
|
ifeq ("$(PLATFORM)",$(filter "$(PLATFORM)","gp2x" "opendingux" "rpi1"))
|
||||||
# very small caches, avoid optimization options making the binary much bigger
|
# very small caches, avoid optimization options making the binary much bigger
|
||||||
CFLAGS += -finline-limit=43 -fno-unroll-loops -fno-ipa-cp -ffast-math
|
CFLAGS += -finline-limit=42 -fno-unroll-loops -fno-ipa-cp -ffast-math
|
||||||
# this gets you about 20% better execution speed on 32bit arm/mips
|
# this gets you about 20% better execution speed on 32bit arm/mips
|
||||||
CFLAGS += -fno-common -fno-stack-protector -fno-guess-branch-probability -fno-caller-saves -fno-tree-loop-if-convert -fno-regmove
|
CFLAGS += -fno-common -fno-stack-protector -fno-guess-branch-probability -fno-caller-saves -fno-tree-loop-if-convert -fno-regmove
|
||||||
endif
|
endif
|
||||||
|
|
|
@ -1393,7 +1393,7 @@ static void emith_sync_t(int sr)
|
||||||
else if (tcond >= 0) {
|
else if (tcond >= 0) {
|
||||||
int tmp = rcache_get_tmp();
|
int tmp = rcache_get_tmp();
|
||||||
EMIT(A64_CSET(tcond, tmp));
|
EMIT(A64_CSET(tcond, tmp));
|
||||||
EMIT(A64_BFI_IMM(sr, tmp, 0, 1)); // assumes SR.T = bit 0
|
EMIT(A64_BFI_IMM(sr, tmp, __builtin_ffs(T)-1, 1));
|
||||||
rcache_free_tmp(tmp);
|
rcache_free_tmp(tmp);
|
||||||
}
|
}
|
||||||
tcond = -1;
|
tcond = -1;
|
||||||
|
|
|
@ -546,7 +546,7 @@ static void PicoWrite8_z80(u32 a, u32 d)
|
||||||
}
|
}
|
||||||
if ((a & 0x6000) == 0x4000) { // FM Sound
|
if ((a & 0x6000) == 0x4000) { // FM Sound
|
||||||
if (PicoIn.opt & POPT_EN_FM)
|
if (PicoIn.opt & POPT_EN_FM)
|
||||||
Pico.m.status |= ym2612_write_local(a & 3, d & 0xff, 0) & 1;
|
ym2612_write_local(a & 3, d & 0xff, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// TODO: probably other VDP access too? Maybe more mirrors?
|
// TODO: probably other VDP access too? Maybe more mirrors?
|
||||||
|
@ -1059,6 +1059,8 @@ static int ym2612_write_local(u32 a, u32 d, int is_from_z80)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int scanline = get_scanline(is_from_z80);
|
||||||
|
PsndDoFM(scanline);
|
||||||
#ifdef __GP2X__
|
#ifdef __GP2X__
|
||||||
if (PicoIn.opt & POPT_EXT_FM)
|
if (PicoIn.opt & POPT_EXT_FM)
|
||||||
return YM2612Write_940(a, d, get_scanline(is_from_z80));
|
return YM2612Write_940(a, d, get_scanline(is_from_z80));
|
||||||
|
@ -1224,7 +1226,7 @@ static unsigned char z80_md_bank_read(unsigned short a)
|
||||||
static void z80_md_ym2612_write(unsigned int a, unsigned char data)
|
static void z80_md_ym2612_write(unsigned int a, unsigned char data)
|
||||||
{
|
{
|
||||||
if (PicoIn.opt & POPT_EN_FM)
|
if (PicoIn.opt & POPT_EN_FM)
|
||||||
Pico.m.status |= ym2612_write_local(a, data, 1) & 1;
|
ym2612_write_local(a, data, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void z80_md_vdp_br_write(unsigned int a, unsigned char data)
|
static void z80_md_vdp_br_write(unsigned int a, unsigned char data)
|
||||||
|
|
|
@ -70,7 +70,7 @@ extern void *p32x_bios_g, *p32x_bios_m, *p32x_bios_s;
|
||||||
#define POPT_EN_DRC (1<<17)
|
#define POPT_EN_DRC (1<<17)
|
||||||
#define POPT_DIS_SPRITE_LIM (1<<18)
|
#define POPT_DIS_SPRITE_LIM (1<<18)
|
||||||
#define POPT_DIS_IDLE_DET (1<<19)
|
#define POPT_DIS_IDLE_DET (1<<19)
|
||||||
#define POPT_EN_32X (1<<20)
|
#define POPT_EN_32X (1<<20) // x0 0000
|
||||||
#define POPT_EN_PWM (1<<21)
|
#define POPT_EN_PWM (1<<21)
|
||||||
#define POPT_PWM_IRQ_OPT (1<<22)
|
#define POPT_PWM_IRQ_OPT (1<<22)
|
||||||
|
|
||||||
|
|
|
@ -88,7 +88,6 @@ static void do_timing_hacks_vb(void)
|
||||||
static int PicoFrameHints(void)
|
static int PicoFrameHints(void)
|
||||||
{
|
{
|
||||||
struct PicoVideo *pv = &Pico.video;
|
struct PicoVideo *pv = &Pico.video;
|
||||||
int line_sample = Pico.m.pal ? 68 : 93;
|
|
||||||
int vdp_slots = (Pico.video.reg[12] & 1) ? 18 : 16;
|
int vdp_slots = (Pico.video.reg[12] & 1) ? 18 : 16;
|
||||||
int lines, y, lines_vis, skip;
|
int lines, y, lines_vis, skip;
|
||||||
int vcnt_wrap, vcnt_adj;
|
int vcnt_wrap, vcnt_adj;
|
||||||
|
@ -150,23 +149,6 @@ static int PicoFrameHints(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// get samples from sound chips
|
|
||||||
if ((y == 224 || y == line_sample) && PicoIn.sndOut)
|
|
||||||
{
|
|
||||||
cycles = SekCyclesDone();
|
|
||||||
|
|
||||||
if (Pico.m.z80Run && !Pico.m.z80_reset && (PicoIn.opt&POPT_EN_Z80))
|
|
||||||
PicoSyncZ80(cycles);
|
|
||||||
#ifdef PICO_CD
|
|
||||||
if (PicoIn.AHW & PAHW_MCD)
|
|
||||||
pcd_sync_s68k(cycles, 0);
|
|
||||||
#endif
|
|
||||||
#ifdef PICO_32X
|
|
||||||
p32x_sync_sh2s(cycles);
|
|
||||||
#endif
|
|
||||||
PsndGetSamples(y);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run scanline:
|
// Run scanline:
|
||||||
Pico.t.m68c_line_start = Pico.t.m68c_aim;
|
Pico.t.m68c_line_start = Pico.t.m68c_aim;
|
||||||
do_timing_hacks_as(pv, vdp_slots);
|
do_timing_hacks_as(pv, vdp_slots);
|
||||||
|
@ -238,10 +220,6 @@ static int PicoFrameHints(void)
|
||||||
p32x_start_blank();
|
p32x_start_blank();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// get samples from sound chips
|
|
||||||
if (y == 224 && PicoIn.sndOut)
|
|
||||||
PsndGetSamples(y);
|
|
||||||
|
|
||||||
// Run scanline:
|
// Run scanline:
|
||||||
CPUS_RUN(CYCLES_M68K_LINE - CYCLES_M68K_VINT_LAG);
|
CPUS_RUN(CYCLES_M68K_LINE - CYCLES_M68K_VINT_LAG);
|
||||||
|
|
||||||
|
@ -298,7 +276,7 @@ static int PicoFrameHints(void)
|
||||||
pv->status |= ((pv->reg[1] >> 3) ^ SR_VB) & SR_VB; // forced blanking
|
pv->status |= ((pv->reg[1] >> 3) ^ SR_VB) & SR_VB; // forced blanking
|
||||||
|
|
||||||
// last scanline
|
// last scanline
|
||||||
Pico.m.scanline = y;
|
Pico.m.scanline = y++;
|
||||||
pv->v_counter = 0xff;
|
pv->v_counter = 0xff;
|
||||||
pv->lwrite_cnt = 0;
|
pv->lwrite_cnt = 0;
|
||||||
|
|
||||||
|
@ -337,6 +315,11 @@ static int PicoFrameHints(void)
|
||||||
#ifdef PICO_32X
|
#ifdef PICO_32X
|
||||||
p32x_sync_sh2s(cycles);
|
p32x_sync_sh2s(cycles);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// get samples from sound chips
|
||||||
|
if (PicoIn.sndOut)
|
||||||
|
PsndGetSamples(y);
|
||||||
|
|
||||||
timers_cycle();
|
timers_cycle();
|
||||||
|
|
||||||
pv->hint_cnt = hint;
|
pv->hint_cnt = hint;
|
||||||
|
|
|
@ -336,7 +336,7 @@ struct PicoMisc
|
||||||
unsigned char eeprom_cycle; // EEPROM cycle number
|
unsigned char eeprom_cycle; // EEPROM cycle number
|
||||||
unsigned char eeprom_slave; // EEPROM slave word for X24C02 and better SRAMs
|
unsigned char eeprom_slave; // EEPROM slave word for X24C02 and better SRAMs
|
||||||
unsigned char eeprom_status;
|
unsigned char eeprom_status;
|
||||||
unsigned char status; // rapid_ym2612, multi_ym_updates
|
unsigned char pad1; // was ym2612 status
|
||||||
unsigned short dma_xfers; // 18
|
unsigned short dma_xfers; // 18
|
||||||
unsigned char eeprom_wb[2]; // EEPROM latch/write buffer
|
unsigned char eeprom_wb[2]; // EEPROM latch/write buffer
|
||||||
unsigned int frame_count; // 1c for movies and idle det
|
unsigned int frame_count; // 1c for movies and idle det
|
||||||
|
@ -433,6 +433,8 @@ struct PicoSound
|
||||||
int len_e_cnt;
|
int len_e_cnt;
|
||||||
short dac_line;
|
short dac_line;
|
||||||
short psg_line;
|
short psg_line;
|
||||||
|
unsigned int fm_mult; // samples per line in Q16
|
||||||
|
unsigned int fm_pos; // last FM position in Q16
|
||||||
};
|
};
|
||||||
|
|
||||||
// run tools/mkoffsets pico/pico_int_offs.h if you change these
|
// run tools/mkoffsets pico/pico_int_offs.h if you change these
|
||||||
|
@ -872,9 +874,10 @@ PICO_INTERNAL void PsndReset(void);
|
||||||
PICO_INTERNAL void PsndStartFrame(void);
|
PICO_INTERNAL void PsndStartFrame(void);
|
||||||
PICO_INTERNAL void PsndDoDAC(int line_to);
|
PICO_INTERNAL void PsndDoDAC(int line_to);
|
||||||
PICO_INTERNAL void PsndDoPSG(int line_to);
|
PICO_INTERNAL void PsndDoPSG(int line_to);
|
||||||
|
PICO_INTERNAL void PsndDoFM(int line_to);
|
||||||
PICO_INTERNAL void PsndClear(void);
|
PICO_INTERNAL void PsndClear(void);
|
||||||
PICO_INTERNAL void PsndGetSamples(int y);
|
PICO_INTERNAL void PsndGetSamples(int y);
|
||||||
PICO_INTERNAL void PsndGetSamplesMS(void);
|
PICO_INTERNAL void PsndGetSamplesMS(int y);
|
||||||
|
|
||||||
// sms.c
|
// sms.c
|
||||||
#ifndef NO_SMS
|
#ifndef NO_SMS
|
||||||
|
|
|
@ -320,16 +320,12 @@ void PicoFrameMS(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 224 because of how it's done for MD...
|
|
||||||
if (y == 224 && PicoIn.sndOut)
|
|
||||||
PsndGetSamplesMS();
|
|
||||||
|
|
||||||
cycles_aim += cycles_line;
|
cycles_aim += cycles_line;
|
||||||
cycles_done += z80_run((cycles_aim - cycles_done) >> 8) << 8;
|
cycles_done += z80_run((cycles_aim - cycles_done) >> 8) << 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PicoIn.sndOut && Pico.snd.psg_line < lines)
|
if (PicoIn.sndOut)
|
||||||
PsndDoPSG(lines - 1);
|
PsndGetSamplesMS(lines);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PicoFrameDrawOnlyMS(void)
|
void PicoFrameDrawOnlyMS(void)
|
||||||
|
|
|
@ -12,16 +12,15 @@
|
||||||
#define MINOUT (-32768)
|
#define MINOUT (-32768)
|
||||||
|
|
||||||
/* limitter */
|
/* limitter */
|
||||||
#define Limit16(val) { \
|
#define Limit16(val) \
|
||||||
val -= (val >> 2); \
|
if ((short)val != val) val = (val < 0 ? MINOUT : MAXOUT)
|
||||||
if ((short)val != val) val = (val < 0 ? MINOUT : MAXOUT); \
|
|
||||||
}
|
|
||||||
|
|
||||||
int mix_32_to_16l_level;
|
int mix_32_to_16l_level;
|
||||||
|
|
||||||
static struct iir2 { // 2-pole IIR
|
static struct iir2 { // 2-pole IIR
|
||||||
int x[2]; // sample buffer
|
int x[2]; // sample buffer
|
||||||
int y[2]; // filter intermediates
|
int y[2]; // filter intermediates
|
||||||
|
int i;
|
||||||
} lfi2, rfi2;
|
} lfi2, rfi2;
|
||||||
|
|
||||||
// NB ">>" rounds to -infinity, "/" to 0. To compensate the effect possibly use
|
// NB ">>" rounds to -infinity, "/" to 0. To compensate the effect possibly use
|
||||||
|
|
|
@ -400,6 +400,8 @@ m32_16l_st_l_no_unal2:
|
||||||
ldmfd sp!, {r4-r11,lr}
|
ldmfd sp!, {r4-r11,lr}
|
||||||
bx lr
|
bx lr
|
||||||
|
|
||||||
|
#endif /* __GP2X__ */
|
||||||
|
|
||||||
.global mix_reset @ void
|
.global mix_reset @ void
|
||||||
mix_reset:
|
mix_reset:
|
||||||
ldr r0, =filter
|
ldr r0, =filter
|
||||||
|
@ -409,11 +411,7 @@ mix_reset:
|
||||||
bx lr
|
bx lr
|
||||||
|
|
||||||
.data
|
.data
|
||||||
DCfilt r4, r10
|
|
||||||
DCfilt r5, r11
|
|
||||||
filter:
|
filter:
|
||||||
.ds 8
|
.ds 8
|
||||||
|
|
||||||
#endif /* __GP2X__ */
|
|
||||||
|
|
||||||
@ vim:filetype=armasm
|
@ vim:filetype=armasm
|
||||||
|
|
|
@ -32,52 +32,17 @@ extern int *sn76496_regs;
|
||||||
static void dac_recalculate(void)
|
static void dac_recalculate(void)
|
||||||
{
|
{
|
||||||
int lines = Pico.m.pal ? 313 : 262;
|
int lines = Pico.m.pal ? 313 : 262;
|
||||||
int mid = Pico.m.pal ? 68 : 93;
|
int i, pos;
|
||||||
int i, dac_cnt, pos, len;
|
|
||||||
|
|
||||||
if (Pico.snd.len <= lines)
|
pos = 0; // Q16
|
||||||
{
|
|
||||||
// shrinking algo
|
|
||||||
dac_cnt = -Pico.snd.len;
|
|
||||||
len=1; pos=0;
|
|
||||||
dac_info[225] = 1;
|
|
||||||
|
|
||||||
for(i=226; i != 225; i++)
|
for(i = 0; i <= lines; i++)
|
||||||
{
|
|
||||||
if (i >= lines) i = 0;
|
|
||||||
if(dac_cnt < 0) {
|
|
||||||
pos++;
|
|
||||||
dac_cnt += lines;
|
|
||||||
}
|
|
||||||
dac_cnt -= Pico.snd.len;
|
|
||||||
dac_info[i] = pos;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
// stretching
|
dac_info[i] = ((pos+(1<<15)) >> 16); // round to nearest
|
||||||
dac_cnt = Pico.snd.len;
|
pos += Pico.snd.fm_mult;
|
||||||
pos=0;
|
|
||||||
for(i = 225; i != 224; i++)
|
|
||||||
{
|
|
||||||
if (i >= lines) i = 0;
|
|
||||||
len=0;
|
|
||||||
while(dac_cnt >= 0) {
|
|
||||||
dac_cnt -= lines;
|
|
||||||
len++;
|
|
||||||
}
|
|
||||||
if (i == mid) // midpoint
|
|
||||||
while(pos+len < Pico.snd.len/2) {
|
|
||||||
dac_cnt -= lines;
|
|
||||||
len++;
|
|
||||||
}
|
|
||||||
dac_cnt += Pico.snd.len;
|
|
||||||
pos += len;
|
|
||||||
dac_info[i] = pos;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
for (i = lines; i < sizeof(dac_info) / sizeof(dac_info[0]); i++)
|
for (i = lines+1; i < sizeof(dac_info) / sizeof(dac_info[0]); i++)
|
||||||
dac_info[i] = dac_info[0];
|
dac_info[i] = dac_info[i-1];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -95,6 +60,7 @@ void PsndRerate(int preserve_state)
|
||||||
{
|
{
|
||||||
void *state = NULL;
|
void *state = NULL;
|
||||||
int target_fps = Pico.m.pal ? 50 : 60;
|
int target_fps = Pico.m.pal ? 50 : 60;
|
||||||
|
int target_lines = Pico.m.pal ? 313 : 262;
|
||||||
|
|
||||||
if (preserve_state) {
|
if (preserve_state) {
|
||||||
state = malloc(0x204);
|
state = malloc(0x204);
|
||||||
|
@ -121,6 +87,9 @@ void PsndRerate(int preserve_state)
|
||||||
Pico.snd.len_e_add = ((PicoIn.sndRate - Pico.snd.len * target_fps) << 16) / target_fps;
|
Pico.snd.len_e_add = ((PicoIn.sndRate - Pico.snd.len * target_fps) << 16) / target_fps;
|
||||||
Pico.snd.len_e_cnt = 0;
|
Pico.snd.len_e_cnt = 0;
|
||||||
|
|
||||||
|
// samples per line
|
||||||
|
Pico.snd.fm_mult = 65536.0 * PicoIn.sndRate / (target_fps*target_lines);
|
||||||
|
|
||||||
// recalculate dac info
|
// recalculate dac info
|
||||||
dac_recalculate();
|
dac_recalculate();
|
||||||
|
|
||||||
|
@ -149,8 +118,7 @@ PICO_INTERNAL void PsndStartFrame(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
Pico.snd.dac_line = Pico.snd.psg_line = 0;
|
Pico.snd.dac_line = Pico.snd.psg_line = 0;
|
||||||
Pico.m.status &= ~1;
|
Pico.snd.fm_pos = 0;
|
||||||
dac_info[224] = Pico.snd.len_use;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PICO_INTERNAL void PsndDoDAC(int line_to)
|
PICO_INTERNAL void PsndDoDAC(int line_to)
|
||||||
|
@ -159,9 +127,6 @@ PICO_INTERNAL void PsndDoDAC(int line_to)
|
||||||
int dout = ym2612.dacout;
|
int dout = ym2612.dacout;
|
||||||
int line_from = Pico.snd.dac_line;
|
int line_from = Pico.snd.dac_line;
|
||||||
|
|
||||||
if (line_to >= 313)
|
|
||||||
line_to = 312;
|
|
||||||
|
|
||||||
pos = dac_info[line_from];
|
pos = dac_info[line_from];
|
||||||
pos1 = dac_info[line_to + 1];
|
pos1 = dac_info[line_to + 1];
|
||||||
len = pos1 - pos;
|
len = pos1 - pos;
|
||||||
|
@ -188,14 +153,9 @@ PICO_INTERNAL void PsndDoPSG(int line_to)
|
||||||
int pos, pos1, len;
|
int pos, pos1, len;
|
||||||
int stereo = 0;
|
int stereo = 0;
|
||||||
|
|
||||||
if (line_to >= 313)
|
|
||||||
line_to = 312;
|
|
||||||
|
|
||||||
pos = dac_info[line_from];
|
pos = dac_info[line_from];
|
||||||
pos1 = dac_info[line_to + 1];
|
pos1 = dac_info[line_to + 1];
|
||||||
len = pos1 - pos;
|
len = pos1 - pos;
|
||||||
//elprintf(EL_STATUS, "%3d %3d %3d %3d %3d",
|
|
||||||
// pos, pos1, len, line_from, line_to);
|
|
||||||
if (len <= 0)
|
if (len <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -211,6 +171,34 @@ PICO_INTERNAL void PsndDoPSG(int line_to)
|
||||||
SN76496Update(PicoIn.sndOut + pos, len, stereo);
|
SN76496Update(PicoIn.sndOut + pos, len, stereo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PICO_INTERNAL void PsndDoFM(int line_to)
|
||||||
|
{
|
||||||
|
int pos, len;
|
||||||
|
int stereo = 0;
|
||||||
|
|
||||||
|
// Q16, number of samples to fill in buffer
|
||||||
|
len = ((line_to-1) * Pico.snd.fm_mult) - Pico.snd.fm_pos;
|
||||||
|
|
||||||
|
// don't do this too often (no more than 256 per sec)
|
||||||
|
if (len >> 16 <= PicoIn.sndRate >> 9)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// update position and calculate buffer offset and length
|
||||||
|
pos = Pico.snd.fm_pos >> 16;
|
||||||
|
Pico.snd.fm_pos += len;
|
||||||
|
len = (Pico.snd.fm_pos >> 16) - pos;
|
||||||
|
|
||||||
|
// fill buffer
|
||||||
|
if (PicoIn.opt & POPT_EN_STEREO) {
|
||||||
|
stereo = 1;
|
||||||
|
pos <<= 1;
|
||||||
|
}
|
||||||
|
if (PicoIn.opt & POPT_EN_FM)
|
||||||
|
YM2612UpdateOne(PsndBuffer + pos, len, stereo, 1);
|
||||||
|
else
|
||||||
|
memset32(PsndBuffer + pos, 0, len<<stereo);
|
||||||
|
}
|
||||||
|
|
||||||
// cdda
|
// cdda
|
||||||
static void cdda_raw_update(int *buffer, int length)
|
static void cdda_raw_update(int *buffer, int length)
|
||||||
{
|
{
|
||||||
|
@ -275,11 +263,12 @@ PICO_INTERNAL void PsndClear(void)
|
||||||
|
|
||||||
static int PsndRender(int offset, int length)
|
static int PsndRender(int offset, int length)
|
||||||
{
|
{
|
||||||
int buf32_updated = 0;
|
int *buf32;
|
||||||
int *buf32 = PsndBuffer+offset;
|
|
||||||
int stereo = (PicoIn.opt & 8) >> 3;
|
int stereo = (PicoIn.opt & 8) >> 3;
|
||||||
|
int fmlen = (Pico.snd.fm_pos >> 16) - offset;
|
||||||
|
|
||||||
offset <<= stereo;
|
offset <<= stereo;
|
||||||
|
buf32 = PsndBuffer+offset;
|
||||||
|
|
||||||
pprof_start(sound);
|
pprof_start(sound);
|
||||||
|
|
||||||
|
@ -288,14 +277,15 @@ static int PsndRender(int offset, int length)
|
||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add in the stereo FM buffer
|
// Add in parts of the FM buffer not yet done
|
||||||
if (PicoIn.opt & POPT_EN_FM) {
|
if (length-fmlen > 0) {
|
||||||
buf32_updated = YM2612UpdateOne(buf32, length, stereo, 1);
|
int *fmbuf = buf32 + (fmlen << stereo);
|
||||||
} else
|
if (PicoIn.opt & POPT_EN_FM)
|
||||||
memset32(buf32, 0, length<<stereo);
|
YM2612UpdateOne(fmbuf, length-fmlen, stereo, 1);
|
||||||
|
else
|
||||||
//printf("active_chs: %02x\n", buf32_updated);
|
memset32(fmbuf, 0, (length-fmlen)<<stereo);
|
||||||
(void)buf32_updated;
|
Pico.snd.fm_pos += (length-fmlen)<<16;
|
||||||
|
}
|
||||||
|
|
||||||
// CD: PCM sound
|
// CD: PCM sound
|
||||||
if (PicoIn.AHW & PAHW_MCD) {
|
if (PicoIn.AHW & PAHW_MCD) {
|
||||||
|
@ -327,7 +317,6 @@ static int PsndRender(int offset, int length)
|
||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
|
|
||||||
// to be called on 224 or line_sample scanlines only
|
|
||||||
PICO_INTERNAL void PsndGetSamples(int y)
|
PICO_INTERNAL void PsndGetSamples(int y)
|
||||||
{
|
{
|
||||||
static int curr_pos = 0;
|
static int curr_pos = 0;
|
||||||
|
@ -336,33 +325,20 @@ PICO_INTERNAL void PsndGetSamples(int y)
|
||||||
PsndDoDAC(y - 1);
|
PsndDoDAC(y - 1);
|
||||||
PsndDoPSG(y - 1);
|
PsndDoPSG(y - 1);
|
||||||
|
|
||||||
if (y == 224)
|
curr_pos = PsndRender(0, Pico.snd.len_use);
|
||||||
{
|
|
||||||
if (Pico.m.status & 2)
|
if (PicoIn.writeSound)
|
||||||
curr_pos += PsndRender(curr_pos, Pico.snd.len-Pico.snd.len/2);
|
PicoIn.writeSound(curr_pos * ((PicoIn.opt & POPT_EN_STEREO) ? 4 : 2));
|
||||||
else curr_pos = PsndRender(0, Pico.snd.len_use);
|
// clear sound buffer
|
||||||
if (Pico.m.status & 1)
|
PsndClear();
|
||||||
Pico.m.status |= 2;
|
Pico.snd.dac_line = y;
|
||||||
else Pico.m.status &= ~2;
|
|
||||||
if (PicoIn.writeSound)
|
|
||||||
PicoIn.writeSound(curr_pos * ((PicoIn.opt & POPT_EN_STEREO) ? 4 : 2));
|
|
||||||
// clear sound buffer
|
|
||||||
PsndClear();
|
|
||||||
Pico.snd.dac_line = 224;
|
|
||||||
dac_info[224] = 0;
|
|
||||||
}
|
|
||||||
else if (Pico.m.status & 3) {
|
|
||||||
Pico.m.status |= 2;
|
|
||||||
Pico.m.status &= ~1;
|
|
||||||
curr_pos = PsndRender(0, Pico.snd.len/2);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PICO_INTERNAL void PsndGetSamplesMS(void)
|
PICO_INTERNAL void PsndGetSamplesMS(int y)
|
||||||
{
|
{
|
||||||
int length = Pico.snd.len_use;
|
int length = Pico.snd.len_use;
|
||||||
|
|
||||||
PsndDoPSG(223);
|
PsndDoPSG(y - 1);
|
||||||
|
|
||||||
// upmix to "stereo" if needed
|
// upmix to "stereo" if needed
|
||||||
if (PicoIn.opt & POPT_EN_STEREO) {
|
if (PicoIn.opt & POPT_EN_STEREO) {
|
||||||
|
@ -374,8 +350,6 @@ PICO_INTERNAL void PsndGetSamplesMS(void)
|
||||||
if (PicoIn.writeSound != NULL)
|
if (PicoIn.writeSound != NULL)
|
||||||
PicoIn.writeSound(length * ((PicoIn.opt & POPT_EN_STEREO) ? 4 : 2));
|
PicoIn.writeSound(length * ((PicoIn.opt & POPT_EN_STEREO) ? 4 : 2));
|
||||||
PsndClear();
|
PsndClear();
|
||||||
|
|
||||||
dac_info[224] = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// vim:shiftwidth=2:ts=2:expandtab
|
// vim:shiftwidth=2:ts=2:expandtab
|
||||||
|
|
|
@ -7,6 +7,8 @@
|
||||||
** document it ("proprietary") and tells to write 0 to SSG-EG control register.
|
** document it ("proprietary") and tells to write 0 to SSG-EG control register.
|
||||||
**
|
**
|
||||||
** updated with fixes from mame 0.216 (file version 1.5.1) (kub)
|
** updated with fixes from mame 0.216 (file version 1.5.1) (kub)
|
||||||
|
** SSG-EG readded from GenPlus (kub)
|
||||||
|
** linear sample interpolation for chip to output rate adaption (kub)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -174,16 +176,6 @@ void memset32(int *dest, int c, int count);
|
||||||
|
|
||||||
#define EG_TIMER_OVERFLOW (3*(1<<EG_SH)) /* envelope generator timer overflows every 3 samples (on real chip) */
|
#define EG_TIMER_OVERFLOW (3*(1<<EG_SH)) /* envelope generator timer overflows every 3 samples (on real chip) */
|
||||||
|
|
||||||
#define MAXOUT (+32767)
|
|
||||||
#define MINOUT (-32768)
|
|
||||||
|
|
||||||
/* limitter */
|
|
||||||
#define Limit(val, max,min) { \
|
|
||||||
if ( val > max ) val = max; \
|
|
||||||
else if ( val < min ) val = min; \
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* TL_TAB_LEN is calculated as:
|
/* TL_TAB_LEN is calculated as:
|
||||||
* 13 - sinus amplitude bits (Y axis)
|
* 13 - sinus amplitude bits (Y axis)
|
||||||
* 2 - sinus sign bit (Y axis)
|
* 2 - sinus sign bit (Y axis)
|
||||||
|
@ -289,8 +281,8 @@ O(18),O(18),O(18),O(18),O(18),O(18),O(18),O(18),
|
||||||
O(18),O(18),O(18),O(18),O(18),O(18),O(18),O(18),
|
O(18),O(18),O(18),O(18),O(18),O(18),O(18),O(18),
|
||||||
|
|
||||||
/* rates 00-11 */
|
/* rates 00-11 */
|
||||||
O(18),O(18),O( 0),O( 0),
|
O(18),O(18),O( 2),O( 3),
|
||||||
O( 0),O( 0),O( 2),O( 2),
|
O( 0),O( 1),O( 2),O( 3),
|
||||||
O( 0),O( 1),O( 2),O( 3),
|
O( 0),O( 1),O( 2),O( 3),
|
||||||
O( 0),O( 1),O( 2),O( 3),
|
O( 0),O( 1),O( 2),O( 3),
|
||||||
O( 0),O( 1),O( 2),O( 3),
|
O( 0),O( 1),O( 2),O( 3),
|
||||||
|
@ -554,6 +546,13 @@ INLINE void set_timers( int v )
|
||||||
ym2612.OPN.ST.status &= ~1;
|
ym2612.OPN.ST.status &= ~1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
INLINE void recalc_volout(FM_SLOT *SLOT)
|
||||||
|
{
|
||||||
|
INT16 vol_out = SLOT->volume;
|
||||||
|
if ((SLOT->ssg&0x0c) == 0x0c)
|
||||||
|
vol_out = (0x200 - SLOT->volume) & MAX_ATT_INDEX;
|
||||||
|
SLOT->vol_out = vol_out + SLOT->tl;
|
||||||
|
}
|
||||||
|
|
||||||
INLINE void FM_KEYON(int c , int s )
|
INLINE void FM_KEYON(int c , int s )
|
||||||
{
|
{
|
||||||
|
@ -562,13 +561,15 @@ INLINE void FM_KEYON(int c , int s )
|
||||||
{
|
{
|
||||||
SLOT->key = 1;
|
SLOT->key = 1;
|
||||||
SLOT->phase = 0; /* restart Phase Generator */
|
SLOT->phase = 0; /* restart Phase Generator */
|
||||||
|
SLOT->ssg ^= SLOT->ssgn;
|
||||||
|
SLOT->ssgn = 0;
|
||||||
|
SLOT->state = (SLOT->sl == MIN_ATT_INDEX) ? EG_SUS : EG_DEC;
|
||||||
if (SLOT->ar + SLOT->ksr < 32+62) {
|
if (SLOT->ar + SLOT->ksr < 32+62) {
|
||||||
SLOT->state = (SLOT->volume > MIN_ATT_INDEX) ? EG_ATT :
|
if (SLOT->volume > MIN_ATT_INDEX) SLOT->state = EG_ATT;
|
||||||
((SLOT->sl == MIN_ATT_INDEX) ? EG_SUS : EG_DEC);
|
|
||||||
} else {
|
} else {
|
||||||
SLOT->volume = MIN_ATT_INDEX;
|
SLOT->volume = MIN_ATT_INDEX;
|
||||||
SLOT->state = (SLOT->sl == MIN_ATT_INDEX) ? EG_SUS : EG_DEC;
|
|
||||||
}
|
}
|
||||||
|
recalc_volout(SLOT);
|
||||||
ym2612.slot_mask |= (1<<s) << (c*4);
|
ym2612.slot_mask |= (1<<s) << (c*4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -579,8 +580,18 @@ INLINE void FM_KEYOFF(int c , int s )
|
||||||
if( SLOT->key )
|
if( SLOT->key )
|
||||||
{
|
{
|
||||||
SLOT->key = 0;
|
SLOT->key = 0;
|
||||||
if (SLOT->state>EG_REL)
|
if (SLOT->state>EG_REL) {
|
||||||
SLOT->state = EG_REL;/* phase -> Release */
|
SLOT->state = EG_REL;/* phase -> Release */
|
||||||
|
if (SLOT->ssg&0x08) {
|
||||||
|
if (SLOT->ssg&0x04)
|
||||||
|
SLOT->volume = (0x200 - SLOT->volume);
|
||||||
|
if (SLOT->volume >= 0x200) {
|
||||||
|
SLOT->volume = MAX_ATT_INDEX;
|
||||||
|
SLOT->state = EG_OFF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SLOT->vol_out = SLOT->volume + SLOT->tl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -597,12 +608,15 @@ INLINE void set_det_mul(FM_CH *CH, FM_SLOT *SLOT, int v)
|
||||||
INLINE void set_tl(FM_SLOT *SLOT, int v)
|
INLINE void set_tl(FM_SLOT *SLOT, int v)
|
||||||
{
|
{
|
||||||
SLOT->tl = (v&0x7f)<<(ENV_BITS-7); /* 7bit TL */
|
SLOT->tl = (v&0x7f)<<(ENV_BITS-7); /* 7bit TL */
|
||||||
|
if (SLOT->state > EG_REL)
|
||||||
|
recalc_volout(SLOT);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* set attack rate & key scale */
|
/* set attack rate & key scale */
|
||||||
INLINE void set_ar_ksr(FM_CH *CH, FM_SLOT *SLOT, int v)
|
INLINE void set_ar_ksr(FM_CH *CH, FM_SLOT *SLOT, int v)
|
||||||
{
|
{
|
||||||
UINT8 old_KSR = SLOT->KSR;
|
UINT8 old_KSR = SLOT->KSR;
|
||||||
|
int eg_sh_ar, eg_sel_ar;
|
||||||
|
|
||||||
SLOT->ar = (v&0x1f) ? 32 + ((v&0x1f)<<1) : 0;
|
SLOT->ar = (v&0x1f) ? 32 + ((v&0x1f)<<1) : 0;
|
||||||
|
|
||||||
|
@ -611,24 +625,20 @@ INLINE void set_ar_ksr(FM_CH *CH, FM_SLOT *SLOT, int v)
|
||||||
{
|
{
|
||||||
CH->SLOT[SLOT1].Incr=-1;
|
CH->SLOT[SLOT1].Incr=-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* refresh Attack rate */
|
||||||
|
if ((SLOT->ar + SLOT->ksr) < 32+62)
|
||||||
|
{
|
||||||
|
eg_sh_ar = eg_rate_shift [SLOT->ar + SLOT->ksr ];
|
||||||
|
eg_sel_ar = eg_rate_select[SLOT->ar + SLOT->ksr ];
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int eg_sh_ar, eg_sel_ar;
|
eg_sh_ar = 0;
|
||||||
|
eg_sel_ar = 18;
|
||||||
/* refresh Attack rate */
|
|
||||||
if ((SLOT->ar + SLOT->ksr) < 32+62)
|
|
||||||
{
|
|
||||||
eg_sh_ar = eg_rate_shift [SLOT->ar + SLOT->ksr ];
|
|
||||||
eg_sel_ar = eg_rate_select[SLOT->ar + SLOT->ksr ];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
eg_sh_ar = 0;
|
|
||||||
eg_sel_ar = 18;
|
|
||||||
}
|
|
||||||
|
|
||||||
SLOT->eg_pack_ar = eg_inc_pack[eg_sel_ar] | (eg_sh_ar<<24);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SLOT->eg_pack_ar = eg_inc_pack[eg_sel_ar] | (eg_sh_ar<<24);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* set decay rate */
|
/* set decay rate */
|
||||||
|
@ -750,7 +760,7 @@ INLINE int advance_lfo(int lfo_ampm, UINT32 lfo_cnt_old, UINT32 lfo_cnt)
|
||||||
return lfo_ampm;
|
return lfo_ampm;
|
||||||
}
|
}
|
||||||
|
|
||||||
INLINE void update_eg_phase(UINT16 *vol_out, FM_SLOT *SLOT, UINT32 eg_cnt)
|
INLINE void update_eg_phase(FM_SLOT *SLOT, UINT32 eg_cnt)
|
||||||
{
|
{
|
||||||
INT32 volume = SLOT->volume;
|
INT32 volume = SLOT->volume;
|
||||||
UINT32 pack = SLOT->eg_pack[SLOT->state - 1];
|
UINT32 pack = SLOT->eg_pack[SLOT->state - 1];
|
||||||
|
@ -763,44 +773,113 @@ INLINE void update_eg_phase(UINT16 *vol_out, FM_SLOT *SLOT, UINT32 eg_cnt)
|
||||||
eg_inc_val = pack >> ((eg_cnt >> shift) & 7) * 3;
|
eg_inc_val = pack >> ((eg_cnt >> shift) & 7) * 3;
|
||||||
eg_inc_val = (1 << (eg_inc_val & 7)) >> 1;
|
eg_inc_val = (1 << (eg_inc_val & 7)) >> 1;
|
||||||
|
|
||||||
switch (SLOT->state)
|
if (SLOT->ssg&0x08) {
|
||||||
{
|
switch (SLOT->state)
|
||||||
case EG_ATT: /* attack phase */
|
|
||||||
volume += ( ~volume * eg_inc_val ) >> 4;
|
|
||||||
if ( volume <= MIN_ATT_INDEX )
|
|
||||||
{
|
{
|
||||||
volume = MIN_ATT_INDEX;
|
case EG_ATT: /* attack phase */
|
||||||
SLOT->state = (SLOT->sl == MIN_ATT_INDEX) ? EG_SUS: EG_DEC;
|
volume += ( ~volume * eg_inc_val ) >> 4;
|
||||||
|
if ( volume <= MIN_ATT_INDEX )
|
||||||
|
{
|
||||||
|
volume = MIN_ATT_INDEX;
|
||||||
|
SLOT->state = (SLOT->sl == MIN_ATT_INDEX) ? EG_SUS: EG_DEC;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EG_DEC: /* decay phase */
|
||||||
|
if (volume < 0x200)
|
||||||
|
volume += 4*eg_inc_val;
|
||||||
|
if ( volume >= (INT32) SLOT->sl )
|
||||||
|
SLOT->state = EG_SUS;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EG_SUS: /* sustain phase */
|
||||||
|
if (volume < 0x200)
|
||||||
|
volume += 4*eg_inc_val;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EG_REL: /* release phase */
|
||||||
|
if (volume < 0x200)
|
||||||
|
volume += 4*eg_inc_val;
|
||||||
|
if ( volume >= 0x200 )
|
||||||
|
{
|
||||||
|
volume = MAX_ATT_INDEX;
|
||||||
|
SLOT->state = EG_OFF;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
|
|
||||||
case EG_DEC: /* decay phase */
|
SLOT->vol_out = volume + SLOT->tl;
|
||||||
volume += eg_inc_val;
|
if ((SLOT->ssg&0x04) && (SLOT->state > EG_REL))
|
||||||
if ( volume >= (INT32) SLOT->sl )
|
SLOT->vol_out = ((0x200 - volume) & MAX_ATT_INDEX) + SLOT->tl;
|
||||||
SLOT->state = EG_SUS;
|
} else {
|
||||||
break;
|
switch (SLOT->state)
|
||||||
|
|
||||||
case EG_SUS: /* sustain phase */
|
|
||||||
volume += eg_inc_val;
|
|
||||||
if ( volume >= MAX_ATT_INDEX )
|
|
||||||
{
|
{
|
||||||
volume = MAX_ATT_INDEX;
|
case EG_ATT: /* attack phase */
|
||||||
/* do not change SLOT->state (verified on real chip) */
|
volume += ( ~volume * eg_inc_val ) >> 4;
|
||||||
}
|
if ( volume <= MIN_ATT_INDEX )
|
||||||
break;
|
{
|
||||||
|
volume = MIN_ATT_INDEX;
|
||||||
|
SLOT->state = (SLOT->sl == MIN_ATT_INDEX) ? EG_SUS: EG_DEC;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case EG_REL: /* release phase */
|
case EG_DEC: /* decay phase */
|
||||||
volume += eg_inc_val;
|
volume += eg_inc_val;
|
||||||
if ( volume >= MAX_ATT_INDEX )
|
if ( volume >= (INT32) SLOT->sl )
|
||||||
{
|
SLOT->state = EG_SUS;
|
||||||
volume = MAX_ATT_INDEX;
|
break;
|
||||||
SLOT->state = EG_OFF;
|
|
||||||
|
case EG_SUS: /* sustain phase */
|
||||||
|
volume += eg_inc_val;
|
||||||
|
if ( volume >= MAX_ATT_INDEX )
|
||||||
|
{
|
||||||
|
volume = MAX_ATT_INDEX;
|
||||||
|
/* do not change SLOT->state (verified on real chip) */
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EG_REL: /* release phase */
|
||||||
|
volume += eg_inc_val;
|
||||||
|
if ( volume >= MAX_ATT_INDEX )
|
||||||
|
{
|
||||||
|
volume = MAX_ATT_INDEX;
|
||||||
|
SLOT->state = EG_OFF;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
|
SLOT->vol_out = volume + SLOT->tl;
|
||||||
}
|
}
|
||||||
|
|
||||||
SLOT->volume = volume;
|
SLOT->volume = volume;
|
||||||
*vol_out = SLOT->tl + volume; /* tl is 7bit<<3, volume 0-1023 (0-2039 total) */
|
}
|
||||||
|
|
||||||
|
INLINE void update_ssg_eg_phase(FM_SLOT *SLOT)
|
||||||
|
{
|
||||||
|
if (SLOT->ssg&0x01) {
|
||||||
|
if (SLOT->ssg&0x02) {
|
||||||
|
SLOT->ssg ^= SLOT->ssgn ^ 4;
|
||||||
|
SLOT->ssgn = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SLOT->state != EG_ATT && !(SLOT->ssg&0x04))
|
||||||
|
SLOT->volume = MAX_ATT_INDEX;
|
||||||
|
} else {
|
||||||
|
if (SLOT->ssg&0x02) {
|
||||||
|
SLOT->ssg ^= 4;
|
||||||
|
SLOT->ssgn ^= 4;
|
||||||
|
} else
|
||||||
|
SLOT->phase = 0;
|
||||||
|
|
||||||
|
if (SLOT->state != EG_ATT) {
|
||||||
|
SLOT->state = (SLOT->sl == MIN_ATT_INDEX) ? EG_SUS : EG_DEC;
|
||||||
|
if (SLOT->ar + SLOT->ksr < 32+62) {
|
||||||
|
if (SLOT->volume > MIN_ATT_INDEX) SLOT->state = EG_ATT;
|
||||||
|
} else {
|
||||||
|
SLOT->volume = MIN_ATT_INDEX;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
recalc_volout(SLOT);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -846,6 +925,16 @@ static void chan_render_loop(chan_rend_context *ct, int *buffer, int length)
|
||||||
{
|
{
|
||||||
int smp = 0; /* produced sample */
|
int smp = 0; /* produced sample */
|
||||||
unsigned int eg_out, eg_out2, eg_out4;
|
unsigned int eg_out, eg_out2, eg_out4;
|
||||||
|
FM_SLOT *SLOT;
|
||||||
|
|
||||||
|
SLOT = &ct->CH->SLOT[SLOT1];
|
||||||
|
if ((SLOT->ssg&0x08) && SLOT->state > EG_REL && SLOT->volume >= 0x200) update_ssg_eg_phase(SLOT);
|
||||||
|
SLOT = &ct->CH->SLOT[SLOT2];
|
||||||
|
if ((SLOT->ssg&0x08) && SLOT->state > EG_REL && SLOT->volume >= 0x200) update_ssg_eg_phase(SLOT);
|
||||||
|
SLOT = &ct->CH->SLOT[SLOT3];
|
||||||
|
if ((SLOT->ssg&0x08) && SLOT->state > EG_REL && SLOT->volume >= 0x200) update_ssg_eg_phase(SLOT);
|
||||||
|
SLOT = &ct->CH->SLOT[SLOT4];
|
||||||
|
if ((SLOT->ssg&0x08) && SLOT->state > EG_REL && SLOT->volume >= 0x200) update_ssg_eg_phase(SLOT);
|
||||||
|
|
||||||
if (ct->pack & 8) { /* LFO enabled ? (test Earthworm Jim in between demo 1 and 2) */
|
if (ct->pack & 8) { /* LFO enabled ? (test Earthworm Jim in between demo 1 and 2) */
|
||||||
ct->pack = (ct->pack&0xffff) | (advance_lfo(ct->pack >> 16, ct->lfo_cnt, ct->lfo_cnt + ct->lfo_inc) << 16);
|
ct->pack = (ct->pack&0xffff) | (advance_lfo(ct->pack >> 16, ct->lfo_cnt, ct->lfo_cnt + ct->lfo_inc) << 16);
|
||||||
|
@ -857,12 +946,58 @@ static void chan_render_loop(chan_rend_context *ct, int *buffer, int length)
|
||||||
{
|
{
|
||||||
ct->eg_timer -= EG_TIMER_OVERFLOW;
|
ct->eg_timer -= EG_TIMER_OVERFLOW;
|
||||||
ct->eg_cnt++;
|
ct->eg_cnt++;
|
||||||
|
if (ct->eg_cnt >= 4096) ct->eg_cnt = 1;
|
||||||
|
|
||||||
if (ct->CH->SLOT[SLOT1].state != EG_OFF) update_eg_phase(&ct->vol_out1, &ct->CH->SLOT[SLOT1], ct->eg_cnt);
|
SLOT = &ct->CH->SLOT[SLOT1];
|
||||||
if (ct->CH->SLOT[SLOT2].state != EG_OFF) update_eg_phase(&ct->vol_out2, &ct->CH->SLOT[SLOT2], ct->eg_cnt);
|
SLOT->vol_ipol = SLOT->vol_out;
|
||||||
if (ct->CH->SLOT[SLOT3].state != EG_OFF) update_eg_phase(&ct->vol_out3, &ct->CH->SLOT[SLOT3], ct->eg_cnt);
|
if (SLOT->state != EG_OFF) update_eg_phase(SLOT, ct->eg_cnt);
|
||||||
if (ct->CH->SLOT[SLOT4].state != EG_OFF) update_eg_phase(&ct->vol_out4, &ct->CH->SLOT[SLOT4], ct->eg_cnt);
|
SLOT = &ct->CH->SLOT[SLOT2];
|
||||||
|
SLOT->vol_ipol = SLOT->vol_out;
|
||||||
|
if (SLOT->state != EG_OFF) update_eg_phase(SLOT, ct->eg_cnt);
|
||||||
|
SLOT = &ct->CH->SLOT[SLOT3];
|
||||||
|
SLOT->vol_ipol = SLOT->vol_out;
|
||||||
|
if (SLOT->state != EG_OFF) update_eg_phase(SLOT, ct->eg_cnt);
|
||||||
|
SLOT = &ct->CH->SLOT[SLOT4];
|
||||||
|
SLOT->vol_ipol = SLOT->vol_out;
|
||||||
|
if (SLOT->state != EG_OFF) update_eg_phase(SLOT, ct->eg_cnt);
|
||||||
}
|
}
|
||||||
|
#if 0
|
||||||
|
UINT32 ifrac0 = ct->eg_timer / (EG_TIMER_OVERFLOW>>EG_SH);
|
||||||
|
UINT32 ifrac1 = (1<<EG_SH) - ifrac0;
|
||||||
|
SLOT = &ct->CH->SLOT[SLOT1];
|
||||||
|
ct->vol_out1 = (SLOT->vol_ipol*ifrac1 + SLOT->vol_out*ifrac0) >> EG_SH;
|
||||||
|
SLOT = &ct->CH->SLOT[SLOT2];
|
||||||
|
ct->vol_out2 = (SLOT->vol_ipol*ifrac1 + SLOT->vol_out*ifrac0) >> EG_SH;
|
||||||
|
SLOT = &ct->CH->SLOT[SLOT3];
|
||||||
|
ct->vol_out3 = (SLOT->vol_ipol*ifrac1 + SLOT->vol_out*ifrac0) >> EG_SH;
|
||||||
|
SLOT = &ct->CH->SLOT[SLOT4];
|
||||||
|
ct->vol_out4 = (SLOT->vol_ipol*ifrac1 + SLOT->vol_out*ifrac0) >> EG_SH;
|
||||||
|
#else
|
||||||
|
switch (ct->eg_timer >> EG_SH)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
ct->vol_out1 = ct->CH->SLOT[SLOT1].vol_ipol;
|
||||||
|
ct->vol_out2 = ct->CH->SLOT[SLOT2].vol_ipol;
|
||||||
|
ct->vol_out3 = ct->CH->SLOT[SLOT3].vol_ipol;
|
||||||
|
ct->vol_out4 = ct->CH->SLOT[SLOT4].vol_ipol;
|
||||||
|
break;
|
||||||
|
case (EG_TIMER_OVERFLOW>>EG_SH)-1:
|
||||||
|
ct->vol_out1 = ct->CH->SLOT[SLOT1].vol_out;
|
||||||
|
ct->vol_out2 = ct->CH->SLOT[SLOT2].vol_out;
|
||||||
|
ct->vol_out3 = ct->CH->SLOT[SLOT3].vol_out;
|
||||||
|
ct->vol_out4 = ct->CH->SLOT[SLOT4].vol_out;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ct->vol_out1 = (ct->CH->SLOT[SLOT1].vol_ipol +
|
||||||
|
ct->CH->SLOT[SLOT1].vol_out) >> 1;
|
||||||
|
ct->vol_out2 = (ct->CH->SLOT[SLOT2].vol_ipol +
|
||||||
|
ct->CH->SLOT[SLOT2].vol_out) >> 1;
|
||||||
|
ct->vol_out3 = (ct->CH->SLOT[SLOT3].vol_ipol +
|
||||||
|
ct->CH->SLOT[SLOT3].vol_out) >> 1;
|
||||||
|
ct->vol_out4 = (ct->CH->SLOT[SLOT4].vol_ipol +
|
||||||
|
ct->CH->SLOT[SLOT4].vol_out) >> 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (ct->pack & 4) continue; /* output disabled */
|
if (ct->pack & 4) continue; /* output disabled */
|
||||||
|
|
||||||
|
@ -892,7 +1027,7 @@ static void chan_render_loop(chan_rend_context *ct, int *buffer, int length)
|
||||||
if (ct->pack & (1<<(SLOT4+8))) eg_out4 += add;
|
if (ct->pack & (1<<(SLOT4+8))) eg_out4 += add;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch( ct->CH->ALGO )
|
switch( ct->algo&0x7 )
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
{
|
{
|
||||||
|
@ -1086,6 +1221,33 @@ static void chan_render_finish(void)
|
||||||
ym2612.OPN.lfo_cnt = crct.lfo_cnt;
|
ym2612.OPN.lfo_cnt = crct.lfo_cnt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static UINT32 update_lfo_phase(FM_SLOT *SLOT, UINT32 block_fnum)
|
||||||
|
{
|
||||||
|
UINT32 fnum_lfo;
|
||||||
|
INT32 lfo_fn_table_index_offset;
|
||||||
|
UINT8 blk;
|
||||||
|
UINT32 fn;
|
||||||
|
int fc,fdt;
|
||||||
|
|
||||||
|
fnum_lfo = ((block_fnum & 0x7f0) >> 4) * 32 * 8;
|
||||||
|
lfo_fn_table_index_offset = lfo_pm_table[ fnum_lfo + crct.CH->pms + ((crct.pack>>16)&0xff) ];
|
||||||
|
if (lfo_fn_table_index_offset) /* LFO phase modulation active */
|
||||||
|
{
|
||||||
|
block_fnum = block_fnum*2 + lfo_fn_table_index_offset;
|
||||||
|
blk = (block_fnum&0x7000) >> 12;
|
||||||
|
fn = block_fnum & 0xfff;
|
||||||
|
|
||||||
|
/* phase increment counter */
|
||||||
|
fc = (fn_table[fn]>>(7-blk));
|
||||||
|
|
||||||
|
fdt = fc + SLOT->DT[crct.CH->kcode];
|
||||||
|
if (fdt < 0) fdt += fn_table[0x7ff*2] >> 2;
|
||||||
|
|
||||||
|
return (fdt * SLOT->mul) >> 1;
|
||||||
|
} else
|
||||||
|
return SLOT->Incr;
|
||||||
|
}
|
||||||
|
|
||||||
static int chan_render(int *buffer, int length, int c, UINT32 flags) // flags: stereo, ?, disabled, ?, pan_r, pan_l
|
static int chan_render(int *buffer, int length, int c, UINT32 flags) // flags: stereo, ?, disabled, ?, pan_r, pan_l
|
||||||
{
|
{
|
||||||
crct.CH = &ym2612.CH[c];
|
crct.CH = &ym2612.CH[c];
|
||||||
|
@ -1114,58 +1276,22 @@ static int chan_render(int *buffer, int length, int c, UINT32 flags) // flags: s
|
||||||
crct.phase3 = crct.CH->SLOT[SLOT3].phase;
|
crct.phase3 = crct.CH->SLOT[SLOT3].phase;
|
||||||
crct.phase4 = crct.CH->SLOT[SLOT4].phase;
|
crct.phase4 = crct.CH->SLOT[SLOT4].phase;
|
||||||
|
|
||||||
/* current output from EG circuit (without AM from LFO) */
|
|
||||||
crct.vol_out1 = crct.CH->SLOT[SLOT1].tl + ((UINT32)crct.CH->SLOT[SLOT1].volume);
|
|
||||||
crct.vol_out2 = crct.CH->SLOT[SLOT2].tl + ((UINT32)crct.CH->SLOT[SLOT2].volume);
|
|
||||||
crct.vol_out3 = crct.CH->SLOT[SLOT3].tl + ((UINT32)crct.CH->SLOT[SLOT3].volume);
|
|
||||||
crct.vol_out4 = crct.CH->SLOT[SLOT4].tl + ((UINT32)crct.CH->SLOT[SLOT4].volume);
|
|
||||||
|
|
||||||
crct.op1_out = crct.CH->op1_out;
|
crct.op1_out = crct.CH->op1_out;
|
||||||
crct.algo = crct.CH->ALGO & 7;
|
crct.algo = crct.CH->ALGO & 7;
|
||||||
|
|
||||||
if(crct.CH->pms)
|
if(crct.CH->pms && (ym2612.OPN.ST.mode & 0xC0) && c == 2) {
|
||||||
|
/* 3 slot mode */
|
||||||
|
crct.incr1 = update_lfo_phase(&crct.CH->SLOT[SLOT1], ym2612.OPN.SL3.block_fnum[1]);
|
||||||
|
crct.incr2 = update_lfo_phase(&crct.CH->SLOT[SLOT2], ym2612.OPN.SL3.block_fnum[2]);
|
||||||
|
crct.incr3 = update_lfo_phase(&crct.CH->SLOT[SLOT3], ym2612.OPN.SL3.block_fnum[0]);
|
||||||
|
crct.incr4 = update_lfo_phase(&crct.CH->SLOT[SLOT4], crct.CH->block_fnum);
|
||||||
|
}
|
||||||
|
else if(crct.CH->pms)
|
||||||
{
|
{
|
||||||
/* add support for 3 slot mode */
|
crct.incr1 = update_lfo_phase(&crct.CH->SLOT[SLOT1], crct.CH->block_fnum);
|
||||||
UINT32 block_fnum = crct.CH->block_fnum;
|
crct.incr2 = update_lfo_phase(&crct.CH->SLOT[SLOT2], crct.CH->block_fnum);
|
||||||
|
crct.incr3 = update_lfo_phase(&crct.CH->SLOT[SLOT3], crct.CH->block_fnum);
|
||||||
UINT32 fnum_lfo = ((block_fnum & 0x7f0) >> 4) * 32 * 8;
|
crct.incr4 = update_lfo_phase(&crct.CH->SLOT[SLOT4], crct.CH->block_fnum);
|
||||||
INT32 lfo_fn_table_index_offset = lfo_pm_table[ fnum_lfo + crct.CH->pms + ((crct.pack>>16)&0xff) ];
|
|
||||||
|
|
||||||
if (lfo_fn_table_index_offset) /* LFO phase modulation active */
|
|
||||||
{
|
|
||||||
UINT8 blk;
|
|
||||||
UINT32 fn;
|
|
||||||
int kc,fc,fdt;
|
|
||||||
|
|
||||||
block_fnum = block_fnum*2 + lfo_fn_table_index_offset;
|
|
||||||
blk = (block_fnum&0x7000) >> 12;
|
|
||||||
fn = block_fnum & 0xfff;
|
|
||||||
|
|
||||||
/* keyscale code */
|
|
||||||
kc = (blk<<2) | opn_fktable[(fn >> 7) & 0xf];
|
|
||||||
/* phase increment counter */
|
|
||||||
fc = (fn_table[fn]>>(7-blk));
|
|
||||||
|
|
||||||
fdt = fc + crct.CH->SLOT[SLOT1].DT[kc];
|
|
||||||
if (fdt < 0) fdt += fn_table[0x7ff*2] >> 2;
|
|
||||||
crct.incr1 = (fdt*crct.CH->SLOT[SLOT1].mul) >> 1;
|
|
||||||
fdt = fc + crct.CH->SLOT[SLOT2].DT[kc];
|
|
||||||
if (fdt < 0) fdt += fn_table[0x7ff*2] >> 2;
|
|
||||||
crct.incr2 = (fdt*crct.CH->SLOT[SLOT2].mul) >> 1;
|
|
||||||
fdt = fc + crct.CH->SLOT[SLOT3].DT[kc];
|
|
||||||
if (fdt < 0) fdt += fn_table[0x7ff*2] >> 2;
|
|
||||||
crct.incr3 = (fdt*crct.CH->SLOT[SLOT3].mul) >> 1;
|
|
||||||
fdt = fc + crct.CH->SLOT[SLOT4].DT[kc];
|
|
||||||
if (fdt < 0) fdt += fn_table[0x7ff*2] >> 2;
|
|
||||||
crct.incr4 = (fdt*crct.CH->SLOT[SLOT4].mul) >> 1;
|
|
||||||
}
|
|
||||||
else /* LFO phase modulation = zero */
|
|
||||||
{
|
|
||||||
crct.incr1 = crct.CH->SLOT[SLOT1].Incr;
|
|
||||||
crct.incr2 = crct.CH->SLOT[SLOT2].Incr;
|
|
||||||
crct.incr3 = crct.CH->SLOT[SLOT3].Incr;
|
|
||||||
crct.incr4 = crct.CH->SLOT[SLOT4].Incr;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else /* no LFO phase modulation */
|
else /* no LFO phase modulation */
|
||||||
{
|
{
|
||||||
|
@ -1297,8 +1423,13 @@ static void reset_channels(FM_CH *CH)
|
||||||
CH[c].fc = 0;
|
CH[c].fc = 0;
|
||||||
for(s = 0 ; s < 4 ; s++ )
|
for(s = 0 ; s < 4 ; s++ )
|
||||||
{
|
{
|
||||||
|
CH[c].SLOT[s].Incr = -1;
|
||||||
|
CH[c].SLOT[s].key = 0;
|
||||||
|
CH[c].SLOT[s].phase = 0;
|
||||||
|
CH[c].SLOT[s].ssg = CH[c].SLOT[s].ssgn = 0;
|
||||||
CH[c].SLOT[s].state= EG_OFF;
|
CH[c].SLOT[s].state= EG_OFF;
|
||||||
CH[c].SLOT[s].volume = MAX_ATT_INDEX;
|
CH[c].SLOT[s].volume = MAX_ATT_INDEX;
|
||||||
|
CH[c].SLOT[s].vol_out = MAX_ATT_INDEX;
|
||||||
}
|
}
|
||||||
CH[c].mem_value = CH[c].op1_out = 0;
|
CH[c].mem_value = CH[c].op1_out = 0;
|
||||||
}
|
}
|
||||||
|
@ -1503,8 +1634,10 @@ static int OPNWriteReg(int r, int v)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x90: /* SSG-EG */
|
case 0x90: /* SSG-EG */
|
||||||
// removed.
|
SLOT->ssg = v&0x0f;
|
||||||
ret = 0;
|
SLOT->ssg ^= SLOT->ssgn;
|
||||||
|
if (SLOT->state > EG_REL)
|
||||||
|
recalc_volout(SLOT);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0xa0:
|
case 0xa0:
|
||||||
|
|
|
@ -53,6 +53,11 @@ typedef struct
|
||||||
};
|
};
|
||||||
UINT32 eg_pack[4];
|
UINT32 eg_pack[4];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
UINT8 ssg; /* 0x30 SSG-EG waveform */
|
||||||
|
UINT8 ssgn;
|
||||||
|
UINT16 vol_out; /* 0x32 current output from EG (without LFO) */
|
||||||
|
UINT16 vol_ipol; /* 0x34 interpolator memory */
|
||||||
} FM_SLOT;
|
} FM_SLOT;
|
||||||
|
|
||||||
|
|
||||||
|
@ -176,21 +181,22 @@ int YM2612PicoStateLoad2(int *tat, int *tbt);
|
||||||
#else
|
#else
|
||||||
/* GP2X specific */
|
/* GP2X specific */
|
||||||
#include "../../platform/gp2x/940ctl.h"
|
#include "../../platform/gp2x/940ctl.h"
|
||||||
#define YM2612Init(baseclock,rate) { \
|
#define YM2612Init(baseclock,rate) do { \
|
||||||
if (PicoIn.opt&POPT_EXT_FM) YM2612Init_940(baseclock, rate); \
|
if (PicoIn.opt&POPT_EXT_FM) YM2612Init_940(baseclock, rate); \
|
||||||
else YM2612Init_(baseclock, rate); \
|
else YM2612Init_(baseclock, rate); \
|
||||||
}
|
} while (0)
|
||||||
#define YM2612ResetChip() { \
|
#define YM2612ResetChip() do { \
|
||||||
if (PicoIn.opt&POPT_EXT_FM) YM2612ResetChip_940(); \
|
if (PicoIn.opt&POPT_EXT_FM) YM2612ResetChip_940(); \
|
||||||
else YM2612ResetChip_(); \
|
else YM2612ResetChip_(); \
|
||||||
}
|
} while (0)
|
||||||
#define YM2612UpdateOne(buffer,length,stereo,is_buf_empty) \
|
#define YM2612UpdateOne(buffer,length,stereo,is_buf_empty) do { \
|
||||||
(PicoIn.opt&POPT_EXT_FM) ? YM2612UpdateOne_940(buffer, length, stereo, is_buf_empty) : \
|
(PicoIn.opt&POPT_EXT_FM) ? YM2612UpdateOne_940(buffer, length, stereo, is_buf_empty) : \
|
||||||
YM2612UpdateOne_(buffer, length, stereo, is_buf_empty);
|
YM2612UpdateOne_(buffer, length, stereo, is_buf_empty); \
|
||||||
#define YM2612PicoStateLoad() { \
|
} while (0)
|
||||||
|
#define YM2612PicoStateLoad() do { \
|
||||||
if (PicoIn.opt&POPT_EXT_FM) YM2612PicoStateLoad_940(); \
|
if (PicoIn.opt&POPT_EXT_FM) YM2612PicoStateLoad_940(); \
|
||||||
else YM2612PicoStateLoad_(); \
|
else YM2612PicoStateLoad_(); \
|
||||||
}
|
} while (0)
|
||||||
#endif /* __GP2X__ */
|
#endif /* __GP2X__ */
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* PicoDrive
|
* PicoDrive
|
||||||
* (C) notaz, 2006
|
* (C) notaz, 2006
|
||||||
|
* (C) kub, 2020 added SSG-EG and simple output rate interpolation
|
||||||
*
|
*
|
||||||
* This work is licensed under the terms of MAME license.
|
* This work is licensed under the terms of MAME license.
|
||||||
* See COPYING file in the top-level directory.
|
* See COPYING file in the top-level directory.
|
||||||
|
@ -18,7 +19,7 @@
|
||||||
.equiv SLOT2, 2
|
.equiv SLOT2, 2
|
||||||
.equiv SLOT3, 1
|
.equiv SLOT3, 1
|
||||||
.equiv SLOT4, 3
|
.equiv SLOT4, 3
|
||||||
.equiv SLOT_STRUCT_SIZE, 0x30
|
.equiv SLOT_STRUCT_SIZE, 0x38
|
||||||
|
|
||||||
.equiv TL_TAB_LEN, 0x1A00
|
.equiv TL_TAB_LEN, 0x1A00
|
||||||
|
|
||||||
|
@ -28,11 +29,11 @@
|
||||||
.equiv EG_REL, 1
|
.equiv EG_REL, 1
|
||||||
.equiv EG_OFF, 0
|
.equiv EG_OFF, 0
|
||||||
|
|
||||||
.equiv EG_SH, 16 @ 16.16 fixed point (envelope generator timing)
|
.equiv EG_SH, 16 @ 16.16 fixed point (envelope generator timing)
|
||||||
.equiv EG_TIMER_OVERFLOW, (3*(1<<EG_SH)) @ envelope generator timer overflows every 3 samples (on real chip)
|
.equiv EG_TIMER_OVERFLOW, (3*(1<<EG_SH)) @ envelope generator timer overflows every 3 samples (on real chip)
|
||||||
.equiv LFO_SH, 24 /* 8.24 fixed point (LFO calculations) */
|
.equiv LFO_SH, 24 /* 8.24 fixed point (LFO calculations) */
|
||||||
|
|
||||||
.equiv ENV_QUIET, (2*13*256/8)
|
.equiv ENV_QUIET, (2*13*256/8)
|
||||||
|
|
||||||
.text
|
.text
|
||||||
.align 2
|
.align 2
|
||||||
|
@ -41,8 +42,10 @@
|
||||||
@ r5=slot, r1=eg_cnt, trashes: r0,r2,r3
|
@ r5=slot, r1=eg_cnt, trashes: r0,r2,r3
|
||||||
@ writes output to routp, but only if vol_out changes
|
@ writes output to routp, but only if vol_out changes
|
||||||
.macro update_eg_phase_slot slot
|
.macro update_eg_phase_slot slot
|
||||||
|
ldrh r0, [r5,#0x32] @ vol_out
|
||||||
ldrb r2, [r5,#0x17] @ state
|
ldrb r2, [r5,#0x17] @ state
|
||||||
add r3, r5, #0x1c
|
add r3, r5, #0x1c
|
||||||
|
strh r0, [r5,#0x34] @ vol_ipol
|
||||||
tst r2, r2
|
tst r2, r2
|
||||||
beq 0f @ EG_OFF
|
beq 0f @ EG_OFF
|
||||||
|
|
||||||
|
@ -60,11 +63,17 @@
|
||||||
add r3, r3, r3, lsl #1
|
add r3, r3, r3, lsl #1
|
||||||
mov r3, r2, lsr r3
|
mov r3, r2, lsr r3
|
||||||
and r3, r3, #7 @ eg_inc_val shift, may be 0
|
and r3, r3, #7 @ eg_inc_val shift, may be 0
|
||||||
|
ldrb r0, [r5,#0x30] @ ssg
|
||||||
ldrb r2, [r5,#0x17] @ state
|
ldrb r2, [r5,#0x17] @ state
|
||||||
ldrh r0, [r5,#0x1a] @ volume, unsigned (0-1023)
|
|
||||||
|
|
||||||
|
tst r0, #0x08 @ ssg enabled?
|
||||||
|
bne 9f
|
||||||
|
|
||||||
|
@ non-SSG-EG mode
|
||||||
cmp r2, #4 @ EG_ATT
|
cmp r2, #4 @ EG_ATT
|
||||||
|
ldrh r0, [r5,#0x1a] @ volume, unsigned (0-1023)
|
||||||
beq 4f
|
beq 4f
|
||||||
|
|
||||||
cmp r2, #2
|
cmp r2, #2
|
||||||
mov r2, #1
|
mov r2, #1
|
||||||
mov r2, r2, lsl r3
|
mov r2, r2, lsl r3
|
||||||
|
@ -82,10 +91,9 @@
|
||||||
|
|
||||||
4: @ EG_ATT
|
4: @ EG_ATT
|
||||||
subs r3, r3, #1 @ eg_inc_val_shift - 1
|
subs r3, r3, #1 @ eg_inc_val_shift - 1
|
||||||
mov r2, #0
|
|
||||||
mvnpl r2, r0
|
mvnpl r2, r0
|
||||||
mov r2, r2, lsl r3
|
movpl r2, r2, lsl r3
|
||||||
add r0, r0, r2, asr #4
|
addpl r0, r0, r2, asr #4
|
||||||
cmp r0, #0 @ if (volume <= MIN_ATT_INDEX)
|
cmp r0, #0 @ if (volume <= MIN_ATT_INDEX)
|
||||||
bgt 10f
|
bgt 10f
|
||||||
ldr r2, [r5,#0x1c]
|
ldr r2, [r5,#0x1c]
|
||||||
|
@ -112,24 +120,81 @@
|
||||||
strgeb r3, [r5,#0x17] @ state
|
strgeb r3, [r5,#0x17] @ state
|
||||||
|
|
||||||
10: @ finish
|
10: @ finish
|
||||||
ldrh r3, [r5,#0x18] @ tl
|
|
||||||
strh r0, [r5,#0x1a] @ volume
|
strh r0, [r5,#0x1a] @ volume
|
||||||
|
b 11f
|
||||||
|
|
||||||
|
9: @ SSG-EG mode
|
||||||
|
cmp r2, #4 @ EG_ATT
|
||||||
|
ldrh r0, [r5,#0x1a] @ volume, unsigned (0-1023)
|
||||||
|
beq 4f
|
||||||
|
|
||||||
|
cmp r0, #0x200 @ if ( volume < 0x200 )
|
||||||
|
movlt r0, #1
|
||||||
|
movlt r3, r0, lsl r3
|
||||||
|
ldrlth r0, [r5,#0x1a] @ volume, unsigned (0-1023)
|
||||||
|
movlt r3, r3, lsr #1 @ eg_inc_val
|
||||||
|
addlt r0, r0, r3, lsr #2
|
||||||
|
|
||||||
|
cmp r2, #2
|
||||||
|
blt 1f @ EG_REL
|
||||||
|
beq 10f @ EG_SUS - nothing more to do
|
||||||
|
|
||||||
|
3: @ EG_DEC
|
||||||
|
ldr r2, [r5,#0x1c] @ sl (can be 16bit?)
|
||||||
|
mov r3, #EG_SUS
|
||||||
|
cmp r0, r2 @ if ( volume >= (INT32) SLOT->sl )
|
||||||
|
strgeb r3, [r5,#0x17] @ state
|
||||||
|
b 10f
|
||||||
|
|
||||||
|
4: @ EG_ATT
|
||||||
|
subs r3, r3, #1 @ eg_inc_val_shift - 1
|
||||||
|
mvnpl r2, r0
|
||||||
|
movpl r2, r2, lsl r3
|
||||||
|
addpl r0, r0, r2, asr #4
|
||||||
|
cmp r0, #0 @ if (volume <= MIN_ATT_INDEX)
|
||||||
|
bgt 10f
|
||||||
|
ldr r2, [r5,#0x1c]
|
||||||
|
mov r0, #0
|
||||||
|
cmp r2, #0
|
||||||
|
movne r3, #EG_DEC
|
||||||
|
moveq r3, #EG_SUS
|
||||||
|
strb r3, [r5,#0x17] @ state
|
||||||
|
b 10f
|
||||||
|
|
||||||
|
1: @ EG_REL
|
||||||
|
mov r2, #0x200
|
||||||
|
cmp r0, r2 @ if ( volume >= 0x200 )
|
||||||
|
movge r0, #1024
|
||||||
|
subge r0, #1
|
||||||
|
movge r3, #EG_OFF
|
||||||
|
strgeb r3, [r5,#0x17] @ state
|
||||||
|
|
||||||
|
10: @ finish
|
||||||
|
strh r0, [r5,#0x1a] @ volume
|
||||||
|
ldrb r2, [r5,#0x30] @ ssg
|
||||||
|
ldrb r3, [r5,#0x17] @ state
|
||||||
|
cmp r2, #0x0c @ if ( ssg&0x04 && state > EG_REL )
|
||||||
|
cmpge r3, #EG_REL+1
|
||||||
|
rsbge r0, r0, #0x200 @ volume = (0x200-volume) & MAX_ATT
|
||||||
|
lslge r0, r0, #10
|
||||||
|
lsrge r0, r0, #10
|
||||||
|
|
||||||
|
11:
|
||||||
|
ldrh r3, [r5,#0x18] @ tl
|
||||||
|
add r0, r0, r3 @ volume += tl
|
||||||
|
strh r0, [r5,#0x32] @ vol_out
|
||||||
.if \slot == SLOT1
|
.if \slot == SLOT1
|
||||||
mov r6, r6, lsr #16
|
mov r6, r6, lsr #16
|
||||||
add r0, r0, r3
|
|
||||||
orr r6, r0, r6, lsl #16
|
orr r6, r0, r6, lsl #16
|
||||||
.elseif \slot == SLOT2
|
.elseif \slot == SLOT2
|
||||||
mov r6, r6, lsl #16
|
mov r6, r6, lsl #16
|
||||||
add r0, r0, r3
|
|
||||||
mov r0, r0, lsl #16
|
mov r0, r0, lsl #16
|
||||||
orr r6, r0, r6, lsr #16
|
orr r6, r0, r6, lsr #16
|
||||||
.elseif \slot == SLOT3
|
.elseif \slot == SLOT3
|
||||||
mov r7, r7, lsr #16
|
mov r7, r7, lsr #16
|
||||||
add r0, r0, r3
|
|
||||||
orr r7, r0, r7, lsl #16
|
orr r7, r0, r7, lsl #16
|
||||||
.elseif \slot == SLOT4
|
.elseif \slot == SLOT4
|
||||||
mov r7, r7, lsl #16
|
mov r7, r7, lsl #16
|
||||||
add r0, r0, r3
|
|
||||||
mov r0, r0, lsl #16
|
mov r0, r0, lsl #16
|
||||||
orr r7, r0, r7, lsr #16
|
orr r7, r0, r7, lsr #16
|
||||||
.endif
|
.endif
|
||||||
|
@ -137,6 +202,63 @@
|
||||||
0: @ EG_OFF
|
0: @ EG_OFF
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
|
@ r5=slot, trashes: r0,r2,r3
|
||||||
|
.macro update_ssg_eg
|
||||||
|
ldrh r0, [r5,#0x30] @ ssg+ssgn
|
||||||
|
ldrb r2, [r5,#0x17] @ state
|
||||||
|
ldrh r3, [r5,#0x1a] @ volume
|
||||||
|
tst r0, #0x08 @ ssg enabled?
|
||||||
|
beq 9f
|
||||||
|
cmp r2, #EG_REL @ state > EG_REL?
|
||||||
|
ble 9f
|
||||||
|
cmp r3, #0x200 @ volume >= 0x200?
|
||||||
|
blt 9f
|
||||||
|
|
||||||
|
tst r0, #0x01
|
||||||
|
beq 1f
|
||||||
|
|
||||||
|
tst r0, #0x02
|
||||||
|
eorne r0, r0, lsr #8 @ ssg ^= ssgn ^ 4
|
||||||
|
eorne r0, r0, #0x4
|
||||||
|
orrne r0, r0, #0x400 @ ssgn = 4
|
||||||
|
strneh r0, [r5,#0x30]
|
||||||
|
|
||||||
|
eor r0, r0, #0x4 @ if ( !(ssg&0x04 )
|
||||||
|
tst r0, #0x4
|
||||||
|
cmpne r2, #EG_ATT @ if ( state != EG_ATT )
|
||||||
|
movne r0, #0x400
|
||||||
|
subne r0, r0, #1
|
||||||
|
strneh r0, [r5,#0x1a] @ volume = MAX_ATT
|
||||||
|
b 9f
|
||||||
|
|
||||||
|
1: tst r0, #0x02
|
||||||
|
eorne r0, r0, #0x4 @ ssg ^= 4
|
||||||
|
eorne r0, r0, #0x400 @ ssgn ^= 4
|
||||||
|
strneh r0, [r5,#0x30]
|
||||||
|
moveq r3, #0
|
||||||
|
streq r3, [r5,#0x0c] @ phase = 0
|
||||||
|
|
||||||
|
cmp r2, #EG_ATT @ if ( state != EG_ATT )
|
||||||
|
beq 9f
|
||||||
|
|
||||||
|
ldr r3, [r5,#0x1c] @ sl
|
||||||
|
mov r2, #EG_SUS @ state = sl==MIN_ATT ? EG_SUS:EG_DEC
|
||||||
|
cmp r3, #0
|
||||||
|
|
||||||
|
ldr r0, [r5,#0x04] @ ar
|
||||||
|
ldr r3, [r5,#0x14] @ ksr
|
||||||
|
movne r2, #EG_DEC
|
||||||
|
add r0, r0, r3
|
||||||
|
cmp r0, #32+62 @ if ( ar+ksr >= 32+62 )
|
||||||
|
ldrlt r0, [r5,#0x1a]
|
||||||
|
movge r0, #0
|
||||||
|
strgeh r0, [r5,#0x1a] @ volume = MIN_ATT
|
||||||
|
|
||||||
|
cmp r0, #0
|
||||||
|
movgt r2, #EG_ATT
|
||||||
|
strb r2, [r5,#0x17] @ state
|
||||||
|
9:
|
||||||
|
.endm
|
||||||
|
|
||||||
@ r12=lfo_ampm[31:16], r1=lfo_cnt_old, r2=lfo_cnt, r3=scratch
|
@ r12=lfo_ampm[31:16], r1=lfo_cnt_old, r2=lfo_cnt, r3=scratch
|
||||||
.macro advance_lfo_m
|
.macro advance_lfo_m
|
||||||
|
@ -532,187 +654,6 @@
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
.global update_eg_phase @ FM_SLOT *SLOT, UINT32 eg_cnt
|
|
||||||
|
|
||||||
update_eg_phase:
|
|
||||||
stmfd sp!, {r5,r6}
|
|
||||||
mov r5, r0 @ slot
|
|
||||||
ldrh r3, [r5,#0x18] @ tl
|
|
||||||
ldrh r6, [r5,#0x1a] @ volume
|
|
||||||
add r6, r6, r3
|
|
||||||
update_eg_phase_slot SLOT1
|
|
||||||
mov r0, r6
|
|
||||||
ldmfd sp!, {r5,r6}
|
|
||||||
bx lr
|
|
||||||
.pool
|
|
||||||
|
|
||||||
|
|
||||||
.global advance_lfo @ int lfo_ampm, UINT32 lfo_cnt_old, UINT32 lfo_cnt
|
|
||||||
|
|
||||||
advance_lfo:
|
|
||||||
mov r12, r0, lsl #16
|
|
||||||
advance_lfo_m
|
|
||||||
mov r0, r12, lsr #16
|
|
||||||
bx lr
|
|
||||||
.pool
|
|
||||||
|
|
||||||
|
|
||||||
.global upd_algo0 @ chan_rend_context *c
|
|
||||||
upd_algo0:
|
|
||||||
stmfd sp!, {r4-r10,lr}
|
|
||||||
mov lr, r0
|
|
||||||
|
|
||||||
PIC_LDR(r3, ip, ym_sin_tab)
|
|
||||||
PIC_LDR(r5, ip, ym_tl_tab)
|
|
||||||
ldmia lr, {r6-r7}
|
|
||||||
ldr r10, [lr, #0x54]
|
|
||||||
ldr r12, [lr, #0x4c]
|
|
||||||
|
|
||||||
upd_algo0_m
|
|
||||||
|
|
||||||
ldmfd sp!, {r4-r10,pc}
|
|
||||||
.pool
|
|
||||||
|
|
||||||
|
|
||||||
.global upd_algo1 @ chan_rend_context *c
|
|
||||||
upd_algo1:
|
|
||||||
stmfd sp!, {r4-r10,lr}
|
|
||||||
mov lr, r0
|
|
||||||
|
|
||||||
PIC_LDR(r3, ip, ym_sin_tab)
|
|
||||||
PIC_LDR(r5, ip, ym_tl_tab)
|
|
||||||
ldmia lr, {r6-r7}
|
|
||||||
ldr r10, [lr, #0x54]
|
|
||||||
ldr r12, [lr, #0x4c]
|
|
||||||
|
|
||||||
upd_algo1_m
|
|
||||||
|
|
||||||
ldmfd sp!, {r4-r10,pc}
|
|
||||||
.pool
|
|
||||||
|
|
||||||
|
|
||||||
.global upd_algo2 @ chan_rend_context *c
|
|
||||||
upd_algo2:
|
|
||||||
stmfd sp!, {r4-r10,lr}
|
|
||||||
mov lr, r0
|
|
||||||
|
|
||||||
PIC_LDR(r3, ip, ym_sin_tab)
|
|
||||||
PIC_LDR(r5, ip, ym_tl_tab)
|
|
||||||
ldmia lr, {r6-r7}
|
|
||||||
ldr r10, [lr, #0x54]
|
|
||||||
ldr r12, [lr, #0x4c]
|
|
||||||
|
|
||||||
upd_algo2_m
|
|
||||||
|
|
||||||
ldmfd sp!, {r4-r10,pc}
|
|
||||||
.pool
|
|
||||||
|
|
||||||
|
|
||||||
.global upd_algo3 @ chan_rend_context *c
|
|
||||||
upd_algo3:
|
|
||||||
stmfd sp!, {r4-r10,lr}
|
|
||||||
mov lr, r0
|
|
||||||
|
|
||||||
PIC_LDR(r3, ip, ym_sin_tab)
|
|
||||||
PIC_LDR(r5, ip, ym_tl_tab)
|
|
||||||
ldmia lr, {r6-r7}
|
|
||||||
ldr r10, [lr, #0x54]
|
|
||||||
ldr r12, [lr, #0x4c]
|
|
||||||
|
|
||||||
upd_algo3_m
|
|
||||||
|
|
||||||
ldmfd sp!, {r4-r10,pc}
|
|
||||||
.pool
|
|
||||||
|
|
||||||
|
|
||||||
.global upd_algo4 @ chan_rend_context *c
|
|
||||||
upd_algo4:
|
|
||||||
stmfd sp!, {r4-r10,lr}
|
|
||||||
mov lr, r0
|
|
||||||
|
|
||||||
PIC_LDR(r3, ip, ym_sin_tab)
|
|
||||||
PIC_LDR(r5, ip, ym_tl_tab)
|
|
||||||
ldmia lr, {r6-r7}
|
|
||||||
ldr r10, [lr, #0x54]
|
|
||||||
ldr r12, [lr, #0x4c]
|
|
||||||
|
|
||||||
upd_algo4_m
|
|
||||||
|
|
||||||
ldmfd sp!, {r4-r10,pc}
|
|
||||||
.pool
|
|
||||||
|
|
||||||
|
|
||||||
.global upd_algo5 @ chan_rend_context *c
|
|
||||||
upd_algo5:
|
|
||||||
stmfd sp!, {r4-r10,lr}
|
|
||||||
mov lr, r0
|
|
||||||
|
|
||||||
PIC_LDR(r3, ip, ym_sin_tab)
|
|
||||||
PIC_LDR(r5, ip, ym_tl_tab)
|
|
||||||
ldmia lr, {r6-r7}
|
|
||||||
ldr r10, [lr, #0x54]
|
|
||||||
ldr r12, [lr, #0x4c]
|
|
||||||
|
|
||||||
upd_algo5_m
|
|
||||||
|
|
||||||
ldmfd sp!, {r4-r10,pc}
|
|
||||||
.pool
|
|
||||||
|
|
||||||
|
|
||||||
.global upd_algo6 @ chan_rend_context *c
|
|
||||||
upd_algo6:
|
|
||||||
stmfd sp!, {r4-r10,lr}
|
|
||||||
mov lr, r0
|
|
||||||
|
|
||||||
PIC_LDR(r3, ip, ym_sin_tab)
|
|
||||||
PIC_LDR(r5, ip, ym_tl_tab)
|
|
||||||
ldmia lr, {r6-r7}
|
|
||||||
ldr r10, [lr, #0x54]
|
|
||||||
ldr r12, [lr, #0x4c]
|
|
||||||
|
|
||||||
upd_algo6_m
|
|
||||||
|
|
||||||
ldmfd sp!, {r4-r10,pc}
|
|
||||||
.pool
|
|
||||||
|
|
||||||
|
|
||||||
.global upd_algo7 @ chan_rend_context *c
|
|
||||||
upd_algo7:
|
|
||||||
stmfd sp!, {r4-r10,lr}
|
|
||||||
mov lr, r0
|
|
||||||
|
|
||||||
PIC_LDR(r3, ip, ym_sin_tab)
|
|
||||||
PIC_LDR(r5, ip, ym_tl_tab)
|
|
||||||
ldmia lr, {r6-r7}
|
|
||||||
ldr r10, [lr, #0x54]
|
|
||||||
ldr r12, [lr, #0x4c]
|
|
||||||
|
|
||||||
upd_algo7_m
|
|
||||||
|
|
||||||
ldmfd sp!, {r4-r10,pc}
|
|
||||||
.pool
|
|
||||||
|
|
||||||
|
|
||||||
.global upd_slot1 @ chan_rend_context *c
|
|
||||||
upd_slot1:
|
|
||||||
stmfd sp!, {r4-r10,lr}
|
|
||||||
mov lr, r0
|
|
||||||
|
|
||||||
PIC_LDR(r3, ip, ym_sin_tab)
|
|
||||||
PIC_LDR(r5, ip, ym_tl_tab)
|
|
||||||
ldmia lr, {r6-r7}
|
|
||||||
ldr r10, [lr, #0x54]
|
|
||||||
ldr r12, [lr, #0x4c]
|
|
||||||
|
|
||||||
upd_slot1_m
|
|
||||||
str r10, [lr, #0x38]
|
|
||||||
|
|
||||||
ldmfd sp!, {r4-r10,pc}
|
|
||||||
.pool
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
@ lr=context, r12=pack (stereo, lastchan, disabled, lfo_enabled | pan_r, pan_l, ams[2] | AMmasks[4] | FB[4] | lfo_ampm[16])
|
@ lr=context, r12=pack (stereo, lastchan, disabled, lfo_enabled | pan_r, pan_l, ams[2] | AMmasks[4] | FB[4] | lfo_ampm[16])
|
||||||
@ r0-r2=scratch, r3=sin_tab/scratch, r4=(length<<8)|unused[4],was_update,algo[3], r5=tl_tab/slot,
|
@ r0-r2=scratch, r3=sin_tab/scratch, r4=(length<<8)|unused[4],was_update,algo[3], r5=tl_tab/slot,
|
||||||
@ r6-r7=vol_out[4], r8=eg_timer, r9=eg_timer_add[31:16], r10=op1_out, r11=buffer
|
@ r6-r7=vol_out[4], r8=eg_timer, r9=eg_timer_add[31:16], r10=op1_out, r11=buffer
|
||||||
|
@ -730,14 +671,21 @@ chan_render_loop:
|
||||||
add r0, lr, #0x44
|
add r0, lr, #0x44
|
||||||
ldmia r0, {r8,r9} @ eg_timer, eg_timer_add
|
ldmia r0, {r8,r9} @ eg_timer, eg_timer_add
|
||||||
ldr r10, [lr, #0x54] @ op1_out
|
ldr r10, [lr, #0x54] @ op1_out
|
||||||
ldmia lr, {r6,r7} @ load volumes
|
@ ldmia lr, {r6,r7} @ load volumes
|
||||||
|
ldr r5, [lr, #0x40] @ CH
|
||||||
|
ldrh r6, [r5, #0x32] @ vol_out values for all slots
|
||||||
|
ldrh r2, [r5, #0x32+SLOT_STRUCT_SIZE*2]
|
||||||
|
ldrh r7, [r5, #0x32+SLOT_STRUCT_SIZE]
|
||||||
|
ldrh r3, [r5, #0x32+SLOT_STRUCT_SIZE*3]
|
||||||
|
orr r6, r6, r2, lsl #16
|
||||||
|
orr r7, r7, r3, lsl #16
|
||||||
|
|
||||||
tst r12, #8 @ lfo?
|
tst r12, #8 @ lfo?
|
||||||
beq crl_loop
|
beq crl_loop
|
||||||
|
|
||||||
crl_loop_lfo:
|
crl_loop_lfo:
|
||||||
add r0, lr, #0x30
|
add r0, lr, #0x30
|
||||||
ldmia r0, {r1,r2}
|
ldmia r0, {r1,r2} @ lfo_cnt, lfo_inc
|
||||||
|
|
||||||
subs r4, r4, #0x100
|
subs r4, r4, #0x100
|
||||||
bmi crl_loop_end
|
bmi crl_loop_end
|
||||||
|
@ -754,15 +702,29 @@ crl_loop:
|
||||||
subs r4, r4, #0x100
|
subs r4, r4, #0x100
|
||||||
bmi crl_loop_end
|
bmi crl_loop_end
|
||||||
|
|
||||||
|
@ -- SSG --
|
||||||
|
add r0, lr, #0x3c
|
||||||
|
ldmia r0, {r1,r5} @ eg_cnt, CH
|
||||||
|
|
||||||
|
@ r5=slot, trashes: r0,r2,r3
|
||||||
|
update_ssg_eg
|
||||||
|
add r5, r5, #SLOT_STRUCT_SIZE*2 @ SLOT2 (2)
|
||||||
|
update_ssg_eg
|
||||||
|
sub r5, r5, #SLOT_STRUCT_SIZE @ SLOT3 (1)
|
||||||
|
update_ssg_eg
|
||||||
|
add r5, r5, #SLOT_STRUCT_SIZE*2 @ SLOT4 (3)
|
||||||
|
update_ssg_eg
|
||||||
|
sub r5, r5, #SLOT_STRUCT_SIZE*3
|
||||||
|
|
||||||
@ -- EG --
|
@ -- EG --
|
||||||
add r8, r8, r9
|
add r8, r8, r9
|
||||||
cmp r8, #EG_TIMER_OVERFLOW
|
cmp r8, #EG_TIMER_OVERFLOW
|
||||||
bcc eg_done
|
bcc eg_done
|
||||||
add r0, lr, #0x3c
|
|
||||||
ldmia r0, {r1,r5} @ eg_cnt, CH
|
|
||||||
eg_loop:
|
eg_loop:
|
||||||
sub r8, r8, #EG_TIMER_OVERFLOW
|
sub r8, r8, #EG_TIMER_OVERFLOW
|
||||||
add r1, r1, #1
|
add r1, r1, #1
|
||||||
|
cmp r1, #4096
|
||||||
|
movge r1, #1
|
||||||
@ SLOT1 (0)
|
@ SLOT1 (0)
|
||||||
@ r5=slot, r1=eg_cnt, trashes: r0,r2,r3
|
@ r5=slot, r1=eg_cnt, trashes: r0,r2,r3
|
||||||
update_eg_phase_slot SLOT1
|
update_eg_phase_slot SLOT1
|
||||||
|
@ -774,8 +736,8 @@ eg_loop:
|
||||||
update_eg_phase_slot SLOT4
|
update_eg_phase_slot SLOT4
|
||||||
|
|
||||||
cmp r8, #EG_TIMER_OVERFLOW
|
cmp r8, #EG_TIMER_OVERFLOW
|
||||||
subcs r5, r5, #SLOT_STRUCT_SIZE*3
|
sub r5, r5, #SLOT_STRUCT_SIZE*3
|
||||||
bcs eg_loop
|
bhs eg_loop
|
||||||
str r1, [lr, #0x3c]
|
str r1, [lr, #0x3c]
|
||||||
|
|
||||||
eg_done:
|
eg_done:
|
||||||
|
@ -787,6 +749,66 @@ eg_done:
|
||||||
cmp r0, #0x4
|
cmp r0, #0x4
|
||||||
beq crl_loop
|
beq crl_loop
|
||||||
|
|
||||||
|
@ output interpolation
|
||||||
|
#if 0
|
||||||
|
@ basic interpolator, interpolate in middle region, else use closer value
|
||||||
|
mov r3, r8, lsr #EG_SH @ eg_timer, [0..3<<EG_SH) after loop
|
||||||
|
cmp r3, #(EG_TIMER_OVERFLOW>>EG_SH)/2
|
||||||
|
bgt 0f @ mix is vol_out
|
||||||
|
|
||||||
|
ldrh r0, [r5,#0x34] @ SLOT1 vol_ipol
|
||||||
|
lsleq r2, r6, #16
|
||||||
|
addeq r0, r0, r2, lsr #16
|
||||||
|
lsreq r0, r0, #1
|
||||||
|
mov r6, r6, lsr #16
|
||||||
|
orr r6, r0, r6, lsl #16
|
||||||
|
|
||||||
|
ldrh r0, [r5,#0x34+SLOT_STRUCT_SIZE*2] @ SLOT2 vol_ipol
|
||||||
|
addeq r0, r0, r6, lsr #16
|
||||||
|
lsreq r0, r0, #1
|
||||||
|
mov r6, r6, lsl #16
|
||||||
|
orr r6, r6, r0
|
||||||
|
ror r6, r6, #16
|
||||||
|
|
||||||
|
ldrh r0, [r5,#0x34+SLOT_STRUCT_SIZE] @ SLOT3 vol_ipol
|
||||||
|
lsleq r2, r7, #16
|
||||||
|
addeq r0, r0, r2, lsr #16
|
||||||
|
lsreq r0, r0, #1
|
||||||
|
mov r7, r7, lsr #16
|
||||||
|
orr r7, r0, r7, lsl #16
|
||||||
|
|
||||||
|
ldrh r0, [r5,#0x34+SLOT_STRUCT_SIZE*3] @ SLOT4 vol_ipol
|
||||||
|
addeq r0, r0, r7, lsr #16
|
||||||
|
lsreq r0, r0, #1
|
||||||
|
mov r7, r7, lsl #16
|
||||||
|
orr r7, r7, r0
|
||||||
|
ror r7, r7, #16
|
||||||
|
#elif 0
|
||||||
|
@ super-basic... just take value closest to sample point
|
||||||
|
mov r3, r8, lsr #EG_SH-1 @ eg_timer, [0..3<<EG_SH) after loop
|
||||||
|
cmp r3, #(EG_TIMER_OVERFLOW>>EG_SH)
|
||||||
|
bgt 0f @ mix is vol_out
|
||||||
|
|
||||||
|
ldrh r0, [r5,#0x34] @ SLOT1 vol_ipol
|
||||||
|
mov r6, r6, lsr #16
|
||||||
|
orr r6, r0, r6, lsl #16
|
||||||
|
|
||||||
|
ldrh r0, [r5,#0x34+SLOT_STRUCT_SIZE*2] @ SLOT2 vol_ipol
|
||||||
|
mov r6, r6, lsl #16
|
||||||
|
orr r6, r6, r0
|
||||||
|
ror r6, r6, #16
|
||||||
|
|
||||||
|
ldrh r0, [r5,#0x34+SLOT_STRUCT_SIZE] @ SLOT3 vol_ipol
|
||||||
|
mov r7, r7, lsr #16
|
||||||
|
orr r7, r0, r7, lsl #16
|
||||||
|
|
||||||
|
ldrh r0, [r5,#0x34+SLOT_STRUCT_SIZE*3] @ SLOT4 vol_ipol
|
||||||
|
mov r7, r7, lsl #16
|
||||||
|
orr r7, r7, r0
|
||||||
|
ror r7, r7, #16
|
||||||
|
#endif
|
||||||
|
0:
|
||||||
|
|
||||||
@ -- SLOT1 --
|
@ -- SLOT1 --
|
||||||
PIC_LDR(r3, r2, ym_tl_tab)
|
PIC_LDR(r3, r2, ym_tl_tab)
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue