shithub: psxe

Download patch

ref: 333b95a4bd31ca40541e4b6f76f94628042b6bc4
parent: 9857397eae26af09d2e85fb6b5af04121d149bdb
author: allkern <lisandroaalarcon@gmail.com>
date: Tue Oct 10 19:55:51 EDT 2023

Implement ADSRs and fix CVOL bug

Start working on reverb

--- a/psx/dev/spu.c
+++ b/psx/dev/spu.c
@@ -6,8 +6,10 @@
 #include "../log.h"
 
 #define CLAMP(v, l, h) ((v <= l) ? l : ((v >= h) ? h : v))
-#define MAX(a, b) (a > b ? a : b)
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
 
+#define VOICE_COUNT 24
+
 static const int g_spu_pos_adpcm_table[] = {
     0, +60, +115, +98, +122
 };
@@ -153,7 +155,7 @@
 #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
+#define LEVEL spu->data[v].cvol
 
 /*
   ____lower 16bit (at 1F801C08h+N*10h)___________________________________
@@ -178,47 +180,15 @@
   -     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;
-        } break;
+enum {
+    ADSR_ATTACK,
+    ADSR_DECAY,
+    ADSR_SUSTAIN,
+    ADSR_RELEASE,
+    ADSR_END
+};
 
-        // Attack->Decay
-        case 1: {
-            EXPONENTIAL = 1;
-            DECREASE    = 1;
-            SHIFT       = (spu->voice[v].envctl1 >> 4) & 0xf;
-            STEP        = -8;
-            LEVEL       = 0x7fff;
-        } 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);
-        } 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;
-        } break;
-    }
-
+void adsr_calculate_values(psx_spu_t* spu, int v) {
     CYCLES = 1 << MAX(0, SHIFT - 11);
     LEVEL_STEP = STEP << MAX(0, 11 - SHIFT);
 
@@ -226,50 +196,105 @@
         CYCLES *= 4;
     
     if (EXPONENTIAL && DECREASE)
-        LEVEL_STEP *= LEVEL / 0x8000;
+        LEVEL_STEP = (LEVEL_STEP * LEVEL) >> 15;
     
     spu->data[v].adsr_cycles_reload = CYCLES;
-    
-    log_fatal("voice %u ADSR advance %u c=%u, s=%04x, step=%04x, level=%04x",
-        v, spu->data[v].adsr_phase, CYCLES, LEVEL_STEP, STEP, LEVEL
-    );
 }
 
+void adsr_load_attack(psx_spu_t* spu, int v) {
+    EXPONENTIAL = spu->data[v].envctl >> 15;
+    DECREASE    = 0;
+    SHIFT       = (spu->data[v].envctl >> 10) & 0x1f;
+    STEP        = 7 - ((spu->data[v].envctl >> 8) & 3);
+    LEVEL       = 0;
+    PHASE       = ADSR_ATTACK;
+
+    adsr_calculate_values(spu, v);
+}
+
+void adsr_load_decay(psx_spu_t* spu, int v) {
+    EXPONENTIAL = 1;
+    DECREASE    = 1;
+    SHIFT       = (spu->data[v].envctl >> 4) & 0xf;
+    STEP        = -8;
+    LEVEL       = 0x7fff;
+    PHASE       = ADSR_DECAY;
+
+    adsr_calculate_values(spu, v);
+}
+
+void adsr_load_sustain(psx_spu_t* spu, int v) {
+    EXPONENTIAL = spu->data[v].envctl >> 31;
+    DECREASE    = (spu->data[v].envctl >> 30) & 1;
+    SHIFT       = (spu->data[v].envctl >> 24) & 0x1f;
+    STEP        = (spu->data[v].envctl >> 22) & 3;
+    LEVEL       = spu->data[v].adsr_sustain_level;
+    STEP        = DECREASE ? (-8 + STEP) : (7 - STEP);
+    PHASE       = ADSR_SUSTAIN;
+
+    adsr_calculate_values(spu, v);
+}
+
+void adsr_load_release(psx_spu_t* spu, int v) {
+    EXPONENTIAL = (spu->data[v].envctl >> 21) & 1;
+    DECREASE    = 1;
+    SHIFT       = (spu->data[v].envctl >> 16) & 0x1f;
+    STEP        = -8;
+    PHASE       = ADSR_RELEASE;
+
+    adsr_calculate_values(spu, v);
+}
+
 void spu_handle_adsr(psx_spu_t* spu, int v) {
-    CYCLES = spu->data[v].adsr_cycles_reload;
+    if (CYCLES) {
+        CYCLES -= 1;
 
+        return;
+    }
+
     LEVEL += LEVEL_STEP;
 
     switch (spu->data[v].adsr_phase) {
-        case 0: {
+        case ADSR_ATTACK: {
             LEVEL = CLAMP(LEVEL, 0x0000, 0x7fff);
 
-            if (LEVEL == 0x7fff) {
-                spu->data[v].adsr_phase = 1;
-
-                spu_advance_adsr(spu, v);
-            }
+            if (LEVEL == 0x7fff)
+                adsr_load_decay(spu, v);
         } break;
 
-        case 1: {
+        case ADSR_DECAY: {
             LEVEL = CLAMP(LEVEL, 0x0000, 0x7fff);
 
-            if (LEVEL >= spu->data[v].adsr_sustain_level) {
-                spu->data[v].adsr_phase = 2;
+            if (LEVEL <= spu->data[v].adsr_sustain_level)
+                adsr_load_sustain(spu, v);
+        } break;
 
-                spu_advance_adsr(spu, v);
-            }
+        case ADSR_SUSTAIN: {
+            LEVEL = CLAMP(LEVEL, 0x0000, 0x7fff);
+
+            /* Not stopped automatically, need to KOFF */
         } break;
 
