diff options
author | Dana Conrad <dconrad@fastmail.com> | 2021-08-01 21:58:33 -0500 |
---|---|---|
committer | Aidan MacDonald <amachronic@protonmail.com> | 2021-08-07 14:21:47 +0000 |
commit | 56b0dde5451ddedfd85c82391536e310cd05e1a8 (patch) | |
tree | 19d988f8cad0976abd086ee306ecbc840a1d477d | |
parent | 16b009825608164b17dabd877c78123a667b4981 (diff) | |
download | rockbox-56b0dde5451ddedfd85c82391536e310cd05e1a8.tar.gz rockbox-56b0dde5451ddedfd85c82391536e310cd05e1a8.zip |
Higher bitdepth software volume scaling
Operates between 0 and -74 dB (mute) without issue
Change-Id: I497e002bd8db43833a09ebbc29212fbb6cc8ebfd
-rw-r--r-- | firmware/drivers/audio/eros_qn_codec.c | 12 | ||||
-rw-r--r-- | firmware/export/config/erosqnative.h | 3 | ||||
-rw-r--r-- | firmware/export/eros_qn_codec.h | 2 | ||||
-rw-r--r-- | firmware/pcm_sw_volume.c | 126 | ||||
-rw-r--r-- | firmware/target/mips/ingenic_x1000/pcm-x1000.c | 7 |
5 files changed, 118 insertions, 32 deletions
diff --git a/firmware/drivers/audio/eros_qn_codec.c b/firmware/drivers/audio/eros_qn_codec.c index fdf21d2f9d..17b0acf13e 100644 --- a/firmware/drivers/audio/eros_qn_codec.c +++ b/firmware/drivers/audio/eros_qn_codec.c | |||
@@ -70,10 +70,14 @@ void audiohw_set_volume(int vol_l, int vol_r) | |||
70 | } | 70 | } |
71 | #endif | 71 | #endif |
72 | 72 | ||
73 | l = l <= PCM5102A_VOLUME_MIN ? PCM_MUTE_LEVEL : l; | 73 | if (l <= PCM5102A_VOLUME_MIN || r <= PCM5102A_VOLUME_MIN) |
74 | r = r <= PCM5102A_VOLUME_MIN ? PCM_MUTE_LEVEL : r; | 74 | { |
75 | 75 | pcm_set_master_volume(PCM_MUTE_LEVEL, PCM_MUTE_LEVEL); | |
76 | pcm_set_master_volume(l, r); | 76 | } |
77 | else | ||
78 | { | ||
79 | pcm_set_master_volume(l/20, r/20); | ||
80 | } | ||
77 | } | 81 | } |
78 | 82 | ||
79 | void audiohw_mute_hp(int mute) | 83 | void audiohw_mute_hp(int mute) |
diff --git a/firmware/export/config/erosqnative.h b/firmware/export/config/erosqnative.h index 1b37b6042a..b2b6f3f89e 100644 --- a/firmware/export/config/erosqnative.h +++ b/firmware/export/config/erosqnative.h | |||
@@ -64,6 +64,9 @@ | |||
64 | #define HAVE_SW_TONE_CONTROLS | 64 | #define HAVE_SW_TONE_CONTROLS |
65 | #define HAVE_SW_VOLUME_CONTROL | 65 | #define HAVE_SW_VOLUME_CONTROL |
66 | 66 | ||
67 | /* use high-bitdepth volume scaling */ | ||
68 | #define PCM_NATIVE_BITDEPTH 24 | ||
69 | |||
67 | /* Button defines */ | 70 | /* Button defines */ |
68 | #define CONFIG_KEYPAD EROSQ_PAD | 71 | #define CONFIG_KEYPAD EROSQ_PAD |
69 | #define HAVE_SCROLLWHEEL | 72 | #define HAVE_SCROLLWHEEL |
diff --git a/firmware/export/eros_qn_codec.h b/firmware/export/eros_qn_codec.h index 9c900186a8..ae04c66799 100644 --- a/firmware/export/eros_qn_codec.h +++ b/firmware/export/eros_qn_codec.h | |||
@@ -29,7 +29,7 @@ | |||
29 | /* a small DC offset appears to prevent play/pause clicking */ | 29 | /* a small DC offset appears to prevent play/pause clicking */ |
30 | #define PCM_DC_OFFSET_VALUE -1 | 30 | #define PCM_DC_OFFSET_VALUE -1 |
31 | 31 | ||
32 | AUDIOHW_SETTING(VOLUME, "dB", 0, 1, PCM5102A_VOLUME_MIN/10, PCM5102A_VOLUME_MAX/10, 0) | 32 | AUDIOHW_SETTING(VOLUME, "dB", 0, 2, PCM5102A_VOLUME_MIN/10, PCM5102A_VOLUME_MAX/10, 0) |
33 | 33 | ||
34 | /* this just calls audiohw_set_volume() with the last (locally) known volume, | 34 | /* this just calls audiohw_set_volume() with the last (locally) known volume, |
35 | * used for switching to/from fixed line out volume. */ | 35 | * used for switching to/from fixed line out volume. */ |
diff --git a/firmware/pcm_sw_volume.c b/firmware/pcm_sw_volume.c index 3593c684af..646f2a680a 100644 --- a/firmware/pcm_sw_volume.c +++ b/firmware/pcm_sw_volume.c | |||
@@ -26,6 +26,16 @@ | |||
26 | #include "fixedpoint.h" | 26 | #include "fixedpoint.h" |
27 | #include "pcm_sw_volume.h" | 27 | #include "pcm_sw_volume.h" |
28 | 28 | ||
29 | /* | ||
30 | * NOTE: With the addition of 32-bit software scaling to this | ||
31 | * file, sometimes the "size" variable gets a little confusing. | ||
32 | * | ||
33 | * The source buffer (as of right now) is always 16-bit, and the | ||
34 | * destination buffer can potentially be 32-bit. I've tried to | ||
35 | * make it consistent: when passed in a function call, try to use | ||
36 | * the source buffer (16-bit) size. | ||
37 | */ | ||
38 | |||
29 | /* volume factors set by pcm_set_master_volume */ | 39 | /* volume factors set by pcm_set_master_volume */ |
30 | static uint32_t vol_factor_l = 0, vol_factor_r = 0; | 40 | static uint32_t vol_factor_l = 0, vol_factor_r = 0; |
31 | 41 | ||
@@ -39,6 +49,30 @@ static uint32_t pcm_new_factor_l = 0, pcm_new_factor_r = 0; | |||
39 | static uint32_t pcm_factor_l = 0, pcm_factor_r = 0; | 49 | static uint32_t pcm_factor_l = 0, pcm_factor_r = 0; |
40 | static typeof (memcpy) *pcm_scaling_fn = NULL; | 50 | static typeof (memcpy) *pcm_scaling_fn = NULL; |
41 | 51 | ||
52 | /* default to 16-bit volume scaling unless specified */ | ||
53 | #if !defined(PCM_NATIVE_BITDEPTH) | ||
54 | # define PCM_NATIVE_BITDEPTH 16 | ||
55 | #endif | ||
56 | |||
57 | /* take care of some defines for 32-bit software vol */ | ||
58 | #if (PCM_NATIVE_BITDEPTH > 16) /* >16-bit */ | ||
59 | |||
60 | # define HAVE_SWVOL_32 | ||
61 | # define PCM_VOL_SAMPLE_SIZE (2 * sizeof (int32_t)) | ||
62 | # define PCM_DBL_BUF_SIZE_T int32_t | ||
63 | |||
64 | # if !defined(PCM_DC_OFFSET_VALUE) | ||
65 | /* PCM_DC_OFFSET_VALUE is only needed due to hardware quirk on Eros Q */ | ||
66 | # define PCM_DC_OFFSET_VALUE 0 | ||
67 | # endif | ||
68 | |||
69 | #else /* 16-BIT */ | ||
70 | |||
71 | # define PCM_VOL_SAMPLE_SIZE PCM_SAMPLE_SIZE | ||
72 | # define PCM_DBL_BUF_SIZE_T int16_t | ||
73 | |||
74 | #endif /* 16-BIT */ | ||
75 | |||
42 | /*** | 76 | /*** |
43 | ** Volume scaling routines | 77 | ** Volume scaling routines |
44 | ** If unbuffered, called externally by pcm driver | 78 | ** If unbuffered, called externally by pcm driver |
@@ -54,54 +88,53 @@ static typeof (memcpy) *pcm_scaling_fn = NULL; | |||
54 | /* Scale sample by PCM factor */ | 88 | /* Scale sample by PCM factor */ |
55 | static inline int32_t pcm_scale_sample(PCM_F_T f, int32_t s) | 89 | static inline int32_t pcm_scale_sample(PCM_F_T f, int32_t s) |
56 | { | 90 | { |
57 | #if defined(PCM_DC_OFFSET_VALUE) | 91 | #if defined(HAVE_SWVOL_32) |
58 | return (f * s + PCM_DC_OFFSET_VALUE) >> PCM_SW_VOLUME_FRACBITS; | 92 | return (f * s + PCM_DC_OFFSET_VALUE) >> (32 - PCM_NATIVE_BITDEPTH); |
59 | #else | 93 | #else |
60 | return (f * s) >> PCM_SW_VOLUME_FRACBITS; | 94 | return (f * s) >> PCM_SW_VOLUME_FRACBITS; |
61 | #endif | 95 | #endif |
62 | } | 96 | } |
63 | 97 | ||
64 | /* Both UNITY, use direct copy */ | ||
65 | /* static void * memcpy(void *dst, const void *src, size_t size); */ | ||
66 | |||
67 | /* Either cut (both <= UNITY), no clipping needed */ | 98 | /* Either cut (both <= UNITY), no clipping needed */ |
68 | static void * pcm_scale_buffer_cut(void *dst, const void *src, size_t size) | 99 | static void * pcm_scale_buffer_cut(void *dst, const void *src, size_t src_size) |
69 | { | 100 | { |
70 | int16_t *d = dst; | 101 | PCM_DBL_BUF_SIZE_T *d = dst; |
71 | const int16_t *s = src; | 102 | const int16_t *s = src; |
72 | uint32_t factor_l = pcm_factor_l, factor_r = pcm_factor_r; | 103 | uint32_t factor_l = pcm_factor_l, factor_r = pcm_factor_r; |
73 | 104 | ||
74 | while (size) | 105 | while (src_size) |
75 | { | 106 | { |
76 | *d++ = pcm_scale_sample(factor_l, *s++); | 107 | *d++ = pcm_scale_sample(factor_l, *s++); |
77 | *d++ = pcm_scale_sample(factor_r, *s++); | 108 | *d++ = pcm_scale_sample(factor_r, *s++); |
78 | size -= PCM_SAMPLE_SIZE; | 109 | src_size -= PCM_SAMPLE_SIZE; |
79 | } | 110 | } |
80 | 111 | ||
81 | return dst; | 112 | return dst; |
82 | } | 113 | } |
83 | 114 | ||
115 | #if !defined(HAVE_SWVOL_32) /* NOTE: 32-bit scaling is hardcoded to the cut function! */ | ||
84 | /* Either boost (any > UNITY) requires clipping */ | 116 | /* Either boost (any > UNITY) requires clipping */ |
85 | static void * pcm_scale_buffer_boost(void *dst, const void *src, size_t size) | 117 | static void * pcm_scale_buffer_boost(void *dst, const void *src, size_t src_size) |
86 | { | 118 | { |
87 | int16_t *d = dst; | 119 | int16_t *d = dst; |
88 | const int16_t *s = src; | 120 | const int16_t *s = src; |
89 | uint32_t factor_l = pcm_factor_l, factor_r = pcm_factor_r; | 121 | uint32_t factor_l = pcm_factor_l, factor_r = pcm_factor_r; |
90 | 122 | ||
91 | while (size) | 123 | while (src_size) |
92 | { | 124 | { |
93 | *d++ = clip_sample_16(pcm_scale_sample(factor_l, *s++)); | 125 | *d++ = clip_sample_16(pcm_scale_sample(factor_l, *s++)); |
94 | *d++ = clip_sample_16(pcm_scale_sample(factor_r, *s++)); | 126 | *d++ = clip_sample_16(pcm_scale_sample(factor_r, *s++)); |
95 | size -= PCM_SAMPLE_SIZE; | 127 | src_size -= PCM_SAMPLE_SIZE; |
96 | } | 128 | } |
97 | 129 | ||
98 | return dst; | 130 | return dst; |
99 | } | 131 | } |
132 | #endif | ||
100 | 133 | ||
101 | /* Transition the volume change smoothly across a frame */ | 134 | /* Transition the volume change smoothly across a frame */ |
102 | static void * pcm_scale_buffer_trans(void *dst, const void *src, size_t size) | 135 | static void * pcm_scale_buffer_trans(void *dst, const void *src, size_t src_size) |
103 | { | 136 | { |
104 | int16_t *d = dst; | 137 | PCM_DBL_BUF_SIZE_T *d = dst; |
105 | const int16_t *s = src; | 138 | const int16_t *s = src; |
106 | uint32_t factor_l = pcm_factor_l, factor_r = pcm_factor_r; | 139 | uint32_t factor_l = pcm_factor_l, factor_r = pcm_factor_r; |
107 | 140 | ||
@@ -114,13 +147,19 @@ static void * pcm_scale_buffer_trans(void *dst, const void *src, size_t size) | |||
114 | int32_t diff_l = (int32_t)new_factor_l - (int32_t)factor_l; | 147 | int32_t diff_l = (int32_t)new_factor_l - (int32_t)factor_l; |
115 | int32_t diff_r = (int32_t)new_factor_r - (int32_t)factor_r; | 148 | int32_t diff_r = (int32_t)new_factor_r - (int32_t)factor_r; |
116 | 149 | ||
117 | for (size_t done = 0; done < size; done += PCM_SAMPLE_SIZE) | 150 | for (size_t done = 0; done < src_size; done += PCM_SAMPLE_SIZE) |
118 | { | 151 | { |
119 | int32_t sweep = (1 << 14) - fp14_cos(180*done / size); /* 0.0..2.0 */ | 152 | int32_t sweep = (1 << 14) - fp14_cos(180*done / src_size); /* 0.0..2.0 */ |
120 | uint32_t f_l = fp_mul(sweep, diff_l, 15) + factor_l; | 153 | uint32_t f_l = fp_mul(sweep, diff_l, 15) + factor_l; |
121 | uint32_t f_r = fp_mul(sweep, diff_r, 15) + factor_r; | 154 | uint32_t f_r = fp_mul(sweep, diff_r, 15) + factor_r; |
155 | #if defined(HAVE_SWVOL_32) | ||
156 | /* do not clip to 16 bits */ | ||
157 | *d++ = pcm_scale_sample(f_l, *s++); | ||
158 | *d++ = pcm_scale_sample(f_r, *s++); | ||
159 | #else | ||
122 | *d++ = clip_sample_16(pcm_scale_sample(f_l, *s++)); | 160 | *d++ = clip_sample_16(pcm_scale_sample(f_l, *s++)); |
123 | *d++ = clip_sample_16(pcm_scale_sample(f_r, *s++)); | 161 | *d++ = clip_sample_16(pcm_scale_sample(f_r, *s++)); |
162 | #endif | ||
124 | } | 163 | } |
125 | 164 | ||
126 | /* Select steady-state operation */ | 165 | /* Select steady-state operation */ |
@@ -133,9 +172,9 @@ static void * pcm_scale_buffer_trans(void *dst, const void *src, size_t size) | |||
133 | #ifndef PCM_SW_VOLUME_UNBUFFERED | 172 | #ifndef PCM_SW_VOLUME_UNBUFFERED |
134 | static inline | 173 | static inline |
135 | #endif | 174 | #endif |
136 | void pcm_sw_volume_copy_buffer(void *dst, const void *src, size_t size) | 175 | void pcm_sw_volume_copy_buffer(void *dst, const void *src, size_t src_size) |
137 | { | 176 | { |
138 | pcm_scaling_fn(dst, src, size); | 177 | pcm_scaling_fn(dst, src, src_size); |
139 | } | 178 | } |
140 | 179 | ||
141 | /* Assign the new scaling function for normal steady-state operation */ | 180 | /* Assign the new scaling function for normal steady-state operation */ |
@@ -147,6 +186,13 @@ void pcm_sync_pcm_factors(void) | |||
147 | pcm_factor_l = new_factor_l; | 186 | pcm_factor_l = new_factor_l; |
148 | pcm_factor_r = new_factor_r; | 187 | pcm_factor_r = new_factor_r; |
149 | 188 | ||
189 | /* NOTE: 32-bit scaling is limited to 0 db <--> -74 db, we will hardcode to cut. | ||
190 | * MEMCPY CANNOT BE USED, because we do need to at minimum multiply each | ||
191 | * sample up to 32-bit size. */ | ||
192 | #if defined(HAVE_SWVOL_32) | ||
193 | pcm_scaling_fn = pcm_scale_buffer_cut; | ||
194 | #else | ||
195 | |||
150 | if (new_factor_l == PCM_FACTOR_UNITY && | 196 | if (new_factor_l == PCM_FACTOR_UNITY && |
151 | new_factor_r == PCM_FACTOR_UNITY) | 197 | new_factor_r == PCM_FACTOR_UNITY) |
152 | { | 198 | { |
@@ -161,6 +207,7 @@ void pcm_sync_pcm_factors(void) | |||
161 | { | 207 | { |
162 | pcm_scaling_fn = pcm_scale_buffer_boost; | 208 | pcm_scaling_fn = pcm_scale_buffer_boost; |
163 | } | 209 | } |
210 | #endif | ||
164 | } | 211 | } |
165 | 212 | ||
166 | #ifndef PCM_SW_VOLUME_UNBUFFERED | 213 | #ifndef PCM_SW_VOLUME_UNBUFFERED |
@@ -168,10 +215,10 @@ void pcm_sync_pcm_factors(void) | |||
168 | static const void * volatile src_buf_addr = NULL; | 215 | static const void * volatile src_buf_addr = NULL; |
169 | static size_t volatile src_buf_rem = 0; | 216 | static size_t volatile src_buf_rem = 0; |
170 | 217 | ||
171 | #define PCM_PLAY_DBL_BUF_SIZE (PCM_PLAY_DBL_BUF_SAMPLE*PCM_SAMPLE_SIZE) | 218 | #define PCM_PLAY_DBL_BUF_SIZE (PCM_PLAY_DBL_BUF_SAMPLE*PCM_VOL_SAMPLE_SIZE) |
172 | 219 | ||
173 | /* double buffer and frame length control */ | 220 | /* double buffer and frame length control */ |
174 | static int16_t pcm_dbl_buf[2][PCM_PLAY_DBL_BUF_SAMPLES*2] | 221 | static PCM_DBL_BUF_SIZE_T pcm_dbl_buf[2][PCM_PLAY_DBL_BUF_SAMPLES*2] |
175 | PCM_DBL_BUF_BSS MEM_ALIGN_ATTR; | 222 | PCM_DBL_BUF_BSS MEM_ALIGN_ATTR; |
176 | static size_t pcm_dbl_buf_size[2]; | 223 | static size_t pcm_dbl_buf_size[2]; |
177 | static int pcm_dbl_buf_num = 0; | 224 | static int pcm_dbl_buf_num = 0; |
@@ -209,11 +256,12 @@ bool pcm_play_dma_complete_callback(enum pcm_dma_status status, | |||
209 | in one chunk */ | 256 | in one chunk */ |
210 | static void update_frame_params(size_t size) | 257 | static void update_frame_params(size_t size) |
211 | { | 258 | { |
212 | int count = size / PCM_SAMPLE_SIZE; | 259 | /* multiply by 2 for 32 bit, optimize away to 1 for 16 bit */ |
260 | int count = (size * (sizeof(PCM_DBL_BUF_SIZE_T)/sizeof(int16_t))) / PCM_VOL_SAMPLE_SIZE; | ||
213 | frame_count = (count + PCM_PLAY_DBL_BUF_SAMPLES - 1) / | 261 | frame_count = (count + PCM_PLAY_DBL_BUF_SAMPLES - 1) / |
214 | PCM_PLAY_DBL_BUF_SAMPLES; | 262 | PCM_PLAY_DBL_BUF_SAMPLES; |
215 | int perframe = count / frame_count; | 263 | int perframe = count / frame_count; |
216 | frame_size = perframe * PCM_SAMPLE_SIZE; | 264 | frame_size = perframe * PCM_VOL_SAMPLE_SIZE; |
217 | frame_frac = count - perframe * frame_count; | 265 | frame_frac = count - perframe * frame_count; |
218 | frame_err = 0; | 266 | frame_err = 0; |
219 | } | 267 | } |
@@ -225,7 +273,8 @@ pcm_play_dma_status_callback_int(enum pcm_dma_status status) | |||
225 | if (status != PCM_DMAST_STARTED) | 273 | if (status != PCM_DMAST_STARTED) |
226 | return status; | 274 | return status; |
227 | 275 | ||
228 | size_t size = pcm_dbl_buf_size[pcm_dbl_buf_num]; | 276 | /* divide by 2 for 32 bit, optimize away to 1 for 16 bit */ |
277 | size_t size = pcm_dbl_buf_size[pcm_dbl_buf_num] / (sizeof(PCM_DBL_BUF_SIZE_T)/sizeof(int16_t)); | ||
229 | const void *addr = src_buf_addr + size; | 278 | const void *addr = src_buf_addr + size; |
230 | 279 | ||
231 | size = src_buf_rem - size; | 280 | size = src_buf_rem - size; |
@@ -241,7 +290,8 @@ pcm_play_dma_status_callback_int(enum pcm_dma_status status) | |||
241 | 290 | ||
242 | if (size != 0) | 291 | if (size != 0) |
243 | { | 292 | { |
244 | size = frame_size; | 293 | /* multiply by 2 for 32 bit, optimize away to 1 for 16 bit */ |
294 | size = frame_size / (sizeof(PCM_DBL_BUF_SIZE_T)/sizeof(int16_t)); | ||
245 | 295 | ||
246 | if ((frame_err += frame_frac) >= frame_count) | 296 | if ((frame_err += frame_frac) >= frame_count) |
247 | { | 297 | { |
@@ -251,7 +301,8 @@ pcm_play_dma_status_callback_int(enum pcm_dma_status status) | |||
251 | } | 301 | } |
252 | 302 | ||
253 | pcm_dbl_buf_num ^= 1; | 303 | pcm_dbl_buf_num ^= 1; |
254 | pcm_dbl_buf_size[pcm_dbl_buf_num] = size; | 304 | /* multiply by 2 for 32 bit, optimize away to 1 for 16 bit */ |
305 | pcm_dbl_buf_size[pcm_dbl_buf_num] = size * (sizeof(PCM_DBL_BUF_SIZE_T)/sizeof(int16_t)); | ||
255 | pcm_sw_volume_copy_buffer(pcm_dbl_buf[pcm_dbl_buf_num], addr, size); | 306 | pcm_sw_volume_copy_buffer(pcm_dbl_buf[pcm_dbl_buf_num], addr, size); |
256 | 307 | ||
257 | return PCM_DMAST_OK; | 308 | return PCM_DMAST_OK; |
@@ -269,6 +320,7 @@ static void start_pcm(bool reframe) | |||
269 | if (reframe) | 320 | if (reframe) |
270 | update_frame_params(src_buf_rem); | 321 | update_frame_params(src_buf_rem); |
271 | 322 | ||
323 | |||
272 | pcm_play_dma_status_callback(PCM_DMAST_STARTED); | 324 | pcm_play_dma_status_callback(PCM_DMAST_STARTED); |
273 | pcm_play_dma_status_callback(PCM_DMAST_STARTED); | 325 | pcm_play_dma_status_callback(PCM_DMAST_STARTED); |
274 | 326 | ||
@@ -278,7 +330,8 @@ static void start_pcm(bool reframe) | |||
278 | void pcm_play_dma_start_int(const void *addr, size_t size) | 330 | void pcm_play_dma_start_int(const void *addr, size_t size) |
279 | { | 331 | { |
280 | src_buf_addr = addr; | 332 | src_buf_addr = addr; |
281 | src_buf_rem = size; | 333 | /* divide by 2 for 32 bit, optimize away to 1 for 16 bit */ |
334 | src_buf_rem = size / (sizeof(PCM_DBL_BUF_SIZE_T)/sizeof(int16_t)); | ||
282 | start_pcm(true); | 335 | start_pcm(true); |
283 | } | 336 | } |
284 | 337 | ||
@@ -299,13 +352,32 @@ static uint32_t pcm_centibels_to_factor(int volume) | |||
299 | { | 352 | { |
300 | if (volume == PCM_MUTE_LEVEL) | 353 | if (volume == PCM_MUTE_LEVEL) |
301 | return 0; /* mute */ | 354 | return 0; /* mute */ |
302 | 355 | #if defined(HAVE_SWVOL_32) | |
356 | /* | ||
357 | * 32-bit software volume taken from pcm-alsa.c | ||
358 | */ | ||
359 | volume += 48; /* -42dB .. 0dB => 5dB .. 48dB */ | ||
360 | /* NOTE if vol_dB = 5 then vol_shift = 1 but r = 1 so we do vol_shift - 1 >= 0 | ||
361 | * otherwise vol_dB >= 0 implies vol_shift >= 2 so vol_shift - 2 >= 0 */ | ||
362 | int vol_shift = volume / 3; | ||
363 | int r = volume % 3; | ||
364 | int32_t dig_vol_mult; | ||
365 | if(r == 0) | ||
366 | dig_vol_mult = 1 << vol_shift; | ||
367 | else if(r == 1) | ||
368 | dig_vol_mult = 1 << vol_shift | 1 << (vol_shift - 2); | ||
369 | else | ||
370 | dig_vol_mult = 1 << vol_shift | 1 << (vol_shift - 1); | ||
371 | return dig_vol_mult; | ||
372 | #else /* standard software volume */ | ||
303 | /* Centibels -> fixedpoint */ | 373 | /* Centibels -> fixedpoint */ |
304 | return (uint32_t)fp_factor(fp_div(volume, 10, PCM_SW_VOLUME_FRACBITS), | 374 | return (uint32_t)fp_factor(fp_div(volume, 10, PCM_SW_VOLUME_FRACBITS), |
305 | PCM_SW_VOLUME_FRACBITS); | 375 | PCM_SW_VOLUME_FRACBITS); |
376 | #endif /* HAVE_SWVOL_32 */ | ||
306 | } | 377 | } |
307 | 378 | ||
308 | 379 | ||
380 | |||
309 | /** Public functions **/ | 381 | /** Public functions **/ |
310 | 382 | ||
311 | /* Produce final pcm scale factor */ | 383 | /* Produce final pcm scale factor */ |
diff --git a/firmware/target/mips/ingenic_x1000/pcm-x1000.c b/firmware/target/mips/ingenic_x1000/pcm-x1000.c index a3da3411f2..ce2fbb17a9 100644 --- a/firmware/target/mips/ingenic_x1000/pcm-x1000.c +++ b/firmware/target/mips/ingenic_x1000/pcm-x1000.c | |||
@@ -66,10 +66,17 @@ void pcm_play_dma_init(void) | |||
66 | /* Let the target initialize its hardware and setup the AIC */ | 66 | /* Let the target initialize its hardware and setup the AIC */ |
67 | audiohw_init(); | 67 | audiohw_init(); |
68 | 68 | ||
69 | #if (PCM_NATIVE_BITDEPTH > 16) | ||
70 | /* Program audio format (stereo, 24 bit samples) */ | ||
71 | jz_writef(AIC_CCR, PACK16(0), CHANNEL_V(STEREO), | ||
72 | OSS_V(24BIT), ISS_V(24BIT), M2S(0)); | ||
73 | jz_writef(AIC_I2SCR, SWLH(0)); | ||
74 | #else | ||
69 | /* Program audio format (stereo, packed 16 bit samples) */ | 75 | /* Program audio format (stereo, packed 16 bit samples) */ |
70 | jz_writef(AIC_CCR, PACK16(1), CHANNEL_V(STEREO), | 76 | jz_writef(AIC_CCR, PACK16(1), CHANNEL_V(STEREO), |
71 | OSS_V(16BIT), ISS_V(16BIT), M2S(0)); | 77 | OSS_V(16BIT), ISS_V(16BIT), M2S(0)); |
72 | jz_writef(AIC_I2SCR, SWLH(0)); | 78 | jz_writef(AIC_I2SCR, SWLH(0)); |
79 | #endif | ||
73 | 80 | ||
74 | /* Set DMA settings */ | 81 | /* Set DMA settings */ |
75 | jz_writef(AIC_CFG, TFTH(16), RFTH(16)); | 82 | jz_writef(AIC_CFG, TFTH(16), RFTH(16)); |