summaryrefslogtreecommitdiffstats
path: root/firmware/export/pcm-internal.h
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/export/pcm-internal.h')
-rw-r--r--firmware/export/pcm-internal.h39
1 files changed, 31 insertions, 8 deletions
diff --git a/firmware/export/pcm-internal.h b/firmware/export/pcm-internal.h
index 03e5c5e6e7..2b73f64ef6 100644
--- a/firmware/export/pcm-internal.h
+++ b/firmware/export/pcm-internal.h
@@ -27,13 +27,36 @@
#ifdef HAVE_SW_VOLUME_CONTROL
/* Default settings - architecture may have other optimal values */
-#define PCM_FACTOR_BITS 15 /* Allows -73 to +6dB gain, sans 64-bit math */
+#ifndef PCM_SW_VOLUME_FRACBITS
+/* Allows -73 to +6dB gain, sans large integer math */
+#define PCM_SW_VOLUME_FRACBITS (15)
+#endif
+
+/* Constants selected based on integer math overflow avoidance */
+#if PCM_SW_VOLUME_FRACBITS <= 16
+#define PCM_FACTOR_MAX 0x00010000u
+#define PCM_FACTOR_UNITY (1u << PCM_SW_VOLUME_FRACBITS)
+#elif PCM_SW_VOLUME_FRACBITS <= 31
+#define PCM_FACTOR_MAX 0x80000000u
+#define PCM_FACTOR_UNITY (1u << PCM_SW_VOLUME_FRACBITS)
+#endif /* PCM_SW_VOLUME_FRACBITS */
+
+#ifdef PCM_SW_VOLUME_UNBUFFERED
+/* Copies buffer with volume scaling applied */
+void pcm_sw_volume_copy_buffer(void *dst, const void *src, size_t size);
+#define pcm_copy_buffer pcm_sw_volume_copy_buffer
+#else /* !PCM_SW_VOLUME_UNBUFFERED */
+#ifdef HAVE_SDL_AUDIO
+#define pcm_copy_buffer memcpy
+#endif
+#ifndef PCM_PLAY_DBL_BUF_SAMPLES
#define PCM_PLAY_DBL_BUF_SAMPLES 1024 /* Max 4KByte chunks */
+#endif
+#ifndef PCM_DBL_BUF_BSS
#define PCM_DBL_BUF_BSS /* In DRAM, uncached may be better */
-#define PCM_FACTOR_MIN 0x00000 /* Minimum final factor */
-#define PCM_FACTOR_MAX 0x10000 /* Maximum final factor */
+#endif
+#endif /* PCM_SW_VOLUME_UNBUFFERED */
-#define PCM_FACTOR_UNITY (1 << PCM_FACTOR_BITS)
#endif /* HAVE_SW_VOLUME_CONTROL */
#define PCM_SAMPLE_SIZE (2 * sizeof (int16_t))
@@ -84,22 +107,22 @@ static FORCE_INLINE enum pcm_dma_status pcm_play_call_status_cb(
static FORCE_INLINE enum pcm_dma_status
pcm_play_dma_status_callback(enum pcm_dma_status status)
{
-#ifdef HAVE_SW_VOLUME_CONTROL
+#if defined(HAVE_SW_VOLUME_CONTROL) && !defined(PCM_SW_VOLUME_UNBUFFERED)
extern enum pcm_dma_status
pcm_play_dma_status_callback_int(enum pcm_dma_status status);
return pcm_play_dma_status_callback_int(status);
#else
return pcm_play_call_status_cb(status);
-#endif /* HAVE_SW_VOLUME_CONTROL */
+#endif /* HAVE_SW_VOLUME_CONTROL && !PCM_SW_VOLUME_UNBUFFERED */
}
-#ifdef HAVE_SW_VOLUME_CONTROL
+#if defined(HAVE_SW_VOLUME_CONTROL) && !defined(PCM_SW_VOLUME_UNBUFFERED)
void pcm_play_dma_start_int(const void *addr, size_t size);
void pcm_play_dma_pause_int(bool pause);
void pcm_play_dma_stop_int(void);
void pcm_play_stop_int(void);
const void *pcm_play_dma_get_peak_buffer_int(int *count);
-#endif /* HAVE_SW_VOLUME_CONTROL */
+#endif /* HAVE_SW_VOLUME_CONTROL && !PCM_SW_VOLUME_UNBUFFERED */
/* Called by the bottom layer ISR when more data is needed. Returns true
* if a new buffer is available, false otherwise. */