pcm_freesurround.c (28039B)
1 /* 2 3 FreeSurround Output Plugin 4 5 Copyright (c) 2009 Michel Cailhol 6 Based on foo_dsp_freesurround (c) 2007 Christian Kothe 7 8 This program is free software; you can redistribute it and/or 9 modify it under the terms of the GNU General Public License 10 as published by the Free Software Foundation; either version 2 11 of the License, or (at your option) any later version. 12 13 This program is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with this program; if not, write to the Free Software 20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 21 */ 22 23 #include <stdio.h> 24 #include <string.h> 25 #define __USE_XOPEN 26 #include <unistd.h> 27 #include <alsa/asoundlib.h> 28 #include <alsa/pcm_external.h> 29 #include <alsa/pcm_plugin.h> 30 #include <fftw3.h> 31 #include <complex.h> 32 #include <math.h> 33 34 const float PI = 3.141592654; 35 const float epsilon = 0.000001; 36 const float center_level = 0.5*sqrt(0.5); // gain of center channel 37 #define BLOCK_SIZE 8192 38 #define DBL_BLOCK_SIZE (2 * BLOCK_SIZE) 39 #define DBL_BLOCK_SIZE_MIN_ONE ((2 * BLOCK_SIZE) - 1) 40 const int INPUT_CHANNELS = 2; 41 const int OUTPUT_CHANNELS = 6; 42 43 44 typedef float complex cfloat; 45 typedef float farraybs[BLOCK_SIZE]; 46 typedef float farraybse[BLOCK_SIZE + BLOCK_SIZE/2]; 47 typedef short sarraydbs[DBL_BLOCK_SIZE]; 48 typedef cfloat cfarraybs[BLOCK_SIZE]; 49 50 typedef struct snd_pcm_fsupmix snd_pcm_fsupmix_t; 51 52 typedef void (*fsupmixer_t)(snd_pcm_fsupmix_t *fsmix, 53 const snd_pcm_channel_area_t *dst_areas, 54 snd_pcm_uframes_t dst_offset, 55 const snd_pcm_channel_area_t *src_areas, 56 snd_pcm_uframes_t src_offset, 57 snd_pcm_uframes_t size); 58 59 60 struct snd_pcm_fsupmix { 61 snd_pcm_extplug_t ext; 62 snd_pcm_format_t format; 63 unsigned int channels; 64 unsigned int rate; 65 unsigned int bitrate; 66 int outbuf_size; 67 snd_pcm_uframes_t transfer; 68 int remain; 69 unsigned int slave_period_size; 70 unsigned int slave_buffer_size; 71 snd_pcm_hw_params_t *hw_params; 72 farraybs myinput[2]; 73 sarraydbs myoutput[6]; 74 unsigned int myout_count; 75 unsigned int myout_write_offset; 76 unsigned int myout_read_offset; 77 78 int preupmixed; 79 // FFTW data structures 80 float *lt,*rt,*dst; // left total, right total (source arrays), destination array 81 fftwf_complex *dftL,*dftR,*src; // intermediate arrays (FFTs of lt & rt, processing source) 82 fftwf_plan loadL,loadR,store; // plans for loading the data into the intermediate format and back 83 84 // buffers 85 cfarraybs frontL; // the signal (phase-corrected) in the frequency domain 86 cfarraybs frontR; // the signal (phase-corrected) in the frequency domain 87 cfarraybs avg; // the signal (phase-corrected) in the frequency domain 88 cfarraybs surL; // the signal (phase-corrected) in the frequency domain 89 cfarraybs surR; // the signal (phase-corrected) in the frequency domain 90 cfarraybs trueavg; // for lfe generation 91 92 farraybs xfs ; // the feature space positions for each frequency bin 93 farraybs yfs ; // the feature space positions for each frequency bin 94 farraybs wnd ; // the window function, precalculated 95 farraybs filter[6] ; // a frequency filter for each output channel 96 97 farraybse fsinbuf[2]; // the sliding input buffers 98 farraybse fsoutbuf[6]; // the sliding output buffers 99 100 // coefficients 101 float surround_high,surround_low; // high and low surround mixing coefficient (e.g. 0.8165/0.5774) 102 float surround_balance; // the xfs balance that follows from the coeffs 103 float surround_level; // gain for the surround channels (follows from the coeffs 104 float master_gain; // gain for all channels 105 float phase_offsetL, phase_offsetR;// phase shifts to be applied to the rear channels 106 float front_separation; // front stereo separation 107 float rear_separation; // rear stereo separation 108 int linear_steering; // whether the steering should be linear or not 109 float center_width; // distribution of the center information towards the front left/right channels 110 float dimension; 111 float adaption_rate; 112 unsigned int phase_mode; 113 114 }; 115 116 117 118 static inline void *area_addr(const snd_pcm_channel_area_t *area, snd_pcm_uframes_t offset) { 119 unsigned int bitofs = area->first + area->step * offset; 120 return (char *) area->addr + bitofs / 8; 121 } 122 123 static inline unsigned int area_step(const snd_pcm_channel_area_t *area) { 124 return area->step / 8; 125 } 126 127 128 129 130 // set the assumed surround mixing coefficients 131 static void surround_coefficients(snd_pcm_fsupmix_t *fsmix, float a, float b) { 132 fsmix->master_gain = 1.0; 133 // calc the simple coefficients 134 fsmix->surround_high = a; 135 fsmix->surround_low = b; 136 fsmix->surround_balance = (a-b)/(a+b); 137 // increase the rear volume 138 //fsmix->surround_level = 1/(a+b); 139 fsmix->surround_level = 0.85; 140 } 141 142 143 // set the phase shifting mode for decoding 144 // 0 = (+0°,+0°) - music mode 145 // 1 = (+0°,+180°) - PowerDVD compatibility 146 // 2 = (+180°,+0°) - BeSweet compatibility 147 // 3 = (-90°,+90°) - experimental exact reconstuction; not clear whether this is entirely correct 148 static void set_phase_mode(snd_pcm_fsupmix_t *fsmix) { 149 const float modes[4][2] = {{0,0},{0,PI},{PI,0},{-PI/2,PI/2}}; 150 fsmix->phase_offsetL = modes[fsmix->phase_mode][0]; 151 fsmix->phase_offsetR = modes[fsmix->phase_mode][1]; 152 } 153 154 // what steering mode should be chosen 155 static void steering_mode(snd_pcm_fsupmix_t *fsmix, int mode) { 156 fsmix->linear_steering = mode; 157 } 158 159 // set front & rear separation controls 160 static void separation(snd_pcm_fsupmix_t *fsmix, float front, float rear) { 161 fsmix->front_separation = front; 162 fsmix->rear_separation = rear; 163 } 164 165 // set lfe filter params 166 static void sample_rate(snd_pcm_fsupmix_t *fsmix, unsigned int srate) { 167 // lfe filter is just straight through band limited 168 unsigned int cutoff = (250*BLOCK_SIZE)/srate; 169 unsigned f; 170 for (f=0;f<=BLOCK_SIZE/2;f++) { 171 if ((f>=2) && (f<cutoff)) 172 //fsmix->filter[5][f] = 0.5*sqrt(0.5); 173 fsmix->filter[5][f] = 1.0; 174 else 175 fsmix->filter[5][f] = 0.0; 176 } 177 } 178 179 180 181 182 // polar <-> cartesian coodinates conversion 183 static inline float amplitude(const float cf[2]) { return sqrt(cf[0]*cf[0] + cf[1]*cf[1]); } 184 static inline float phase(const float cf[2]) { return atan2(cf[1],cf[0]); } 185 static cfloat polar(float a, float p) { 186 cfloat cpf = a*cos(p) + I*(a*sin(p)); 187 return cpf; 188 //return cfloat (a*cos(p),a*sin(p)); 189 } 190 static inline float sqr(float x) { return x*x; } 191 // the dreaded min/max 192 static inline float min(float a, float b) { return a<b?a:b; } 193 static inline float max(float a, float b) { return a>b?a:b; } 194 static inline float clamp(float x) { return max(-1,min(1,x)); } 195 196 197 198 // map from amplitude difference and phase difference to yfs 199 static inline double get_yfs(double ampDiff, double phaseDiff) { 200 double x = 1-(((1-sqr(ampDiff))*phaseDiff)/PI*2); 201 return 0.16468622925824683 + 0.5009268347818189*x - 0.06462757726992101*x*x 202 + 0.09170680403453149*x*x*x + 0.2617754892323973*tan(x) - 0.04180413533856156*sqr(tan(x)); 203 } 204 205 // map from amplitude difference and yfs to xfs 206 static inline double get_xfs(double ampDiff, double yfs) { 207 double x=ampDiff,y=yfs; 208 return 2.464833559224702*x - 423.52131153259404*x*y + 209 67.8557858606918*x*x*x*y + 788.2429425544392*x*y*y - 210 79.97650354902909*x*x*x*y*y - 513.8966153850349*x*y*y*y + 211 35.68117670186306*x*x*x*y*y*y + 13867.406173420834*y*asin(x) - 212 2075.8237075786396*y*y*asin(x) - 908.2722068360281*y*y*y*asin(x) - 213 12934.654772878019*asin(x)*sin(y) - 13216.736529661162*y*tan(x) + 214 1288.6463247741938*y*y*tan(x) + 1384.372969378453*y*y*y*tan(x) + 215 12699.231471126128*sin(y)*tan(x) + 95.37131275594336*sin(x)*tan(y) - 216 91.21223198407546*tan(x)*tan(y); 217 } 218 219 // filter the complex source signal and add it to target 220 static void apply_filter(snd_pcm_fsupmix_t *fsmix, cfarraybs signal, int nfilter, int nchannel ) { 221 // filter the signal 222 unsigned f; 223 for (f=0; f<=BLOCK_SIZE/2; f++) { 224 fsmix->src[f][0] = crealf(signal[f]) * fsmix->filter[nfilter][f]; 225 fsmix->src[f][1] = cimagf(signal[f]) * fsmix->filter[nfilter][f]; 226 } 227 // transform into time domain 228 fftwf_execute(fsmix->store); 229 // add the result to target, windowed 230 unsigned k; 231 for ( k=0; k<BLOCK_SIZE; k++) { 232 fsmix->fsoutbuf[nchannel][k + BLOCK_SIZE/2] += fsmix->wnd[k]*fsmix->dst[k]; 233 } 234 } 235 236 237 238 239 // CORE FUNCTION: decode a block of data 240 static void block_decode(snd_pcm_fsupmix_t *fsmix, int buffoffset) { 241 242 243 // 1. scale the input by the window function; this serves a dual purpose: 244 // - first it improves the FFT resolution b/c boundary discontinuities (and their frequencies) get removed 245 // - second it allows for smooth blending of varying filters between the blocks 246 unsigned k; 247 for (k=0; k<BLOCK_SIZE; k++) { 248 fsmix->lt[k] = fsmix->fsinbuf[0][k + buffoffset] * fsmix->wnd[k] * fsmix->master_gain; 249 fsmix->rt[k] = fsmix->fsinbuf[1][k + buffoffset] * fsmix->wnd[k] * fsmix->master_gain; 250 } 251 252 // ... and tranform it into the frequency domain 253 fftwf_execute(fsmix->loadL); 254 fftwf_execute(fsmix->loadR); 255 256 // 2. compare amplitude and phase of each DFT bin and produce the X/Y coordinates in the sound field 257 unsigned f; 258 for (f=0; f<=BLOCK_SIZE/2; f++) { 259 // get left/right amplitudes/phases 260 float ampL = amplitude(fsmix->dftL[f]), ampR = amplitude(fsmix->dftR[f]); 261 float phaseL = phase(fsmix->dftL[f]), phaseR = phase(fsmix->dftR[f]); 262 263 // calculate the amplitude/phase difference 264 float ampDiff = clamp((ampL+ampR < epsilon) ? 0 : (ampR-ampL) / (ampR+ampL)); 265 float phaseDiff = phaseL - phaseR; 266 if (phaseDiff < -PI) phaseDiff += 2*PI; 267 if (phaseDiff > PI) phaseDiff -= 2*PI; 268 phaseDiff = fabs(phaseDiff); 269 270 if (fsmix->linear_steering) { 271 // --- the new linear mode --- 272 273 // get sound field x/y position 274 fsmix->yfs[f] = get_yfs(ampDiff,phaseDiff); 275 fsmix->xfs[f] = get_xfs(ampDiff, fsmix->yfs[f]); 276 277 // add dimension control 278 fsmix->yfs[f] = clamp(fsmix->yfs[f] - fsmix->dimension); 279 280 // add crossfeed control 281 fsmix->xfs[f] = clamp(fsmix->xfs[f] * (fsmix->front_separation*(1+fsmix->yfs[f])/2 + fsmix->rear_separation*(1-fsmix->yfs[f])/2)); 282 283 // 3. generate frequency filters for each output channel 284 float left = (1-fsmix->xfs[f])/2, right = (1+fsmix->xfs[f])/2; 285 float front = (1+fsmix->yfs[f])/2, back = (1-fsmix->yfs[f])/2; 286 float volume[5] = { 287 front * (left * fsmix->center_width + max(0,-fsmix->xfs[f]) * (1-fsmix->center_width)), // left 288 front * center_level*((1-fabs(fsmix->xfs[f])) * (1-fsmix->center_width)), // center 289 front * (right * fsmix->center_width + max(0, fsmix->xfs[f]) * (1-fsmix->center_width)), // right 290 back * fsmix->surround_level * left, // left surround 291 back * fsmix->surround_level * right // right surround 292 }; 293 294 // adapt the prior filter 295 unsigned c; 296 for (c=0;c<5;c++) 297 fsmix->filter[c][f] = (1-fsmix->adaption_rate)*fsmix->filter[c][f] + fsmix->adaption_rate*volume[c]/BLOCK_SIZE; 298 299 } else { 300 // --- the old & simple steering mode --- 301 // calculate the amplitude/phase difference 302 float ampDiff = clamp((ampL+ampR < epsilon) ? 0 : (ampR-ampL) / (ampR+ampL)); 303 float phaseDiff = phaseL - phaseR; 304 if (phaseDiff < -PI) phaseDiff += 2*PI; 305 if (phaseDiff > PI) phaseDiff -= 2*PI; 306 phaseDiff = fabs(phaseDiff); 307 308 // determine sound field x-position 309 fsmix->xfs[f] = ampDiff; 310 311 // determine preliminary sound field y-position from phase difference 312 fsmix->yfs[f] = 1 - (phaseDiff/PI)*2; 313 314 if (fabs(fsmix->xfs[f]) > fsmix->surround_balance) { 315 // blend linearly between the surrounds and the fronts if the balance exceeds the surround encoding balance 316 // this is necessary because the sound field is trapezoidal and will be stretched behind the listener 317 float frontness = (fabs(fsmix->xfs[f]) - fsmix->surround_balance)/(1-fsmix->surround_balance); 318 fsmix->yfs[f] = (1-frontness) * fsmix->yfs[f] + frontness * 1; 319 } 320 321 // add dimension control 322 fsmix->yfs[f] = clamp(fsmix->yfs[f] - fsmix->dimension); 323 324 // add crossfeed control 325 fsmix->xfs[f] = clamp(fsmix->xfs[f] * (fsmix->front_separation*(1+fsmix->yfs[f])/2 + fsmix->rear_separation*(1-fsmix->yfs[f])/2)); 326 327 // 3. generate frequency filters for each output channel, according to the signal position 328 // the sum of all channel volumes must be 1.0 329 float left = (1-fsmix->xfs[f])/2, right = (1+fsmix->xfs[f])/2; 330 float front = (1+fsmix->yfs[f])/2, back = (1-fsmix->yfs[f])/2; 331 float volume[5] = { 332 front * (left * fsmix->center_width + max(0,-fsmix->xfs[f]) * (1-fsmix->center_width)), // left 333 front * center_level*((1-fabs(fsmix->xfs[f])) * (1-fsmix->center_width)), // center 334 front * (right * fsmix->center_width + max(0, fsmix->xfs[f]) * (1-fsmix->center_width)), // right 335 back * fsmix->surround_level*max(0,min(1,((1-(fsmix->xfs[f]/fsmix->surround_balance))/2))), // left surround 336 back * fsmix->surround_level*max(0,min(1,((1+(fsmix->xfs[f]/fsmix->surround_balance))/2))) // right surround 337 }; 338 339 // adapt the prior filter 340 unsigned c; 341 for (c=0;c<5;c++) 342 fsmix->filter[c][f] = (1-fsmix->adaption_rate)*fsmix->filter[c][f] + fsmix->adaption_rate*volume[c]/BLOCK_SIZE; 343 } 344 345 // ... and build the signal which we want to position 346 fsmix->frontL[f] = polar(ampL+ampR,phaseL); 347 fsmix->frontR[f] = polar(ampL+ampR,phaseR); 348 fsmix->avg[f] = fsmix->frontL[f] + fsmix->frontR[f]; 349 fsmix->surL[f] = polar(ampL+ampR,phaseL+fsmix->phase_offsetL); 350 fsmix->surR[f] = polar(ampL+ampR,phaseR+fsmix->phase_offsetR); 351 fsmix->trueavg[f] = (fsmix->dftL[f][0] + fsmix->dftR[f][0]) + I*(fsmix->dftL[f][1] + fsmix->dftR[f][1]); 352 } 353 354 // 4. distribute the unfiltered reference signals over the channels 355 apply_filter(fsmix, fsmix->frontL, 0, 0); // front left 356 apply_filter(fsmix, fsmix->avg, 1, 4); // front center 357 apply_filter(fsmix, fsmix->frontR, 2, 1); // front right 358 apply_filter(fsmix, fsmix->surL, 3, 2); // surround left 359 apply_filter(fsmix, fsmix->surR, 4, 3); // surround right 360 //apply_filter(fsmix, fsmix->trueavg, 5, 5); // lfe 361 } 362 363 364 365 366 // handle the output buffering for overlapped calls of block_decode 367 static void add_output(snd_pcm_fsupmix_t *fsmix, int buffoffset, int result) { 368 369 // add the windowed data to the last 2/3 of the output buffer 370 block_decode(fsmix, buffoffset); 371 unsigned c, k; 372 unsigned int ooffset; 373 374 for (c=0;c<6;c++) { 375 if (result) 376 // return the first 2/3 of the ouput buffer 377 for (k=0;k<BLOCK_SIZE;k++) { 378 ooffset = (fsmix->myout_write_offset + k) & DBL_BLOCK_SIZE_MIN_ONE; 379 if (c != 5) 380 fsmix->myoutput[c][ooffset] = (short)(fsmix->fsoutbuf[c][k] + 0.5); 381 else // lfe channel 382 fsmix->myoutput[5][ooffset] = (fsmix->myoutput[0][ooffset] >> 1) + (fsmix->myoutput[1][ooffset] >> 1); 383 } 384 385 for ( k=0;k<BLOCK_SIZE;k++) 386 // shift the last 2/3 to the first 2/3 of the output buffer 387 fsmix->fsoutbuf[c][k] = fsmix->fsoutbuf[c][k+BLOCK_SIZE/2]; 388 // and clear the rest 389 for (k=BLOCK_SIZE; k<BLOCK_SIZE+BLOCK_SIZE/2; k++) 390 fsmix->fsoutbuf[c][k] = 0; 391 } 392 if (result) { 393 fsmix->myout_count += BLOCK_SIZE; 394 fsmix->myout_write_offset += BLOCK_SIZE; 395 fsmix->myout_write_offset &= DBL_BLOCK_SIZE_MIN_ONE; 396 } 397 } 398 399 400 401 402 // decode a chunk of stereo sound, has to contain exactly blocksize samples 403 static void decode(snd_pcm_fsupmix_t *fsmix) { 404 // append incoming data to the end of the input buffer 405 unsigned k; 406 for (k=0; k<BLOCK_SIZE; k++) { 407 fsmix->fsinbuf[0][k+BLOCK_SIZE/2] = fsmix->myinput[0][k]; 408 fsmix->fsinbuf[1][k+BLOCK_SIZE/2] = fsmix->myinput[1][k]; 409 } 410 // process first part 411 add_output(fsmix, 0, 0); 412 // process second part (overlapped) and return result 413 add_output(fsmix, BLOCK_SIZE/2, 1); 414 // shift last third of input buffer to the beginning 415 for (k=0; k<BLOCK_SIZE/2; k++) { 416 fsmix->fsinbuf[0][k] = fsmix->fsinbuf[0][k+BLOCK_SIZE]; 417 fsmix->fsinbuf[1][k] = fsmix->fsinbuf[1][k+BLOCK_SIZE]; 418 } 419 } 420 421 422 /* 423 * transfer callback 424 */ 425 static snd_pcm_sframes_t fs_transfer(snd_pcm_extplug_t *ext, 426 const snd_pcm_channel_area_t *dst_areas, 427 snd_pcm_uframes_t dst_offset, 428 const snd_pcm_channel_area_t *src_areas, 429 snd_pcm_uframes_t src_offset, 430 snd_pcm_uframes_t size) 431 { 432 snd_pcm_fsupmix_t *fsmix = (snd_pcm_fsupmix_t *)ext; 433 434 unsigned int len2 = BLOCK_SIZE - fsmix->preupmixed; 435 short *src[2], *dst[6]; 436 unsigned int src_step[2], dst_step[6], i, k; 437 438 if (size > len2) { 439 size = len2; 440 // printf("on en a trop : size2=%u, len2=%u\n",size2,len2); 441 } 442 //printf("size1=%u\n",size); 443 for (i = 0; i < INPUT_CHANNELS; i++) { 444 src[i] = (short *)area_addr(src_areas + i, src_offset); 445 src_step[i] = area_step(src_areas + i) / 2; 446 } 447 for (i = 0; i < OUTPUT_CHANNELS; i++) { 448 dst[i] = (short *)area_addr(dst_areas + i, dst_offset); 449 // printf("dst[%u]=%p\n",i,dst[i]); 450 dst_step[i] = area_step(dst_areas + i) / 2; 451 } 452 453 for (k=0; k<size; k++) { 454 fsmix->myinput[0][fsmix->preupmixed + k] = (float)*src[0]; 455 fsmix->myinput[1][fsmix->preupmixed + k] = (float)*src[1]; 456 src[0] += src_step[0]; 457 src[1] += src_step[1]; 458 } 459 fsmix->preupmixed += size; 460 461 if (fsmix->preupmixed == BLOCK_SIZE && fsmix->myout_count > BLOCK_SIZE) { 462 fsmix->preupmixed -= size; 463 size = 0; 464 } 465 else 466 if (fsmix->preupmixed == BLOCK_SIZE) { 467 // printf("on a rempli un bloc : on ecrit a partir de %u\n",fsmix->myout_write_offset); 468 decode(fsmix); // adaption_rate 469 /* unsigned int ooffset; 470 for (k=0; k<BLOCK_SIZE; k++) { 471 ooffset = (rec->myout_write_offset + k) & DBL_BLOCK_SIZE_MIN_ONE; 472 rec->myoutput[0][ooffset] = (short)(rec->myinput[0][k] + 0.5); 473 rec->myoutput[1][ooffset] = (short)(rec->myinput[1][k] + 0.5); 474 rec->myoutput[2][ooffset] = (short)(rec->myinput[0][k] + 0.5); 475 rec->myoutput[3][ooffset] = (short)(rec->myinput[1][k] + 0.5); 476 rec->myoutput[4][ooffset] = 0; 477 rec->myoutput[5][ooffset] = 0; 478 } 479 rec->myout_count += BLOCK_SIZE; 480 rec->myout_write_offset += BLOCK_SIZE; 481 rec->myout_write_offset &= DBL_BLOCK_SIZE_MIN_ONE; */ 482 fsmix->preupmixed = 0; 483 } 484 // printf("buffer contient %i\n", fsmix->myout_count); 485 486 unsigned int ooffset; 487 /* flatten copy to n-channel interleaved */ 488 for (k = 0; k < size; k++) { 489 for (i = 0; i < OUTPUT_CHANNELS; i++) { 490 // printf("k=%u, i=%u\n",k,i); 491 ooffset = (fsmix->myout_read_offset + k) & DBL_BLOCK_SIZE_MIN_ONE; 492 *dst[i] = fsmix->myoutput[i][ooffset]; 493 dst[i] += dst_step[i]; 494 } 495 } 496 497 fsmix->myout_count -= size; 498 fsmix->myout_read_offset += size; 499 fsmix->myout_read_offset &= DBL_BLOCK_SIZE_MIN_ONE; 500 501 return size; 502 } 503 504 505 506 507 /* 508 * prepare callback 509 * 510 * Allocate internal buffers 511 */ 512 static int fs_prepare(snd_pcm_extplug_t *ext) 513 { 514 snd_pcm_fsupmix_t *fsmix = (snd_pcm_fsupmix_t *)ext; 515 516 517 fsmix->myout_count = BLOCK_SIZE; 518 fsmix->myout_write_offset = BLOCK_SIZE; 519 fsmix->myout_read_offset = 0; 520 521 // create FFTW buffers 522 fsmix->lt = (float*)fftwf_malloc(sizeof(float)*BLOCK_SIZE); 523 fsmix->rt = (float*)fftwf_malloc(sizeof(float)*BLOCK_SIZE); 524 fsmix->dst = (float*)fftwf_malloc(sizeof(float)*BLOCK_SIZE); 525 fsmix->dftL = (fftwf_complex*)fftwf_malloc(sizeof(fftwf_complex)*BLOCK_SIZE); 526 fsmix->dftR = (fftwf_complex*)fftwf_malloc(sizeof(fftwf_complex)*BLOCK_SIZE); 527 fsmix->src = (fftwf_complex*)fftwf_malloc(sizeof(fftwf_complex)*BLOCK_SIZE); 528 fsmix->loadL = fftwf_plan_dft_r2c_1d(BLOCK_SIZE, fsmix->lt, fsmix->dftL,FFTW_MEASURE); 529 fsmix->loadR = fftwf_plan_dft_r2c_1d(BLOCK_SIZE, fsmix->rt, fsmix->dftR,FFTW_MEASURE); 530 fsmix->store = fftwf_plan_dft_c2r_1d(BLOCK_SIZE, fsmix->src, fsmix->dst,FFTW_MEASURE); 531 532 533 fsmix->transfer = 0; 534 fsmix->remain = 0; 535 fsmix->preupmixed = 0; 536 537 unsigned k; 538 for (k=0;k<BLOCK_SIZE;k++) 539 fsmix->wnd[k] = sqrt(0.5*(1-cos(2*PI*k/BLOCK_SIZE))); // square root of hann 540 541 surround_coefficients(fsmix, 0.8165,0.5774); 542 set_phase_mode(fsmix); 543 //separation(fsmix, 1.0,1.0); 544 //steering_mode(rec, 1); 545 sample_rate(fsmix, 48000); 546 547 // printf("prepare : center_width=%f dimension=%f adaption_rate=%f phase_mode=%u linear_steering=%i\n", 548 // rec->center_width, rec->dimension, rec->adaption_rate, rec->phase_mode, rec->linear_steering); 549 550 return 0; 551 } 552 553 554 555 /* 556 * close callback 557 */ 558 static int fs_close(snd_pcm_extplug_t *ext) 559 { 560 snd_pcm_fsupmix_t *fsmix = (snd_pcm_fsupmix_t *)ext; 561 562 // clean up the FFTW stuff 563 fftwf_destroy_plan(fsmix->store); 564 fftwf_destroy_plan(fsmix->loadR); 565 fftwf_destroy_plan(fsmix->loadL); 566 fftwf_free(fsmix->src); 567 fftwf_free(fsmix->dftR); 568 fftwf_free(fsmix->dftL); 569 fftwf_free(fsmix->dst); 570 fftwf_free(fsmix->rt); 571 fftwf_free(fsmix->lt);; 572 return 0; 573 } 574 575 /* 576 * callback table 577 */ 578 static snd_pcm_extplug_callback_t fs_callback = { 579 .transfer = fs_transfer, 580 .close = fs_close, 581 .init = fs_prepare, 582 }; 583 584 585 586 /* 587 * Main entry point 588 */ 589 SND_PCM_PLUGIN_DEFINE_FUNC(freesurround) 590 { 591 snd_config_iterator_t i, next; 592 snd_pcm_fsupmix_t *fsmix; 593 snd_config_t *sconf = NULL; 594 static const unsigned int chlist[2] = {4, 6}; 595 int err; 596 unsigned int rate = 48000; 597 unsigned int bitrate = 448; 598 unsigned int channels = 6; 599 snd_pcm_format_t format = SND_PCM_FORMAT_S16_LE; 600 float center_width = 0.50; 601 float dimension = 0.25; 602 float adaption_rate = 0.9; 603 unsigned int phase_mode = 0; 604 int linear_steering = 1; 605 float front_separation = 1.0; 606 float rear_separation = 1.0; 607 608 if (stream != SND_PCM_STREAM_PLAYBACK) { 609 SNDERR("freesurround is only for playback"); 610 return -EINVAL; 611 } 612 613 snd_config_for_each(i, next, conf) { 614 snd_config_t *n = snd_config_iterator_entry(i); 615 const char *id; 616 if (snd_config_get_id(n, &id) < 0) 617 continue; 618 if (strcmp(id, "comment") == 0 || strcmp(id, "type") == 0 || strcmp(id, "hint") == 0) 619 continue; 620 if (strcmp(id, "slave") == 0) { 621 sconf = n; 622 continue; 623 } 624 625 if (strcmp(id, "channels") == 0) { 626 long val; 627 if (snd_config_get_integer(n, &val) < 0) { 628 SNDERR("Invalid type for %s", id); 629 return -EINVAL; 630 } 631 channels = val; 632 if (channels != 2 && channels != 4 && channels != 6) { 633 SNDERR("channels must be 2, 4 or 6"); 634 return -EINVAL; 635 } 636 continue; 637 } 638 639 if (strcmp(id, "center_width") == 0) { 640 double val; 641 if (snd_config_get_real(n, &val) < 0) { 642 SNDERR("Invalid type for %s", id); 643 return -EINVAL; 644 } 645 center_width = (float)val; // center_width [0..1] distributes the center information towards the front left/right channels, 1=full distribution, 0=no distribution 646 if (center_width < 0.0 || center_width > 1.0) { 647 SNDERR("center_width must be between 0.0 and 1.0"); 648 return -EINVAL; 649 } 650 continue; 651 } 652 if (strcmp(id, "dimension") == 0) { 653 double val; 654 if (snd_config_get_real(n, &val) < 0) { 655 SNDERR("Invalid type for %s", id); 656 return -EINVAL; 657 } 658 dimension = (float)val; // dimension [0..1] moves the soundfield backwards, 0=front, 1=side 659 if (dimension < -0.5 || dimension > 1.0) { 660 SNDERR("dimension must be between -0.5 and 1.0"); 661 return -EINVAL; 662 } 663 continue; 664 } 665 if (strcmp(id, "adaption_rate") == 0) { 666 double val; 667 if (snd_config_get_real(n, &val) < 0) { 668 SNDERR("Invalid type for %s", id); 669 return -EINVAL; 670 } 671 adaption_rate = (float)val; // adaption_rate [0..1] determines how fast the steering gets adapted, 1=instantaneous, 0.1 = very slow adaption 672 if (adaption_rate < 0.0 || adaption_rate > 1.0) { 673 SNDERR("adaption_rate must be between 0.0 and 1.0"); 674 return -EINVAL; 675 } 676 continue; 677 } 678 if (strcmp(id, "phase_mode") == 0) { 679 long val; 680 if (snd_config_get_integer(n, &val) < 0) { 681 SNDERR("Invalid type for %s", id); 682 return -EINVAL; 683 } 684 phase_mode = (unsigned int)val; 685 if (phase_mode < 0 || phase_mode > 3) { 686 SNDERR("phase_mode must be between 0 and 3"); 687 return -EINVAL; 688 } 689 continue; 690 } 691 if (strcmp(id, "linear_steering") == 0) { 692 long val; 693 if (snd_config_get_integer(n, &val) < 0) { 694 SNDERR("Invalid type for %s", id); 695 return -EINVAL; 696 } 697 linear_steering = (unsigned int)val; // 698 if (linear_steering != 0 && linear_steering != 1) { 699 SNDERR("linear_steering must be 0 or 1"); 700 return -EINVAL; 701 } 702 continue; 703 } 704 if (strcmp(id, "front_separation") == 0) { 705 double val; 706 if (snd_config_get_real(n, &val) < 0) { 707 SNDERR("Invalid type for %s", id); 708 return -EINVAL; 709 } 710 front_separation = (float)val; // front_separation [0..1.5] 711 if (front_separation < 0.0 || front_separation > 1.5) { 712 SNDERR("front_separation must be between 0.0 and 1.5"); 713 return -EINVAL; 714 } 715 continue; 716 } 717 if (strcmp(id, "rear_separation") == 0) { 718 double val; 719 if (snd_config_get_real(n, &val) < 0) { 720 SNDERR("Invalid type for %s", id); 721 return -EINVAL; 722 } 723 rear_separation = (float)val; // rear_separation [0..1.5] 724 if (rear_separation < 0.0 || rear_separation > 1.5) { 725 SNDERR("rear_separation must be between 0.0 and 1.5"); 726 return -EINVAL; 727 } 728 continue; 729 } 730 SNDERR("Unknown field %s", id); 731 return -EINVAL; 732 } 733 734 if (! sconf) { 735 SNDERR("No slave configuration for freesurround pcm"); 736 return -EINVAL; 737 } 738 739 fsmix = calloc(1, sizeof(*fsmix)); 740 if (! fsmix) { 741 SNDERR("cannot allocate"); 742 return -ENOMEM; 743 } 744 745 fsmix->rate = rate; 746 fsmix->bitrate = bitrate; 747 fsmix->channels = channels; 748 fsmix->format = format; 749 750 fsmix->center_width = center_width; 751 fsmix->dimension = dimension; 752 fsmix->adaption_rate = adaption_rate; 753 fsmix->phase_mode = phase_mode; 754 fsmix->linear_steering = linear_steering; 755 fsmix->front_separation = front_separation; 756 fsmix->rear_separation = rear_separation; 757 758 759 fsmix->ext.version = SND_PCM_IOPLUG_VERSION; 760 fsmix->ext.name = "FreeSurround upmix plugin"; 761 fsmix->ext.callback = &fs_callback; 762 fsmix->ext.private_data = fsmix; 763 764 err = snd_pcm_extplug_create(&fsmix->ext, name, root, sconf, stream, mode); 765 if (err < 0) { 766 free(fsmix); 767 return err; 768 } 769 770 snd_pcm_extplug_set_param_minmax(&fsmix->ext, 771 SND_PCM_EXTPLUG_HW_CHANNELS, 772 1, 6); 773 if (channels) 774 snd_pcm_extplug_set_slave_param_minmax(&fsmix->ext, 775 SND_PCM_EXTPLUG_HW_CHANNELS, 776 channels, channels); 777 else 778 snd_pcm_extplug_set_slave_param_list(&fsmix->ext, 779 SND_PCM_EXTPLUG_HW_CHANNELS, 780 2, chlist); 781 snd_pcm_extplug_set_param(&fsmix->ext, SND_PCM_EXTPLUG_HW_FORMAT, 782 SND_PCM_FORMAT_S16); 783 snd_pcm_extplug_set_slave_param(&fsmix->ext, SND_PCM_EXTPLUG_HW_FORMAT, 784 SND_PCM_FORMAT_S16); 785 786 *pcmp = fsmix->ext.pcm; 787 return 0; 788 789 } 790 791 SND_PCM_PLUGIN_SYMBOL(freesurround);