-        case 3: {
+        case ADSR_RELEASE: {
             LEVEL = CLAMP(LEVEL, 0x0000, 0x7fff);
 
             if (!LEVEL) {
-                spu->data[v].adsr_phase = 0;
+                PHASE = ADSR_END;
+                CYCLES = 0;
+                LEVEL_STEP = 0;
+
                 spu->data[v].playing = 0;
             }
         } break;
+
+        case ADSR_END: {
+            spu->data[v].playing = 0;
+        } break;
     }
+
+    spu->voice[v].envcvol = spu->data[v].cvol;
+
+    CYCLES = spu->data[v].adsr_cycles_reload;
 }
 
 #undef PHASE
@@ -280,83 +305,55 @@
 #undef STEP
 #undef PENDING_STEP
 
-int spu_handle_write(psx_spu_t* spu, uint32_t offset, uint32_t value) {
-    switch (offset) {
-        case SPUR_KON: {
-            if (!value)
-                return 1;
+void spu_kon(psx_spu_t* spu, uint32_t value) {
+    for (int i = 0; i < VOICE_COUNT; i++) {
+        if ((value & (1 << i))) {
+            spu->data[i].playing = 1;
+            spu->data[i].current_addr = spu->voice[i].adsaddr << 3;
+            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].envctl = (((uint32_t)spu->voice[i].envctl2) << 16) |
+                                    (uint32_t)spu->voice[i].envctl1;
 
-            // log_set_quiet(0);
-            log_fatal("KON %04x:", value);
-            for (int i = 0; i < 24; i++) {
-                if ((value & (1 << i))) {
-                    spu->data[i].playing = 1;
-                    spu->data[i].current_addr = spu->voice[i].adsaddr << 3;
-                    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;
+            adsr_load_attack(spu, i);
+            spu_read_block(spu, i);
+        }
+    }
 
-                    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->voice[i].envctl1,
-                        spu->voice[i].envctl2,
-                        spu->voice[i].envcvol
-                    );
+    spu->endx &= ~(value & 0x00ffffff);
+}
 
-                    spu_advance_adsr(spu, i);
-                    spu_read_block(spu, i);
-                }
-            }
-                    
-            // log_set_quiet(1);
-            spu->endx &= ~(value & 0x00ffffff);
-        } return 1;
+void spu_koff(psx_spu_t* spu, uint32_t value) {
+    for (int i = 0; i < VOICE_COUNT; i++)
+        if ((value & (1 << i)))
+            adsr_load_release(spu, i);
+}
 
