sound, fix ym2612 ladder effect, add option
authorkub <derkub@gmail.com>
Fri, 19 Nov 2021 20:01:50 +0000 (21:01 +0100)
committerkub <derkub@gmail.com>
Fri, 19 Nov 2021 20:01:50 +0000 (21:01 +0100)
pico/pico.h
pico/sound/sound.c
pico/sound/ym2612.c
pico/sound/ym2612.h
pico/sound/ym2612_arm.S
platform/common/menu_pico.c
platform/common/menu_pico.h
platform/libretro/libretro.c
platform/libretro/libretro_core_options.h

index f474d56..5102107 100644 (file)
@@ -75,7 +75,7 @@ extern void *p32x_bios_g, *p32x_bios_m, *p32x_bios_s;
 #define POPT_EN_PWM         (1<<21)\r
 #define POPT_PWM_IRQ_OPT    (1<<22)\r
 #define POPT_DIS_FM_SSGEG   (1<<23)\r
-#define POPT_EN_FM_LADDER   (1<<24) //x00 0000\r
+#define POPT_EN_FM_DAC      (1<<24) //x00 0000\r
 \r
 #define PAHW_MCD  (1<<0)\r
 #define PAHW_32X  (1<<1)\r
index ac79a84..083c642 100644 (file)
@@ -69,7 +69,7 @@ void PsndRerate(int preserve_state)
   }\r
   YM2612Init(Pico.m.pal ? OSC_PAL/7 : OSC_NTSC/7, PicoIn.sndRate,\r
         ((PicoIn.opt&POPT_DIS_FM_SSGEG) ? 0 : ST_SSG) |\r
-        ((PicoIn.opt&POPT_EN_FM_LADDER) ? ST_LADDER : 0));\r
+        ((PicoIn.opt&POPT_EN_FM_DAC)    ? ST_DAC : 0));\r
   if (preserve_state) {\r
     // feed it back it's own registers, just like after loading state\r
     memcpy(YM2612GetRegs(), state, 0x204);\r
index 502326e..a10e678 100644 (file)
@@ -922,7 +922,8 @@ typedef struct
 static int clip(int n) \r
 {\r
     unsigned b = 14, s = n < 0;\r
-    if (s + (n>>(b-1))) n = (int)(s + INT_MAX) >> (8*sizeof(int)-b);\r
+    int m = s + INT_MAX;\r
+    if (s + (n>>(b-1))) n = m >> (8*sizeof(int)-b);\r
     return n;\r
 }\r
 \r
@@ -1234,7 +1235,11 @@ static void chan_render_loop(chan_rend_context *ct, int *buffer, int length)
 \r
                /* mix sample to output buffer */\r
                if (smp) {\r
-                       smp = clip(smp);  /* saturate to 14 bit */\r
+                       smp = clip(smp); /* saturate to 14 bit */\r
+                       if (ct->algo & 0x80) {\r
+                               smp &= ~0x1f; /* drop bits (DAC has 9 bits) */\r
+                               smp -= (smp < 0 ? 7:0) << 5; /* discontinuity */\r
+                       }\r
                        if (ct->pack & 1) { /* stereo */\r
                                if (ct->pack & 0x20) /* L */ /* TODO: check correctness */\r
                                        buffer[scounter*2] += smp;\r
@@ -1271,15 +1276,6 @@ static void chan_render_finish(int *buffer, unsigned short length, int active_ch
        ym2612.OPN.eg_timer = crct.eg_timer;\r
        g_lfo_ampm = crct.pack >> 16; // need_save\r
        ym2612.OPN.lfo_cnt = crct.lfo_cnt;\r
-\r
-       /* apply ladder effect. NB only works if buffer was empty beforehand! */\r
-       if (active_chans && (ym2612.OPN.ST.flags & ST_LADDER)) {\r
-               length <<= crct.pack & 1;\r
-               while (length--) {\r
-                       *buffer -= (*buffer < 0)*4 << 5;\r
-                       buffer++;\r
-               }\r
-       }\r
 }\r
 \r
 static UINT32 update_lfo_phase(FM_SLOT *SLOT, UINT32 block_fnum)\r
@@ -1339,6 +1335,8 @@ static int chan_render(int *buffer, int length, int c, UINT32 flags) // flags: s
 \r
        crct.op1_out = crct.CH->op1_out;\r
        crct.algo = crct.CH->ALGO & 7;\r
+       if (ym2612.OPN.ST.flags & ST_DAC)\r
+               crct.algo |= 0x80;\r
 \r
        if(crct.CH->pms && (ym2612.OPN.ST.mode & 0xC0) && c == 2) {\r
                /* 3 slot mode */\r
index 9b7fff4..9d0f19a 100644 (file)
@@ -109,7 +109,7 @@ typedef struct
 } FM_ST;\r
 \r
 #define ST_SSG         1\r
-#define ST_LADDER      2\r
+#define ST_DAC         2\r
 \r
 /***********************************************************/\r
 /* OPN unit                                                */\r
index 5cb42f2..bb74833 100644 (file)
 
 
 @ lr=context, r12=pack (stereo, ssg_enabled, 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[3],ssg_update,was_update,algo[3], r5=tl_tab/slot,
+@ r0-r2=scratch, r3=sin_tab/scratch, r4=(length<<8)|dac,unused[2],ssg_update,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
 .global chan_render_loop @ chan_rend_context *ct, int *buffer, int length
 
@@ -688,8 +688,8 @@ chan_render_loop:
     ldr     r12, [lr, #0x4c]
     ldr     r0,  [lr, #0x50]
     mov     r11, r1
-    and     r0,  r0, #7
-    orr     r4,  r4, r0          @ (length<<8)|algo
+    and     r0,  r0, #0x87
+    orr     r4,  r4, r0          @ (length<<8)|dac,unused[4],algo[3]
     ldr     r8, [lr, #0x44]      @ eg_timer
     ldr     r9, [lr, #0x48]      @ eg_timer_add
     ldr     r10, [lr, #0x54]     @ op1_out
@@ -925,9 +925,12 @@ crl_algo_done:
     beq     ctl_sample_skip
     orr     r4, r4, #8              @ have_output
     lsr     r1, r0, #31             @ clip (saturate) sample to 14 bit
-    adds    r2, r1, r0, asr #13
+    cmn     r1, r0, asr #13
     subne   r0, r1, #0x80000001
     asrne   r0, r0, #18
+    tst     r4, r1, lsl #7          @ (sample < 0) && dac?
+    bicne   r0, r0, #0x1f
+    subne   r0, r0, #7<<5
     tst     r12, #1
     beq     ctl_sample_mono
 
index b5b4453..1151ad4 100644 (file)
@@ -561,7 +561,7 @@ static menu_entry e_menu_adv_options[] =
        mee_onoff     ("Emulate Z80",              MA_OPT2_ENABLE_Z80,    PicoIn.opt, POPT_EN_Z80),
        mee_onoff     ("Emulate YM2612 (FM)",      MA_OPT2_ENABLE_YM2612, PicoIn.opt, POPT_EN_FM),
        mee_onoff     ("Disable YM2612 SSG-EG",    MA_OPT2_DISABLE_YM_SSG,PicoIn.opt, POPT_DIS_FM_SSGEG),
-       mee_onoff     ("Enable YM2612 ladder effect",MA_OPT2_DISABLE_YM_LAD,PicoIn.opt, POPT_EN_FM_LADDER),
+       mee_onoff     ("Enable YM2612 DAC noise",  MA_OPT2_ENABLE_YM_DAC, PicoIn.opt, POPT_EN_FM_DAC),
        mee_onoff     ("Emulate SN76496 (PSG)",    MA_OPT2_ENABLE_SN76496,PicoIn.opt, POPT_EN_PSG),
        mee_onoff     ("Emulate Game Gear LCD",    MA_OPT2_ENABLE_GGLCD  ,PicoIn.opt, POPT_EN_GG_LCD),
        mee_onoff     ("Disable idle loop patching",MA_OPT2_NO_IDLE_LOOPS,PicoIn.opt, POPT_DIS_IDLE_DET),
index 5b1800d..0c81563 100644 (file)
@@ -50,7 +50,7 @@ typedef enum
        MA_OPT2_ENABLE_Z80,
        MA_OPT2_ENABLE_YM2612,
        MA_OPT2_DISABLE_YM_SSG,
-       MA_OPT2_DISABLE_YM_LAD,
+       MA_OPT2_ENABLE_YM_DAC,
        MA_OPT2_ENABLE_SN76496,
        MA_OPT2_ENABLE_YM2413,
        MA_OPT2_ENABLE_GGLCD,
index f82dcbe..1e15a2a 100644 (file)
@@ -1594,6 +1594,15 @@ static void update_variables(bool first_run)
       PicoIn.opt &= ~POPT_EN_DRC;
 #endif
 
+   var.value = NULL;
+   var.key = "picodrive_dacnoise";
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) {
+      if (strcmp(var.value, "enabled") == 0)
+         PicoIn.opt |= POPT_EN_FM_DAC;
+      else
+         PicoIn.opt &= ~POPT_EN_FM_DAC;
+   }
+
    old_snd_filter = PicoIn.opt & POPT_EN_SNDFILTER;
    var.value = NULL;
    var.key = "picodrive_audio_filter";
index 55ef834..07e8b72 100644 (file)
@@ -64,7 +64,7 @@ struct retro_core_option_v2_category option_cats_us[] = {
    {
       "audio",
       "Audio",
-      "Configure sample rate / emulated audio devices / low pass filter."
+      "Configure sample rate / emulated audio devices / low pass filter / DAC noise."
    },
    {
       "input",
@@ -231,11 +231,25 @@ struct retro_core_option_v2_definition option_defs_us[] = {
       },
       "off"
    },
+   {
+      "picodrive_dacnoise",
+      "Mega Drive FM DAC noise",
+      NULL,
+      "Enable emulation of YM2612 DAC noise. This option generates a distortion which existed on most Model 1 Mega Drive/Genesis, but not on newer models.",
+      NULL,
+      "audio",
+      {
+         { "off", "disabled" },
+         { "on",  "enabled" },
+         { NULL, NULL },
+      },
+      "off"
+   },
    {
       "picodrive_audio_filter",
       "Audio Filter",
       NULL,
-      "Enable a low pass audio filter to better simulate the characteristic sound of a Model 1 Genesis. This option is ignored when running Master System and PICO titles. Only the Genesis and its add-on hardware (Sega CD, 32X) employed a physical low pass filter.",
+      "Enable a low pass audio filter to better simulate the characteristic sound of a Model 1 Mega Drive/Genesis. Note that although only the Genesis and its add-on hardware (Sega CD, 32X) employed a physical low pass filter, the filter setting is not restricted to that.",
       NULL,
       "audio",
       {