shithub: psxe

Download patch

ref: 23f12a941b9d8e82951288842302344ecba9ace8
parent: c48f128074614094e15b019389c8efb7cbc14ad1
author: allkern <lisandroaalarcon@gmail.com>
date: Sun Oct 1 08:50:55 EDT 2023

Initial ADSR implementation

--- a/psx/dev/spu.c
+++ b/psx/dev/spu.c
@@ -6,6 +6,7 @@
 #include "../log.h"
 
 #define CLAMP(v, l, h) ((v <= l) ? l : ((v >= h) ? h : v))
+#define MAX(a, b) (a > b ? a : b)
 
 static const int g_spu_pos_adpcm_table[] = {
     0, +60, +115, +98, +122
@@ -145,6 +146,168 @@
     }
 }
 
+#define PHASE spu->data[v].adsr_phase
+#define CYCLES spu->data[v].adsr_cycles
+#define EXPONENTIAL spu->data[v].adsr_mode
+#define DECREASE spu->data[v].adsr_dir
+#define SHIFT spu->data[v].adsr_shift
+#define STEP spu->data[v].adsr_step
+#define LEVEL_STEP spu->data[v].adsr_pending_step
+#define LEVEL spu->voice[v].envcvol
+
+/*
+  ____lower 16bit (at 1F801C08h+N*10h)___________________________________
+  15    Attack Mode       (0=Linear, 1=Exponential)
+  -     Attack Direction  (Fixed, always Increase) (until Level 7FFFh)
+  14-10 Attack Shift      (0..1Fh = Fast..Slow)
+  9-8   Attack Step       (0..3 = "+7,+6,+5,+4")
+  -     Decay Mode        (Fixed, always Exponential)
+  -     Decay Direction   (Fixed, always Decrease) (until Sustain Level)
+  7-4   Decay Shift       (0..0Fh = Fast..Slow)
+  -     Decay Step        (Fixed, always "-8")
+  3-0   Sustain Level     (0..0Fh)  ;Level=(N+1)*800h
+  ____upper 16bit (at 1F801C0Ah+N*10h)___________________________________
+  31    Sustain Mode      (0=Linear, 1=Exponential)
+  30    Sustain Direction (0=Increase, 1=Decrease) (until Key OFF flag)
+  29    Not used?         (should be zero)
+  28-24 Sustain Shift     (0..1Fh = Fast..Slow)
+  23-22 Sustain Step      (0..3 = "+7,+6,+5,+4" or "-8,-7,-6,-5") (inc/dec)
+  21    Release Mode      (0=Linear, 1=Exponential)
+  -     Release Direction (Fixed, always Decrease) (until Level 0000h)
+  20-16 Release Shift     (0..1Fh = Fast..Slow)
+  -     Release Step      (Fixed, always "-8")
+*/
+
+void spu_advance_adsr(psx_spu_t* spu, int v) {
+    switch (spu->data[v].adsr_phase) {
+        // KON->Attack
+        case 0: {
+            EXPONENTIAL = spu->voice[v].envctl1 >> 15;
+            DECREASE    = 0;
+            SHIFT       = (spu->voice[v].envctl1 >> 10) & 0x1f;
+            STEP        = 7 - ((spu->voice[v].envctl1 >> 8) & 3);
+            LEVEL       = 0;
+
+            log_fatal("        voice %u KON->Attack e=%u d=%u sh=%u st=%u, l=%04x",
+                v,
+                EXPONENTIAL,
+                DECREASE,
+                SHIFT,
+                STEP,
+                LEVEL
+            );
+        } break;
+
+        // Attack->Decay
+        case 1: {
+            EXPONENTIAL = 1;
+            DECREASE    = 1;
+            SHIFT       = (spu->voice[v].envctl1 >> 4) & 0xf;
+            STEP        = -8;
+            LEVEL       = 0x7fff;
+
+            log_fatal("        voice %u Attack->Decay e=%u d=%u sh=%u st=%u, l=%04x",
+                v,
+                EXPONENTIAL,
+                DECREASE,
+                SHIFT,
+                STEP,
+                LEVEL
+            );
+        } break;
+
+        // Decay->Sustain
+        case 2: {
+            EXPONENTIAL = spu->voice[v].envctl2 >> 15;
+            DECREASE    = (spu->voice[v].envctl2 >> 14) & 1;
+            SHIFT       = (spu->voice[v].envctl2 >> 8) & 0x1f;
+            STEP        = (spu->voice[v].envctl2 >> 6) & 3;
+            LEVEL       = spu->data[v].adsr_sustain_level;
+
+            STEP = DECREASE ? (-8 + STEP) : (7 - STEP);
+
+            log_fatal("        voice %u Decay->Sustain e=%u d=%u sh=%u st=%u, l=%04x",
+                v,
+                EXPONENTIAL,
+                DECREASE,
+                SHIFT,
+                STEP,
+                LEVEL
+            );
+        } break;
+
+        // Sustain->Release
+        case 3: {
+            EXPONENTIAL = (spu->voice[v].envctl2 >> 5) & 1;
+            DECREASE    = 1;
+            SHIFT       = spu->voice[v].envctl2 & 0x1f;
+            STEP        = -8;
+            //LEVEL       = spu->data[v].adsr_sustain_level;
+
+            log_fatal("        voice %u Sustain->Release e=%u d=%u sh=%u st=%u, l=%04x",
+                v,
+                EXPONENTIAL,
+                DECREASE,
+                SHIFT,
+                STEP,
+                LEVEL
+            );
+        } break;
+    }
+
+    CYCLES = 1 << MAX(0, SHIFT - 11);
+    LEVEL_STEP = STEP << MAX(0, 11 - SHIFT);
+
+    if (EXPONENTIAL && (LEVEL > 0x6000) && !DECREASE)
+        CYCLES *= 4;
+    
+    if (EXPONENTIAL && DECREASE)
+        STEP *= LEVEL / 0x8000;
+}
+
+void spu_handle_adsr(psx_spu_t* spu, int v) {
+    LEVEL += LEVEL_STEP;
+
+    switch (spu->data[v].adsr_phase) {
+        case 0: {
+            LEVEL = CLAMP(LEVEL, 0x0000, 0x7fff);
+
+            if (LEVEL == 0x7fff) {
+                spu->data[v].adsr_phase = 1;
+
+                spu_advance_adsr(spu, v);
+            }
+        } break;
+
+        case 1: {
+            LEVEL = CLAMP(LEVEL, 0x0000, 0x7fff);
+
+            if (LEVEL >= spu->data[v].adsr_sustain_level) {
+                spu->data[v].adsr_phase = 2;
+
+                spu_advance_adsr(spu, v);
+            }
+        } break;
+
+        case 3: {
+            LEVEL = CLAMP(LEVEL, 0x0000, 0x7fff);
+
+            if (!LEVEL) {
+                spu->data[v].adsr_phase = 0;
+                spu->data[v].playing = 0;
+            }
+        } break;
+    }
+}
+
+#undef PHASE
+#undef CYCLES
+#undef MODE
+#undef DIR
+#undef SHIFT
+#undef STEP
+#undef PENDING_STEP
+
 int spu_handle_write(psx_spu_t* spu, uint32_t offset, uint32_t value) {
     switch (offset) {
         case SPUR_KON: {
@@ -160,16 +323,22 @@
                     spu->data[i].repeat_addr = spu->data[i].current_addr;
                     spu->data[i].lvol = (float)(spu->voice[i].volumel << 1) / (float)0x7fff;
                     spu->data[i].rvol = (float)(spu->voice[i].volumer << 1) / (float)0x7fff;
+                    spu->data[i].adsr_sustain_level = ((spu->voice[i].envctl1 & 0xf) + 1) * 0x800;
+                    spu->data[i].adsr_phase = 0;
 
-                    log_fatal("    voice %2u s=%06x r=%06x p=%04x vol=%f,%f",
+                    log_fatal("    voice %2u s=%06x r=%06x p=%04x vol=%f,%f adsr=%04x,%04x cvol=%04x",
                         i,
                         spu->voice[i].adsaddr << 3,
                         spu->voice[i].adraddr << 3,
                         spu->voice[i].adsampr,
                         spu->data[i].lvol,
-                        spu->data[i].rvol
+                        spu->data[i].rvol,
+                        spu->voice[i].envctl1,
+                        spu->voice[i].envctl2,
+                        spu->voice[i].envcvol
                     );
 
+                    spu_advance_adsr(spu, i);
                     spu_read_block(spu, i);
                 }
             }
@@ -183,8 +352,10 @@
             log_fatal("KOFF %04x:", value);
             for (int i = 0; i < 24; i++) {
                 if ((value & (1 << i))) {
-                    spu->data[i].playing = 0;
+                    spu->data[i].adsr_phase = 3;
 
+                    spu_advance_adsr(spu, i);
+
                     log_fatal("    voice %2u",
                         i,
                         spu->voice[i].adsaddr << 3,
@@ -295,6 +466,11 @@
     int right = 0x0000;
 
     for (int v = 0; v < 24; v++) {
+        --spu->data[v].adsr_cycles;
+
+        if (!spu->data[v].adsr_cycles)
+            spu_handle_adsr(spu, v);
+
         if (!spu->data[v].playing)
             continue;
         
--- a/psx/dev/spu.h
+++ b/psx/dev/spu.h
@@ -115,6 +115,38 @@
         int16_t h[2];
         float lvol;
         float rvol;
+
+        /*
+        ____lower 16bit (at 1F801C08h+N*10h)___________________________________
+        15    Attack Mode       (0=Linear, 1=Exponential)
+        -     Attack Direction  (Fixed, always Increase) (until Level 7FFFh)
+        14-10 Attack Shift      (0..1Fh = Fast..Slow)
+        9-8   Attack Step       (0..3 = "+7,+6,+5,+4")
+        -     Decay Mode        (Fixed, always Exponential)
+        -     Decay Direction   (Fixed, always Decrease) (until Sustain Level)
+        7-4   Decay Shift       (0..0Fh = Fast..Slow)
+        -     Decay Step        (Fixed, always "-8")
+        3-0   Sustain Level     (0..0Fh)  ;Level=(N+1)*800h
+        ____upper 16bit (at 1F801C0Ah+N*10h)___________________________________
+        31    Sustain Mode      (0=Linear, 1=Exponential)
+        30    Sustain Direction (0=Increase, 1=Decrease) (until Key OFF flag)
+        29    Not used?         (should be zero)
+        28-24 Sustain Shift     (0..1Fh = Fast..Slow)
+        23-22 Sustain Step      (0..3 = "+7,+6,+5,+4" or "-8,-7,-6,-5") (inc/dec)
+        21    Release Mode      (0=Linear, 1=Exponential)
+        -     Release Direction (Fixed, always Decrease) (until Level 0000h)
+        20-16 Release Shift     (0..1Fh = Fast..Slow)
+        -     Release Step      (Fixed, always "-8")
+        */
+
+        int adsr_phase;
+        int adsr_cycles;
+        int adsr_mode;
+        int adsr_dir;
+        int adsr_shift;
+        int adsr_step;
+        int adsr_pending_step;
+        int adsr_sustain_level;
     } data[24];
 } psx_spu_t;
 
--