freesurround-alsa-plugin

FORK: Freesurround ALSA plugin
git clone https://git.neptards.moe/u3shit/freesurround-alsa-plugin.git
Log | Files | Refs | README | LICENSE

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);