diff options
| author | Xavier Del Campo Romero <xavi.dcr@tutanota.com> | 2021-07-03 00:49:03 +0200 |
|---|---|---|
| committer | Xavier Del Campo Romero <xavi.dcr@tutanota.com> | 2022-03-30 08:20:20 +0200 |
| commit | 6b9f686913efc3725b2690033cd4f398e07076ba (patch) | |
| tree | e9aa91a6b9f617d78123ebe7ad272fc42a60d306 /src/sfx/ps1 | |
| parent | c9e6ae44a9aeb89b3f48f3443d6baa80103f7445 (diff) | |
| download | jancity-6b9f686913efc3725b2690033cd4f398e07076ba.tar.gz | |
Add project source code
Diffstat (limited to 'src/sfx/ps1')
| -rw-r--r-- | src/sfx/ps1/inc/sfx/port.h | 17 | ||||
| -rw-r--r-- | src/sfx/ps1/src/sound.c | 188 |
2 files changed, 205 insertions, 0 deletions
diff --git a/src/sfx/ps1/inc/sfx/port.h b/src/sfx/ps1/inc/sfx/port.h new file mode 100644 index 0000000..80c97e8 --- /dev/null +++ b/src/sfx/ps1/inc/sfx/port.h @@ -0,0 +1,17 @@ +#ifndef SFX_PS1_H +#define SFX_PS1_H + +#include <stddef.h> +#include <stdint.h> + +typedef uint32_t sfx_spu_addr; +typedef uint8_t sfx_spu_voice; + +struct sound +{ + sfx_spu_addr addr; + uint16_t sample_rate; + sfx_spu_voice voice; +}; + +#endif /* SFX_PS1_H */ diff --git a/src/sfx/ps1/src/sound.c b/src/sfx/ps1/src/sound.c new file mode 100644 index 0000000..e0377c7 --- /dev/null +++ b/src/sfx/ps1/src/sound.c @@ -0,0 +1,188 @@ +#include <sfx.h> +#include <sfx/port.h> +#include <psxspu.h> +#include <ctype.h> +#include <stddef.h> +#include <stdio.h> +#include <stdint.h> +#include <string.h> + +void sfx_free(struct sound *const s) +{ +} + +void sfx_deinit(void) +{ +} + +static int vag_ntohs(int n) +{ + return (n & 0xFF) << 24 + | (n & 0xFF00) << 16 + | (n & 0xFF0000) >> 8 + | (n & 0xFF000000) >> 24; +} + +static const char magic[] = "VAGp"; + +struct vag_header +{ + char magic_bytes[sizeof magic - 1]; + uint32_t version; + uint32_t :32; + uint32_t size; + uint32_t sample_rate; + uint8_t reserved[12]; + char name[16]; +}; + +static int get_header(struct vag_header *const h, FILE *const f) +{ + int ret = -1; + + if (!fread(h, sizeof *h, 1, f)) + { + fprintf(stderr, "VAG header not found\n"); + goto end; + } + else if (strncmp(h->magic_bytes, magic, sizeof h->magic_bytes)) + { + fprintf(stderr, "Expected magic bytes \"%s\", found: ", magic); + enum {N = sizeof h->magic_bytes / sizeof *h->magic_bytes}; + + for (size_t i = 0; i < N; i++) + { + const char c = h->magic_bytes[i]; + + fprintf(stderr, "[%zu] = %#x", i, c); + + if ((i + 1) < N) + fprintf(stderr, ", "); + + if (isalnum(c)) + fprintf(stderr, "(%c)", c); + } + + putchar('\n'); + goto end; + } + + /* File data is stored as big endian for some reason. */ + h->version = vag_ntohs(h->version); + h->sample_rate = vag_ntohs(h->sample_rate); + h->size = vag_ntohs(h->size); + ret = 0; + +end: + return ret; +} + +static sfx_spu_addr cur_addr = SPU_DATA_BASE_ADDR; + +static int upload_vag(const struct vag_header *const h, + struct sound *const s, FILE *const f) +{ + enum {SPU_RAM = 512 << 10}; + const sfx_spu_addr end_addr = cur_addr + h->size; + + if (end_addr >= SPU_RAM) + { + fprintf(stderr, "maximum SPU address exceeded (%#x, max %#x)\n", + end_addr, SPU_RAM); + return -1; + } + + s->addr = cur_addr; + s->sample_rate = h->sample_rate; + + for (size_t i = 0; i < h->size; /* See loop body. */) + { + /* From https://problemkaputt.de/psx-spx.htm#soundprocessingunitspu : + * "Sound RAM Data Transfer Fifo" supports up to 32 samples. */ + uint16_t hwords[32]; + const size_t rem = h->size - i; + const size_t n = rem > sizeof hwords ? sizeof hwords : rem; + + if (!fread(&hwords, n, 1, f)) + { + fprintf(stderr, "%s: failed to read %zu bytes\n", __func__, n); + return -1; + } + + SsUpload(&hwords, n, cur_addr); + cur_addr += n; + i += n; + } + +#if 0 + const unsigned used = cur_addr - SPU_DATA_BASE_ADDR; + printf("SPU RAM: %u bytes (%u%%)\n", used, (used * 100) / (SPU_RAM - SPU_DATA_BASE_ADDR)); +#endif + return 0; +} + +typedef volatile struct +{ + uint16_t l_vol, r_vol; + uint16_t adpcm_sample_rate; + uint16_t adpcm_start_addr; + + union + { + struct + { + uint32_t sustain_lvl :4; + uint32_t decay_shift :4; + uint32_t attack_step :2; + uint32_t attack_shift :5; + uint32_t attack_mode :1; + uint32_t release_shift :5; + uint32_t release_mode :1; + uint32_t sustain_step :2; + uint32_t sustain_shift :5; + uint32_t :1; + uint32_t sustain_dir :1; + uint32_t sustain_mode :1; + } bit; + + uint32_t mask; + } adsr; + + uint16_t adsr_vol; + uint16_t adsr_repeat_addr; +} *spu_voice; + +#define SPU_VOICE ((spu_voice)0x1f801c00) + +int sfx_play(const struct sound *const s) +{ + const sfx_spu_voice voice = s->voice; + + SPU_VOICE[voice].adpcm_sample_rate = SsFreqToPitch(s->sample_rate); + SPU_VOICE[voice].adpcm_start_addr = s->addr >> 3; + SPU_VOICE[voice].l_vol = 0x3FFF; + SPU_VOICE[voice].r_vol = 0x3FFF; + + if (voice > sizeof SPU_KEY_ON1 * 8) + SPU_KEY_ON2 = 1 << (voice - sizeof SPU_KEY_ON1 * 8); + else + SPU_KEY_ON1 = 1 << voice; + + return 0; +} + +int sfx_sound_from_fp(struct sound *const s, FILE *const f) +{ + struct vag_header h; + + if (get_header(&h, f) || upload_vag(&h, s, f)) + return -1; + + return 0; +} + +int sfx_init(void) +{ + SsInit(); + return 0; +} |
