From 70efc52db8ca92b8d5c4e0db4d3e85fb9fc7d7c1 Mon Sep 17 00:00:00 2001 From: kub Date: Sun, 21 Jan 2024 21:41:31 +0100 Subject: [PATCH] core, implement GG stereo --- pico/pico.h | 2 +- pico/sms.c | 2 ++ pico/sound/mix.c | 21 +++++++------- pico/sound/mix.h | 6 ++-- pico/sound/mix_arm.S | 66 +++++++++++++++++++++++--------------------- pico/sound/sn76496.c | 44 ++++++++++++++++++++++------- pico/sound/sn76496.h | 1 + pico/sound/sound.c | 48 +++++++++++++++++--------------- platform/gp2x/emu.c | 6 ++-- 9 files changed, 114 insertions(+), 82 deletions(-) diff --git a/pico/pico.h b/pico/pico.h index e91cad29e..2db502d5b 100644 --- a/pico/pico.h +++ b/pico/pico.h @@ -267,7 +267,7 @@ void Pico32xSetClocks(int msh2_hz, int ssh2_hz); #define PICO_SSH2_HZ ((int)(7670442.0 * 2.4)) // sound.c -extern void (*PsndMix_32_to_16l)(s16 *dest, s32 *src, int count); +extern void (*PsndMix_32_to_16)(s16 *dest, s32 *src, int count); void PsndRerate(int preserve_state); // media.c diff --git a/pico/sms.c b/pico/sms.c index 398a4da3c..615ba36ea 100644 --- a/pico/sms.c +++ b/pico/sms.c @@ -241,6 +241,8 @@ static void z80_sms_out(unsigned short a, unsigned char d) case 0x00: if ((PicoIn.AHW & PAHW_GG) && a < 0x8) // GG I/O area Pico.ms.io_gg[a] = d; + if ((PicoIn.AHW & PAHW_GG) && a == 0x6) + SN76496Config(d); break; case 0x01: if ((PicoIn.AHW & PAHW_GG) && a < 0x8) { // GG I/O area diff --git a/pico/sound/mix.c b/pico/sound/mix.c index 8f75ef0ab..1c79b4854 100644 --- a/pico/sound/mix.c +++ b/pico/sound/mix.c @@ -18,7 +18,7 @@ val -= val >> 3; /* reduce level to avoid clipping */ \ if ((s16)val != val) val = (val < 0 ? MINOUT : MAXOUT) -int mix_32_to_16l_level; +int mix_32_to_16_level; static struct iir { int alpha; // alpha for EMA low pass @@ -63,33 +63,34 @@ static inline int filter_null(struct iir *fi2, int x) #define filter filter_band -#define mix_32_to_16l_stereo_core(dest, src, count, lv, fl) { \ +#define mix_32_to_16_stereo_core(dest, src, count, lv, fl) { \ int l, r; \ struct iir lf = lfi2, rf = rfi2; \ \ for (; count > 0; count--) \ { \ - l = r = *dest; \ + l = *dest; \ l += *src++ >> lv; \ - r += *src++ >> lv; \ l = fl(&lf, l); \ - r = fl(&rf, r); \ Limit16(l); \ - Limit16(r); \ *dest++ = l; \ + r = *dest; \ + r += *src++ >> lv; \ + r = fl(&rf, r); \ + Limit16(r); \ *dest++ = r; \ } \ lfi2 = lf, rfi2 = rf; \ } -void mix_32_to_16l_stereo_lvl(s16 *dest, s32 *src, int count) +void mix_32_to_16_stereo_lvl(s16 *dest, s32 *src, int count) { - mix_32_to_16l_stereo_core(dest, src, count, mix_32_to_16l_level, filter); + mix_32_to_16_stereo_core(dest, src, count, mix_32_to_16_level, filter); } -void mix_32_to_16l_stereo(s16 *dest, s32 *src, int count) +void mix_32_to_16_stereo(s16 *dest, s32 *src, int count) { - mix_32_to_16l_stereo_core(dest, src, count, 0, filter); + mix_32_to_16_stereo_core(dest, src, count, 0, filter); } void mix_32_to_16_mono(s16 *dest, s32 *src, int count) diff --git a/pico/sound/mix.h b/pico/sound/mix.h index 3aa3ee874..43fb52a52 100644 --- a/pico/sound/mix.h +++ b/pico/sound/mix.h @@ -6,9 +6,9 @@ void mix_16h_to_32_s2(s32 *dest, s16 *src, int count); void mix_16h_to_32_resample_stereo(s32 *dest, s16 *src, int count, int fac16); void mix_16h_to_32_resample_mono(s32 *dest, s16 *src, int count, int fac16); -void mix_32_to_16l_stereo(s16 *dest, s32 *src, int count); +void mix_32_to_16_stereo(s16 *dest, s32 *src, int count); void mix_32_to_16_mono(s16 *dest, s32 *src, int count); -extern int mix_32_to_16l_level; -void mix_32_to_16l_stereo_lvl(s16 *dest, s32 *src, int count); +extern int mix_32_to_16_level; +void mix_32_to_16_stereo_lvl(s16 *dest, s32 *src, int count); void mix_reset(int alpha_q16); diff --git a/pico/sound/mix_arm.S b/pico/sound/mix_arm.S index f051b3861..dc9e980b4 100644 --- a/pico/sound/mix_arm.S +++ b/pico/sound/mix_arm.S @@ -282,29 +282,29 @@ m16_32_rsm_end: @ mix 32bit audio (with 16bits really used, upper bits indicate overflow) with normal 16 bit audio with left channel only @ warning: this function assumes dest is word aligned -.global mix_32_to_16l_stereo @ short *dest, int *src, int count +.global mix_32_to_16_stereo @ short *dest, int *src, int count -mix_32_to_16l_stereo: +mix_32_to_16_stereo: stmfd sp!, {r4-r8,r10-r11,lr} mov r2, r2, lsl #1 subs r2, r2, #4 - bmi m32_16l_st_end + bmi m32_16_st_end ldr r12, =filter ldr r8, [r12], #4 ldmia r12, {r3,r10-r11,lr} str r8, [sp, #-4]! -m32_16l_st_loop: +m32_16_st_loop: ldmia r0, {r8,r12} ldmia r1!, {r4-r7} + add r5, r5, r8, asr #16 + add r7, r7, r12,asr #16 mov r8, r8, lsl #16 mov r12,r12,lsl #16 add r4, r4, r8, asr #16 - add r5, r5, r8, asr #16 add r6, r6, r12,asr #16 - add r7, r7, r12,asr #16 ldr r12,[sp] LPfilt r4, r3 LPfilt r5, lr @@ -323,16 +323,17 @@ m32_16l_st_loop: orr r4, r5, r4, lsr #16 orr r5, r7, r6, lsr #16 stmia r0!, {r4,r5} - bpl m32_16l_st_loop + bpl m32_16_st_loop -m32_16l_st_end: +m32_16_st_end: @ check for remaining bytes to convert tst r2, #2 - beq m32_16l_st_no_unal2 - ldrsh r6, [r0] + beq m32_16_st_no_unal2 + ldr r6, [r0] ldmia r1!,{r4,r5} - add r4, r4, r6 - add r5, r5, r6 + add r5, r5, r6, asr #16 + mov r6, r6, lsl #16 + add r4, r4, r6, asr #16 ldr r12,[sp] LPfilt r4, r3 LPfilt r5, lr @@ -344,7 +345,7 @@ m32_16l_st_end: orr r4, r5, r4, lsr #16 str r4, [r0], #4 -m32_16l_st_no_unal2: +m32_16_st_no_unal2: ldr r12, =filter add r12,r12, #4 stmia r12, {r3,r10-r11,lr} @@ -386,10 +387,10 @@ m32_16_mo_loop: ldmia r0, {r8,r12} ldmia r1!, {r4-r7} add r5, r5, r8, asr #16 - mov r8, r8, lsl #16 - add r4, r4, r8, asr #16 add r7, r7, r12,asr #16 + mov r8, r8, lsl #16 mov r12,r12,lsl #16 + add r4, r4, r8, asr #16 add r6, r6, r12,asr #16 ldr r12,[sp] LPfilt r4, r11 @@ -458,20 +459,20 @@ m32_16_mo_no_unal: .data .align 4 -.global mix_32_to_16l_level -mix_32_to_16l_level: +.global mix_32_to_16_level +mix_32_to_16_level: .word 0 .text .align 4 -@ same as mix_32_to_16l_stereo, but with additional shift -.global mix_32_to_16l_stereo_lvl @ short *dest, int *src, int count +@ same as mix_32_to_16_stereo, but with additional shift +.global mix_32_to_16_stereo_lvl @ short *dest, int *src, int count -mix_32_to_16l_stereo_lvl: +mix_32_to_16_stereo_lvl: stmfd sp!, {r4-r11,lr} - ldr r9, =mix_32_to_16l_level + ldr r9, =mix_32_to_16_level mov lr, #1 ldr r9, [r9] ldr r12, =filter @@ -481,17 +482,17 @@ mix_32_to_16l_stereo_lvl: mov r2, r2, lsl #1 subs r2, r2, #4 - bmi m32_16l_st_l_end + bmi m32_16_st_l_end -m32_16l_st_l_loop: +m32_16_st_l_loop: ldmia r0, {r8,r12} ldmia r1!, {r4-r7} + add r5, r5, r8, asr #16 + add r7, r7, r12,asr #16 mov r8, r8, lsl #16 mov r12,r12,lsl #16 add r4, r4, r8, asr #16 - add r5, r5, r8, asr #16 add r6, r6, r12,asr #16 - add r7, r7, r12,asr #16 mov r4, r4, asr r9 mov r5, r5, asr r9 mov r6, r6, asr r9 @@ -514,16 +515,17 @@ m32_16l_st_l_loop: orr r4, r5, r4, lsr #16 orr r5, r7, r6, lsr #16 stmia r0!, {r4,r5} - bpl m32_16l_st_l_loop + bpl m32_16_st_l_loop -m32_16l_st_l_end: +m32_16_st_l_end: @ check for remaining bytes to convert tst r2, #2 - beq m32_16l_st_l_no_unal2 - ldrsh r6, [r0] + beq m32_16_st_l_no_unal2 + ldr r6, [r0] ldmia r1!,{r4,r5} - add r4, r4, r6 - add r5, r5, r6 + add r5, r5, r6, asr #16 + mov r6, r6, lsl #16 + add r4, r4, r6, asr #16 mov r4, r4, asr r9 mov r5, r5, asr r9 ldr r12,[sp] @@ -537,7 +539,7 @@ m32_16l_st_l_end: orr r4, r5, r4, lsr #16 str r4, [r0], #4 -m32_16l_st_l_no_unal2: +m32_16_st_l_no_unal2: ldr r12, =filter add r12,r12, #4 stmia r12, {r3,r10-r11,lr} diff --git a/pico/sound/sn76496.c b/pico/sound/sn76496.c index 3bb5cf741..0837839c8 100644 --- a/pico/sound/sn76496.c +++ b/pico/sound/sn76496.c @@ -56,7 +56,7 @@ struct SN76496 int Period[4]; int Count[4]; int Output[4]; - int pad[1]; + int Panning; }; static struct SN76496 ono_sn; // one and only SN76496 @@ -135,7 +135,6 @@ void SN76496Update(short *buffer, int length, int stereo) while (length > 0) { int vol[4]; - unsigned int out; int left; @@ -203,19 +202,43 @@ void SN76496Update(short *buffer, int length, int stereo) } while (left > 0 && R->Volume[3]); if (R->Output[3]) vol[3] -= R->Count[3]; - out = vol[0] * R->Volume[0] + vol[1] * R->Volume[1] + + length--; + if (R->Panning == 0xff || !stereo) { + unsigned int out = + vol[0] * R->Volume[0] + vol[1] * R->Volume[1] + vol[2] * R->Volume[2] + vol[3] * R->Volume[3]; - if (out > MAX_OUTPUT * STEP) out = MAX_OUTPUT * STEP; - - out /= STEP; // will be optimized to shift; max 0x4800 = 18432 - *buffer++ += out; - if (stereo) *buffer++ += out; - - length--; + if (out > MAX_OUTPUT * STEP) out = MAX_OUTPUT * STEP; + + out /= STEP; // will be optimized to shift; max 0x4800 = 18432 + *buffer++ += out; + if (stereo) *buffer++ += out; + } else { +#define P(n) !!(R->Panning & (1<<(n))) + unsigned int outl = + vol[0] * R->Volume[0] * P(4) + vol[1] * R->Volume[1] * P(5) + + vol[2] * R->Volume[2] * P(6) + vol[3] * R->Volume[3] * P(7); + unsigned int outr = + vol[0] * R->Volume[0] * P(0) + vol[1] * R->Volume[1] * P(1) + + vol[2] * R->Volume[2] * P(2) + vol[3] * R->Volume[3] * P(3); +#undef P + if (outl > MAX_OUTPUT * STEP) outl = MAX_OUTPUT * STEP; + if (outr > MAX_OUTPUT * STEP) outr = MAX_OUTPUT * STEP; + + outl /= STEP; // will be optimized to shift; max 0x4800 = 18432 + outr /= STEP; // will be optimized to shift; max 0x4800 = 18432 + *buffer++ += outl; + *buffer++ += outr; + } } } +void SN76496Config(int panning) +{ + struct SN76496 *R = &ono_sn; + R->Panning = panning & 0xff; +} + static void SN76496_set_clock(struct SN76496 *R,int clock) { @@ -286,6 +309,7 @@ int SN76496_init(int clock,int sample_rate) // added SN76496_set_gain(R, 0); + R->Panning = 0xff; return 0; } diff --git a/pico/sound/sn76496.h b/pico/sound/sn76496.h index e0de6edaf..707bb5dd1 100644 --- a/pico/sound/sn76496.h +++ b/pico/sound/sn76496.h @@ -3,6 +3,7 @@ void SN76496Write(int data); void SN76496Update(short *buffer,int length,int stereo); +void SN76496Config(int panning); int SN76496_init(int clock,int sample_rate); #endif diff --git a/pico/sound/sound.c b/pico/sound/sound.c index 5d7fac630..edf9c8960 100644 --- a/pico/sound/sound.c +++ b/pico/sound/sound.c @@ -15,7 +15,7 @@ #include "resampler.h" #include "mix.h" -void (*PsndMix_32_to_16l)(s16 *dest, s32 *src, int count) = mix_32_to_16l_stereo; +void (*PsndMix_32_to_16)(s16 *dest, s32 *src, int count) = mix_32_to_16_stereo; // master int buffer to mix to // +1 for a fill triggered by an instruction overhanging into the next scanline @@ -228,7 +228,7 @@ void PsndRerate(int preserve_state) PsndClear(); // set mixer - PsndMix_32_to_16l = (PicoIn.opt & POPT_EN_STEREO) ? mix_32_to_16l_stereo : mix_32_to_16_mono; + PsndMix_32_to_16 = (PicoIn.opt & POPT_EN_STEREO) ? mix_32_to_16_stereo : mix_32_to_16_mono; mix_reset(PicoIn.opt & POPT_EN_SNDFILTER ? PicoIn.sndFilterAlpha : 0); if (PicoIn.AHW & PAHW_PICO) @@ -275,8 +275,8 @@ PICO_INTERNAL void PsndDoDAC(int cyc_to) if (PicoIn.opt & POPT_EN_STEREO) { s16 *d = PicoIn.sndOut + pos*2; // left channel only, mixed ro right channel in mixing phase - *d++ += Pico.snd.dac_val2; d++; - while (--len) *d++ += Pico.snd.dac_val, d++; + *d++ += Pico.snd.dac_val2, *d++ += Pico.snd.dac_val2; + while (--len) *d++ += Pico.snd.dac_val, *d++ += Pico.snd.dac_val; } else { s16 *d = PicoIn.sndOut + pos; *d++ += Pico.snd.dac_val2; @@ -345,10 +345,15 @@ PICO_INTERNAL void PsndDoSMSFM(int cyc_to) if (Pico.m.hardware & PMS_HW_FMUSED) { buf += pos; PsndFMUpdate(buf32, len, 0, 0); - while (len--) { - *buf++ += *buf32++; - buf += stereo; - } + if (stereo) + while (len--) { + *buf++ += *buf32; + *buf++ += *buf32++; + } + else + while (len--) { + *buf++ += *buf32++; + } } } @@ -506,10 +511,10 @@ static int PsndRender(int offset, int length) s16 *dacbuf = PicoIn.sndOut + (daclen << stereo); Pico.snd.dac_pos += (length-daclen) << 20; *dacbuf++ += Pico.snd.dac_val2; - if (stereo) dacbuf++; + if (stereo) *dacbuf++ += Pico.snd.dac_val2; for (daclen++; length-daclen > 0; daclen++) { *dacbuf++ += Pico.snd.dac_val; - if (stereo) dacbuf++; + if (stereo) *dacbuf++ += Pico.snd.dac_val; } Pico.snd.dac_val2 = Pico.snd.dac_val; } @@ -544,7 +549,7 @@ static int PsndRender(int offset, int length) // convert + limit to normal 16bit output if (PicoIn.sndOut) - PsndMix_32_to_16l(PicoIn.sndOut+(offset< 0; i--, p+=2) - *(p + 1) = *p; - } - pprof_end(sound); return length; diff --git a/platform/gp2x/emu.c b/platform/gp2x/emu.c index 6bc96df78..d59f3ecae 100644 --- a/platform/gp2x/emu.c +++ b/platform/gp2x/emu.c @@ -753,10 +753,10 @@ void plat_update_volume(int has_changed, int is_up) /* set the right mixer func */ if (vol >= 5) - PsndMix_32_to_16l = mix_32_to_16l_stereo; + PsndMix_32_to_16 = mix_32_to_16_stereo; else { - mix_32_to_16l_level = 5 - vol; - PsndMix_32_to_16l = mix_32_to_16l_stereo_lvl; + mix_32_to_16_level = 5 - vol; + PsndMix_32_to_16 = mix_32_to_16_stereo_lvl; } }