summaryrefslogtreecommitdiffstats
path: root/firmware/export
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/export')
-rw-r--r--firmware/export/audiohw.h5
-rw-r--r--firmware/export/config.h18
-rw-r--r--firmware/export/hosted_codec.h5
-rw-r--r--firmware/export/pcm-internal.h39
-rw-r--r--firmware/export/pcm_sw_volume.h6
5 files changed, 60 insertions, 13 deletions
diff --git a/firmware/export/audiohw.h b/firmware/export/audiohw.h
index 843ac0c0c4..4379c20a79 100644
--- a/firmware/export/audiohw.h
+++ b/firmware/export/audiohw.h
@@ -111,11 +111,6 @@ struct sound_settings_info
#include "hosted_codec.h"
#endif
-#if defined(SIMULATOR) && !defined(HAVE_SW_VOLUME_CONTROL)
-/* For now, without software volume control, sim only supports mono control */
-#define AUDIOHW_HAVE_MONO_VOLUME
-#endif
-
/* convert caps into defines */
#ifdef AUDIOHW_CAPS
/* Tone controls */
diff --git a/firmware/export/config.h b/firmware/export/config.h
index 6a4a4648c8..7d7a18cc23 100644
--- a/firmware/export/config.h
+++ b/firmware/export/config.h
@@ -1139,6 +1139,24 @@ Lyre prototype 1 */
#define ROCKBOX_HAS_LOGDISKF
#endif
+#if defined(HAVE_SDL_AUDIO) \
+ && !(CONFIG_PLATFORM & PLATFORM_MAEMO5) \
+ && !defined(HAVE_SW_VOLUME_CONTROL) \
+ && CONFIG_CODEC == SWCODEC
+/* SW volume is needed for accurate control and no double buffering should be
+ * required. If target uses SW volume, then its definitions are used instead
+ * so things are as on target. */
+#define HAVE_SW_VOLUME_CONTROL
+#define PCM_SW_VOLUME_UNBUFFERED /* pcm driver itself is buffered */
+#ifdef SIMULATOR
+/* For sim, nice res for ~ -127dB..+36dB that so far covers all targets */
+#define PCM_SW_VOLUME_FRACBITS (24)
+#else
+/* For app, use fractional-only setup for -79..+0, no large-integer math */
+#define PCM_SW_VOLUME_FRACBITS (16)
+#endif /* SIMULATOR */
+#endif /* default SDL SW volume conditions */
+
/* null audiohw setting macro for when codec header is included for reasons
other than audio support */
#define AUDIOHW_SETTING(name, us, nd, st, minv, maxv, defv, expr...)
diff --git a/firmware/export/hosted_codec.h b/firmware/export/hosted_codec.h
index 72495709e8..f5e92ed297 100644
--- a/firmware/export/hosted_codec.h
+++ b/firmware/export/hosted_codec.h
@@ -21,8 +21,13 @@
#ifndef HOSTED_CODEC_H
#define HOSTED_CODEC_H
+#if defined(HAVE_SDL_AUDIO) \
+ && !(CONFIG_PLATFORM & PLATFORM_MAEMO5)
+AUDIOHW_SETTING(VOLUME, "dB", 0, 1, -80, 0, 0)
+#else
#define AUDIOHW_CAPS (MONO_VOL_CAP)
AUDIOHW_SETTING(VOLUME, "dB", 0, 1, -99, 0, 0)
+#endif /* CONFIG_PLATFORM & PLATFORM_SDL */
#if (CONFIG_PLATFORM & PLATFORM_ANDROID)
/* Bass and treble tone controls */
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. */
diff --git a/firmware/export/pcm_sw_volume.h b/firmware/export/pcm_sw_volume.h
index b5d70654a1..5088eadeb1 100644
--- a/firmware/export/pcm_sw_volume.h
+++ b/firmware/export/pcm_sw_volume.h
@@ -21,6 +21,12 @@
#ifndef PCM_SW_VOLUME_H
#define PCM_SW_VOLUME_H
+/***
+ ** Note: Only PCM drivers that are themselves buffered should use the
+ ** PCM_SW_VOLUME_UNBUFFERED configuration. This may be part of the platform,
+ ** the library or a hardware necessity. Normally, it shouldn't be used and
+ ** only the port developer can properly decide.
+ **/
#ifdef HAVE_SW_VOLUME_CONTROL
#include <audiohw.h>