From: ljsebald <ljs...@us...> - 2023-11-06 02:56:56
|
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "A pseudo Operating System for the Dreamcast.". The branch, master has been updated via da29948e4c088cbbb2e475a59e0e0ce2e18af970 (commit) via d2a80c5c8b053acd7df796ef23e5a04d6c4302a2 (commit) via a47865639ff1afed05494b69b79608794a0c61d0 (commit) from 3065978c74fe2e03df1eda3464d35a1115d8f830 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit da29948e4c088cbbb2e475a59e0e0ce2e18af970 Merge: 3065978 d2a80c5 Author: Lawrence Sebald <ljs...@us...> Date: Sun Nov 5 21:56:35 2023 -0500 Merge pull request #340 from DC-SWAT/snd_sfx_fmt Added 8-bit PCM for stream and SFX and added interleaved ADPCM support for SFX commit d2a80c5c8b053acd7df796ef23e5a04d6c4302a2 Author: DC-SWAT <sw...@21...> Date: Sun Nov 5 22:08:15 2023 +0700 Added support for 8-bit PCM stream commit a47865639ff1afed05494b69b79608794a0c61d0 Author: DC-SWAT <sw...@21...> Date: Sun Nov 5 18:12:05 2023 +0700 Added 8-bit PCM and interleaved ADPCM support for SFX ----------------------------------------------------------------------- Summary of changes: kernel/arch/dreamcast/exports-naomi.txt | 3 + kernel/arch/dreamcast/exports-pristine.txt | 3 + kernel/arch/dreamcast/include/dc/sound/sfxmgr.h | 9 +- kernel/arch/dreamcast/include/dc/sound/sound.h | 14 ++++ kernel/arch/dreamcast/include/dc/sound/stream.h | 11 +++ kernel/arch/dreamcast/sound/snd_pcm_split.s | 27 ++++++ kernel/arch/dreamcast/sound/snd_sfxmgr.c | 105 ++++++++++++++++++++---- kernel/arch/dreamcast/sound/snd_stream.c | 14 +++- 8 files changed, 163 insertions(+), 23 deletions(-) diff --git a/kernel/arch/dreamcast/exports-naomi.txt b/kernel/arch/dreamcast/exports-naomi.txt index 3a5587d..2e90505 100644 --- a/kernel/arch/dreamcast/exports-naomi.txt +++ b/kernel/arch/dreamcast/exports-naomi.txt @@ -120,6 +120,8 @@ snd_stream_shutdown snd_stream_queue_enable snd_stream_queue_disable snd_stream_start +snd_stream_start_pcm8 +snd_stream_start_adpcm snd_stream_queue_go snd_stream_stop snd_stream_poll @@ -130,6 +132,7 @@ snd_stream_reinit snd_stream_prefill snd_pcm16_split snd_pcm16_split_sq +snd_pcm8_split snd_adpcm_split # Video diff --git a/kernel/arch/dreamcast/exports-pristine.txt b/kernel/arch/dreamcast/exports-pristine.txt index 93e0c14..9c04303 100644 --- a/kernel/arch/dreamcast/exports-pristine.txt +++ b/kernel/arch/dreamcast/exports-pristine.txt @@ -163,6 +163,8 @@ snd_stream_shutdown snd_stream_queue_enable snd_stream_queue_disable snd_stream_start +snd_stream_start_pcm8 +snd_stream_start_adpcm snd_stream_queue_go snd_stream_stop snd_stream_poll @@ -173,6 +175,7 @@ snd_stream_reinit snd_stream_prefill snd_pcm16_split snd_pcm16_split_sq +snd_pcm8_split snd_adpcm_split # Video diff --git a/kernel/arch/dreamcast/include/dc/sound/sfxmgr.h b/kernel/arch/dreamcast/include/dc/sound/sfxmgr.h index 338cdcb..8737aa7 100644 --- a/kernel/arch/dreamcast/include/dc/sound/sfxmgr.h +++ b/kernel/arch/dreamcast/include/dc/sound/sfxmgr.h @@ -2,6 +2,7 @@ dc/sound/sfxmgr.h Copyright (C) 2002 Megan Potter + Copyright (C) 2023 Ruslan Rostovtsev */ @@ -9,8 +10,8 @@ \brief Basic sound effect support. This file contains declarations for doing simple sound effects. This code is - only usable for simple WAV files containing either 16-bit samples (stereo or - mono) or Yamaha ADPCM (4-bits, stereo or mono). Also, all sounds played in + only usable for simple WAV files containing either 8-bit or 16-bit samples (stereo + or mono) or Yamaha ADPCM (4-bits, stereo or mono). Also, all sounds played in this manner must be at most 65534 samples in length, as this does not handle buffer chaining or anything else complex. For more interesting stuff, you should probably look at the sound stream stuff instead. @@ -43,8 +44,8 @@ typedef uint32 sfxhnd_t; /** \brief Load a sound effect. This function loads a sound effect from a WAV file and returns a handle to - it. The sound effect can be either stereo or mono, and must either be 16-bit - uncompressed PCM samples or 4-bit Yamaha ADPCM. + it. The sound effect can be either stereo or mono, and must either be 8-bit + or 16-bit uncompressed PCM samples or 4-bit Yamaha ADPCM. \param fn The file to load. \return A handle to the sound effect on success. On error, diff --git a/kernel/arch/dreamcast/include/dc/sound/sound.h b/kernel/arch/dreamcast/include/dc/sound/sound.h index 02bcdbe..0fb8d8f 100644 --- a/kernel/arch/dreamcast/include/dc/sound/sound.h +++ b/kernel/arch/dreamcast/include/dc/sound/sound.h @@ -176,6 +176,20 @@ void snd_pcm16_split(uint32_t *data, uint32_t *left, uint32_t *right, size_t siz */ void snd_pcm16_split_sq(uint32_t *data, uintptr_t left, uintptr_t right, size_t size); +/** \brief Separates stereo PCM samples into 2 mono channels. + + Splits a buffer containing 2 interleaved channels of 8-bit PCM samples + into 2 separate buffers of 8-bit PCM samples. + + \param data Source buffer of interleaved stereo samples + \param left Destination buffer for left mono samples + \param right Destination buffer for right mono samples + \param size Size of the source buffer in bytes + + \sa snd_adpcm_split() +*/ +void snd_pcm8_split(uint32_t *data, uint32_t *left, uint32_t *right, size_t size); + /** \brief Separates stereo ADPCM samples into 2 mono channels. Splits a buffer containing 2 interleaved channels of 4-bit ADPCM samples diff --git a/kernel/arch/dreamcast/include/dc/sound/stream.h b/kernel/arch/dreamcast/include/dc/sound/stream.h index 97825ff..ad69192 100644 --- a/kernel/arch/dreamcast/include/dc/sound/stream.h +++ b/kernel/arch/dreamcast/include/dc/sound/stream.h @@ -249,6 +249,17 @@ void snd_stream_queue_go(snd_stream_hnd_t hnd); */ void snd_stream_start(snd_stream_hnd_t hnd, uint32 freq, int st); +/** \brief Start a 8-bit PCM stream. + + This function starts processing the given stream, prefilling the buffers as + necessary. In queueing mode, this will not start playback. + + \param hnd The stream to start. + \param freq The frequency of the sound. + \param st 1 if the sound is stereo, 0 if mono. +*/ +void snd_stream_start_pcm8(snd_stream_hnd_t hnd, uint32 freq, int st); + /** \brief Start a 4-bit ADPCM stream. This function starts processing the given stream, prefilling the buffers as diff --git a/kernel/arch/dreamcast/sound/snd_pcm_split.s b/kernel/arch/dreamcast/sound/snd_pcm_split.s index 1752b41..f9aad72 100644 --- a/kernel/arch/dreamcast/sound/snd_pcm_split.s +++ b/kernel/arch/dreamcast/sound/snd_pcm_split.s @@ -9,6 +9,7 @@ .section .text .globl _snd_pcm16_split .globl _snd_pcm16_split_sq_start +.globl _snd_pcm8_split .globl _snd_adpcm_split .align 2 @@ -114,6 +115,32 @@ _snd_pcm16_split_sq_start: rts nop +! +! void snd_pcm8_split(uint32_t *data, uint32_t *left, uint32_t *right, size_t size); +! +_snd_pcm8_split: + mov #-5, r1 + shld r1, r7 + mov #0, r0 + mov #16, r1 +.pcm8_pref: + add #32, r4 + pref @r4 + add #-32, r4 +.pcm8_copy: + mov.b @r4+, r3 + mov.b r3, @(r0,r5) + dt r1 + mov.b @r4+, r3 + mov.b r3, @(r0,r6) + bf/s .pcm8_copy + add #1, r0 + dt r7 + bf/s .pcm8_pref + mov #16, r1 + rts + nop + ! ! void snd_adpcm_split(uint32_t *data, uint32_t *left, uint32_t *right, size_t size); ! diff --git a/kernel/arch/dreamcast/sound/snd_sfxmgr.c b/kernel/arch/dreamcast/sound/snd_sfxmgr.c index d0eb44a..222f92c 100644 --- a/kernel/arch/dreamcast/sound/snd_sfxmgr.c +++ b/kernel/arch/dreamcast/sound/snd_sfxmgr.c @@ -96,10 +96,15 @@ void snd_sfx_unload(sfxhnd_t idx) { */ +/* WAV sample formats */ +#define WAVE_FMT_PCM 0x0001 /* PCM */ +#define WAVE_FMT_YAMAHA_ADPCM_ITU_G723 0x0014 /* ITU G.723 Yamaha ADPCM (KallistiOS) */ +#define WAVE_FMT_YAMAHA_ADPCM 0x0020 /* Yamaha ADPCM (ffmpeg) */ + /* Load a sound effect from a WAV file and return a handle to it */ sfxhnd_t snd_sfx_load(const char *fn) { file_t fd; - uint32_t len, hz; + uint32_t len, hz, rd; uint8_t *tmp; uint16_t channels, bitsize, fmt; snd_effect_t *t; @@ -146,7 +151,7 @@ sfxhnd_t snd_sfx_load(const char *fn) { return SFXHND_INVALID; } - uint32_t rd = fs_read(fd, tmp, len); + rd = fs_read(fd, tmp, len); fs_close(fd); if (rd != len) { @@ -168,23 +173,29 @@ sfxhnd_t snd_sfx_load(const char *fn) { if(channels == 1) { /* Mono PCM/ADPCM */ - t->len = len / 2; /* 16-bit samples */ + if(fmt == WAVE_FMT_YAMAHA_ADPCM_ITU_G723 || fmt == WAVE_FMT_YAMAHA_ADPCM) { + t->fmt = AICA_SM_ADPCM; + t->len = len * 2; /* 4-bit packed samples */ + } + else if(fmt == WAVE_FMT_PCM && bitsize == 8) { + t->fmt = AICA_SM_8BIT; + t->len = len; + } + else if(fmt == WAVE_FMT_PCM && bitsize == 16) { + t->fmt = AICA_SM_16BIT; + t->len = len / 2; + } else { + goto err_exit; + } t->locl = snd_mem_malloc(len); if(t->locl) spu_memload_sq(t->locl, tmp, len); t->locr = 0; - - if(fmt == 20) { - t->fmt = AICA_SM_ADPCM; - t->len *= 4; /* 4-bit packed samples */ - } - else - t->fmt = AICA_SM_16BIT; } - else if(channels == 2 && fmt == 1) { - /* Stereo PCM */ + else if(channels == 2 && fmt == WAVE_FMT_PCM && bitsize == 16) { + /* Stereo 16-bit PCM */ t->len = len / 4; /* Two stereo, 16-bit samples */ t->fmt = AICA_SM_16BIT; t->locl = snd_mem_malloc(len / 2); @@ -193,7 +204,36 @@ sfxhnd_t snd_sfx_load(const char *fn) { if(t->locl && t->locr) snd_pcm16_split_sq((uint32_t *)tmp, t->locl, t->locr, len); } - else if(channels == 2 && fmt == 20) { + else if(channels == 2 && fmt == WAVE_FMT_PCM && bitsize == 8) { + /* Stereo 8-bit PCM */ + uint32_t *left_buf = (uint32_t *)memalign(32, len / 2); + + if(left_buf == NULL) { + goto err_exit; + } + uint32_t *right_buf = (uint32_t *)memalign(32, len / 2); + + if(right_buf == NULL) { + free(left_buf); + goto err_exit; + } + snd_pcm8_split((uint32_t *)tmp, left_buf, right_buf, len); + + t->fmt = AICA_SM_8BIT; + t->len = len / 2; + t->locl = snd_mem_malloc(len / 2); + t->locr = snd_mem_malloc(len / 2); + + if(t->locl) + spu_memload_sq(t->locl, left_buf, len / 2); + + if(t->locr) + spu_memload_sq(t->locr, right_buf, len / 2); + + free(left_buf); + free(right_buf); + } + else if(channels == 2 && fmt == WAVE_FMT_YAMAHA_ADPCM_ITU_G723) { /* Stereo ADPCM ITU G.723 (channels are not interleaved) */ uint8_t *right_buf = tmp + (len / 2); int ownmem = 0; @@ -203,11 +243,8 @@ sfxhnd_t snd_sfx_load(const char *fn) { ownmem = 1; if(right_buf == NULL) { - free(tmp); - free(t); - return SFXHND_INVALID; + goto err_exit; } - memcpy(right_buf, tmp + (len / 2), len / 2); } @@ -225,6 +262,35 @@ sfxhnd_t snd_sfx_load(const char *fn) { if(ownmem) free(right_buf); } + else if(channels == 2 && fmt == WAVE_FMT_YAMAHA_ADPCM) { + /* Stereo Yamaha ADPCM (channels are interleaved) */ + uint32_t *left_buf = (uint32_t *)memalign(32, len / 2); + + if(left_buf == NULL) { + goto err_exit; + } + uint32_t *right_buf = (uint32_t *)memalign(32, len / 2); + + if(right_buf == NULL) { + free(left_buf); + goto err_exit; + } + snd_adpcm_split((uint32_t *)tmp, left_buf, right_buf, len); + + t->len = len; /* Two stereo, 4-bit samples */ + t->fmt = AICA_SM_ADPCM; + t->locl = snd_mem_malloc(len / 2); + t->locr = snd_mem_malloc(len / 2); + + if(t->locl) + spu_memload_sq(t->locl, left_buf, len / 2); + + if(t->locr) + spu_memload_sq(t->locr, right_buf, len / 2); + + free(left_buf); + free(right_buf); + } else { free(t); t = SFXHND_INVALID; @@ -236,6 +302,11 @@ sfxhnd_t snd_sfx_load(const char *fn) { LIST_INSERT_HEAD(&snd_effects, t, list); return (sfxhnd_t)t; + +err_exit: + free(tmp); + free(t); + return SFXHND_INVALID; } int snd_sfx_play_chn(int chn, sfxhnd_t idx, int vol, int pan) { diff --git a/kernel/arch/dreamcast/sound/snd_stream.c b/kernel/arch/dreamcast/sound/snd_stream.c index 2b802cb..1b5c83c 100644 --- a/kernel/arch/dreamcast/sound/snd_stream.c +++ b/kernel/arch/dreamcast/sound/snd_stream.c @@ -250,8 +250,11 @@ static void snd_stream_prefill_part(snd_stream_hnd_t hnd, uint32_t offset) { spu_memload_sq(left, buf, got); spu_memload_sq(right, buf, got); } - else if(((uintptr_t)buf & 31) || streams[hnd].type == AICA_SM_ADPCM_LS) { - if(streams[hnd].type == AICA_SM_ADPCM_LS) { + else if(((uintptr_t)buf & 31) || streams[hnd].type != AICA_SM_16BIT) { + if(streams[hnd].type == AICA_SM_8BIT) { + snd_pcm8_split(buf, sep_buffer[0], sep_buffer[1], got); + } + else if(streams[hnd].type == AICA_SM_ADPCM_LS) { snd_adpcm_split(buf, sep_buffer[0], sep_buffer[1], got); } else { @@ -469,6 +472,10 @@ void snd_stream_start(snd_stream_hnd_t hnd, uint32 freq, int st) { snd_stream_start_type(hnd, AICA_SM_16BIT, freq, st); } +void snd_stream_start_pcm8(snd_stream_hnd_t hnd, uint32 freq, int st) { + snd_stream_start_type(hnd, AICA_SM_8BIT, freq, st); +} + void snd_stream_start_adpcm(snd_stream_hnd_t hnd, uint32 freq, int st) { snd_stream_start_type(hnd, AICA_SM_ADPCM_LS, freq, st); } @@ -590,6 +597,9 @@ int snd_stream_poll(snd_stream_hnd_t hnd) { if(streams[hnd].type == AICA_SM_16BIT) { snd_pcm16_split(data, sep_buffer[0], sep_buffer[1], needed_samples * 4); } + else if(streams[hnd].type == AICA_SM_8BIT) { + snd_pcm8_split(data, sep_buffer[0], sep_buffer[1], needed_samples * 4); + } else { snd_adpcm_split(data, sep_buffer[0], sep_buffer[1], needed_samples * 4); } hooks/post-receive -- A pseudo Operating System for the Dreamcast. |