core, implement GG stereo
authorkub <derkub@gmail.com>
Sun, 21 Jan 2024 20:41:31 +0000 (21:41 +0100)
committerkub <derkub@gmail.com>
Tue, 23 Jan 2024 21:21:15 +0000 (22:21 +0100)
pico/pico.h
pico/sms.c
pico/sound/mix.c
pico/sound/mix.h
pico/sound/mix_arm.S
pico/sound/sn76496.c
pico/sound/sn76496.h
pico/sound/sound.c
platform/gp2x/emu.c

index e91cad2..2db502d 100644 (file)
@@ -267,7 +267,7 @@ void Pico32xSetClocks(int msh2_hz, int ssh2_hz);
 #define PICO_SSH2_HZ ((int)(7670442.0 * 2.4))\r
 \r
 // sound.c\r
-extern void (*PsndMix_32_to_16l)(s16 *dest, s32 *src, int count);\r
+extern void (*PsndMix_32_to_16)(s16 *dest, s32 *src, int count);\r
 void PsndRerate(int preserve_state);\r
 \r
 // media.c\r
index 398a4da..615ba36 100644 (file)
@@ -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
index 8f75ef0..1c79b48 100644 (file)
@@ -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)
index 3aa3ee8..43fb52a 100644 (file)
@@ -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);
index f051b38..dc9e980 100644 (file)
@@ -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}
index 3bb5cf7..0837839 100644 (file)
@@ -56,7 +56,7 @@ struct SN76496
        int Period[4];\r
        int Count[4];\r
        int Output[4];\r
-       int pad[1];\r
+       int Panning;\r
 };\r
 \r
 static struct SN76496 ono_sn; // one and only SN76496\r
@@ -135,7 +135,6 @@ void SN76496Update(short *buffer, int length, int stereo)
        while (length > 0)\r
        {\r
                int vol[4];\r
-               unsigned int out;\r
                int left;\r
 \r
 \r
@@ -203,19 +202,43 @@ void SN76496Update(short *buffer, int length, int stereo)
                } while (left > 0 && R->Volume[3]);\r
                if (R->Output[3]) vol[3] -= R->Count[3];\r
 \r
-               out = vol[0] * R->Volume[0] + vol[1] * R->Volume[1] +\r
+               length--;\r
+               if (R->Panning == 0xff || !stereo) {\r
+                       unsigned int out =\r
+                               vol[0] * R->Volume[0] + vol[1] * R->Volume[1] +\r
                                vol[2] * R->Volume[2] + vol[3] * R->Volume[3];\r
 \r
-               if (out > MAX_OUTPUT * STEP) out = MAX_OUTPUT * STEP;\r
-\r
-               out /= STEP; // will be optimized to shift; max 0x4800 = 18432\r
-               *buffer++ += out;\r
-               if (stereo) *buffer++ += out;\r
-\r
-               length--;\r
+                       if (out > MAX_OUTPUT * STEP) out = MAX_OUTPUT * STEP;\r
+\r
+                       out /= STEP; // will be optimized to shift; max 0x4800 = 18432\r
+                       *buffer++ += out;\r
+                       if (stereo) *buffer++ += out;\r
+               } else {\r
+#define P(n) !!(R->Panning & (1<<(n)))\r
+                       unsigned int outl =\r
+                               vol[0] * R->Volume[0] * P(4) + vol[1] * R->Volume[1] * P(5) +\r
+                               vol[2] * R->Volume[2] * P(6) + vol[3] * R->Volume[3] * P(7);\r
+                       unsigned int outr =\r
+                               vol[0] * R->Volume[0] * P(0) + vol[1] * R->Volume[1] * P(1) +\r
+                               vol[2] * R->Volume[2] * P(2) + vol[3] * R->Volume[3] * P(3);\r
+#undef P\r
+                       if (outl > MAX_OUTPUT * STEP) outl = MAX_OUTPUT * STEP;\r
+                       if (outr > MAX_OUTPUT * STEP) outr = MAX_OUTPUT * STEP;\r
+\r
+                       outl /= STEP; // will be optimized to shift; max 0x4800 = 18432\r
+                       outr /= STEP; // will be optimized to shift; max 0x4800 = 18432\r
+                       *buffer++ += outl;\r
+                       *buffer++ += outr;\r
+               }\r
        }\r
 }\r
 \r
+void SN76496Config(int panning)\r
+{\r
+       struct SN76496 *R = &ono_sn;\r
+       R->Panning = panning & 0xff;\r
+}\r
+\r
 \r
 static void SN76496_set_clock(struct SN76496 *R,int clock)\r
 {\r
@@ -286,6 +309,7 @@ int SN76496_init(int clock,int sample_rate)
 \r
        // added\r
        SN76496_set_gain(R, 0);\r
+       R->Panning = 0xff;\r
 \r
        return 0;\r
 }\r
index e0de6ed..707bb5d 100644 (file)
@@ -3,6 +3,7 @@
 \r
 void SN76496Write(int data);\r
 void SN76496Update(short *buffer,int length,int stereo);\r
+void SN76496Config(int panning);\r
 int  SN76496_init(int clock,int sample_rate);\r
 \r
 #endif\r
index 5d7fac6..edf9c89 100644 (file)
@@ -15,7 +15,7 @@
 #include "resampler.h"\r
 #include "mix.h"\r
 \r
