From: quzar <qu...@us...> - 2024-10-16 03:17:13
|
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 fb5168a380cac5cb99696ad38ceb4b360dedcd20 (commit) from 45525d79ba9ec9a3dd17f45a8ed3c4cf8bf77053 (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 fb5168a380cac5cb99696ad38ceb4b360dedcd20 Author: Ruslan Rostovtsev <sw...@21...> Date: Wed Oct 16 10:15:33 2024 +0700 Sound improvements and fixes (#762) * Added snd_stream_init_ex() with the ability to reduce consumption of memory. * Added direct DMA streaming capability for G1Bus-based storage devices. * Improved sound streams data transfer to the SPU. * Reduced the number of data requests for sound streams. * Improved ADPCM channel separation by 56%. * Added spu_memload_dma() as an alternative for spu_memload_sq(). * Added snd_stream_pan() to use 2 separate mono streams as one stereo or something. * Added snd_sfx_load_ex() for optimized loading of RAW files with ability to direct transfer from G1Bus-based devices. * Handling out of SPU memory in snd_sfx_load(). * Added snd_sfx_load_fd() the same as snd_sfx_load_ex() but for working with sets. * Changed SPU DMA trigger to avoid extra stalls since SH4 can frequently accesses AICA registers. * Reduced the impact and number of mutex triggers on streams. * Some minor fixes and optimizations. * Improved ADPCM channel separation by 56%. ----------------------------------------------------------------------- Summary of changes: kernel/arch/dreamcast/exports-naomi.txt | 6 + kernel/arch/dreamcast/exports-pristine.txt | 6 + kernel/arch/dreamcast/hardware/g2dma.c | 9 +- kernel/arch/dreamcast/hardware/spu.c | 54 +++++- kernel/arch/dreamcast/include/dc/sound/sfxmgr.h | 40 +++- kernel/arch/dreamcast/include/dc/sound/stream.h | 52 +++++- kernel/arch/dreamcast/include/dc/spu.h | 16 +- kernel/arch/dreamcast/sound/snd_pcm_split.s | 226 +++++++++++++++++++--- kernel/arch/dreamcast/sound/snd_sfxmgr.c | 239 +++++++++++++++++------- kernel/arch/dreamcast/sound/snd_stream.c | 233 +++++++++++++++++------ 10 files changed, 721 insertions(+), 160 deletions(-) diff --git a/kernel/arch/dreamcast/exports-naomi.txt b/kernel/arch/dreamcast/exports-naomi.txt index 38740a2f..4e3c4615 100644 --- a/kernel/arch/dreamcast/exports-naomi.txt +++ b/kernel/arch/dreamcast/exports-naomi.txt @@ -77,6 +77,7 @@ vmu_pkg_parse # SPU spu_memload spu_memload_sq +spu_memload_dma spu_memread spu_memset spu_memset_sq @@ -112,6 +113,8 @@ snd_poll_resp snd_sfx_unload_all snd_sfx_unload snd_sfx_load +snd_sfx_load_ex +snd_sfx_load_fd snd_sfx_play snd_sfx_stop_all snd_sfx_play_chn @@ -119,9 +122,11 @@ snd_sfx_stop snd_sfx_chn_alloc snd_sfx_chn_free snd_stream_set_callback +snd_stream_set_callback_direct snd_stream_filter_add snd_stream_filter_remove snd_stream_init +snd_stream_init_ex snd_stream_shutdown snd_stream_queue_enable snd_stream_queue_disable @@ -132,6 +137,7 @@ snd_stream_queue_go snd_stream_stop snd_stream_poll snd_stream_volume +snd_stream_pan snd_stream_alloc snd_stream_destroy snd_stream_reinit diff --git a/kernel/arch/dreamcast/exports-pristine.txt b/kernel/arch/dreamcast/exports-pristine.txt index f3b46562..bdb05bf9 100644 --- a/kernel/arch/dreamcast/exports-pristine.txt +++ b/kernel/arch/dreamcast/exports-pristine.txt @@ -120,6 +120,7 @@ flashrom_get_region # SPU spu_memload spu_memload_sq +spu_memload_dma spu_memread spu_memset spu_memset_sq @@ -155,6 +156,8 @@ snd_poll_resp snd_sfx_unload_all snd_sfx_unload snd_sfx_load +snd_sfx_load_ex +snd_sfx_load_fd snd_sfx_play snd_sfx_stop_all snd_sfx_play_chn @@ -162,9 +165,11 @@ snd_sfx_stop snd_sfx_chn_alloc snd_sfx_chn_free snd_stream_set_callback +snd_stream_set_callback_direct snd_stream_filter_add snd_stream_filter_remove snd_stream_init +snd_stream_init_ex snd_stream_shutdown snd_stream_queue_enable snd_stream_queue_disable @@ -175,6 +180,7 @@ snd_stream_queue_go snd_stream_stop snd_stream_poll snd_stream_volume +snd_stream_pan snd_stream_alloc snd_stream_destroy snd_stream_reinit diff --git a/kernel/arch/dreamcast/hardware/g2dma.c b/kernel/arch/dreamcast/hardware/g2dma.c index 829b76f0..5f9a301b 100644 --- a/kernel/arch/dreamcast/hardware/g2dma.c +++ b/kernel/arch/dreamcast/hardware/g2dma.c @@ -197,7 +197,14 @@ int g2_dma_transfer(void *sh4, void *g2bus, size_t length, uint32_t block, g2_dma->dma[g2chn].sh4_addr = ((uint32_t)sh4) & MASK_ADDRESS; g2_dma->dma[g2chn].size = length | RESET_ENABLED; g2_dma->dma[g2chn].dir = dir; - g2_dma->dma[g2chn].trigger_select = CPU_TRIGGER | DMA_SUSPEND_ENABLED; + + if(g2chn == G2_DMA_CHAN_SPU) { + /* Wait until fifo is empty and start. */ + g2_dma->dma[g2chn].trigger_select = HARDWARE_TRIGGER | DMA_SUSPEND_ENABLED; + } + else { + g2_dma->dma[g2chn].trigger_select = CPU_TRIGGER | DMA_SUSPEND_ENABLED; + } /* Start the DMA transfer */ g2_dma->dma[g2chn].enable = 1; diff --git a/kernel/arch/dreamcast/hardware/spu.c b/kernel/arch/dreamcast/hardware/spu.c index 8d80e5d6..b17ddde7 100644 --- a/kernel/arch/dreamcast/hardware/spu.c +++ b/kernel/arch/dreamcast/hardware/spu.c @@ -2,13 +2,15 @@ spu.c Copyright (C) 2000, 2001 Megan Potter - Copyright (C) 2023 Ruslan Rostovtsev + Copyright (C) 2023, 2024 Ruslan Rostovtsev */ +#include <kos/thread.h> #include <dc/spu.h> #include <dc/g2bus.h> #include <dc/sq.h> #include <arch/timer.h> +#include <errno.h> /* @@ -62,7 +64,12 @@ void spu_memload(uintptr_t dst, void *src_void, size_t length) { void spu_memload_sq(uintptr_t dst, void *src_void, size_t length) { uint8_t *src = (uint8_t *)src_void; - int aligned_len; + size_t aligned_len; + + if(length < 32) { + spu_memload(dst, src_void, length); + return; + } /* Round up to the nearest multiple of 4 */ if(length & 3) { @@ -91,6 +98,49 @@ void spu_memload_sq(uintptr_t dst, void *src_void, size_t length) { } } +void spu_memload_dma(uintptr_t dst, void *src_void, size_t length) { + uint8_t *src = (uint8_t *)src_void; + size_t aligned_len; + + if(length < 32) { + spu_memload(dst, src_void, length); + return; + } + if(((uintptr_t)src_void) & 31) { + spu_memload_sq(dst, src_void, length); + return; + } + + /* Round up to the nearest multiple of 4 */ + if(length & 3) { + length = (length + 4) & ~3; + } + + /* Using DMA (or SQ's on fail) for all that is divisible by 32 */ + aligned_len = length & ~31; + length &= 31; + + do { + if(spu_dma_transfer(src_void, dst, aligned_len, 1, NULL, NULL) < 0) { + if(errno == EINPROGRESS) { + thd_pass(); + continue; + } + spu_memload_sq(dst, src_void, aligned_len); + } + break; + } while (1); + + if(length > 0) { + /* Make sure the destination is in a non-cached area */ + dst |= (MEM_AREA_P2_BASE | SPU_RAM_BASE); + dst += aligned_len; + src += aligned_len; + g2_fifo_wait(); + g2_write_block_32((uint32_t *)src, dst, length >> 2); + } +} + void spu_memread(void *dst_void, uintptr_t src, size_t length) { uint8_t *dst = (uint8_t *)dst_void; diff --git a/kernel/arch/dreamcast/include/dc/sound/sfxmgr.h b/kernel/arch/dreamcast/include/dc/sound/sfxmgr.h index cfb67785..39451dcd 100644 --- a/kernel/arch/dreamcast/include/dc/sound/sfxmgr.h +++ b/kernel/arch/dreamcast/include/dc/sound/sfxmgr.h @@ -2,7 +2,7 @@ dc/sound/sfxmgr.h Copyright (C) 2002 Megan Potter - Copyright (C) 2023 Ruslan Rostovtsev + Copyright (C) 2023, 2024 Ruslan Rostovtsev Copyright (C) 2023 Andy Barajas */ @@ -30,6 +30,7 @@ __BEGIN_DECLS #include <arch/types.h> +#include <kos/fs.h> #include <stdint.h> /** \defgroup audio_sfx Sound Effects @@ -68,6 +69,43 @@ typedef uint32_t sfxhnd_t; */ sfxhnd_t snd_sfx_load(const char *fn); +/** \brief Load a sound effect without wav header. + + This function loads a sound effect from a RAW file and returns a handle to + 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. + + \warning The sound effect you are loading must be at most 65534 samples + in length and multiple by 32 bytes for each channel. + + \param fn The file to load. + \param rate The frequency of the sound. + \param bitsize The sample size (bits per sample). + \param channels Number of channels. + \return A handle to the sound effect on success. On error, + SFXHND_INVALID is returned. +*/ +sfxhnd_t snd_sfx_load_ex(const char *fn, uint32_t rate, uint16_t bitsize, uint16_t channels); + +/** \brief Load a sound effect without wav header by file handler. + + This function loads a sound effect from a RAW file and returns a handle to + 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. + + \warning The sound effect you are loading must be at most 65534 samples + in length and multiple by 32 bytes for each channel. + + \param fd The file handler. + \param len The file length. + \param rate The frequency of the sound. + \param bitsize The sample size (bits per sample). + \param channels Number of channels. + \return A handle to the sound effect on success. On error, + SFXHND_INVALID is returned. +*/ +sfxhnd_t snd_sfx_load_fd(file_t fd, size_t len, uint32_t rate, uint16_t bitsize, uint16_t channels); + /** \brief Unload a sound effect. This function unloads a previously loaded sound effect, and frees the memory diff --git a/kernel/arch/dreamcast/include/dc/sound/stream.h b/kernel/arch/dreamcast/include/dc/sound/stream.h index 38dd622c..80395f06 100644 --- a/kernel/arch/dreamcast/include/dc/sound/stream.h +++ b/kernel/arch/dreamcast/include/dc/sound/stream.h @@ -3,7 +3,7 @@ dc/sound/stream.h Copyright (C) 2002, 2004 Megan Potter Copyright (C) 2020 Lawrence Sebald - Copyright (C) 2023 Ruslan Rostovtsev + Copyright (C) 2023, 2024 Ruslan Rostovtsev */ @@ -71,6 +71,21 @@ typedef int snd_stream_hnd_t; typedef void *(*snd_stream_callback_t)(snd_stream_hnd_t hnd, int smp_req, int *smp_recv); +/** \brief Direct stream data transfer callback type. + + Functions for providing stream data will be of this type, and can be + registered with snd_stream_set_callback_direct(). + + \param hnd The stream handle being referred to. + \param left Left channel buffer address on AICA side. + \param right Right channel buffer address on AICA side. + \param size_req Requested size for each channel. + \retval -1 On failure. + \retval size_recv On success, received size. +*/ +typedef size_t (*snd_stream_callback_direct_t)(snd_stream_hnd_t hnd, + uintptr_t left, uintptr_t right, size_t size_req); + /** \brief Set the callback for a given stream. This function sets the get data callback function for a given stream, @@ -81,6 +96,16 @@ typedef void *(*snd_stream_callback_t)(snd_stream_hnd_t hnd, int smp_req, */ void snd_stream_set_callback(snd_stream_hnd_t hnd, snd_stream_callback_t cb); +/** \brief Set the callback for a given stream with direct transfer. + + This function sets the get data callback function for a given stream, + overwriting any old callback that may have been in place. + + \param hnd The stream handle for the callback. + \param cb A pointer to the callback function. +*/ +void snd_stream_set_callback_direct(snd_stream_hnd_t hnd, snd_stream_callback_direct_t cb); + /** \brief Set the user data for a given stream. This function sets the user data pointer for the given stream, overwriting @@ -177,6 +202,19 @@ void snd_stream_prefill(snd_stream_hnd_t hnd); */ int snd_stream_init(void); +/** \brief Initialize the stream system with limits. + + The same as \ref snd_stream_init but it can either reduce or not allocate + the buffer for splitting the stereo stream at all. + + \param channels Max channels for any streams. + \param buffer_size Max channel buffer size for any streams. + + \retval -1 On failure. + \retval 0 On success. +*/ +int snd_stream_init_ex(int channels, size_t buffer_size); + /** \brief Shut down the stream system. This function shuts down the stream system and frees the memory associated @@ -189,7 +227,7 @@ void snd_stream_shutdown(void); This function allocates a stream and sets its parameters. \param cb The get data callback for the stream. - \param bufsize The size of the buffer for the stream. + \param bufsize The size of the buffer for each channel of the stream. \return A handle to the new stream on success, SND_STREAM_INVALID on failure. */ @@ -309,6 +347,16 @@ int snd_stream_poll(snd_stream_hnd_t hnd); */ void snd_stream_volume(snd_stream_hnd_t hnd, int vol); +/** \brief Set the panning on the stream. + + This function sets the panning of the specified stream. + + \param hnd The stream to set volume on. + \param left_pan The left panning to set. Valid values are 0-255. + \param right_pan The right panning to set. Valid values are 0-255. +*/ +void snd_stream_pan(snd_stream_hnd_t hnd, int left_pan, int right_pan); + /** @} */ __END_DECLS diff --git a/kernel/arch/dreamcast/include/dc/spu.h b/kernel/arch/dreamcast/include/dc/spu.h index ee081100..b2232093 100644 --- a/kernel/arch/dreamcast/include/dc/spu.h +++ b/kernel/arch/dreamcast/include/dc/spu.h @@ -2,7 +2,7 @@ dc/spu.h Copyright (C) 2000, 2001 Megan Potter - Copyright (C) 2023 Ruslan Rostovtsev + Copyright (C) 2023, 2024 Ruslan Rostovtsev */ @@ -47,7 +47,7 @@ __BEGIN_DECLS void spu_memload(uintptr_t to, void *from, size_t length); -/** \brief Copy a block of data to sound RAM. +/** \brief Copy a block of data to sound RAM by using the Store Queues. This function acts much like memcpy() but copies to the sound RAM area by using the Store Queues. @@ -60,6 +60,18 @@ void spu_memload(uintptr_t to, void *from, size_t length); */ void spu_memload_sq(uintptr_t to, void *from, size_t length); +/** \brief Copy a block of data to sound RAM by using DMA (or SQ on fails). + + This function acts much like memcpy() but copies to the sound RAM area + by using the DMA. If DMA fails, then will be used the Store Queues. + + \param to The offset in sound RAM to copy to. Do not include + the 0xA0800000 part, it is implied. + \param from A pointer to copy from. + \param length The number of bytes to copy. Must be a multiple of 32. +*/ +void spu_memload_dma(uintptr_t to, void *from, size_t length); + /** \brief Copy a block of data from sound RAM. This function acts much like memcpy() but copies from the sound RAM area. diff --git a/kernel/arch/dreamcast/sound/snd_pcm_split.s b/kernel/arch/dreamcast/sound/snd_pcm_split.s index 089b568c..2fd6faec 100644 --- a/kernel/arch/dreamcast/sound/snd_pcm_split.s +++ b/kernel/arch/dreamcast/sound/snd_pcm_split.s @@ -1,7 +1,7 @@ ! KallistiOS ##version## ! ! arch/dreamcast/sound/snd_pcm_split.s -! Copyright (C) 2023 Ruslan Rostovtsev +! Copyright (C) 2023, 2024 Ruslan Rostovtsev ! ! Optimized SH4 assembler code for separating stereo 8/16-bit PCM and ! stereo 4-bit ADPCM into independent single channels. @@ -67,7 +67,7 @@ _snd_pcm16_split: ! ! void snd_pcm8_split(uint32_t *data, uint32_t *left, uint32_t *right, size_t size); ! - .align 2 + .align 2 _snd_pcm8_split: mov #-5, r1 shld r1, r7 @@ -94,44 +94,216 @@ _snd_pcm8_split: ! ! void snd_adpcm_split(uint32_t *data, uint32_t *left, uint32_t *right, size_t size); ! - .align 2 + .align 2 _snd_adpcm_split: mov #-5, r1 shld r1, r7 + mov.l r8, @-r15 + mov.l r9, @-r15 mov.l r10, @-r15 - mov #16, r1 + mov.l r11, @-r15 + mov #4, r1 + mov #15, r11 .adpcm_pref: add #32, r4 pref @r4 add #-32, r4 .adpcm_copy: dt r1 - mov.w @r4+, r10 - mov r10, r0 - and #0xf0, r0 - mov r0, r2 - shlr2 r2 - mov r10, r0 - shlr2 r2 - and #0x0f, r0 + !!! src = *data++; + mov.l @r4+, r0 + + !!! dst_r = src & 0xf mov r0, r3 - shlr8 r10 - mov r10, r0 - and #0xf0, r0 - or r0, r2 - mov.b r2, @r5 - add #1, r5 - mov r10, r0 - and #0x0f, r0 - shll2 r0 - shll2 r0 - or r0, r3 - mov.b r3, @r6 + and r11, r3 + + !!! src >>= 4 + mov #-4, r10 + shld r10, r0 + + !!! dst_l = src & 0xf + mov r0, r2 + and r11, r2 + + !!! src >>= 4 + shld r10, r0 + + !!! tmp_r = src & 0xf + mov r0, r9 + and r11, r9 + + !!! src >>= 4 + shld r10, r0 + + !!! tmp_l = src & 0xf + mov r0, r8 + and r11, r8 + + !!! src >>= 4 + shld r10, r0 + + !!! tmp <<= 4, + mov #4, r10 + shld r10, r9 + shld r10, r8 + + !!! dst |= tmp + or r9, r3 + or r8, r2 + + !!! tmp_r = src & 0xf + mov r0, r9 + and r11, r9 + ...<truncated>... hooks/post-receive -- A pseudo Operating System for the Dreamcast. |