summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--firmware/drivers/audio/sdl.c47
-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
-rw-r--r--firmware/pcm.c7
-rw-r--r--firmware/pcm_sw_volume.c121
-rw-r--r--firmware/target/hosted/sdl/pcm-sdl.c23
9 files changed, 177 insertions, 94 deletions
diff --git a/firmware/drivers/audio/sdl.c b/firmware/drivers/audio/sdl.c
index 9bb399b910..ae66380d16 100644
--- a/firmware/drivers/audio/sdl.c
+++ b/firmware/drivers/audio/sdl.c
@@ -23,36 +23,48 @@
23#include "config.h" 23#include "config.h"
24#include "sound.h" 24#include "sound.h"
25#include "pcm_sampr.h" 25#include "pcm_sampr.h"
26#ifdef HAVE_SW_VOLUME_CONTROL
27#include "pcm_sw_volume.h"
28#include "fixedpoint.h"
29#endif
26 30
27/** 31/**
28 * Audio Hardware api. Make them do nothing as we cannot properly simulate with 32 * Audio Hardware api. Make some of them do nothing as we cannot properly
29 * SDL. if we used DSP we would run code that doesn't actually run on the target 33 * simulate with SDL. if we used DSP we would run code that doesn't actually
34 * run on the target
30 **/ 35 **/
31
32#ifdef HAVE_SW_VOLUME_CONTROL 36#ifdef HAVE_SW_VOLUME_CONTROL
33#include "pcm_sw_volume.h" 37static int sdl_volume_level(int volume)
34
35void audiohw_set_volume(int vol_l, int vol_r)
36{ 38{
37 pcm_set_master_volume(vol_l, vol_r); 39 int shift = (1 - sound_numdecimals(SOUND_VOLUME)) << 16;
40 int minvol = fp_mul(sound_min(SOUND_VOLUME), fp_exp10(shift, 16), 16);
41 return volume <= minvol ? INT_MIN : volume;
38} 42}
43#endif /* HAVE_SW_VOLUME_CONTROL */
39 44
40#else /* ndef HAVE_SW_VOLUME_CONTROL */ 45#if defined(AUDIOHW_HAVE_MONO_VOLUME)
41
42
43void audiohw_set_volume(int volume) 46void audiohw_set_volume(int volume)
44{ 47{
45#if CONFIG_CODEC == SWCODEC 48#ifdef HAVE_SW_VOLUME_CONTROL
49 volume = sdl_volume_level(volume);
50 pcm_set_master_volume(volume, volume);
51#elif CONFIG_CODEC == SWCODEC
46 extern void pcm_set_mixer_volume(int volume); 52 extern void pcm_set_mixer_volume(int volume);
47 pcm_set_mixer_volume(volume); 53 pcm_set_mixer_volume(volume);
48#endif 54#endif
49 (void)volume; 55 (void)volume;
50} 56}
51#endif /* HAVE_SW_VOLUME_CONTROL */ 57#else /* !AUDIOHW_HAVE_MONO_VOLUME */
52 58void audiohw_set_volume(int vol_l, int vol_r)
53/** 59{
54 * stubs here, for the simulator 60#ifdef HAVE_SW_VOLUME_CONTROL
55 **/ 61 vol_l = sdl_volume_level(vol_l);
62 vol_r = sdl_volume_level(vol_r);
63 pcm_set_master_volume(vol_l, vol_r);
64#endif
65 (void)vol_l; (void)vol_r;
66}
67#endif /* AUDIOHW_HAVE_MONO_VOLUME */
56 68
57#if defined(AUDIOHW_HAVE_PRESCALER) 69#if defined(AUDIOHW_HAVE_PRESCALER)
58void audiohw_set_prescaler(int value) 70void audiohw_set_prescaler(int value)
@@ -62,7 +74,8 @@ void audiohw_set_prescaler(int value)
62#endif 74#endif
63 (void)value; 75 (void)value;
64} 76}
65#endif 77#endif /* AUDIOHW_HAVE_PRESCALER */
78
66#if defined(AUDIOHW_HAVE_BALANCE) 79#if defined(AUDIOHW_HAVE_BALANCE)
67void audiohw_set_balance(int value) { (void)value; } 80void audiohw_set_balance(int value) { (void)value; }
68#endif 81#endif
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
111#include "hosted_codec.h" 111#include "hosted_codec.h"
112#endif 112#endif
113 113
114#if defined(SIMULATOR) && !defined(HAVE_SW_VOLUME_CONTROL)
115/* For now, without software volume control, sim only supports mono control */
116#define AUDIOHW_HAVE_MONO_VOLUME
117#endif
118
119/* convert caps into defines */ 114/* convert caps into defines */
120#ifdef AUDIOHW_CAPS 115#ifdef AUDIOHW_CAPS
121/* Tone controls */ 116/* 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 */
1139#define ROCKBOX_HAS_LOGDISKF 1139#define ROCKBOX_HAS_LOGDISKF
1140#endif 1140#endif
1141 1141
1142#if defined(HAVE_SDL_AUDIO) \
1143 && !(CONFIG_PLATFORM & PLATFORM_MAEMO5) \
1144 && !defined(HAVE_SW_VOLUME_CONTROL) \
1145 && CONFIG_CODEC == SWCODEC
1146/* SW volume is needed for accurate control and no double buffering should be
1147 * required. If target uses SW volume, then its definitions are used instead
1148 * so things are as on target. */
1149#define HAVE_SW_VOLUME_CONTROL
1150#define PCM_SW_VOLUME_UNBUFFERED /* pcm driver itself is buffered */
1151#ifdef SIMULATOR
1152/* For sim, nice res for ~ -127dB..+36dB that so far covers all targets */
1153#define PCM_SW_VOLUME_FRACBITS (24)
1154#else
1155/* For app, use fractional-only setup for -79..+0, no large-integer math */
1156#define PCM_SW_VOLUME_FRACBITS (16)
1157#endif /* SIMULATOR */
1158#endif /* default SDL SW volume conditions */
1159
1142/* null audiohw setting macro for when codec header is included for reasons 1160/* null audiohw setting macro for when codec header is included for reasons
1143 other than audio support */ 1161 other than audio support */
1144#define AUDIOHW_SETTING(name, us, nd, st, minv, maxv, defv, expr...) 1162#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 @@
21#ifndef HOSTED_CODEC_H 21#ifndef HOSTED_CODEC_H
22#define HOSTED_CODEC_H 22#define HOSTED_CODEC_H
23 23
24#if defined(HAVE_SDL_AUDIO) \
25 && !(CONFIG_PLATFORM & PLATFORM_MAEMO5)
26AUDIOHW_SETTING(VOLUME, "dB", 0, 1, -80, 0, 0)
27#else
24#define AUDIOHW_CAPS (MONO_VOL_CAP) 28#define AUDIOHW_CAPS (MONO_VOL_CAP)
25AUDIOHW_SETTING(VOLUME, "dB", 0, 1, -99, 0, 0) 29AUDIOHW_SETTING(VOLUME, "dB", 0, 1, -99, 0, 0)
30#endif /* CONFIG_PLATFORM & PLATFORM_SDL */
26 31
27#if (CONFIG_PLATFORM & PLATFORM_ANDROID) 32#if (CONFIG_PLATFORM & PLATFORM_ANDROID)
28/* Bass and treble tone controls */ 33/* 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 @@
27#ifdef HAVE_SW_VOLUME_CONTROL 27#ifdef HAVE_SW_VOLUME_CONTROL
28/* Default settings - architecture may have other optimal values */ 28/* Default settings - architecture may have other optimal values */
29 29
30#define PCM_FACTOR_BITS 15 /* Allows -73 to +6dB gain, sans 64-bit math */ 30#ifndef PCM_SW_VOLUME_FRACBITS
31/* Allows -73 to +6dB gain, sans large integer math */
32#define PCM_SW_VOLUME_FRACBITS (15)
33#endif
34
35/* Constants selected based on integer math overflow avoidance */
36#if PCM_SW_VOLUME_FRACBITS <= 16
37#define PCM_FACTOR_MAX 0x00010000u
38#define PCM_FACTOR_UNITY (1u << PCM_SW_VOLUME_FRACBITS)
39#elif PCM_SW_VOLUME_FRACBITS <= 31
40#define PCM_FACTOR_MAX 0x80000000u
41#define PCM_FACTOR_UNITY (1u << PCM_SW_VOLUME_FRACBITS)
42#endif /* PCM_SW_VOLUME_FRACBITS */
43
44#ifdef PCM_SW_VOLUME_UNBUFFERED
45/* Copies buffer with volume scaling applied */
46void pcm_sw_volume_copy_buffer(void *dst, const void *src, size_t size);
47#define pcm_copy_buffer pcm_sw_volume_copy_buffer
48#else /* !PCM_SW_VOLUME_UNBUFFERED */
49#ifdef HAVE_SDL_AUDIO
50#define pcm_copy_buffer memcpy
51#endif
52#ifndef PCM_PLAY_DBL_BUF_SAMPLES
31#define PCM_PLAY_DBL_BUF_SAMPLES 1024 /* Max 4KByte chunks */ 53#define PCM_PLAY_DBL_BUF_SAMPLES 1024 /* Max 4KByte chunks */
54#endif
55#ifndef PCM_DBL_BUF_BSS
32#define PCM_DBL_BUF_BSS /* In DRAM, uncached may be better */ 56#define PCM_DBL_BUF_BSS /* In DRAM, uncached may be better */
33#define PCM_FACTOR_MIN 0x00000 /* Minimum final factor */ 57#endif
34#define PCM_FACTOR_MAX 0x10000 /* Maximum final factor */ 58#endif /* PCM_SW_VOLUME_UNBUFFERED */
35 59
36#define PCM_FACTOR_UNITY (1 << PCM_FACTOR_BITS)
37#endif /* HAVE_SW_VOLUME_CONTROL */ 60#endif /* HAVE_SW_VOLUME_CONTROL */
38 61
39#define PCM_SAMPLE_SIZE (2 * sizeof (int16_t)) 62#define PCM_SAMPLE_SIZE (2 * sizeof (int16_t))
@@ -84,22 +107,22 @@ static FORCE_INLINE enum pcm_dma_status pcm_play_call_status_cb(
84static FORCE_INLINE enum pcm_dma_status 107static FORCE_INLINE enum pcm_dma_status
85pcm_play_dma_status_callback(enum pcm_dma_status status) 108pcm_play_dma_status_callback(enum pcm_dma_status status)
86{ 109{
87#ifdef HAVE_SW_VOLUME_CONTROL 110#if defined(HAVE_SW_VOLUME_CONTROL) && !defined(PCM_SW_VOLUME_UNBUFFERED)
88 extern enum pcm_dma_status 111 extern enum pcm_dma_status
89 pcm_play_dma_status_callback_int(enum pcm_dma_status status); 112 pcm_play_dma_status_callback_int(enum pcm_dma_status status);
90 return pcm_play_dma_status_callback_int(status); 113 return pcm_play_dma_status_callback_int(status);
91#else 114#else
92 return pcm_play_call_status_cb(status); 115 return pcm_play_call_status_cb(status);
93#endif /* HAVE_SW_VOLUME_CONTROL */ 116#endif /* HAVE_SW_VOLUME_CONTROL && !PCM_SW_VOLUME_UNBUFFERED */
94} 117}
95 118
96#ifdef HAVE_SW_VOLUME_CONTROL 119#if defined(HAVE_SW_VOLUME_CONTROL) && !defined(PCM_SW_VOLUME_UNBUFFERED)
97void pcm_play_dma_start_int(const void *addr, size_t size); 120void pcm_play_dma_start_int(const void *addr, size_t size);
98void pcm_play_dma_pause_int(bool pause); 121void pcm_play_dma_pause_int(bool pause);
99void pcm_play_dma_stop_int(void); 122void pcm_play_dma_stop_int(void);
100void pcm_play_stop_int(void); 123void pcm_play_stop_int(void);
101const void *pcm_play_dma_get_peak_buffer_int(int *count); 124const void *pcm_play_dma_get_peak_buffer_int(int *count);
102#endif /* HAVE_SW_VOLUME_CONTROL */ 125#endif /* HAVE_SW_VOLUME_CONTROL && !PCM_SW_VOLUME_UNBUFFERED */
103 126
104/* Called by the bottom layer ISR when more data is needed. Returns true 127/* Called by the bottom layer ISR when more data is needed. Returns true
105 * if a new buffer is available, false otherwise. */ 128 * 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 @@
21#ifndef PCM_SW_VOLUME_H 21#ifndef PCM_SW_VOLUME_H
22#define PCM_SW_VOLUME_H 22#define PCM_SW_VOLUME_H
23 23
24/***
25 ** Note: Only PCM drivers that are themselves buffered should use the
26 ** PCM_SW_VOLUME_UNBUFFERED configuration. This may be part of the platform,
27 ** the library or a hardware necessity. Normally, it shouldn't be used and
28 ** only the port developer can properly decide.
29 **/
24#ifdef HAVE_SW_VOLUME_CONTROL 30#ifdef HAVE_SW_VOLUME_CONTROL
25 31
26#include <audiohw.h> 32#include <audiohw.h>
diff --git a/firmware/pcm.c b/firmware/pcm.c
index 6bf0e12c8d..e095ab2cea 100644
--- a/firmware/pcm.c
+++ b/firmware/pcm.c
@@ -106,8 +106,9 @@ static void pcm_play_data_start_int(const void *addr, size_t size);
106static void pcm_play_pause_int(bool play); 106static void pcm_play_pause_int(bool play);
107void pcm_play_stop_int(void); 107void pcm_play_stop_int(void);
108 108
109#ifndef HAVE_SW_VOLUME_CONTROL 109#if !defined(HAVE_SW_VOLUME_CONTROL) || defined(PCM_SW_VOLUME_UNBUFFERED)
110/** Standard hw volume control functions - otherwise, see pcm_sw_volume.c **/ 110/** Standard hw volume/unbuffered control functions - otherwise, see
111 ** pcm_sw_volume.c **/
111static inline void pcm_play_dma_start_int(const void *addr, size_t size) 112static inline void pcm_play_dma_start_int(const void *addr, size_t size)
112{ 113{
113 pcm_play_dma_start(addr, size); 114 pcm_play_dma_start(addr, size);
@@ -150,7 +151,7 @@ bool pcm_play_dma_complete_callback(enum pcm_dma_status status,
150 pcm_play_stop_int(); 151 pcm_play_stop_int();
151 return false; 152 return false;
152} 153}
153#endif /* ndef HAVE_SW_VOLUME_CONTROL */ 154#endif /* !HAVE_SW_VOLUME_CONTROL || PCM_SW_VOLUME_UNBUFFERED */
154 155
155static void pcm_play_data_start_int(const void *addr, size_t size) 156static void pcm_play_data_start_int(const void *addr, size_t size)
156{ 157{
diff --git a/firmware/pcm_sw_volume.c b/firmware/pcm_sw_volume.c
index 473e63c7cb..eb77fe0c6b 100644
--- a/firmware/pcm_sw_volume.c
+++ b/firmware/pcm_sw_volume.c
@@ -26,63 +26,91 @@
26#include "fixedpoint.h" 26#include "fixedpoint.h"
27#include "pcm_sw_volume.h" 27#include "pcm_sw_volume.h"
28 28
29/* source buffer from client */ 29/* volume factors set by pcm_set_master_volume */
30static const void * volatile src_buf_addr = NULL; 30static uint32_t vol_factor_l = 0, vol_factor_r = 0;
31static size_t volatile src_buf_rem = 0;
32 31
33#define PCM_PLAY_DBL_BUF_SIZE (PCM_PLAY_DBL_BUF_SAMPLE*PCM_SAMPLE_SIZE)
34
35/* double buffer and frame length control */
36static int16_t pcm_dbl_buf[2][PCM_PLAY_DBL_BUF_SAMPLES*2]
37 PCM_DBL_BUF_BSS MEM_ALIGN_ATTR;
38static size_t pcm_dbl_buf_size[2];
39static int pcm_dbl_buf_num = 0;
40static size_t frame_size;
41static unsigned int frame_count, frame_err, frame_frac;
42
43static int32_t vol_factor_l = 0, vol_factor_r = 0;
44#ifdef AUDIOHW_HAVE_PRESCALER 32#ifdef AUDIOHW_HAVE_PRESCALER
45static int32_t prescale_factor = PCM_FACTOR_UNITY; 33/* prescale factor set by pcm_set_prescaler */
34static uint32_t prescale_factor = PCM_FACTOR_UNITY;
46#endif /* AUDIOHW_HAVE_PRESCALER */ 35#endif /* AUDIOHW_HAVE_PRESCALER */
47 36
48/* pcm scaling factors */ 37/* final pcm scaling factors */
49static int32_t pcm_factor_l = 0, pcm_factor_r = 0; 38static uint32_t pcm_factor_l = 0, pcm_factor_r = 0;
50
51#define PCM_FACTOR_CLIP(f) \
52 MAX(MIN((f), PCM_FACTOR_MAX), PCM_FACTOR_MIN)
53#define PCM_SCALE_SAMPLE(f, s) \
54 (((f) * (s) + PCM_FACTOR_UNITY/2) >> PCM_FACTOR_BITS)
55 39
40/***
41 ** Volume scaling routine
42 ** If unbuffered, called externally by pcm driver
43 **/
56 44
57/* TODO: #include CPU-optimized routines and move this to /firmware/asm */ 45/* TODO: #include CPU-optimized routines and move this to /firmware/asm */
58static inline void pcm_copy_buffer(int16_t *dst, const int16_t *src, 46
59 size_t size) 47#if PCM_SW_VOLUME_FRACBITS <= 16
48#define PCM_F_T int32_t
49#else
50#define PCM_F_T int64_t /* Requires large integer math */
51#endif /* PCM_SW_VOLUME_FRACBITS */
52
53static inline int32_t pcm_scale_sample(PCM_F_T f, int32_t s)
60{ 54{
61 int32_t factor_l = pcm_factor_l; 55 return (f * s + (PCM_F_T)PCM_FACTOR_UNITY/2) >> PCM_SW_VOLUME_FRACBITS;
62 int32_t factor_r = pcm_factor_r; 56}
63 57
64 if (LIKELY(factor_l <= PCM_FACTOR_UNITY && factor_r <= PCM_FACTOR_UNITY)) 58/* Copies buffer with volume scaling applied */
59#ifndef PCM_SW_VOLUME_UNBUFFERED
60static inline
61#endif
62void pcm_sw_volume_copy_buffer(void *dst, const void *src, size_t size)
63{
64 int16_t *d = dst;
65 const int16_t *s = src;
66 uint32_t factor_l = pcm_factor_l;
67 uint32_t factor_r = pcm_factor_r;
68
69 if (factor_l == PCM_FACTOR_UNITY && factor_r == PCM_FACTOR_UNITY)
70 {
71 /* Both unity */
72 memcpy(dst, src, size);
73 }
74 else if (LIKELY(factor_l <= PCM_FACTOR_UNITY &&
75 factor_r <= PCM_FACTOR_UNITY))
65 { 76 {
66 /* All cut or unity */ 77 /* Either cut, both <= UNITY */
67 while (size) 78 while (size)
68 { 79 {
69 *dst++ = PCM_SCALE_SAMPLE(factor_l, *src++); 80 *d++ = pcm_scale_sample(factor_l, *s++);
70 *dst++ = PCM_SCALE_SAMPLE(factor_r, *src++); 81 *d++ = pcm_scale_sample(factor_r, *s++);
71 size -= PCM_SAMPLE_SIZE; 82 size -= PCM_SAMPLE_SIZE;
72 } 83 }
73 } 84 }
74 else 85 else
75 { 86 {
76 /* Any positive gain requires clipping */ 87 /* Either positive gain, requires clipping */
77 while (size) 88 while (size)
78 { 89 {
79 *dst++ = clip_sample_16(PCM_SCALE_SAMPLE(factor_l, *src++)); 90 *d++ = clip_sample_16(pcm_scale_sample(factor_l, *s++));
80 *dst++ = clip_sample_16(PCM_SCALE_SAMPLE(factor_r, *src++)); 91 *d++ = clip_sample_16(pcm_scale_sample(factor_r, *s++));
81 size -= PCM_SAMPLE_SIZE; 92 size -= PCM_SAMPLE_SIZE;
82 } 93 }
83 } 94 }
84} 95}
85 96
97#ifndef PCM_SW_VOLUME_UNBUFFERED
98/* source buffer from client */
99static const void * volatile src_buf_addr = NULL;
100static size_t volatile src_buf_rem = 0;
101
102#define PCM_PLAY_DBL_BUF_SIZE (PCM_PLAY_DBL_BUF_SAMPLE*PCM_SAMPLE_SIZE)
103
104/* double buffer and frame length control */
105static int16_t pcm_dbl_buf[2][PCM_PLAY_DBL_BUF_SAMPLES*2]
106 PCM_DBL_BUF_BSS MEM_ALIGN_ATTR;
107static size_t pcm_dbl_buf_size[2];
108static int pcm_dbl_buf_num = 0;
109static size_t frame_size;
110static unsigned int frame_count, frame_err, frame_frac;
111
112/** Overrides of certain functions in pcm.c and pcm-internal.h **/
113
86bool pcm_play_dma_complete_callback(enum pcm_dma_status status, 114bool pcm_play_dma_complete_callback(enum pcm_dma_status status,
87 const void **addr, size_t *size) 115 const void **addr, size_t *size)
88{ 116{
@@ -155,7 +183,7 @@ pcm_play_dma_status_callback_int(enum pcm_dma_status status)
155 183
156 pcm_dbl_buf_num ^= 1; 184 pcm_dbl_buf_num ^= 1;
157 pcm_dbl_buf_size[pcm_dbl_buf_num] = size; 185 pcm_dbl_buf_size[pcm_dbl_buf_num] = size;
158 pcm_copy_buffer(pcm_dbl_buf[pcm_dbl_buf_num], addr, size); 186 pcm_sw_volume_copy_buffer(pcm_dbl_buf[pcm_dbl_buf_num], addr, size);
159 187
160 return PCM_DMAST_OK; 188 return PCM_DMAST_OK;
161} 189}
@@ -216,27 +244,36 @@ const void * pcm_play_dma_get_peak_buffer_int(int *count)
216 return NULL; 244 return NULL;
217} 245}
218 246
247#endif /* PCM_SW_VOLUME_UNBUFFERED */
248
249
250/** Internal **/
251
219/* Return the scale factor corresponding to the centibel level */ 252/* Return the scale factor corresponding to the centibel level */
220static int32_t pcm_centibels_to_factor(int volume) 253static uint32_t pcm_centibels_to_factor(int volume)
221{ 254{
222 if (volume == PCM_MUTE_LEVEL) 255 if (volume == PCM_MUTE_LEVEL)
223 return 0; /* mute */ 256 return 0; /* mute */
224 257
225 /* Centibels -> fixedpoint */ 258 /* Centibels -> fixedpoint */
226 return fp_factor(fp_div(volume, 10, PCM_FACTOR_BITS), PCM_FACTOR_BITS); 259 return (uint32_t)fp_factor(fp_div(volume, 10, PCM_SW_VOLUME_FRACBITS),
260 PCM_SW_VOLUME_FRACBITS);
227} 261}
228 262
263
264/** Public functions **/
265
229/* Produce final pcm scale factor */ 266/* Produce final pcm scale factor */
230static void pcm_sync_prescaler(void) 267static void pcm_sync_prescaler(void)
231{ 268{
232 int32_t factor_l = vol_factor_l; 269 uint32_t factor_l = vol_factor_l;
233 int32_t factor_r = vol_factor_r; 270 uint32_t factor_r = vol_factor_r;
234#ifdef AUDIOHW_HAVE_PRESCALER 271#ifdef AUDIOHW_HAVE_PRESCALER
235 factor_l = fp_mul(prescale_factor, factor_l, PCM_FACTOR_BITS); 272 factor_l = fp_mul(prescale_factor, factor_l, PCM_SW_VOLUME_FRACBITS);
236 factor_r = fp_mul(prescale_factor, factor_r, PCM_FACTOR_BITS); 273 factor_r = fp_mul(prescale_factor, factor_r, PCM_SW_VOLUME_FRACBITS);
237#endif 274#endif
238 pcm_factor_l = PCM_FACTOR_CLIP(factor_l); 275 pcm_factor_l = MIN(factor_l, PCM_FACTOR_MAX);
239 pcm_factor_r = PCM_FACTOR_CLIP(factor_r); 276 pcm_factor_r = MIN(factor_r, PCM_FACTOR_MAX);
240} 277}
241 278
242#ifdef AUDIOHW_HAVE_PRESCALER 279#ifdef AUDIOHW_HAVE_PRESCALER
diff --git a/firmware/target/hosted/sdl/pcm-sdl.c b/firmware/target/hosted/sdl/pcm-sdl.c
index beefc7818c..290dffbb95 100644
--- a/firmware/target/hosted/sdl/pcm-sdl.c
+++ b/firmware/target/hosted/sdl/pcm-sdl.c
@@ -51,12 +51,6 @@
51extern bool debug_audio; 51extern bool debug_audio;
52#endif 52#endif
53 53
54#ifdef HAVE_SW_VOLUME_CONTROL
55static int sim_volume = SDL_MIX_MAXVOLUME;
56#else
57static int sim_volume = 0;
58#endif
59
60#if CONFIG_CODEC == SWCODEC 54#if CONFIG_CODEC == SWCODEC
61static int cvt_status = -1; 55static int cvt_status = -1;
62 56
@@ -177,10 +171,10 @@ static void write_to_soundcard(struct pcm_udata *udata)
177 cvt.len = rd * pcm_sample_bytes; 171 cvt.len = rd * pcm_sample_bytes;
178 cvt.buf = (Uint8 *) malloc(cvt.len * cvt.len_mult); 172 cvt.buf = (Uint8 *) malloc(cvt.len * cvt.len_mult);
179 173
180 memcpy(cvt.buf, pcm_data, cvt.len); 174 pcm_copy_buffer(cvt.buf, pcm_data, cvt.len);
181 175
182 SDL_ConvertAudio(&cvt); 176 SDL_ConvertAudio(&cvt);
183 SDL_MixAudio(udata->stream, cvt.buf, cvt.len_cvt, sim_volume); 177 memcpy(udata->stream, cvt.buf, cvt.len_cvt);
184 178
185 udata->num_in = cvt.len / pcm_sample_bytes; 179 udata->num_in = cvt.len / pcm_sample_bytes;
186 udata->num_out = cvt.len_cvt / pcm_sample_bytes; 180 udata->num_out = cvt.len_cvt / pcm_sample_bytes;
@@ -223,8 +217,8 @@ static void write_to_soundcard(struct pcm_udata *udata)
223 } 217 }
224 } else { 218 } else {
225 udata->num_in = udata->num_out = MIN(udata->num_in, udata->num_out); 219 udata->num_in = udata->num_out = MIN(udata->num_in, udata->num_out);
226 SDL_MixAudio(udata->stream, pcm_data, 220 pcm_copy_buffer(udata->stream, pcm_data,
227 udata->num_out * pcm_sample_bytes, sim_volume); 221 udata->num_out * pcm_sample_bytes);
228#ifdef DEBUG 222#ifdef DEBUG
229 if (udata->debug != NULL) { 223 if (udata->debug != NULL) {
230 fwrite(pcm_data, sizeof(Uint8), udata->num_out * pcm_sample_bytes, 224 fwrite(pcm_data, sizeof(Uint8), udata->num_out * pcm_sample_bytes,
@@ -418,13 +412,4 @@ void pcm_play_dma_postinit(void)
418{ 412{
419} 413}
420 414
421#ifndef HAVE_SW_VOLUME_CONTROL
422void pcm_set_mixer_volume(int volume)
423{
424 int minvol = sound_min(SOUND_VOLUME);
425 int volrange = sound_max(SOUND_VOLUME) - minvol;
426 sim_volume = SDL_MIX_MAXVOLUME * (volume / 10 - minvol) / volrange;
427}
428#endif /* HAVE_SW_VOLUME_CONTROL */
429
430#endif /* CONFIG_CODEC == SWCODEC */ 415#endif /* CONFIG_CODEC == SWCODEC */