-void (*PsndMix_32_to_16l)(s16 *dest, s32 *src, int count) = mix_32_to_16l_stereo;\r
+void (*PsndMix_32_to_16)(s16 *dest, s32 *src, int count) = mix_32_to_16_stereo;\r
 \r
 // master int buffer to mix to\r
 // +1 for a fill triggered by an instruction overhanging into the next scanline\r
@@ -228,7 +228,7 @@ void PsndRerate(int preserve_state)
     PsndClear();\r
 \r
   // set mixer\r
-  PsndMix_32_to_16l = (PicoIn.opt & POPT_EN_STEREO) ? mix_32_to_16l_stereo : mix_32_to_16_mono;\r
+  PsndMix_32_to_16 = (PicoIn.opt & POPT_EN_STEREO) ? mix_32_to_16_stereo : mix_32_to_16_mono;\r
   mix_reset(PicoIn.opt & POPT_EN_SNDFILTER ? PicoIn.sndFilterAlpha : 0);\r
 \r
   if (PicoIn.AHW & PAHW_PICO)\r
@@ -275,8 +275,8 @@ PICO_INTERNAL void PsndDoDAC(int cyc_to)
   if (PicoIn.opt & POPT_EN_STEREO) {\r
     s16 *d = PicoIn.sndOut + pos*2;\r
     // left channel only, mixed ro right channel in mixing phase\r
-    *d++ += Pico.snd.dac_val2; d++;\r
-    while (--len) *d++ += Pico.snd.dac_val, d++;\r
+    *d++ += Pico.snd.dac_val2, *d++ += Pico.snd.dac_val2;\r
+    while (--len) *d++ += Pico.snd.dac_val, *d++ += Pico.snd.dac_val;\r
   } else {\r
     s16 *d = PicoIn.sndOut + pos;\r
     *d++ += Pico.snd.dac_val2;\r
@@ -345,10 +345,15 @@ PICO_INTERNAL void PsndDoSMSFM(int cyc_to)
   if (Pico.m.hardware & PMS_HW_FMUSED) {\r
     buf += pos;\r
     PsndFMUpdate(buf32, len, 0, 0);\r
-    while (len--) {\r
-      *buf++ += *buf32++;\r
-      buf += stereo;\r
-    }\r
+    if (stereo) \r
+      while (len--) {\r
+        *buf++ += *buf32;\r
+        *buf++ += *buf32++;\r
+      }\r
+    else\r
+      while (len--) {\r
+        *buf++ += *buf32++;\r
+      }\r
   }\r
 }\r
 \r
@@ -506,10 +511,10 @@ static int PsndRender(int offset, int length)
     s16 *dacbuf = PicoIn.sndOut + (daclen << stereo);\r
     Pico.snd.dac_pos += (length-daclen) << 20;\r
     *dacbuf++ += Pico.snd.dac_val2;\r
-    if (stereo) dacbuf++;\r
+    if (stereo) *dacbuf++ += Pico.snd.dac_val2;\r
     for (daclen++; length-daclen > 0; daclen++) {\r
       *dacbuf++ += Pico.snd.dac_val;\r
-      if (stereo) dacbuf++;\r
+      if (stereo) *dacbuf++ += Pico.snd.dac_val;\r
     }\r
     Pico.snd.dac_val2 = Pico.snd.dac_val;\r
   }\r
@@ -544,7 +549,7 @@ static int PsndRender(int offset, int length)
 \r
   // convert + limit to normal 16bit output\r
   if (PicoIn.sndOut)\r
-    PsndMix_32_to_16l(PicoIn.sndOut+(offset<<stereo), buf32, length-offset);\r
+    PsndMix_32_to_16(PicoIn.sndOut+(offset<<stereo), buf32, length-offset);\r
 \r
   pprof_end(sound);\r
 \r
@@ -589,21 +594,18 @@ static int PsndRenderMS(int offset, int length)
     int len = (length-ym2413len);\r
     if (Pico.m.hardware & PMS_HW_FMUSED) {\r
       PsndFMUpdate(buf32, len, 0, 0);\r
-      while (len--) {\r
-        *ym2413buf++ += *buf32++;\r
-        ym2413buf += stereo;\r
-      }\r
+      if (stereo)\r
+        while (len--) {\r
+          *ym2413buf++ += *buf32;\r
+          *ym2413buf++ += *buf32++;\r
+        }\r
+      else\r
+        while (len--) {\r
+          *ym2413buf++ += *buf32++;\r
+        }\r
     }\r
   }\r
 \r
-  // upmix to "stereo" if needed\r
-  if (PicoIn.opt & POPT_EN_STEREO) {\r
-    int i;\r
-    s16 *p;\r
-    for (i = length, p = (s16 *)PicoIn.sndOut; i > 0; i--, p+=2)\r
-      *(p + 1) = *p;\r
-  }\r
-\r
   pprof_end(sound);\r
 \r
   return length;\r
index 6bc96df..d59f3ec 100644 (file)
@@ -753,10 +753,10 @@ void plat_update_volume(int has_changed, int is_up)
 \r
        /* set the right mixer func */\r
        if (vol >= 5)\r
-               PsndMix_32_to_16l = mix_32_to_16l_stereo;\r
+               PsndMix_32_to_16 = mix_32_to_16_stereo;\r
        else {\r
-               mix_32_to_16l_level = 5 - vol;\r
-               PsndMix_32_to_16l = mix_32_to_16l_stereo_lvl;\r
+               mix_32_to_16_level = 5 - vol;\r
+               PsndMix_32_to_16 = mix_32_to_16_stereo_lvl;\r
        }\r
 }\r
 \r