README.osx wasn't easily readable in Finder. Revert back to
[sox.git] / src / mixer.c
blob20851d3128037d97b32bbd42a9bba36a5d8f1e93
1 /* July 5, 1991
2 * Copyright 1991 Lance Norskog And Sundry Contributors
3 * This source code is freely redistributable and may be used for
4 * any purpose. This copyright notice must be maintained.
5 * Lance Norskog And Sundry Contributors are not responsible for
6 * the consequences of using this software.
8 * Channel duplication code by Graeme W. Gill - 93/5/18
9 * General-purpose panning by Geoffrey H. Kuenning -- 2000/11/28
13 * libSoX stereo/quad -> mono mixdown effect file.
14 * and mono/stereo -> stereo/quad channel duplication.
17 #include "sox_i.h"
18 #include <ctype.h>
19 #include <string.h>
20 #include <stdlib.h>
22 typedef struct {
23 /* How to generate each output channel. sources[i][j] */
24 /* represents the fraction of channel i that should be passed */
25 /* through to channel j on output, and so forth. Channel 0 is */
26 /* left front, channel 1 is right front, and 2 and 3 are left */
27 /* and right rear, respectively. (GHK) */
28 double sources[4][4];
29 int num_pans;
30 int mix; /* How are we mixing it? */
31 } priv_t;
33 /* MIX_CENTER is shorthand to mix channels together at 50% each */
34 #define MIX_CENTER 0
35 #define MIX_SPECIFIED 1
39 * Process options
41 static int getopts(sox_effect_t * effp, int argc, char **argv)
43 priv_t * mixer = (priv_t *) effp->priv;
44 double* pans = &mixer->sources[0][0];
45 int i;
46 --argc, ++argv;
48 for (i = 0; i < 16; i++)
49 pans[i] = 0.0;
50 mixer->mix = MIX_CENTER;
51 mixer->num_pans = 0;
53 /* Parse parameters. Since we don't yet know the number of */
54 /* input and output channels, we'll record the information for */
55 /* later. */
56 if (argc == 1) {
57 if (!strcmp(argv[0], "-l")) mixer->mix = 'l';
58 else if (!strcmp(argv[0], "-r")) mixer->mix = 'r';
59 else if (!strcmp(argv[0], "-f")) mixer->mix = 'f';
60 else if (!strcmp(argv[0], "-b")) mixer->mix = 'b';
61 else if (!strcmp(argv[0], "-1")) mixer->mix = '1';
62 else if (!strcmp(argv[0], "-2")) mixer->mix = '2';
63 else if (!strcmp(argv[0], "-3")) mixer->mix = '3';
64 else if (!strcmp(argv[0], "-4")) mixer->mix = '4';
65 else if (argv[0][0] == '-' && !isdigit((int)argv[0][1])
66 && argv[0][1] != '.')
67 return lsx_usage(effp);
68 else {
69 int commas;
70 char *s;
71 mixer->mix = MIX_SPECIFIED;
72 pans[0] = atof(argv[0]);
73 for (s = argv[0], commas = 0; *s; ++s) {
74 if (*s == ',') {
75 ++commas;
76 if (commas >= 16) {
77 lsx_fail("mixer can only take up to 16 pan values");
78 return (SOX_EOF);
80 pans[commas] = atof(s+1);
83 mixer->num_pans = commas + 1;
86 else if (argc == 0) {
87 mixer->mix = MIX_CENTER;
89 else
90 return lsx_usage(effp);
92 return (SOX_SUCCESS);
96 * Start processing
98 static int start(sox_effect_t * effp)
101 Hmmm, this is tricky. Lemme think:
102 channel orders are [0][0],[0][1], etc.
103 i.e., 0->0, 0->1, 0->2, 0->3, 1->0, 1->1, ...
104 trailing zeros are omitted
105 L/R balance is x= -1 for left only, 1 for right only
106 1->1 channel effects:
107 changing volume by x is x,0,0,0
108 1->2 channel effects:
109 duplicating everywhere is 1,1,0,0
110 1->4 channel effects:
111 duplicating everywhere is 1,1,1,1
112 2->1 channel effects:
113 left only is 1,0,0,0 0,0,0,0
114 right only is 0,0,0,0 1,0,0,0
115 left+right is 0.5,0,0,0 0.5,0,0,0
116 left-right is 1,0,0,0 -1,0,0,0
117 2->2 channel effects:
118 L/R balance can be done several ways. The standard stereo
119 way is both the easiest and the most sensible:
120 min(1-x,1),0,0,0 0,min(1+x,1),0,0
121 left to both is 1,1,0,0
122 right to both is 0,0,0,0 1,1,0,0
123 left+right to both is 0.5,0.5,0,0 0.5,0.5,0,0
124 left-right to both is 1,1,0,0 -1,-1,0,0
125 left-right to left, right-left to right is 1,-1,0,0 -1,1,0,0
126 2->4 channel effects:
127 front duplicated into rear is 1,0,1,0 0,1,0,1
128 front swapped into rear (why?) is 1,0,0,1 0,1,1,0
129 front put into rear as mono (why?) is 1,0,0.5,0.5 0,1,0.5,0.5
130 4->1 channel effects:
131 left front only is 1,0,0,0
132 left only is 0.5,0,0,0 0,0,0,0 0.5,0,0,0
133 etc.
134 4->2 channel effects:
135 merge front/back is 0.5,0,0,0 0,0.5,0,0 0.5,0,0,0 0,0.5,0,0
136 selections similar to above
137 4->4 channel effects:
138 left front to all is 1,1,1,1 0,0,0,0
139 right front to all is 0,0,0,0 1,1,1,1
140 left f/r to all f/r is 1,1,0,0 0,0,0,0 0,0,1,1 0,0,0,0
141 etc.
143 The interesting cases from above (deserving of abbreviations of
144 less than 16 numbers) are:
146 0) n->n volume change (1 number)
147 1) 1->n duplication (0 numbers)
148 2) 2->1 mixdown (0 or 2 numbers)
149 3) 2->2 balance (1 number)
150 4) 2->2 fully general mix (4 numbers)
151 5) 2->4 duplication (0 numbers)
152 6) 4->1 mixdown (0 or 4 numbers)
153 7) 4->2 mixdown (0, or 2 numbers)
154 8) 4->4 balance (1 or 2 numbers)
156 The above has one ambiguity: n->n volume change conflicts with
157 n->n balance for n != 1. In such a case, we'll prefer
158 balance, since there is already a volume effect in vol.c.
160 GHK 2000/11/28
162 priv_t * mixer = (priv_t *) effp->priv;
163 double pans[16];
164 int i, j;
165 int ichan, ochan;
167 for (i = 0; i < 16; i++)
168 pans[i] = ((double*)&mixer->sources[0][0])[i];
170 ichan = effp->in_signal.channels;
171 ochan = effp->out_signal.channels;
172 if (ochan == -1) {
173 lsx_fail("Output must have known number of channels");
174 return(SOX_EOF);
177 if ((ichan != 1 && ichan != 2 && ichan != 4 &&
178 mixer->mix != MIX_CENTER && ochan != 1)
179 || (ochan != 1 && ochan != 2 && ochan != 4)) {
180 lsx_fail("Can't mix %d -> %d channels", ichan, ochan);
181 return (SOX_EOF);
184 /* Handle the special-case flags */
185 switch (mixer->mix) {
186 case MIX_CENTER:
187 if (ichan == ochan)
188 return SOX_EFF_NULL;
189 break; /* Code below will handle this case */
190 case 'l':
191 if (ichan == 2 && ochan == 1)
193 pans[0] = 1.0;
194 pans[1] = 0.0;
195 mixer->num_pans = 2;
197 else if (ichan == 4 && ochan == 1)
199 pans[0] = 0.5;
200 pans[1] = 0.0;
201 pans[2] = 0.5;
202 pans[3] = 0.0;
203 mixer->num_pans = 4;
205 else
207 lsx_fail("Can't mix -%c %d -> %d channels", mixer->mix, ichan, ochan);
208 return SOX_EOF;
210 break;
211 case 'r':
212 if (ichan == 2 && ochan == 1)
214 pans[0] = 0.0;
215 pans[1] = 1.0;
216 mixer->num_pans = 2;
218 else if (ichan == 4 && ochan == 1)
220 pans[0] = 0.0;
221 pans[1] = 0.5;
222 pans[2] = 0.0;
223 pans[3] = 0.5;
224 mixer->num_pans = 4;
226 else
228 lsx_fail("Can't mix -%c %d -> %d channels", mixer->mix, ichan, ochan);
229 return SOX_EOF;
231 break;
232 case 'f':
233 if (ichan == 4 && ochan == 2)
235 pans[0] = 1.0;
236 pans[1] = 0.0;
237 mixer->num_pans = 2;
239 else if (ichan == 4 && ochan == 1)
241 pans[0] = 0.5;
242 pans[1] = 0.5;
243 pans[2] = 0.0;
244 pans[3] = 0.0;
245 mixer->num_pans = 4;
247 else
249 lsx_fail("Can't mix -%c %d -> %d channels", mixer->mix, ichan, ochan);
250 return SOX_EOF;
252 break;
253 case 'b':
254 if (ichan == 4 && ochan == 2)
256 pans[0] = 0.0;
257 pans[1] = 1.0;
258 mixer->num_pans = 2;
260 else if (ichan == 4 && ochan == 1)
262 pans[0] = 0.0;
263 pans[1] = 0.0;
264 pans[2] = 0.5;
265 pans[3] = 0.5;
266 mixer->num_pans = 4;
268 else
270 lsx_fail("Can't mix -%c %d -> %d channels", mixer->mix, ichan, ochan);
271 return SOX_EOF;
273 break;
274 case '1':
275 if (ichan == 2 && ochan == 1)
277 pans[0] = 1.0;
278 pans[1] = 0.0;
279 mixer->num_pans = 2;
281 else if (ichan == 4 && ochan == 1)
283 pans[0] = 1.0;
284 pans[1] = 0.0;
285 pans[2] = 0.0;
286 pans[3] = 0.0;
287 mixer->num_pans = 4;
289 else
291 lsx_fail("Can't mix -%c %d -> %d channels", mixer->mix, ichan, ochan);
292 return SOX_EOF;
294 break;
295 case '2':
296 if (ichan == 2 && ochan == 1)
298 pans[0] = 0.0;
299 pans[1] = 1.0;
300 mixer->num_pans = 2;
302 else if (ichan == 4 && ochan == 1)
304 pans[0] = 0.0;
305 pans[1] = 1.0;
306 pans[2] = 0.0;
307 pans[3] = 0.0;
308 mixer->num_pans = 4;
310 else
312 lsx_fail("Can't mix -%c %d -> %d channels", mixer->mix, ichan, ochan);
313 return SOX_EOF;
315 break;
317 case '3':
318 if (ichan == 4 && ochan == 1)
320 pans[0] = 0.0;
321 pans[1] = 0.0;
322 pans[2] = 1.0;
323 pans[3] = 0.0;
324 mixer->num_pans = 4;
326 else
328 lsx_fail("Can't mix -%c %d -> %d channels", mixer->mix, ichan, ochan);
329 return SOX_EOF;
331 break;
333 case '4':
334 if (ichan == 4 && ochan == 1)
336 pans[0] = 0.0;
337 pans[1] = 0.0;
338 pans[2] = 0.0;
339 pans[3] = 1.0;
340 mixer->num_pans = 4;
342 else
344 lsx_fail("Can't mix -%c %d -> %d channels", mixer->mix, ichan, ochan);
345 return SOX_EOF;
347 break;
349 case MIX_SPECIFIED:
350 break;
351 default:
352 lsx_fail("Unknown mix option");
353 return SOX_EOF;
356 /* If number of pans is 4 or less then its a shorthand
357 * representation. If user specified it, then we have
358 * garbage in our sources[][] array. Need to clear that
359 * now that all data is stored in pans[] array.
361 if (mixer->num_pans <= 4)
363 for (i = 0; i < ichan; i++)
365 for (j = 0; j < ochan; j++)
367 mixer->sources[i][j] = 0;
372 /* If the number of pans given is 4 or fewer, handle the special */
373 /* cases listed in the comments above. The code is lengthy but */
374 /* straightforward. */
375 if (mixer->num_pans == 0) {
376 /* CASE 1 */
377 if (ichan == 1 && ochan > ichan) {
378 mixer->sources[0][0] = 1.0;
379 mixer->sources[0][1] = 1.0;
380 mixer->sources[0][2] = 1.0;
381 mixer->sources[0][3] = 1.0;
383 /* CASE 2, 6 */
384 else if (ochan == 1) {
385 mixer->sources[0][0] = 1.0 / ichan;
387 /* CASE 5 */
388 else if (ichan == 2 && ochan == 4) {
389 mixer->sources[0][0] = 1.0;
390 mixer->sources[0][2] = 1.0;
391 mixer->sources[1][1] = 1.0;
392 mixer->sources[1][3] = 1.0;
394 /* CASE 7 */
395 else if (ichan == 4 && ochan == 2) {
396 mixer->sources[0][0] = 0.5;
397 mixer->sources[1][1] = 0.5;
398 mixer->sources[2][0] = 0.5;
399 mixer->sources[3][1] = 0.5;
401 else {
402 lsx_fail("You must specify at least one mix level when using mixer with an unusual number of channels.");
403 return(SOX_EOF);
406 else if (mixer->num_pans == 1) {
407 /* Might be volume change or balance change */
408 /* CASE 3 and CASE 8 */
409 if ((ichan == 2 || ichan == 4) && ichan == ochan) {
410 /* -1 is left only, 1 is right only */
411 if (pans[0] <= 0.0) {
412 mixer->sources[1][1] = pans[0] + 1.0;
413 if (mixer->sources[1][1] < 0.0)
414 mixer->sources[1][1] = 0.0;
415 mixer->sources[0][0] = 1.0;
417 else {
418 mixer->sources[0][0] = 1.0 - pans[0];
419 if (mixer->sources[0][0] < 0.0)
420 mixer->sources[0][0] = 0.0;
421 mixer->sources[1][1] = 1.0;
423 if (ichan == 4) {
424 mixer->sources[2][2] = mixer->sources[0][0];
425 mixer->sources[3][3] = mixer->sources[1][1];
428 else
430 lsx_fail("Invalid options while not mixing");
431 return SOX_EOF;
434 else if (mixer->num_pans == 2) {
435 /* CASE 2 */
436 if (ichan == 2 && ochan == 1) {
437 mixer->sources[0][0] = pans[0];
438 mixer->sources[1][0] = pans[1];
440 /* CASE 7 */
441 else if (ichan == 4 && ochan == 2) {
442 mixer->sources[0][0] = pans[0];
443 mixer->sources[1][1] = pans[0];
444 mixer->sources[2][0] = pans[1];
445 mixer->sources[3][1] = pans[1];
447 /* CASE 8 */
448 else if (ichan == 4 && ochan == 4) {
449 /* pans[0] is front -> front, pans[1] is for back */
450 mixer->sources[0][0] = pans[0];
451 mixer->sources[1][1] = pans[0];
452 mixer->sources[2][2] = pans[1];
453 mixer->sources[3][3] = pans[1];
455 else
457 lsx_fail("Invalid options for this channel combination");
458 return SOX_EOF;
461 else if (mixer->num_pans == 3) {
462 lsx_fail("Invalid options while not mixing");
463 return SOX_EOF;
465 else if (mixer->num_pans == 4) {
466 /* CASE 4 */
467 if (ichan == 2 && ochan == 2) {
468 /* Shorthand for 2-channel case */
469 mixer->sources[0][0] = pans[0];
470 mixer->sources[0][1] = pans[1];
471 mixer->sources[1][0] = pans[2];
472 mixer->sources[1][1] = pans[3];
474 /* CASE 6 */
475 else if (ichan == 4 && ochan == 1) {
476 mixer->sources[0][0] = pans[0];
477 mixer->sources[1][0] = pans[1];
478 mixer->sources[2][0] = pans[2];
479 mixer->sources[3][0] = pans[3];
481 else
483 lsx_fail("Invalid options for this channel combination");
484 return SOX_EOF;
488 if (effp->in_signal.mult) {
489 double max_sum = 0;
491 for (j = 0; j < (int)effp->out_signal.channels; ++j) {
492 double sum = 0;
493 for (i = 0; i < (int)effp->in_signal.channels; ++i)
494 sum += fabs(mixer->sources[mixer->mix == MIX_CENTER? 0 : i][j]);
495 max_sum = max(max_sum, sum);
497 if (max_sum > 1)
498 *effp->in_signal.mult /= max_sum;
501 if (effp->in_signal.channels != effp->out_signal.channels)
502 return SOX_SUCCESS;
504 for (i = 0; i < (int)effp->in_signal.channels; ++i)
505 for (j = 0; j < (int)effp->out_signal.channels; ++j)
506 if (mixer->sources[i][j] != (i == j))
507 return SOX_SUCCESS;
509 return SOX_EFF_NULL;
513 * Process either isamp or osamp samples, whichever is smaller.
516 static int flow(sox_effect_t * effp, const sox_sample_t *ibuf, sox_sample_t *obuf,
517 size_t *isamp, size_t *osamp)
519 priv_t * mixer = (priv_t *) effp->priv;
520 size_t len, done;
521 int ichan, ochan;
522 int i, j;
523 double samp;
525 ichan = effp->in_signal.channels;
526 ochan = effp->out_signal.channels;
527 len = *isamp / ichan;
528 if (len > *osamp / ochan)
529 len = *osamp / ochan;
530 for (done = 0; done < len; done++, ibuf += ichan, obuf += ochan) {
531 for (j = 0; j < ochan; j++) {
532 samp = 0.0;
533 for (i = 0; i < ichan; i++)
534 samp += ibuf[i] * mixer->sources[mixer->mix == MIX_CENTER? 0 : i][j];
535 SOX_SAMPLE_CLIP_COUNT(samp, effp->clips);
536 obuf[j] = samp;
539 *isamp = len * ichan;
540 *osamp = len * ochan;
541 return (SOX_SUCCESS);
544 sox_effect_handler_t const * lsx_mixer_effect_fn(void)
546 static sox_effect_handler_t handler = {
547 "mixer",
548 "[ -l | -r | -f | -b | -1 | -2 | -3 | -4 | n,n,n...,n ]",
549 SOX_EFF_MCHAN | SOX_EFF_CHAN | SOX_EFF_GAIN,
550 getopts, start, flow, 0, 0, 0, sizeof(priv_t)
552 return &handler;
555 /*------------------------------- oops effect --------------------------------*/
557 static int oops_getopts(sox_effect_t * effp, int argc, char * * argv)
559 char * args[] = {0, "1,1,-1,-1"};
560 args[0] = argv[0];
561 return --argc? lsx_usage(effp) : lsx_mixer_effect_fn()->getopts(effp, (int)array_length(args), args);
564 sox_effect_handler_t const * lsx_oops_effect_fn(void)
566 static sox_effect_handler_t handler;
567 handler = *lsx_mixer_effect_fn();
568 handler.name = "oops";
569 handler.usage = NULL;
570 handler.getopts = oops_getopts;
571 return &handler;