-        case SPUR_KOFF: {
-            // log_set_quiet(0);
-            log_fatal("KOFF %04x:", value);
-            for (int i = 0; i < 24; i++) {
-                if ((value & (1 << i))) {
-                    spu->data[i].adsr_phase = 3;
-                    spu->data[i].playing = 0;
+int spu_handle_write(psx_spu_t* spu, uint32_t offset, uint32_t value) {
+    switch (offset) {
+        case SPUR_KONL: case SPUR_KONH: {
+            int high = (offset & 2) != 0;
 
-                    spu_advance_adsr(spu, i);
+            if (!value)
+                return 1;
 
-                    log_fatal("    voice %2u",
-                        i,
-                        spu->voice[i].adsaddr << 3,
-                        spu->voice[i].adraddr << 3,
-                        spu->voice[i].adsampr,
-                        spu->data[i].lvol,
-                        spu->data[i].rvol
-                    );
-                }
-            }
-            // log_set_quiet(1);
+            spu_kon(spu, value << (16 * high));
+        } return 1;
 
-            //spu->endx |= value & 0x00ffffff;
+        case SPUR_KOFFL: case SPUR_KOFFH: {
+            int high = (offset & 2) != 0;
+
+            spu_koff(spu, value << (16 * high));
         } return 1;
 
         case SPUR_TADDR: {
             spu->ramdta = value;
             spu->taddr = value << 3;
-
-            // // log_set_quiet(0);
-            // log_fatal("ramdta=%04x taddr=%08x", spu->ramdta, spu->taddr);
-            // // log_set_quiet(1);
         } return 1;
 
         case SPUR_TFIFO: {
-            // // log_set_quiet(0);
-            // log_fatal("TFIFO write %04x (index=%u)", value, spu->tfifo_index);
-            // // log_set_quiet(1);
             spu->ramdtf = value;
             spu->tfifo[spu->tfifo_index++] = value;
 
@@ -382,14 +379,15 @@
                     spu->ram[spu->taddr++] = spu->tfifo[i] & 0xff;
                     spu->ram[spu->taddr++] = spu->tfifo[i] >> 8;
                 }
-                    
-                // // log_set_quiet(0);
-                // log_fatal("Transfer start mode=%u size=%u", (value >> 4) & 3, spu->tfifo_index);
-                // // log_set_quiet(1);
 
                 spu->tfifo_index = 0;
             }
         } return 1;
+
+        case SPUR_MBASE: {
+            spu->mbase = value;
+            spu->revbaddr = spu->mbase << 3;
+        } return 1;
     }
 
     return 0;
@@ -412,7 +410,8 @@
 
     const uint8_t* ptr = (uint8_t*)&spu->voice[0].volumel;
 
-    *((uint16_t*)(ptr + offset)) = value;
+    if (offset != 0x0c) 
+        *((uint16_t*)(ptr + offset)) = value;
 }
 
 void psx_spu_write8(psx_spu_t* spu, uint32_t offset, uint8_t value) {
@@ -424,33 +423,85 @@
     free(spu);
 }
 
-/*
-  0-3   Shift  (0..12) (0=Loudest) (13..15=Reserved/Same as 9)
-  4-5   Filter (0..3) (only four filters, unlike SPU-ADPCM which has five)
-  6-7   Unused (should be 0)
-*/
+#define R16(addr) (*((uint16_t*)(&spu->ram[addr])))
+#define W16(addr) *((uint16_t*)(&spu->ram[addr]))
 
