aboutsummaryrefslogtreecommitdiff
path: root/src/sfx
diff options
context:
space:
mode:
authorXavier Del Campo Romero <xavi.dcr@tutanota.com>2021-07-03 00:49:03 +0200
committerXavier Del Campo Romero <xavi.dcr@tutanota.com>2022-03-30 08:20:20 +0200
commit6b9f686913efc3725b2690033cd4f398e07076ba (patch)
treee9aa91a6b9f617d78123ebe7ad272fc42a60d306 /src/sfx
parentc9e6ae44a9aeb89b3f48f3443d6baa80103f7445 (diff)
downloadjancity-6b9f686913efc3725b2690033cd4f398e07076ba.tar.gz
Add project source code
Diffstat (limited to 'src/sfx')
-rw-r--r--src/sfx/CMakeLists.txt37
-rw-r--r--src/sfx/inc/sfx.h22
-rw-r--r--src/sfx/ps1/inc/sfx/port.h17
-rw-r--r--src/sfx/ps1/src/sound.c188
-rw-r--r--src/sfx/sdl-1.2/inc/sfx/port.h11
-rw-r--r--src/sfx/sdl-1.2/src/sound.c71
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;
+}