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.
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) */
30 int mix
; /* How are we mixing it? */
33 /* MIX_CENTER is shorthand to mix channels together at 50% each */
35 #define MIX_SPECIFIED 1
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];
48 for (i
= 0; i
< 16; i
++)
50 mixer
->mix
= MIX_CENTER
;
53 /* Parse parameters. Since we don't yet know the number of */
54 /* input and output channels, we'll record the information for */
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])
67 return lsx_usage(effp
);
71 mixer
->mix
= MIX_SPECIFIED
;
72 pans
[0] = atof(argv
[0]);
73 for (s
= argv
[0], commas
= 0; *s
; ++s
) {
77 lsx_fail("mixer can only take up to 16 pan values");
80 pans
[commas
] = atof(s
+1);
83 mixer
->num_pans
= commas
+ 1;
87 mixer
->mix
= MIX_CENTER
;
90 return lsx_usage(effp
);
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
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
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.
162 priv_t
* mixer
= (priv_t
*) effp
->priv
;
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
;
173 lsx_fail("Output must have known number of channels");
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
);
184 /* Handle the special-case flags */
185 switch (mixer
->mix
) {
189 break; /* Code below will handle this case */
191 if (ichan
== 2 && ochan
== 1)
197 else if (ichan
== 4 && ochan
== 1)
207 lsx_fail("Can't mix -%c %d -> %d channels", mixer
->mix
, ichan
, ochan
);
212 if (ichan
== 2 && ochan
== 1)
218 else if (ichan
== 4 && ochan
== 1)
228 lsx_fail("Can't mix -%c %d -> %d channels", mixer
->mix
, ichan
, ochan
);
233 if (ichan
== 4 && ochan
== 2)
239 else if (ichan
== 4 && ochan
== 1)
249 lsx_fail("Can't mix -%c %d -> %d channels", mixer
->mix
, ichan
, ochan
);
254 if (ichan
== 4 && ochan
== 2)
260 else if (ichan
== 4 && ochan
== 1)
270 lsx_fail("Can't mix -%c %d -> %d channels", mixer
->mix
, ichan
, ochan
);
275 if (ichan
== 2 && ochan
== 1)
281 else if (ichan
== 4 && ochan
== 1)
291 lsx_fail("Can't mix -%c %d -> %d channels", mixer
->mix
, ichan
, ochan
);
296 if (ichan
== 2 && ochan
== 1)
302 else if (ichan
== 4 && ochan
== 1)
312 lsx_fail("Can't mix -%c %d -> %d channels", mixer
->mix
, ichan
, ochan
);
318 if (ichan
== 4 && ochan
== 1)
328 lsx_fail("Can't mix -%c %d -> %d channels", mixer
->mix
, ichan
, ochan
);
334 if (ichan
== 4 && ochan
== 1)
344 lsx_fail("Can't mix -%c %d -> %d channels", mixer
->mix
, ichan
, ochan
);
352 lsx_fail("Unknown mix option");
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) {
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;
384 else if (ochan
== 1) {
385 mixer
->sources
[0][0] = 1.0 / ichan
;
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;
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;
402 lsx_fail("You must specify at least one mix level when using mixer with an unusual number of channels.");
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;
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;
424 mixer
->sources
[2][2] = mixer
->sources
[0][0];
425 mixer
->sources
[3][3] = mixer
->sources
[1][1];
430 lsx_fail("Invalid options while not mixing");
434 else if (mixer
->num_pans
== 2) {
436 if (ichan
== 2 && ochan
== 1) {
437 mixer
->sources
[0][0] = pans
[0];
438 mixer
->sources
[1][0] = pans
[1];
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];
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];
457 lsx_fail("Invalid options for this channel combination");
461 else if (mixer
->num_pans
== 3) {
462 lsx_fail("Invalid options while not mixing");
465 else if (mixer
->num_pans
== 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];
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];
483 lsx_fail("Invalid options for this channel combination");
488 if (effp
->in_signal
.mult
) {
491 for (j
= 0; j
< (int)effp
->out_signal
.channels
; ++j
) {
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
);
498 *effp
->in_signal
.mult
/= max_sum
;
501 if (effp
->in_signal
.channels
!= effp
->out_signal
.channels
)
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
))
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
;
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
++) {
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
);
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
= {
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
)
555 /*------------------------------- oops effect --------------------------------*/
557 static int oops_getopts(sox_effect_t
* effp
, int argc
, char * * argv
)
559 char * args
[] = {0, "1,1,-1,-1"};
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
;