summaryrefslogtreecommitdiffstats
path: root/firmware/export
diff options
context:
space:
mode:
authorMichael Sevakis <jethead71@rockbox.org>2013-04-05 04:36:05 -0400
committerMichael Sevakis <jethead71@rockbox.org>2013-04-11 22:55:16 +0200
commitf5a5b946867677de76c405ee72e2ea47e36e4c83 (patch)
tree8fb97a35059a16681b726973b4a5e13d41f96a35 /firmware/export
parenta9049a79d706dba61837ad02c7d7e3475cb6c193 (diff)
downloadrockbox-f5a5b946867677de76c405ee72e2ea47e36e4c83.tar.gz
rockbox-f5a5b946867677de76c405ee72e2ea47e36e4c83.tar.bz2
rockbox-f5a5b946867677de76c405ee72e2ea47e36e4c83.zip
Implement universal in-PCM-driver software volume control.
Implements double-buffered volume, balance and prescaling control in the main PCM driver when HAVE_SW_VOLUME_CONTROL is defined ensuring that all PCM is volume controlled and level changes are low in latency. Supports -73 to +6 dB using a 15-bit factor so that no large-integer math is needed. Low-level hardware drivers do not have to implement it themselves but parameters can be changed (currently defined in pcm-internal.h) to work best with a particular SoC or to provide different volume ranges. Volume and prescale calls should be made in the codec driver. It should appear as a normal hardware interface. PCM volume calls expect .1 dB units. Change-Id: Idf6316a64ef4fb8abcede10707e1e6c6d01d57db Reviewed-on: http://gerrit.rockbox.org/423 Reviewed-by: Michael Sevakis <jethead71@rockbox.org> Tested-by: Michael Sevakis <jethead71@rockbox.org>
Diffstat (limited to 'firmware/export')
-rw-r--r--firmware/export/config/ondavx747.h5
-rw-r--r--firmware/export/config/ondavx777.h5
-rw-r--r--firmware/export/jz4740-codec.h2
-rw-r--r--firmware/export/pcm-internal.h54
-rw-r--r--firmware/export/pcm_sw_volume.h40
-rw-r--r--firmware/export/sound.h3
6 files changed, 93 insertions, 16 deletions
diff --git a/firmware/export/config/ondavx747.h b/firmware/export/config/ondavx747.h
index d303ea5925..8499c15ce9 100644
--- a/firmware/export/config/ondavx747.h
+++ b/firmware/export/config/ondavx747.h
@@ -132,11 +132,6 @@
/* has no volume control, so we use the software ones */
#define HAVE_SW_VOLUME_CONTROL
-/* software controlled volume ranges from -73 -> 0 dB, other than that
- is controlled by hardware */
-#define SW_VOLUME_MIN -73
-#define SW_VOLUME_MAX 0
-
/* define the bitmask of hardware sample rates */
#define HW_SAMPR_CAPS (SAMPR_CAP_48 | SAMPR_CAP_44 | SAMPR_CAP_32 | \
SAMPR_CAP_24 | SAMPR_CAP_22 | SAMPR_CAP_16 | \
diff --git a/firmware/export/config/ondavx777.h b/firmware/export/config/ondavx777.h
index 33bf6442af..a254b0177c 100644
--- a/firmware/export/config/ondavx777.h
+++ b/firmware/export/config/ondavx777.h
@@ -126,11 +126,6 @@
/* has no volume control, so we use the software ones */
#define HAVE_SW_VOLUME_CONTROL
-/* software controlled volume ranges from -73 -> 0 dB, other than that
- is controlled by hardware */
-#define SW_VOLUME_MIN -73
-#define SW_VOLUME_MAX 0
-
/* define the bitmask of hardware sample rates */
#define HW_SAMPR_CAPS (SAMPR_CAP_48 | SAMPR_CAP_44 | SAMPR_CAP_32 | \
SAMPR_CAP_24 | SAMPR_CAP_22 | SAMPR_CAP_16 | \
diff --git a/firmware/export/jz4740-codec.h b/firmware/export/jz4740-codec.h
index 37d2347f5b..3c088f5bf7 100644
--- a/firmware/export/jz4740-codec.h
+++ b/firmware/export/jz4740-codec.h
@@ -24,6 +24,6 @@
#define VOLUME_MIN -730
#define VOLUME_MAX 60
-void audiohw_set_volume(int v);
+void audiohw_set_master_vol(int vol_l, int vol_r);
#endif /* __JZ4740_CODEC_H_ */
diff --git a/firmware/export/pcm-internal.h b/firmware/export/pcm-internal.h
index 397cf6832f..03e5c5e6e7 100644
--- a/firmware/export/pcm-internal.h
+++ b/firmware/export/pcm-internal.h
@@ -24,6 +24,19 @@
#include "config.h"
+#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 */
+#define PCM_PLAY_DBL_BUF_SAMPLES 1024 /* Max 4KByte chunks */
+#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 */
+
+#define PCM_FACTOR_UNITY (1 << PCM_FACTOR_BITS)
+#endif /* HAVE_SW_VOLUME_CONTROL */
+
+#define PCM_SAMPLE_SIZE (2 * sizeof (int16_t))
/* Cheapo buffer align macro to align to the 16-16 PCM size */
#define ALIGN_AUDIOBUF(start, size) \
({ (start) = (void *)(((uintptr_t)(start) + 3) & ~3); \
@@ -34,6 +47,23 @@ void pcm_do_peak_calculation(struct pcm_peaks *peaks, bool active,
/** The following are for internal use between pcm.c and target-
specific portion **/
+/* Call registered callback to obtain next buffer */
+static inline bool pcm_get_more_int(const void **addr, size_t *size)
+{
+ extern volatile pcm_play_callback_type pcm_callback_for_more;
+ pcm_play_callback_type get_more = pcm_callback_for_more;
+
+ if (UNLIKELY(!get_more))
+ return false;
+
+ *addr = NULL;
+ *size = 0;
+ get_more(addr, size);
+ ALIGN_AUDIOBUF(*addr, *size);
+
+ return *addr && *size;
+}
+
static FORCE_INLINE enum pcm_dma_status pcm_call_status_cb(
pcm_status_callback_type callback, enum pcm_dma_status status)
{
@@ -43,14 +73,34 @@ static FORCE_INLINE enum pcm_dma_status pcm_call_status_cb(
return callback(status);
}
-static FORCE_INLINE enum pcm_dma_status
-pcm_play_dma_status_callback(enum pcm_dma_status status)
+static FORCE_INLINE enum pcm_dma_status pcm_play_call_status_cb(
+ enum pcm_dma_status status)
{
extern enum pcm_dma_status
(* volatile pcm_play_status_callback)(enum pcm_dma_status);
return pcm_call_status_cb(pcm_play_status_callback, status);
}
+static FORCE_INLINE enum pcm_dma_status
+pcm_play_dma_status_callback(enum pcm_dma_status status)
+{
+#ifdef HAVE_SW_VOLUME_CONTROL
+ 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 */
+}
+
+#ifdef HAVE_SW_VOLUME_CONTROL
+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 */
+
/* Called by the bottom layer ISR when more data is needed. Returns true
* if a new buffer is available, false otherwise. */
bool pcm_play_dma_complete_callback(enum pcm_dma_status status,
diff --git a/firmware/export/pcm_sw_volume.h b/firmware/export/pcm_sw_volume.h
new file mode 100644
index 0000000000..b86e78f500
--- /dev/null
+++ b/firmware/export/pcm_sw_volume.h
@@ -0,0 +1,40 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2013 by Michael Sevakis
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#ifndef PCM_SW_VOLUME_H
+#define PCM_SW_VOLUME_H
+
+#ifdef HAVE_SW_VOLUME_CONTROL
+
+#include <audiohw.h>
+
+#define PCM_MUTE_LEVEL INT_MIN
+
+#ifdef AUDIOHW_HAVE_PRESCALER
+/* Set the prescaler value for all PCM playback */
+void pcm_set_prescaler(int prescale);
+#endif /* AUDIOHW_HAVE_PRESCALER */
+
+/* Set the per-channel volume cut/gain for all PCM playback */
+void pcm_set_master_volume(int vol_l, int vol_r);
+
+#endif /* HAVE_SW_VOLUME_CONTROL */
+
+#endif /* PCM_SW_VOLUME_H */
diff --git a/firmware/export/sound.h b/firmware/export/sound.h
index ba6120ce8f..ebf728c7c7 100644
--- a/firmware/export/sound.h
+++ b/firmware/export/sound.h
@@ -32,9 +32,6 @@ enum {
DSP_CALLBACK_SET_TREBLE,
DSP_CALLBACK_SET_CHANNEL_CONFIG,
DSP_CALLBACK_SET_STEREO_WIDTH,
-#ifdef HAVE_SW_VOLUME_CONTROL
- DSP_CALLBACK_SET_SW_VOLUME,
-#endif
};
#endif