ref: 0e56d8b9679d592f9d22fbc4b84e452f5a783404
parent: 60550f8be5060a38225dd0a2ef0e920e48f249f4
author: allkern <lisandroaalarcon@gmail.com>
date: Fri Sep 29 16:03:46 EDT 2023
Initial SPU implementation Fix GPU issue
--- a/frontend/main.c
+++ b/frontend/main.c
@@ -8,9 +8,17 @@
#undef main
void audio_update(void* ud, uint8_t* buf, int size) {- psx_cdrom_t* cdrom = ud;
+ psx_cdrom_t* cdrom = ((psx_t*)ud)->cdrom;
+ psx_spu_t* spu = ((psx_t*)ud)->spu;
psx_cdrom_get_cdda_samples(cdrom, buf, size);
+
+ for (int i = 0; i < (size >> 2); i++) {+ int16_t sample = psx_spu_get_sample(spu);
+
+ *(uint16_t*)(&buf[(i << 2) + 0]) = sample;
+ *(uint16_t*)(&buf[(i << 2) + 2]) = sample;
+ }
}
int main(int argc, const char* argv[]) {@@ -45,7 +53,7 @@
desired.channels = 2;
desired.samples = CD_SECTOR_SIZE >> 2;
desired.callback = &audio_update;
- desired.userdata = cdrom;
+ desired.userdata = psx;
dev = SDL_OpenAudioDevice(NULL, 0, &desired, &obtained, 0);
--- a/psx/dev/dma.c
+++ b/psx/dev/dma.c
@@ -329,20 +329,22 @@
if (!CHCR_BUSY(spu))
return;
- // log_fatal("SPU DMA transfer: madr=%08x, dir=%s, sync=%s (%u), step=%s, size=%x",- // dma->spu.madr,
- // CHCR_TDIR(spu) ? "to device" : "to RAM",
- // g_psx_dma_sync_type_name_table[CHCR_SYNC(spu)], CHCR_SYNC(spu),
- // CHCR_STEP(spu) ? "decrementing" : "incrementing",
- // BCR_SIZE(spu)
- // );
+ log_set_quiet(0);
+ log_fatal("SPU DMA transfer: madr=%08x, dir=%s, sync=%s (%u), step=%s, size=%x",+ dma->spu.madr,
+ CHCR_TDIR(spu) ? "to device" : "to RAM",
+ g_psx_dma_sync_type_name_table[CHCR_SYNC(spu)], CHCR_SYNC(spu),
+ CHCR_STEP(spu) ? "decrementing" : "incrementing",
+ BCR_SIZE(spu)
+ );
- // log_fatal("DICR: force=%u, en=%02x, irqen=%u, flags=%02x",- // (dma->dicr >> 15) & 1,
- // (dma->dicr >> 16) & 0x7f,
- // (dma->dicr >> 23) & 1,
- // (dma->dicr >> 24) & 0x7f
- // );
+ log_fatal("DICR: force=%u, en=%02x, irqen=%u, flags=%02x",+ (dma->dicr >> 15) & 1,
+ (dma->dicr >> 16) & 0x7f,
+ (dma->dicr >> 23) & 1,
+ (dma->dicr >> 24) & 0x7f
+ );
+ log_set_quiet(1);
uint32_t size = BCR_SIZE(spu) * BCR_BCNT(spu);
@@ -353,6 +355,17 @@
}
dma->spu_irq_delay = 1;
+
+ if (CHCR_TDIR(spu)) {+ for (int i = 0; i < size; i++) {+ uint32_t data = psx_bus_read32(dma->bus, dma->spu.madr);
+
+ psx_bus_write16(dma->bus, 0x1f801da8, data >> 16);
+ psx_bus_write16(dma->bus, 0x1f801da8, data & 0xffff);
+
+ dma->spu.madr += CHCR_STEP(spu) ? -4 : 4;
+ }
+ }
// Clear BCR and CHCR trigger and busy bits
dma->spu.chcr = 0;
--- a/psx/dev/gpu.c
+++ b/psx/dev/gpu.c
@@ -144,7 +144,7 @@
// 4-bit
case 0: {uint16_t texel = VRAM(tpx + (tx >> 2), tpy + ty);
- uint16_t index = (texel >> ((tx & 0x1) << 3)) & 0xff;
+ uint16_t index = (texel >> ((tx & 0x3) << 2)) & 0xf;
return VRAM(clutx + index, cluty);
} break;
@@ -938,7 +938,7 @@
xpos = (gpu->xpos + gpu->xcnt) & 0x3ff;
}
- VRAM(xpos, ypos) = gpu->recv_data & 0xffff;
+ VRAM(xpos, ypos) = gpu->recv_data >> 16;
++gpu->xcnt;
@@ -1509,24 +1509,12 @@
void psx_gpu_update_cmd(psx_gpu_t* gpu) {int type = (gpu->buf[0] >> 29) & 7;
- if (type == 3) {- gpu_rect(gpu);
-
- return;
- }
-
- if (type == 1) {- gpu_poly(gpu);
-
- return;
- }
-
switch (type) {- case 1: gpu_poly(gpu); break;
- case 3: gpu_rect(gpu); break;
- case 4: gpu_copy(gpu); break;
- case 5: gpu_recv(gpu); break;
- case 6: gpu_send(gpu); break;
+ case 1: gpu_poly(gpu); return;
+ case 3: gpu_rect(gpu); return;
+ case 4: gpu_copy(gpu); return;
+ case 5: gpu_recv(gpu); return;
+ case 6: gpu_send(gpu); return;
default: break;
}
@@ -1566,8 +1554,8 @@
// case 0x7e: gpu_cmd_7c(gpu); break;
// case 0x7f: gpu_cmd_7c(gpu); break;
// case 0x80: gpu_cmd_80(gpu); break;
- case 0xa0: gpu_cmd_a0(gpu); break;
- case 0xc0: gpu_cmd_c0(gpu); break;
+ // case 0xa0: gpu_cmd_a0(gpu); break;
+ // case 0xc0: gpu_cmd_c0(gpu); break;
case 0xe1: {gpu->gpustat &= 0xfffff800;
gpu->gpustat |= gpu->buf[0] & 0x7ff;
--- a/psx/dev/spu.c
+++ b/psx/dev/spu.c
@@ -5,6 +5,73 @@
#include "spu.h"
#include "../log.h"
+static const int16_t g_psx_spu_gauss_table[] = {+ -0x001, -0x001, -0x001, -0x001, -0x001, -0x001, -0x001, -0x001,
+ -0x001, -0x001, -0x001, -0x001, -0x001, -0x001, -0x001, -0x001,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001,
+ 0x0001, 0x0001, 0x0001, 0x0002, 0x0002, 0x0002, 0x0003, 0x0003,
+ 0x0003, 0x0004, 0x0004, 0x0005, 0x0005, 0x0006, 0x0007, 0x0007,
+ 0x0008, 0x0009, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E,
+ 0x000F, 0x0010, 0x0011, 0x0012, 0x0013, 0x0015, 0x0016, 0x0018,
+ 0x0019, 0x001B, 0x001C, 0x001E, 0x0020, 0x0021, 0x0023, 0x0025,
+ 0x0027, 0x0029, 0x002C, 0x002E, 0x0030, 0x0033, 0x0035, 0x0038,
+ 0x003A, 0x003D, 0x0040, 0x0043, 0x0046, 0x0049, 0x004D, 0x0050,
+ 0x0054, 0x0057, 0x005B, 0x005F, 0x0063, 0x0067, 0x006B, 0x006F,
+ 0x0074, 0x0078, 0x007D, 0x0082, 0x0087, 0x008C, 0x0091, 0x0096,
+ 0x009C, 0x00A1, 0x00A7, 0x00AD, 0x00B3, 0x00BA, 0x00C0, 0x00C7,
+ 0x00CD, 0x00D4, 0x00DB, 0x00E3, 0x00EA, 0x00F2, 0x00FA, 0x0101,
+ 0x010A, 0x0112, 0x011B, 0x0123, 0x012C, 0x0135, 0x013F, 0x0148,
+ 0x0152, 0x015C, 0x0166, 0x0171, 0x017B, 0x0186, 0x0191, 0x019C,
+ 0x01A8, 0x01B4, 0x01C0, 0x01CC, 0x01D9, 0x01E5, 0x01F2, 0x0200,
+ 0x020D, 0x021B, 0x0229, 0x0237, 0x0246, 0x0255, 0x0264, 0x0273,
+ 0x0283, 0x0293, 0x02A3, 0x02B4, 0x02C4, 0x02D6, 0x02E7, 0x02F9,
+ 0x030B, 0x031D, 0x0330, 0x0343, 0x0356, 0x036A, 0x037E, 0x0392,
+ 0x03A7, 0x03BC, 0x03D1, 0x03E7, 0x03FC, 0x0413, 0x042A, 0x0441,
+ 0x0458, 0x0470, 0x0488, 0x04A0, 0x04B9, 0x04D2, 0x04EC, 0x0506,
+ 0x0520, 0x053B, 0x0556, 0x0572, 0x058E, 0x05AA, 0x05C7, 0x05E4,
+ 0x0601, 0x061F, 0x063E, 0x065C, 0x067C, 0x069B, 0x06BB, 0x06DC,
+ 0x06FD, 0x071E, 0x0740, 0x0762, 0x0784, 0x07A7, 0x07CB, 0x07EF,
+ 0x0813, 0x0838, 0x085D, 0x0883, 0x08A9, 0x08D0, 0x08F7, 0x091E,
+ 0x0946, 0x096F, 0x0998, 0x09C1, 0x09EB, 0x0A16, 0x0A40, 0x0A6C,
+ 0x0A98, 0x0AC4, 0x0AF1, 0x0B1E, 0x0B4C, 0x0B7A, 0x0BA9, 0x0BD8,
+ 0x0C07, 0x0C38, 0x0C68, 0x0C99, 0x0CCB, 0x0CFD, 0x0D30, 0x0D63,
+ 0x0D97, 0x0DCB, 0x0E00, 0x0E35, 0x0E6B, 0x0EA1, 0x0ED7, 0x0F0F,
+ 0x0F46, 0x0F7F, 0x0FB7, 0x0FF1, 0x102A, 0x1065, 0x109F, 0x10DB,
+ 0x1116, 0x1153, 0x118F, 0x11CD, 0x120B, 0x1249, 0x1288, 0x12C7,
+ 0x1307, 0x1347, 0x1388, 0x13C9, 0x140B, 0x144D, 0x1490, 0x14D4,
+ 0x1517, 0x155C, 0x15A0, 0x15E6, 0x162C, 0x1672, 0x16B9, 0x1700,
+ 0x1747, 0x1790, 0x17D8, 0x1821, 0x186B, 0x18B5, 0x1900, 0x194B,
+ 0x1996, 0x19E2, 0x1A2E, 0x1A7B, 0x1AC8, 0x1B16, 0x1B64, 0x1BB3,
+ 0x1C02, 0x1C51, 0x1CA1, 0x1CF1, 0x1D42, 0x1D93, 0x1DE5, 0x1E37,
+ 0x1E89, 0x1EDC, 0x1F2F, 0x1F82, 0x1FD6, 0x202A, 0x207F, 0x20D4,
+ 0x2129, 0x217F, 0x21D5, 0x222C, 0x2282, 0x22DA, 0x2331, 0x2389,
+ 0x23E1, 0x2439, 0x2492, 0x24EB, 0x2545, 0x259E, 0x25F8, 0x2653,
+ 0x26AD, 0x2708, 0x2763, 0x27BE, 0x281A, 0x2876, 0x28D2, 0x292E,
+ 0x298B, 0x29E7, 0x2A44, 0x2AA1, 0x2AFF, 0x2B5C, 0x2BBA, 0x2C18,
+ 0x2C76, 0x2CD4, 0x2D33, 0x2D91, 0x2DF0, 0x2E4F, 0x2EAE, 0x2F0D,
+ 0x2F6C, 0x2FCC, 0x302B, 0x308B, 0x30EA, 0x314A, 0x31AA, 0x3209,
+ 0x3269, 0x32C9, 0x3329, 0x3389, 0x33E9, 0x3449, 0x34A9, 0x3509,
+ 0x3569, 0x35C9, 0x3629, 0x3689, 0x36E8, 0x3748, 0x37A8, 0x3807,
+ 0x3867, 0x38C6, 0x3926, 0x3985, 0x39E4, 0x3A43, 0x3AA2, 0x3B00,
+ 0x3B5F, 0x3BBD, 0x3C1B, 0x3C79, 0x3CD7, 0x3D35, 0x3D92, 0x3DEF,
+ 0x3E4C, 0x3EA9, 0x3F05, 0x3F62, 0x3FBD, 0x4019, 0x4074, 0x40D0,
+ 0x412A, 0x4185, 0x41DF, 0x4239, 0x4292, 0x42EB, 0x4344, 0x439C,
+ 0x43F4, 0x444C, 0x44A3, 0x44FA, 0x4550, 0x45A6, 0x45FC, 0x4651,
+ 0x46A6, 0x46FA, 0x474E, 0x47A1, 0x47F4, 0x4846, 0x4898, 0x48E9,
+ 0x493A, 0x498A, 0x49D9, 0x4A29, 0x4A77, 0x4AC5, 0x4B13, 0x4B5F,
+ 0x4BAC, 0x4BF7, 0x4C42, 0x4C8D, 0x4CD7, 0x4D20, 0x4D68, 0x4DB0,
+ 0x4DF7, 0x4E3E, 0x4E84, 0x4EC9, 0x4F0E, 0x4F52, 0x4F95, 0x4FD7,
+ 0x5019, 0x505A, 0x509A, 0x50DA, 0x5118, 0x5156, 0x5194, 0x51D0,
+ 0x520C, 0x5247, 0x5281, 0x52BA, 0x52F3, 0x532A, 0x5361, 0x5397,
+ 0x53CC, 0x5401, 0x5434, 0x5467, 0x5499, 0x54CA, 0x54FA, 0x5529,
+ 0x5558, 0x5585, 0x55B2, 0x55DE, 0x5609, 0x5632, 0x565B, 0x5684,
+ 0x56AB, 0x56D1, 0x56F6, 0x571B, 0x573E, 0x5761, 0x5782, 0x57A3,
+ 0x57C3, 0x57E2, 0x57FF, 0x581C, 0x5838, 0x5853, 0x586D, 0x5886,
+ 0x589E, 0x58B5, 0x58CB, 0x58E0, 0x58F4, 0x5907, 0x5919, 0x592A,
+ 0x593A, 0x5949, 0x5958, 0x5965, 0x5971, 0x597C, 0x5986, 0x598F,
+ 0x5997, 0x599E, 0x59A4, 0x59A9, 0x59AD, 0x59B0, 0x59B2, 0x59B3
+};
+
psx_spu_t* psx_spu_create() {return (psx_spu_t*)malloc(sizeof(psx_spu_t));
}
@@ -15,15 +82,22 @@
spu->io_base = PSX_SPU_BEGIN;
spu->io_size = PSX_SPU_SIZE;
- spu->ram = (uint8_t*)malloc(PSX_SPU_RAM_SIZE);
+ spu->ram = (uint8_t*)malloc(SPU_RAM_SIZE);
+
+ // Mute all voices
+ spu->endx = 0x00ffffff;
}
uint32_t psx_spu_read32(psx_spu_t* spu, uint32_t offset) {- return *(uint32_t*)(&spu->r[offset]);
+ const uint8_t* ptr = (uint8_t*)&spu->voice[0].volumel;
+
+ return *((uint32_t*)(ptr + offset));
}
uint16_t psx_spu_read16(psx_spu_t* spu, uint32_t offset) {- return *(uint16_t*)(&spu->r[offset]);
+ const uint8_t* ptr = (uint8_t*)&spu->voice[0].volumel;
+
+ return *((uint16_t*)(ptr + offset));
}
uint8_t psx_spu_read8(psx_spu_t* spu, uint32_t offset) {@@ -33,13 +107,86 @@
}
void psx_spu_write32(psx_spu_t* spu, uint32_t offset, uint32_t value) {- *(uint32_t*)(&spu->r[offset]) = value;
+ const uint8_t* ptr = (uint8_t*)&spu->voice[0].volumel;
+
+ *((uint32_t*)(ptr + offset)) = value;
}
+
+void spu_read_block(psx_spu_t* spu, int v) {+ spu->data[v].block_flags = spu->ram[spu->data[v].current_addr + 1];
+}
+
void psx_spu_write16(psx_spu_t* spu, uint32_t offset, uint16_t value) {- *(uint16_t*)(&spu->r[offset]) = value;
-}
+ // Handle special cases first
+ switch (offset) {+ case SPUR_KON: {+ log_set_quiet(0);
+ for (int i = 0; i < 24; i++) {+ if (value & (1 << i)) {+ log_fatal("KON voice %2u s=%06x r=%06x p=%04x",+ i,
+ spu->voice[i].adsaddr,
+ spu->voice[i].adraddr,
+ spu->voice[i].adsampr
+ );
+
+ spu->data[i].current_addr = spu->voice[i].adsaddr;
+
+ spu_read_block(spu, i);
+ }
+ }
+
+ log_set_quiet(1);
+ spu->endx &= ~(value & 0x00ffffff);
+ } return;
+ case SPUR_KOFF: {+ spu->endx |= value & 0x00ffffff;
+ } return;
+
+ 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;
+
+ 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;
+ } return;
+
+ case SPUR_SPUCNT: {+ spu->spucnt = value;
+ spu->spustat &= 0xffc0;
+ spu->spustat |= value & 0x3f;
+
+ if ((value >> 4) & 3) {+ for (int i = 0; i < spu->tfifo_index; i++) {+ 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;
+ }
+ } break;
+ }
+
+ const uint8_t* ptr = (uint8_t*)&spu->voice[0].volumel;
+
+ *((uint16_t*)(ptr + offset)) = value;
+}
+
void psx_spu_write8(psx_spu_t* spu, uint32_t offset, uint8_t value) { log_fatal("Unhandled 8-bit SPU write at offset %08x (%02x)", offset, value);}
@@ -47,4 +194,95 @@
void psx_spu_destroy(psx_spu_t* spu) {free(spu->ram);
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)
+*/
+
+int16_t psx_spu_get_sample(psx_spu_t* spu) {+ if (spu->endx == 0x00ffffff)
+ return 0x0000;
+
+ int voice_count = 0;
+ int output = 0x0000;
+
+ for (int v = 0; v < 24; v++) {+ if (spu->endx & (1 << v))
+ continue;
+
+ ++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];
+ spu->data[v].s[1] = spu->data[v].s[0];
+
+ uint32_t sample_index = spu->data[v].counter >> 12;
+
+ if (sample_index >= 28) {+ sample_index -= 28;
+
+ spu->data[v].counter &= 0xfff;
+ spu->data[v].counter |= sample_index << 12;
+
+ switch (spu->data[v].block_flags & 3) {+ case 0: case 2: {+ spu->data[v].current_addr += 2;
+ } break;
+
+ case 1: {+ spu->data[v].current_addr = spu->data[v].repeat_addr;
+ spu->endx |= (1 << v);
+ } break;
+
+ case 3: {+ spu->data[v].current_addr = spu->data[v].repeat_addr;
+ } break;
+ }
+
+ if (spu->data[v].block_flags & 4)
+ spu->data[v].repeat_addr = spu->data[v].current_addr;
+
+ spu_read_block(spu, v);
+ }
+
+ uint8_t hdr = spu->ram[spu->data[v].current_addr];
+
+ // Fetch ADPCM sample
+ uint16_t sample = spu->ram[spu->data[v].current_addr + 2 + (sample_index >> 1)];
+
+ // "Expand" sample (according to XA-ADPCM)
+ sample >>= (sample_index & 1) * 4;
+ sample &= 0xf;
+ sample <<= 12;
+ sample >>= hdr & 0xf;
+
+ spu->data[v].s[0] = sample;
+
+ // Apply 4-point Gaussian interpolation
+ uint8_t gauss_index = (spu->data[v].counter >> 4) & 0xff;
+ int16_t g0 = g_psx_spu_gauss_table[0x0ff - gauss_index];
+ int16_t g1 = g_psx_spu_gauss_table[0x1ff - gauss_index];
+ int16_t g2 = g_psx_spu_gauss_table[0x100 + gauss_index];
+ int16_t g3 = g_psx_spu_gauss_table[0x000 + gauss_index];
+ int16_t out;
+
+ out = (g0 * spu->data[v].s[3]) >> 15;
+ out += (g1 * spu->data[v].s[2]) >> 15;
+ out += (g2 * spu->data[v].s[1]) >> 15;
+ out += (g3 * spu->data[v].s[0]) >> 15;
+
+ output += out;
+
+ uint16_t step = spu->voice[0].adsampr;
+
+ /* To-do: Do pitch modulation here */
+
+ spu->data[v].counter += step;
+ }
+
+ return output / voice_count;
}
\ No newline at end of file
--- a/psx/dev/spu.h
+++ b/psx/dev/spu.h
@@ -7,31 +7,110 @@
#define PSX_SPU_SIZE 0x400
#define PSX_SPU_END 0x1f801fff
-#define PSX_SPU_RAM_SIZE 0x80000
+#define SPU_RAM_SIZE 0x80000
-typedef struct {+/*
+ 1F801D88h - Voice 0..23 Key ON (Start Attack/Decay/Sustain) (KON) (W)
+ 1F801D8Ch - Voice 0..23 Key OFF (Start Release) (KOFF) (W)
+ 1F801D9Ch - Voice 0..23 ON/OFF (status) (ENDX) (R)
+ 1F801DA6h - Sound RAM Data Transfer Address
+ 1F801DA8h - Sound RAM Data Transfer Fifo
+ 1F801DACh - Sound RAM Data Transfer Control (should be 0004h)
+*/
+
+#define SPUR_KON 0x188
+#define SPUR_KOFF 0x18c
+#define SPUR_ENDX 0x19c
+#define SPUR_TADDR 0x1a6
+#define SPUR_TFIFO 0x1a8
+#define SPUR_SPUCNT 0x1aa
+#define SPUR_TCTRL 0x1ac
+#define SPUR_SPUSTAT 0x1ae
+
+typedef struct __attribute__((__packed__)) {uint32_t io_base, io_size;
uint8_t* ram;
- uint8_t r[0x400];
+ struct {+ uint16_t volumel;
+ uint16_t volumer;
+ uint16_t adsampr;
+ uint16_t adsaddr;
+ uint16_t envctl1;
+ uint16_t envctl2;
+ uint16_t envcvol;
+ uint16_t adraddr;
+ } voice[24];
- uint32_t current_addr;
+ uint16_t mainlvol;
+ uint16_t mainrvol;
+ uint16_t revblvol;
+ uint16_t revbrvol;
+ uint32_t kon;
+ uint32_t koff;
+ uint32_t pmon;
+ uint32_t non;
+ uint32_t eon;
+ uint32_t endx;
+ uint16_t unk_da0;
+ uint16_t revbaddr;
+ uint16_t irq9addr;
+ uint16_t ramdta;
+ uint16_t ramdtf;
+ uint16_t spucnt;
+ uint16_t ramdtc;
+ uint16_t spustat;
+ uint32_t cdaivol;
+ uint32_t extivol;
+ uint32_t currvol;
+ 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;
+ uint16_t mlsame;
+ uint16_t mrsame;
+ uint16_t mlcomb1;
+ uint16_t mrcomb1;
+ uint16_t mlcomb2;
+ uint16_t mrcomb2;
+ uint16_t dlsame;
+ uint16_t drsame;
+ uint16_t mldiff;
+ uint16_t mrdiff;
+ uint16_t mlcomb3;
+ uint16_t mrcomb3;
+ uint16_t mlcomb4;
+ uint16_t mrcomb4;
+ uint16_t dldiff;
+ uint16_t drdiff;
+ uint16_t mlapf1;
+ uint16_t mrapf1;
+ uint16_t mlapf2;
+ uint16_t mrapf2;
+ uint16_t vlin;
+ uint16_t vrin;
- // struct {- // uint16_t volumel;
- // uint16_t volumer;
- // uint16_t adsampr;
- // uint16_t adsaddr;
- // uint16_t envctl1;
- // uint16_t envctl2;
- // uint16_t envcvol;
- // uint16_t adraddr;
- // } voice[24];
+ // Internal registers unimplemented
- // uint16_t mainvol[2];
- // uint16_t echovol[2];
- // uint32_t flags[3];
+ uint32_t taddr;
+ uint16_t tfifo[32];
+ uint16_t tfifo_index;
+
+ struct {+ uint32_t counter;
+ uint32_t current_addr;
+ uint32_t repeat_addr;
+ int16_t s[4];
+ int block_flags;
+ } data[24];
} psx_spu_t;
psx_spu_t* psx_spu_create();
@@ -43,5 +122,6 @@
void psx_spu_write16(psx_spu_t*, uint32_t, uint16_t);
void psx_spu_write8(psx_spu_t*, uint32_t, uint8_t);
void psx_spu_destroy(psx_spu_t*);
+int16_t psx_spu_get_sample(psx_spu_t*);
#endif
\ No newline at end of file
--
⑨