comparison libao2/pl_surround.c @ 3681:26126e5c3532

surround channels can now be decoded in stereoish
author steve
date Sun, 23 Dec 2001 19:10:00 +0000
parents cc1c879533ee
children d358dc143a9e
comparison
equal deleted inserted replaced
3680:2cc5737ec923 3681:26126e5c3532
19 19
20 Original author: Steve Davies <steve@daviesfam.org> 20 Original author: Steve Davies <steve@daviesfam.org>
21 */ 21 */
22 22
23 /* The principle: Make rear channels by extracting anti-phase data 23 /* The principle: Make rear channels by extracting anti-phase data
24 from the front channels, delay by 15msec and feed to rear in anti-phase 24 from the front channels, delay by 20msec and feed to rear in anti-phase
25 www.dolby.com has the background
26 */ 25 */
26
27
28 // SPLITREAR: Define to decode two distinct rear channels -
29 // this doesn't work so well in practice because
30 // separation in a passive matrix is not high.
31 // C (dialogue) to Ls and Rs 14dB or so -
32 // so dialogue leaks to the rear.
33 // Still - give it a try and send feedback.
34 // comment this define for old behaviour of a single
35 // surround sent to rear in anti-phase
36 #define SPLITREAR
27 37
28 38
29 #include <stdio.h> 39 #include <stdio.h>
30 #include <stdlib.h> 40 #include <stdlib.h>
31 #include <unistd.h> 41 #include <unistd.h>
63 int format; // input format 73 int format; // input format
64 int input_channels; // input channels 74 int input_channels; // input channels
65 75
66 } pl_surround_t; 76 } pl_surround_t;
67 77
68 static pl_surround_t pl_surround={0,15,NULL,NULL,NULL,0,0,NULL,0,0,0}; 78 static pl_surround_t pl_surround={0,20,NULL,NULL,NULL,0,0,NULL,0,0,0};
69 79
70 // to set/get/query special features/parameters 80 // to set/get/query special features/parameters
71 static int control(int cmd,int arg){ 81 static int control(int cmd,int arg){
72 switch(cmd){ 82 switch(cmd){
73 case AOCONTROL_PLUGIN_SET_LEN: 83 case AOCONTROL_PLUGIN_SET_LEN:
151 pl_surround.delaybuf_pos = 0; 161 pl_surround.delaybuf_pos = 0;
152 memset(pl_surround.Ls_delaybuf, 0, sizeof(int16_t)*pl_surround.delaybuf_len); 162 memset(pl_surround.Ls_delaybuf, 0, sizeof(int16_t)*pl_surround.delaybuf_len);
153 memset(pl_surround.Rs_delaybuf, 0, sizeof(int16_t)*pl_surround.delaybuf_len); 163 memset(pl_surround.Rs_delaybuf, 0, sizeof(int16_t)*pl_surround.delaybuf_len);
154 } 164 }
155 165
166 // The beginnings of an active matrix...
167 static double steering_matrix[][12] = {
168 // LL RL LR RR LS RS LLs RLs LRs RRs LC RC
169 {.707, .0, .0, .707, .5, -.5, .5878, -.3928, .3928, -.5878, .5, .5},
170 };
171
172 // Experimental moving average dominances
173 static int amp_L = 0, amp_R = 0, amp_C = 0, amp_S = 0;
156 174
157 // processes 'ao_plugin_data.len' bytes of 'data' 175 // processes 'ao_plugin_data.len' bytes of 'data'
158 // called for every block of data 176 // called for every block of data
159 static int play(){ 177 static int play(){
160 int16_t *in, *out; 178 int16_t *in, *out;
161 int i, samples; 179 int i, samples;
162 int surround; 180 double *matrix = steering_matrix[0]; // later we'll index based on detected dominance
163 181
164 if (pl_surround.passthrough) return 1; 182 if (pl_surround.passthrough) return 1;
165 183
166 // fprintf(stderr, "pl_surround: play %d bytes, %d samples\n", ao_plugin_data.len, samples); 184 // fprintf(stderr, "pl_surround: play %d bytes, %d samples\n", ao_plugin_data.len, samples);
167 185
168 samples = ao_plugin_data.len / sizeof(int16_t) / pl_surround.input_channels; 186 samples = ao_plugin_data.len / sizeof(int16_t) / pl_surround.input_channels;
169 out = pl_surround.databuf; in = (int16_t *)ao_plugin_data.data; 187 out = pl_surround.databuf; in = (int16_t *)ao_plugin_data.data;
170 188
171 // Testing - place a 1kHz tone in the front channels in anti-phase 189 // Testing - place a 1kHz tone on Lt and Rt in anti-phase: should decode in S
172 //sinewave(in, samples, pl_surround.input_channels, 1000, 0.0, pl_surround.rate); 190 //sinewave(in, samples, pl_surround.input_channels, 1000, 0.0, pl_surround.rate);
173 //sinewave(&in[1], samples, pl_surround.input_channels, 1000, PI, pl_surround.rate); 191 //sinewave(&in[1], samples, pl_surround.input_channels, 1000, PI, pl_surround.rate);
174 192
175 for (i=0; i<samples; i++) { 193 for (i=0; i<samples; i++) {
194
195 // Dominance:
196 //abs(in[0]) abs(in[1]);
197 //abs(in[0]+in[1]) abs(in[0]-in[1]);
198 //10 * log( abs(in[0]) / (abs(in[1])|1) );
199 //10 * log( abs(in[0]+in[1]) / (abs(in[0]-in[1])|1) );
176 200
177 // About volume balancing... 201 // About volume balancing...
178 // Surround encoding does the following: 202 // Surround encoding does the following:
179 // Lt=L+.707*C+.707*S, Rt=R+.707*C-.707*S 203 // Lt=L+.707*C+.707*S, Rt=R+.707*C-.707*S
180 // So S should be extracted as: 204 // So S should be extracted as:
181 // (Lt-Rt) 205 // (Lt-Rt)
182 // But we are splitting the S to two output channels, so we 206 // But we are splitting the S to two output channels, so we
183 // must take 3dB off as we split it: 207 // must take 3dB off as we split it:
184 // Ls=Rs=.707*(Lt-Rt) 208 // Ls=Rs=.707*(Lt-Rt)
185 // Trouble is, Lt could be +32767, Rt -32768, so possibility that S will 209 // Trouble is, Lt could be +32767, Rt -32768, so possibility that S will
186 // clip. So to avoid that, we cut L/R by 3dB (*.707), and S by 6dB (/2). 210 // overflow. So to avoid that, we cut L/R by 3dB (*.707), and S by 6dB (/2).
211 // this keeps the overall balance, but guarantees no overflow.
187 212
188 // output front left and right 213 // output front left and right
189 out[0] = in[0]*.707; 214 out[0] = matrix[0]*in[0] + matrix[1]*in[1];
190 out[1] = in[1]*.707; 215 out[1] = matrix[2]*in[0] + matrix[3]*in[1];
191 // output Ls and Rs - from 15msec ago, lowpass filtered @ 7kHz 216 // output Ls and Rs - from 20msec ago, lowpass filtered @ 7kHz
192 out[2] = firfilter(pl_surround.Ls_delaybuf, pl_surround.delaybuf_pos, 217 out[2] = firfilter(pl_surround.Ls_delaybuf, pl_surround.delaybuf_pos,
193 pl_surround.delaybuf_len, 32, pl_surround.filter_coefs_surround); 218 pl_surround.delaybuf_len, 32, pl_surround.filter_coefs_surround);
194 out[3] = - out[2]; 219 #ifdef SPLITREAR
195 // out[3] = firfilter(pl_surround.Rs_delaybuf, pl_surround.delaybuf_pos, 220 out[3] = firfilter(pl_surround.Rs_delaybuf, pl_surround.delaybuf_pos,
196 // pl_surround.delaybuf_len, 32, pl_surround.filter_coefs_surround); 221 pl_surround.delaybuf_len, 32, pl_surround.filter_coefs_surround);
197 // calculate and save surround for 15msecs time 222 #else
198 surround = (in[0]/2 - in[1]/2); 223 out[3] = -out[2];
199 pl_surround.Ls_delaybuf[pl_surround.delaybuf_pos] = surround; 224 #endif
200 pl_surround.Rs_delaybuf[pl_surround.delaybuf_pos++] = - surround; 225 // calculate and save surround for 20msecs time
226 #ifdef SPLITREAR
227 pl_surround.Ls_delaybuf[pl_surround.delaybuf_pos] =
228 matrix[6]*in[0] + matrix[7]*in[1];
229 pl_surround.Rs_delaybuf[pl_surround.delaybuf_pos++] =
230 matrix[8]*in[0] + matrix[9]*in[1];
231 #else
232 pl_surround.Ls_delaybuf[pl_surround.delaybuf_pos] =
233 matrix[4]*in[0] + matrix[5]*in[1];
234 #endif
201 pl_surround.delaybuf_pos %= pl_surround.delaybuf_len; 235 pl_surround.delaybuf_pos %= pl_surround.delaybuf_len;
236
202 // next samples... 237 // next samples...
203 in = &in[pl_surround.input_channels]; out = &out[4]; 238 in = &in[pl_surround.input_channels]; out = &out[4];
204 } 239 }
240
241 // Show some state
242 //printf("\npl_surround: delaybuf_pos=%d, samples=%d\r\033[A", pl_surround.delaybuf_pos, samples);
205 243
206 // Set output block/len 244 // Set output block/len
207 ao_plugin_data.data=pl_surround.databuf; 245 ao_plugin_data.data=pl_surround.databuf;
208 ao_plugin_data.len=samples*sizeof(int16_t)*4; 246 ao_plugin_data.len=samples*sizeof(int16_t)*4;
209 return 1; 247 return 1;