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 | |
| parent | c9e6ae44a9aeb89b3f48f3443d6baa80103f7445 (diff) | |
| download | jancity-6b9f686913efc3725b2690033cd4f398e07076ba.tar.gz | |
Add project source code
Diffstat (limited to 'src/sfx')
| -rw-r--r-- | src/sfx/CMakeLists.txt | 37 | ||||
| -rw-r--r-- | src/sfx/inc/sfx.h | 22 | ||||
| -rw-r--r-- | src/sfx/ps1/inc/sfx/port.h | 17 | ||||
| -rw-r--r-- | src/sfx/ps1/src/sound.c | 188 | ||||
| -rw-r--r-- | src/sfx/sdl-1.2/inc/sfx/port.h | 11 | ||||
| -rw-r--r-- | src/sfx/sdl-1.2/src/sound.c | 71 |
6 files changed, 346 insertions, 0 deletions
diff --git a/src/sfx/CMakeLists.txt b/src/sfx/CMakeLists.txt new file mode 100644 index 0000000..3453d2e --- /dev/null +++ b/src/sfx/CMakeLists.txt @@ -0,0 +1,37 @@ +set(inc "inc") + +if(PS1_BUILD) + set(src + "ps1/src/sound.c") + set(inc ${inc} "ps1/inc") + set(privdeps system) +elseif(SDL1_2_BUILD) + set(src + "sdl-1.2/src/sound.c") + set(inc ${inc} "sdl-1.2/inc") + set(deps ${deps} SDL_mixer) + set(privdeps ${privdeps} SDL) +endif() + +add_library(sfx ${src}) +target_include_directories(sfx PUBLIC ${inc}) +target_include_directories(sfx PRIVATE ${privinc}) +target_link_libraries(sfx PUBLIC ${deps} PRIVATE ${privdeps}) + +if(PS1_BUILD) + set(modes VMODE_PAL VMODE_NTSC) + + if(VIDEO_MODE) + if(NOT "${VIDEO_MODE}" IN_LIST modes) + message(FATAL_ERROR "Invalid video mode ${VIDEO_MODE}. Available options:\n" + "${modes}\n" + "Run CMake again using one of the available video modes e.g.: cmake .. -DVIDEO_MODE=VMODE_PAL") + endif() + + target_compile_definitions(sfx PRIVATE VIDEO_MODE=${VIDEO_MODE}) + else() + message(FATAL_ERROR "Please define video mode. Available options:\n" + "${modes}\n" + "Run CMake again using one of the available video modes e.g.: cmake .. -DVIDEO_MODE=VMODE_PAL") + endif() +endif() diff --git a/src/sfx/inc/sfx.h b/src/sfx/inc/sfx.h new file mode 100644 index 0000000..b8fe44f --- /dev/null +++ b/src/sfx/inc/sfx.h @@ -0,0 +1,22 @@ +#ifndef SFX_H +#define SFX_H + +#include <sfx/port.h> +#include <stdio.h> + +#ifdef __cplusplus +extern "C" +{ +#endif + +int sfx_init(void); +int sfx_sound_from_fp(struct sound *s, FILE *f); +int sfx_play(const struct sound *s); +void sfx_free(struct sound *s); +void sfx_deinit(void); + +#ifdef __cplusplus +} +#endif + +#endif /* SFX_H */ 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; +} diff --git a/src/sfx/sdl-1.2/inc/sfx/port.h b/src/sfx/sdl-1.2/inc/sfx/port.h new file mode 100644 index 0000000..d8418f7 --- /dev/null +++ b/src/sfx/sdl-1.2/inc/sfx/port.h @@ -0,0 +1,11 @@ +#ifndef SFX_SDL1_2_H +#define SFX_SDL1_2_H + +#include <SDL/SDL_mixer.h> + +struct sound +{ + Mix_Chunk *chunk; +}; + +#endif /* SFX_SDL1_2_H */ diff --git a/src/sfx/sdl-1.2/src/sound.c b/src/sfx/sdl-1.2/src/sound.c new file mode 100644 index 0000000..e843923 --- /dev/null +++ b/src/sfx/sdl-1.2/src/sound.c @@ -0,0 +1,71 @@ +#include <sfx.h> +#include <sfx/port.h> +#include <SDL/SDL.h> +#include <SDL/SDL_mixer.h> +#include <stdio.h> + +void sfx_free(struct sound *const s) +{ + if (s && s->chunk) + Mix_FreeChunk(s->chunk); +} + +int sfx_play(const struct sound *const s) +{ + if (Mix_PlayChannel(-1, s->chunk, 0) < 0) + return -1; + + return 0; +} + +int sfx_sound_from_fp(struct sound *const s, FILE *const f) +{ + int ret = -1; + SDL_RWops *const ops = SDL_RWFromFP(f, 0); + + if (!ops) + { + fprintf(stderr, "SDL_RWFromFP: %s\n", SDL_GetError()); + goto end; + } + else if (!(s->chunk = Mix_LoadWAV_RW(ops, 0))) + { + fprintf(stderr, "Mix_LoadWAV_RW: %s\n", SDL_GetError()); + goto end; + } + + ret = 0; + +end: + SDL_FreeRW(ops); + return ret; +} + +void sfx_deinit(void) +{ + Mix_CloseAudio(); + SDL_QuitSubSystem(SDL_INIT_AUDIO); +} + +int sfx_init(void) +{ + enum {CHUNK_SZ = 4096}; + + if (SDL_InitSubSystem(SDL_INIT_AUDIO)) + { + fprintf(stderr, "SDL_InitSubSystem: %s\n", SDL_GetError()); + goto failure; + } + else if (Mix_OpenAudio(MIX_DEFAULT_FREQUENCY, + MIX_DEFAULT_FORMAT, MIX_DEFAULT_CHANNELS, CHUNK_SZ)) + { + fprintf(stderr, "Mix_OpenAudio: %s\n", SDL_GetError()); + goto failure; + } + + return 0; + +failure: + sfx_deinit(); + return -1; +} |
