A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 413 lines 13 kB view raw
1/*************************************************************************** 2 * __________ __ ___. 3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___ 4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / 5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 7 * \/ \/ \/ \/ \/ 8 * $Id$ 9 * 10 * Copyright (C) 2013 by Michael Sevakis 11 * 12 * This program is free software; you can redistribute it and/or 13 * modify it under the terms of the GNU General Public License 14 * as published by the Free Software Foundation; either version 2 15 * of the License, or (at your option) any later version. 16 * 17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 18 * KIND, either express or implied. 19 * 20 ****************************************************************************/ 21#include "config.h" 22#include "system.h" 23#include "pcm.h" 24#include "pcm-internal.h" 25#include "dsp-util.h" 26#include "fixedpoint.h" 27#include "pcm_sw_volume.h" 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 39/* volume factors set by pcm_set_master_volume */ 40static uint32_t vol_factor_l = 0, vol_factor_r = 0; 41 42#ifdef AUDIOHW_HAVE_PRESCALER 43/* prescale factor set by pcm_set_prescaler */ 44static uint32_t prescale_factor = PCM_FACTOR_UNITY; 45#endif /* AUDIOHW_HAVE_PRESCALER */ 46 47/* final pcm scaling factors */ 48static uint32_t pcm_new_factor_l = 0, pcm_new_factor_r = 0; 49static uint32_t pcm_factor_l = 0, pcm_factor_r = 0; 50static typeof (memcpy) *pcm_scaling_fn = NULL; 51 52/* take care of some defines for 32-bit software vol */ 53#if (PCM_NATIVE_BITDEPTH > 16) /* >16-bit */ 54 55# define HAVE_SWVOL_32 56# define PCM_VOL_SAMPLE_SIZE (2 * sizeof (int32_t)) 57# define PCM_DBL_BUF_SIZE_T int32_t 58 59# if !defined(PCM_DC_OFFSET_VALUE) 60/* PCM_DC_OFFSET_VALUE is only needed due to hardware quirk on Eros Q */ 61# define PCM_DC_OFFSET_VALUE 0 62# endif 63 64#else /* 16-BIT */ 65 66# define PCM_VOL_SAMPLE_SIZE PCM_SAMPLE_SIZE 67# define PCM_DBL_BUF_SIZE_T int16_t 68 69#endif /* 16-BIT */ 70 71/*** 72 ** Volume scaling routines 73 ** If unbuffered, called externally by pcm driver 74 **/ 75 76/* TODO: #include CPU-optimized routines and move this to /firmware/asm */ 77#if PCM_SW_VOLUME_FRACBITS <= 16 78#define PCM_F_T int32_t 79#else 80#define PCM_F_T int64_t /* Requires large integer math */ 81#endif /* PCM_SW_VOLUME_FRACBITS */ 82 83/* Scale sample by PCM factor */ 84static inline int32_t pcm_scale_sample(PCM_F_T f, int32_t s) 85{ 86#if defined(HAVE_SWVOL_32) 87 return (f * s + PCM_DC_OFFSET_VALUE) >> (32 - PCM_NATIVE_BITDEPTH); 88#else 89 return (f * s) >> PCM_SW_VOLUME_FRACBITS; 90#endif 91} 92 93/* Either cut (both <= UNITY), no clipping needed */ 94static void * pcm_scale_buffer_cut(void *dst, const void *src, size_t src_size) 95{ 96 PCM_DBL_BUF_SIZE_T *d = dst; 97 const int16_t *s = src; 98 uint32_t factor_l = pcm_factor_l, factor_r = pcm_factor_r; 99 100 while (src_size) 101 { 102 *d++ = pcm_scale_sample(factor_l, *s++); 103 *d++ = pcm_scale_sample(factor_r, *s++); 104 src_size -= PCM_SAMPLE_SIZE; 105 } 106 107 return dst; 108} 109 110#if !defined(HAVE_SWVOL_32) /* NOTE: 32-bit scaling is hardcoded to the cut function! */ 111/* Either boost (any > UNITY) requires clipping */ 112static void * pcm_scale_buffer_boost(void *dst, const void *src, size_t src_size) 113{ 114 int16_t *d = dst; 115 const int16_t *s = src; 116 uint32_t factor_l = pcm_factor_l, factor_r = pcm_factor_r; 117 118 while (src_size) 119 { 120 *d++ = clip_sample_16(pcm_scale_sample(factor_l, *s++)); 121 *d++ = clip_sample_16(pcm_scale_sample(factor_r, *s++)); 122 src_size -= PCM_SAMPLE_SIZE; 123 } 124 125 return dst; 126} 127#endif 128 129/* Transition the volume change smoothly across a frame */ 130static void * pcm_scale_buffer_trans(void *dst, const void *src, size_t src_size) 131{ 132 PCM_DBL_BUF_SIZE_T *d = dst; 133 const int16_t *s = src; 134 uint32_t factor_l = pcm_factor_l, factor_r = pcm_factor_r; 135 136 /* Transition from the old value to the new value using an inverted cosinus 137 from PI..0 in order to minimize amplitude-modulated harmonics generation 138 (zipper effects). */ 139 uint32_t new_factor_l = pcm_new_factor_l; 140 uint32_t new_factor_r = pcm_new_factor_r; 141 142 int32_t diff_l = (int32_t)new_factor_l - (int32_t)factor_l; 143 int32_t diff_r = (int32_t)new_factor_r - (int32_t)factor_r; 144 145 for (size_t done = 0; done < src_size; done += PCM_SAMPLE_SIZE) 146 { 147 int32_t sweep = (1 << 14) - fp14_cos(180*done / src_size); /* 0.0..2.0 */ 148 uint32_t f_l = fp_mul(sweep, diff_l, 15) + factor_l; 149 uint32_t f_r = fp_mul(sweep, diff_r, 15) + factor_r; 150#if defined(HAVE_SWVOL_32) 151 /* do not clip to 16 bits */ 152 *d++ = pcm_scale_sample(f_l, *s++); 153 *d++ = pcm_scale_sample(f_r, *s++); 154#else 155 *d++ = clip_sample_16(pcm_scale_sample(f_l, *s++)); 156 *d++ = clip_sample_16(pcm_scale_sample(f_r, *s++)); 157#endif 158 } 159 160 /* Select steady-state operation */ 161 pcm_sync_pcm_factors(); 162 163 return dst; 164} 165 166/* Called by completion routine to scale the next buffer of samples */ 167#ifndef PCM_SW_VOLUME_UNBUFFERED 168static inline 169#endif 170void pcm_sw_volume_copy_buffer(void *dst, const void *src, size_t src_size) 171{ 172 pcm_scaling_fn(dst, src, src_size); 173} 174 175/* Assign the new scaling function for normal steady-state operation */ 176void pcm_sync_pcm_factors(void) 177{ 178 uint32_t new_factor_l = pcm_new_factor_l; 179 uint32_t new_factor_r = pcm_new_factor_r; 180 181 pcm_factor_l = new_factor_l; 182 pcm_factor_r = new_factor_r; 183 184/* NOTE: 32-bit scaling is limited to 0 db <--> -74 db, we will hardcode to cut. 185 * MEMCPY CANNOT BE USED, because we do need to at minimum multiply each 186 * sample up to 32-bit size. */ 187#if defined(HAVE_SWVOL_32) 188 pcm_scaling_fn = pcm_scale_buffer_cut; 189#else 190 191 if (new_factor_l == PCM_FACTOR_UNITY && 192 new_factor_r == PCM_FACTOR_UNITY) 193 { 194 pcm_scaling_fn = memcpy; 195 } 196 else if (new_factor_l <= PCM_FACTOR_UNITY && 197 new_factor_r <= PCM_FACTOR_UNITY) 198 { 199 pcm_scaling_fn = pcm_scale_buffer_cut; 200 } 201 else 202 { 203 pcm_scaling_fn = pcm_scale_buffer_boost; 204 } 205#endif 206} 207 208#ifndef PCM_SW_VOLUME_UNBUFFERED 209/* source buffer from client */ 210static const void * volatile src_buf_addr = NULL; 211static size_t volatile src_buf_rem = 0; 212 213#define PCM_PLAY_DBL_BUF_SIZE (PCM_PLAY_DBL_BUF_SAMPLE*PCM_VOL_SAMPLE_SIZE) 214 215/* double buffer and frame length control */ 216static PCM_DBL_BUF_SIZE_T pcm_dbl_buf[2][PCM_PLAY_DBL_BUF_SAMPLES*2] 217 PCM_DBL_BUF_BSS MEM_ALIGN_ATTR; 218static size_t pcm_dbl_buf_size[2]; 219static int pcm_dbl_buf_num = 0; 220static size_t frame_size; 221static unsigned int frame_count, frame_err, frame_frac; 222 223/** Overrides of certain functions in pcm.c and pcm-internal.h **/ 224 225bool pcm_play_dma_complete_callback(enum pcm_dma_status status, 226 const void **addr, size_t *size) 227{ 228 /* Check status callback first if error */ 229 if (status < PCM_DMAST_OK) 230 status = pcm_play_call_status_cb(status); 231 232 size_t sz = pcm_dbl_buf_size[pcm_dbl_buf_num]; 233 234 if (status >= PCM_DMAST_OK && sz) 235 { 236 /* Do next chunk */ 237 *addr = pcm_dbl_buf[pcm_dbl_buf_num]; 238 *size = sz; 239 return true; 240 } 241 else 242 { 243 /* This is a stop chunk or error */ 244 pcm_play_stop_int(); 245 return false; 246 } 247} 248 249/* Equitably divide large source buffers amongst double buffer frames; 250 frames smaller than or equal to the double buffer chunk size will play 251 in one chunk */ 252static void update_frame_params(size_t size) 253{ 254 /* multiply by 2 for 32 bit, optimize away to 1 for 16 bit */ 255 int count = (size * (sizeof(PCM_DBL_BUF_SIZE_T)/sizeof(int16_t))) / PCM_VOL_SAMPLE_SIZE; 256 frame_count = (count + PCM_PLAY_DBL_BUF_SAMPLES - 1) / 257 PCM_PLAY_DBL_BUF_SAMPLES; 258 int perframe = count / frame_count; 259 frame_size = perframe * PCM_VOL_SAMPLE_SIZE; 260 frame_frac = count - perframe * frame_count; 261 frame_err = 0; 262} 263 264/* Obtain the next buffer and prepare it for pcm driver playback */ 265enum pcm_dma_status 266pcm_play_dma_status_callback_int(enum pcm_dma_status status) 267{ 268 if (status != PCM_DMAST_STARTED) 269 return status; 270 271 /* divide by 2 for 32 bit, optimize away to 1 for 16 bit */ 272 size_t size = pcm_dbl_buf_size[pcm_dbl_buf_num] / (sizeof(PCM_DBL_BUF_SIZE_T)/sizeof(int16_t)); 273 const void *addr = src_buf_addr + size; 274 275 size = src_buf_rem - size; 276 277 if (size == 0 && pcm_get_more_int(&addr, &size)) 278 { 279 update_frame_params(size); 280 pcm_play_call_status_cb(PCM_DMAST_STARTED); 281 } 282 283 src_buf_addr = addr; 284 src_buf_rem = size; 285 286 if (size != 0) 287 { 288 /* multiply by 2 for 32 bit, optimize away to 1 for 16 bit */ 289 size = frame_size / (sizeof(PCM_DBL_BUF_SIZE_T)/sizeof(int16_t)); 290 291 if ((frame_err += frame_frac) >= frame_count) 292 { 293 frame_err -= frame_count; 294 size += PCM_SAMPLE_SIZE; 295 } 296 } 297 298 pcm_dbl_buf_num ^= 1; 299 /* multiply by 2 for 32 bit, optimize away to 1 for 16 bit */ 300 pcm_dbl_buf_size[pcm_dbl_buf_num] = size * (sizeof(PCM_DBL_BUF_SIZE_T)/sizeof(int16_t)); 301 pcm_sw_volume_copy_buffer(pcm_dbl_buf[pcm_dbl_buf_num], addr, size); 302 303 return PCM_DMAST_OK; 304} 305 306/* Prefill double buffer and start pcm driver */ 307static void start_pcm(bool reframe) 308{ 309 /* Smoothed transition might not have happened so sync now */ 310 pcm_sync_pcm_factors(); 311 312 pcm_dbl_buf_num = 0; 313 pcm_dbl_buf_size[0] = 0; 314 315 if (reframe) 316 update_frame_params(src_buf_rem); 317 318 319 pcm_play_dma_status_callback(PCM_DMAST_STARTED); 320 pcm_play_dma_status_callback(PCM_DMAST_STARTED); 321 322 pcm_play_dma_start(pcm_dbl_buf[1], pcm_dbl_buf_size[1]); 323} 324 325void pcm_play_dma_start_int(const void *addr, size_t size) 326{ 327 src_buf_addr = addr; 328 /* divide by 2 for 32 bit, optimize away to 1 for 16 bit */ 329 src_buf_rem = size / (sizeof(PCM_DBL_BUF_SIZE_T)/sizeof(int16_t)); 330 start_pcm(true); 331} 332 333void pcm_play_dma_stop_int(void) 334{ 335 pcm_play_dma_stop(); 336 src_buf_addr = NULL; 337 src_buf_rem = 0; 338} 339 340#endif /* PCM_SW_VOLUME_UNBUFFERED */ 341 342 343/** Internal **/ 344 345/* Return the scale factor corresponding to the centibel level */ 346static uint32_t pcm_centibels_to_factor(int volume) 347{ 348 if (volume == PCM_MUTE_LEVEL) 349 return 0; /* mute */ 350#if defined(HAVE_SWVOL_32) 351 /* 352 * 32-bit software volume taken from pcm-alsa.c 353 */ 354 volume += 48; /* -42dB .. 0dB => 5dB .. 48dB */ 355 /* NOTE if vol_dB = 5 then vol_shift = 1 but r = 1 so we do vol_shift - 1 >= 0 356 * otherwise vol_dB >= 0 implies vol_shift >= 2 so vol_shift - 2 >= 0 */ 357 int vol_shift = volume / 3; 358 int r = volume % 3; 359 int32_t dig_vol_mult; 360 if(r == 0) 361 dig_vol_mult = 1 << vol_shift; 362 else if(r == 1) 363 dig_vol_mult = 1 << vol_shift | 1 << (vol_shift - 2); 364 else 365 dig_vol_mult = 1 << vol_shift | 1 << (vol_shift - 1); 366 return dig_vol_mult; 367#else /* standard software volume */ 368 /* Centibels -> fixedpoint */ 369 return (uint32_t)fp_factor(fp_div(volume, 10, PCM_SW_VOLUME_FRACBITS), 370 PCM_SW_VOLUME_FRACBITS); 371#endif /* HAVE_SWVOL_32 */ 372} 373 374 375 376/** Public functions **/ 377 378/* Produce final pcm scale factor */ 379static void pcm_sync_prescaler(void) 380{ 381 uint32_t factor_l = vol_factor_l; 382 uint32_t factor_r = vol_factor_r; 383#ifdef AUDIOHW_HAVE_PRESCALER 384 factor_l = fp_mul(prescale_factor, factor_l, PCM_SW_VOLUME_FRACBITS); 385 factor_r = fp_mul(prescale_factor, factor_r, PCM_SW_VOLUME_FRACBITS); 386#endif 387 pcm_play_lock(); 388 389 pcm_new_factor_l = MIN(factor_l, PCM_FACTOR_MAX); 390 pcm_new_factor_r = MIN(factor_r, PCM_FACTOR_MAX); 391 392 if (pcm_new_factor_l != pcm_factor_l || pcm_new_factor_r != pcm_factor_r) 393 pcm_scaling_fn = pcm_scale_buffer_trans; 394 395 pcm_play_unlock(); 396} 397 398#ifdef AUDIOHW_HAVE_PRESCALER 399/* Set the prescaler value for all PCM playback */ 400void pcm_set_prescaler(int prescale) 401{ 402 prescale_factor = pcm_centibels_to_factor(-prescale); 403 pcm_sync_prescaler(); 404} 405#endif /* AUDIOHW_HAVE_PRESCALER */ 406 407/* Set the per-channel volume cut/gain for all PCM playback */ 408void pcm_set_master_volume(int vol_l, int vol_r) 409{ 410 vol_factor_l = pcm_centibels_to_factor(vol_l); 411 vol_factor_r = pcm_centibels_to_factor(vol_r); 412 pcm_sync_prescaler(); 413}