-uint32_t psx_spu_get_sample(psx_spu_t* spu) {
-    if (spu->endx == 0x00ffffff)
-        return 0x0000;
+void spu_get_reverb_sample(psx_spu_t* spu, int inl, int inr, int* outl, int* outr) {
+    uint32_t mbase = spu->mbase << 3;
+    uint32_t dapf1 = spu->dapf1 << 3;
+    uint32_t dapf2 = spu->dapf2 << 3;
+    uint32_t mlsame = MAX(mbase, (spu->revbaddr + (spu->mlsame << 3)) & 0x7fffe);
+    uint32_t mrsame = MAX(mbase, (spu->revbaddr + (spu->mrsame << 3)) & 0x7fffe);
+    uint32_t dlsame = MAX(mbase, (spu->revbaddr + (spu->dlsame << 3)) & 0x7fffe);
+    uint32_t drsame = MAX(mbase, (spu->revbaddr + (spu->drsame << 3)) & 0x7fffe);
+    uint32_t mldiff = MAX(mbase, (spu->revbaddr + (spu->mldiff << 3)) & 0x7fffe);
+    uint32_t mrdiff = MAX(mbase, (spu->revbaddr + (spu->mrdiff << 3)) & 0x7fffe);
+    uint32_t dldiff = MAX(mbase, (spu->revbaddr + (spu->dldiff << 3)) & 0x7fffe);
+    uint32_t drdiff = MAX(mbase, (spu->revbaddr + (spu->drdiff << 3)) & 0x7fffe);
+    uint32_t mlcomb1 = MAX(mbase, (spu->revbaddr + (spu->mlcomb1 << 3)) & 0x7fffe);
+    uint32_t mlcomb2 = MAX(mbase, (spu->revbaddr + (spu->mlcomb2 << 3)) & 0x7fffe);
+    uint32_t mlcomb3 = MAX(mbase, (spu->revbaddr + (spu->mlcomb3 << 3)) & 0x7fffe);
+    uint32_t mlcomb4 = MAX(mbase, (spu->revbaddr + (spu->mlcomb4 << 3)) & 0x7fffe);
+    uint32_t mrcomb1 = MAX(mbase, (spu->revbaddr + (spu->mrcomb1 << 3)) & 0x7fffe);
+    uint32_t mrcomb2 = MAX(mbase, (spu->revbaddr + (spu->mrcomb2 << 3)) & 0x7fffe);
+    uint32_t mrcomb3 = MAX(mbase, (spu->revbaddr + (spu->mrcomb3 << 3)) & 0x7fffe);
+    uint32_t mrcomb4 = MAX(mbase, (spu->revbaddr + (spu->mrcomb4 << 3)) & 0x7fffe);
+    uint32_t mlapf1 = MAX(mbase, (spu->revbaddr + ((spu->mlapf1 << 3) - dapf1)) & 0x7fffe);
+    uint32_t mlapf2 = MAX(mbase, (spu->revbaddr + ((spu->mlapf2 << 3) - dapf2)) & 0x7fffe);
+    uint32_t mrapf1 = MAX(mbase, (spu->revbaddr + ((spu->mrapf1 << 3) - dapf1)) & 0x7fffe);
+    uint32_t mrapf2 = MAX(mbase, (spu->revbaddr + ((spu->mrapf2 << 3) - dapf2)) & 0x7fffe);
+    int16_t viir = spu->viir;
+    int16_t vwall = spu->vwall;
+    int16_t vcomb1 = spu->vcomb1;
+    int16_t vcomb2 = spu->vcomb2;
+    int16_t vcomb3 = spu->vcomb3;
+    int16_t vcomb4 = spu->vcomb4;
+    int16_t vapf1 = spu->vapf1;
+    int16_t vapf2 = spu->vapf2;
+    int16_t vlout = spu->vlout;
+    int16_t vrout = spu->vrout;
 
-    int voice_count = 0;
-    int left = 0x0000;
-    int right = 0x0000;
+    int lin = inl * spu->vlin;
+    int rin = inr * spu->vrin;
 
-    for (int v = 0; v < 24; v++) {
-        // if (spu->data[v].adsr_cycles) {
-        //     --spu->data[v].adsr_cycles;
+    W16(mlsame) = (lin + R16(dlsame)*vwall - R16(mlsame-2))*viir + R16(mlsame-2);
+    W16(mrsame) = (rin + R16(drsame)*vwall - R16(mrsame-2))*viir + R16(mrsame-2);
+    W16(mldiff) = (lin + R16(drdiff)*vwall - R16(mldiff-2))*viir + R16(mldiff-2);
+    W16(mrdiff) = (rin + R16(dldiff)*vwall - R16(mrdiff-2))*viir + R16(mrdiff-2);
 
-        //     if (!spu->data[v].adsr_cycles)
-        //         spu_handle_adsr(spu, v);
-        // }
+    int lout=vcomb1*R16(mlcomb1)+vcomb2*R16(mlcomb2)+vcomb3*R16(mlcomb3)+vcomb4*R16(mlcomb4);
+    int rout=vcomb1*R16(mrcomb1)+vcomb2*R16(mrcomb2)+vcomb3*R16(mrcomb3)+vcomb4*R16(mrcomb4);
 
+    lout-=vapf1*R16(mlapf1); R16(mlapf1)=lout; lout*=vapf1+R16(mlapf1);
+    rout-=vapf1*R16(mrapf1); R16(mrapf1)=rout; rout*=vapf1+R16(mrapf1);
+    lout-=vapf2*R16(mlapf2); R16(mlapf2)=lout; lout*=vapf2+R16(mlapf2);
+    rout-=vapf2*R16(mrapf2); R16(mrapf2)=rout; rout*=vapf2+R16(mrapf2);
+
+    *outl = lout * vlout;
+    *outr = rout * vrout;
+
+    spu->revbaddr = MAX(mbase, (spu->revbaddr + 2) & 0x7fffe);
+}
+
+#undef R16
+#undef W16
+
+uint32_t psx_spu_get_sample(psx_spu_t* spu) {
+    spu->even_cycle ^= 1;
+    int active_voice_count = 0;
+    int left = 0;
+    int right = 0;
+    int revl = 0;
+    int revr = 0;
+
+    for (int v = 0; v < VOICE_COUNT; v++) {
         if (!spu->data[v].playing)
             continue;
-        
-        ++voice_count;
 
+        spu_handle_adsr(spu, v);
+
+        ++active_voice_count;
+
         // Shift 3 older samples around
         spu->data[v].s[3] = spu->data[v].s[2];
         spu->data[v].s[2] = spu->data[v].s[1];
@@ -470,12 +521,14 @@
                 } break;
 
                 case 1: {
+                    spu->endx |= (1 << v);
                     spu->data[v].current_addr = spu->data[v].repeat_addr;
-                    //spu->endx |= (1 << v);
                     spu->data[v].playing = 0;
+                    spu->voice[v].envcvol = 0;
                 } break;
 
                 case 3: {
+                    spu->endx |= (1 << v);
                     spu->data[v].current_addr = spu->data[v].repeat_addr;
                 } break;
             }
@@ -502,14 +555,19 @@
         out += (g2 * spu->data[v].s[1]) >> 15;
         out += (g3 * spu->data[v].s[0]) >> 15;
 
-        //float adsr_vol = (float)spu->voice[v].envcvol / 32767.0f;
+        float adsr_vol = (float)spu->voice[v].envcvol / 32767.0f;
 
-        left += out * spu->data[v].lvol;
-        right += out * spu->data[v].rvol;
+        float samplel = (out * spu->data[v].lvol) * adsr_vol;
+        float sampler = (out * spu->data[v].rvol) * adsr_vol;
 
-        // left *= adsr_vol;
-        // right *= adsr_vol;
+        left += samplel;
+        right += sampler;
 
+        if (spu->eon & (1 << v)) {
+            revl += samplel;
+            revr += sampler;
+        }
+
         uint16_t step = spu->voice[v].adsampr;
 
         /* To-do: Do pitch modulation here */
@@ -517,8 +575,12 @@
         spu->data[v].counter += step;
     }
 
-    if (!voice_count)
+    if (!active_voice_count)
         return 0x00000000;
+
+    // To-do: Fix reverb
+    // if ((spu->spucnt & 0x0080) && spu->even_cycle)
+    //     spu_get_reverb_sample(spu, revl, revr, &spu->lrsl, &spu->lrsr);
 
     uint16_t clampl = CLAMP(left, INT16_MIN, INT16_MAX);
     uint16_t clampr = CLAMP(right, INT16_MIN, INT16_MAX);
--- a/psx/dev/spu.h
+++ b/psx/dev/spu.h
@@ -18,14 +18,20 @@
     1F801DACh - Sound RAM Data Transfer Control (should be 0004h)
 */
 
-#define SPUR_KON     0x188
-#define SPUR_KOFF    0x18c
-#define SPUR_ENDX    0x19c
+#define SPUR_KONL    0x188
+#define SPUR_KONH    0x18a
+#define SPUR_KOFFL   0x18c
+#define SPUR_KOFFH   0x18e
+#define SPUR_EONL    0x198
+#define SPUR_EONH    0x19a
+#define SPUR_ENDXL   0x19c
+#define SPUR_ENDXH   0x19e
 #define SPUR_TADDR   0x1a6
 #define SPUR_TFIFO   0x1a8
 #define SPUR_SPUCNT  0x1aa
 #define SPUR_TCTRL   0x1ac
 #define SPUR_SPUSTAT 0x1ae
+#define SPUR_MBASE   0x1a2
 
 typedef struct __attribute__((__packed__)) {
     uint32_t io_base, io_size;
@@ -32,7 +38,7 @@
 
     uint8_t* ram;
 
-    struct {
+    struct __attribute__((__packed__)) {
         uint16_t volumel;
         uint16_t volumer;
         uint16_t adsampr;
@@ -45,8 +51,8 @@
 
     uint16_t mainlvol;
     uint16_t mainrvol;
-    uint16_t revblvol;
-    uint16_t revbrvol;
+    uint16_t vlout;
+    uint16_t vrout;
     uint32_t kon;
     uint32_t koff;
     uint32_t pmon;
@@ -54,7 +60,7 @@
     uint32_t eon;
     uint32_t endx;
     uint16_t unk_da0;
-    uint16_t revbaddr;
+    uint16_t mbase;
     uint16_t irq9addr;
     uint16_t ramdta;
     uint16_t ramdtf;
@@ -67,14 +73,14 @@
     uint32_t unk_dbc;
     uint16_t dapf1;
     uint16_t dapf2;
-    uint16_t viir;
-    uint16_t vcomb1;
-    uint16_t vcomb2;
-    uint16_t vcomb3;
-    uint16_t vcomb4;
-    uint16_t vwall;
-    uint16_t vapf1;
-    uint16_t vapf2;
+    int16_t  viir;
+    int16_t  vcomb1;
+    int16_t  vcomb2;
+    int16_t  vcomb3;
+    int16_t  vcomb4;
+    int16_t  vwall;
+    int16_t  vapf1;
+    int16_t  vapf2;
     uint16_t mlsame;
     uint16_t mrsame;
     uint16_t mlcomb1;
@@ -95,8 +101,8 @@
     uint16_t mrapf1;
     uint16_t mlapf2;
     uint16_t mrapf2;
-    uint16_t vlin;
-    uint16_t vrin;
+    int16_t  vlin;
+    int16_t  vrin;
 
     // Internal registers unimplemented
 
@@ -103,6 +109,10 @@
     uint32_t taddr;
     uint16_t tfifo[32];
     uint16_t tfifo_index;
+    uint32_t revbaddr;
+    int lrsl;
+    int lrsr;
+    int even_cycle;
 
     struct {
         int playing;
@@ -115,6 +125,8 @@
         int16_t h[2];
         float lvol;
         float rvol;
+        int cvol;
+        int eon;
 
         /*
         ____lower 16bit (at 1F801C08h+N*10h)___________________________________
@@ -148,6 +160,7 @@
         int adsr_step;
         int adsr_pending_step;
         int adsr_sustain_level;
+        uint32_t envctl;
     } data[24];
 } psx_spu_t;
 
--