xref: /openbsd-src/usr.bin/sndiod/dsp.c (revision 7b6392009e6e5a7f8e494c162a4d259ea5e13a62)
1*7b639200Sratchov /*	$OpenBSD: dsp.c,v 1.22 2024/12/20 07:35:56 ratchov Exp $	*/
287bc9f6aSratchov /*
387bc9f6aSratchov  * Copyright (c) 2008-2012 Alexandre Ratchov <alex@caoua.org>
487bc9f6aSratchov  *
587bc9f6aSratchov  * Permission to use, copy, modify, and distribute this software for any
687bc9f6aSratchov  * purpose with or without fee is hereby granted, provided that the above
787bc9f6aSratchov  * copyright notice and this permission notice appear in all copies.
887bc9f6aSratchov  *
987bc9f6aSratchov  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1087bc9f6aSratchov  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1187bc9f6aSratchov  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1287bc9f6aSratchov  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1387bc9f6aSratchov  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1487bc9f6aSratchov  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1587bc9f6aSratchov  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1687bc9f6aSratchov  */
17*7b639200Sratchov #include <stdio.h>
1887bc9f6aSratchov #include <string.h>
1987bc9f6aSratchov #include "dsp.h"
2087bc9f6aSratchov #include "utils.h"
2187bc9f6aSratchov 
22b020cfe1Snaddy const int aparams_ctltovol[128] = {
23be3fa683Sratchov 	        0,     65536,     68109,     70783,
24be3fa683Sratchov 	    73562,     76450,     79451,     82570,
25be3fa683Sratchov 	    85812,     89181,     92682,     96321,
26be3fa683Sratchov 	   100102,    104032,    108116,    112361,
27be3fa683Sratchov 	   116772,    121356,    126121,    131072,
28be3fa683Sratchov 	   136218,    141566,    147123,    152899,
29be3fa683Sratchov 	   158902,    165140,    171624,    178361,
30be3fa683Sratchov 	   185364,    192641,    200204,    208064,
31be3fa683Sratchov 	   216232,    224721,    233544,    242713,
32be3fa683Sratchov 	   252241,    262144,    272436,    283131,
33be3fa683Sratchov 	   294247,    305799,    317804,    330281,
34be3fa683Sratchov 	   343247,    356723,    370728,    385282,
35be3fa683Sratchov 	   400408,    416128,    432465,    449443,
36be3fa683Sratchov 	   467088,    485425,    504482,    524288,
37be3fa683Sratchov 	   544871,    566262,    588493,    611597,
38be3fa683Sratchov 	   635608,    660561,    686495,    713446,
39be3fa683Sratchov 	   741455,    770564,    800816,    832255,
40be3fa683Sratchov 	   864929,    898885,    934175,    970850,
41be3fa683Sratchov 	  1008965,   1048576,   1089742,   1132525,
42be3fa683Sratchov 	  1176987,   1223194,   1271216,   1321123,
43be3fa683Sratchov 	  1372989,   1426892,   1482910,   1541128,
44be3fa683Sratchov 	  1601632,   1664511,   1729858,   1797771,
45be3fa683Sratchov 	  1868350,   1941700,   2017930,   2097152,
46be3fa683Sratchov 	  2179485,   2265049,   2353974,   2446389,
47be3fa683Sratchov 	  2542432,   2642246,   2745978,   2853783,
48be3fa683Sratchov 	  2965821,   3082257,   3203264,   3329021,
49be3fa683Sratchov 	  3459716,   3595542,   3736700,   3883400,
50be3fa683Sratchov 	  4035859,   4194304,   4358969,   4530099,
51be3fa683Sratchov 	  4707947,   4892777,   5084864,   5284492,
52be3fa683Sratchov 	  5491957,   5707567,   5931642,   6164513,
53be3fa683Sratchov 	  6406527,   6658043,   6919432,   7191084,
54be3fa683Sratchov 	  7473400,   7766800,   8071719,   8388608
5587bc9f6aSratchov };
5687bc9f6aSratchov 
57b020cfe1Snaddy const int resamp_filt[RESAMP_LENGTH / RESAMP_STEP + 1] = {
583220ebbaSratchov 	      0,       0,       3,       9,      22,      42,      73,     116,
593220ebbaSratchov 	    174,     248,     341,     454,     589,     749,     934,    1148,
603220ebbaSratchov 	   1392,    1666,    1974,    2316,    2693,    3107,    3560,    4051,
613220ebbaSratchov 	   4582,    5154,    5766,    6420,    7116,    7853,    8632,    9451,
623220ebbaSratchov 	  10311,   11210,   12148,   13123,   14133,   15178,   16253,   17359,
633220ebbaSratchov 	  18491,   19647,   20824,   22018,   23226,   24443,   25665,   26888,
643220ebbaSratchov 	  28106,   29315,   30509,   31681,   32826,   33938,   35009,   36033,
653220ebbaSratchov 	  37001,   37908,   38744,   39502,   40174,   40750,   41223,   41582,
663220ebbaSratchov 	  41819,   41925,   41890,   41704,   41358,   40842,   40147,   39261,
673220ebbaSratchov 	  38176,   36881,   35366,   33623,   31641,   29411,   26923,   24169,
683220ebbaSratchov 	  21140,   17827,   14222,   10317,    6105,    1580,   -3267,   -8440,
693220ebbaSratchov 	 -13944,  -19785,  -25967,  -32492,  -39364,  -46584,  -54153,  -62072,
703220ebbaSratchov 	 -70339,  -78953,  -87911,  -97209, -106843, -116806, -127092, -137692,
713220ebbaSratchov 	-148596, -159795, -171276, -183025, -195029, -207271, -219735, -232401,
723220ebbaSratchov 	-245249, -258259, -271407, -284670, -298021, -311434, -324880, -338329,
733220ebbaSratchov 	-351750, -365111, -378378, -391515, -404485, -417252, -429775, -442015,
743220ebbaSratchov 	-453930, -465477, -476613, -487294, -497472, -507102, -516137, -524527,
753220ebbaSratchov 	-532225, -539181, -545344, -550664, -555090, -558571, -561055, -562490,
763220ebbaSratchov 	-562826, -562010, -559990, -556717, -552139, -546205, -538866, -530074,
773220ebbaSratchov 	-519779, -507936, -494496, -479416, -462652, -444160, -423901, -401835,
783220ebbaSratchov 	-377923, -352132, -324425, -294772, -263143, -229509, -193847, -156134,
793220ebbaSratchov 	-116348,  -74474,  -30494,   15601,   63822,  114174,  166661,  221283,
803220ebbaSratchov 	 278037,  336916,  397911,  461009,  526194,  593446,  662741,  734054,
813220ebbaSratchov 	 807354,  882608,  959779, 1038826, 1119706, 1202370, 1286768, 1372846,
823220ebbaSratchov 	1460546, 1549808, 1640566, 1732753, 1826299, 1921130, 2017169, 2114336,
833220ebbaSratchov 	2212550, 2311723, 2411770, 2512598, 2614116, 2716228, 2818836, 2921841,
843220ebbaSratchov 	3025142, 3128636, 3232218, 3335782, 3439219, 3542423, 3645282, 3747687,
853220ebbaSratchov 	3849526, 3950687, 4051059, 4150530, 4248987, 4346320, 4442415, 4537163,
863220ebbaSratchov 	4630453, 4722177, 4812225, 4900493, 4986873, 5071263, 5153561, 5233668,
873220ebbaSratchov 	5311485, 5386917, 5459872, 5530259, 5597992, 5662986, 5725160, 5784436,
883220ebbaSratchov 	5840739, 5893999, 5944148, 5991122, 6034862, 6075313, 6112422, 6146142,
893220ebbaSratchov 	6176430, 6203247, 6226559, 6246335, 6262551, 6275185, 6284220, 6289647,
903220ebbaSratchov 	6291456, 6289647, 6284220, 6275185, 6262551, 6246335, 6226559, 6203247,
913220ebbaSratchov 	6176430, 6146142, 6112422, 6075313, 6034862, 5991122, 5944148, 5893999,
923220ebbaSratchov 	5840739, 5784436, 5725160, 5662986, 5597992, 5530259, 5459872, 5386917,
933220ebbaSratchov 	5311485, 5233668, 5153561, 5071263, 4986873, 4900493, 4812225, 4722177,
943220ebbaSratchov 	4630453, 4537163, 4442415, 4346320, 4248987, 4150530, 4051059, 3950687,
953220ebbaSratchov 	3849526, 3747687, 3645282, 3542423, 3439219, 3335782, 3232218, 3128636,
963220ebbaSratchov 	3025142, 2921841, 2818836, 2716228, 2614116, 2512598, 2411770, 2311723,
973220ebbaSratchov 	2212550, 2114336, 2017169, 1921130, 1826299, 1732753, 1640566, 1549808,
983220ebbaSratchov 	1460546, 1372846, 1286768, 1202370, 1119706, 1038826,  959779,  882608,
993220ebbaSratchov 	 807354,  734054,  662741,  593446,  526194,  461009,  397911,  336916,
1003220ebbaSratchov 	 278037,  221283,  166661,  114174,   63822,   15601,  -30494,  -74474,
1013220ebbaSratchov 	-116348, -156134, -193847, -229509, -263143, -294772, -324425, -352132,
1023220ebbaSratchov 	-377923, -401835, -423901, -444160, -462652, -479416, -494496, -507936,
1033220ebbaSratchov 	-519779, -530074, -538866, -546205, -552139, -556717, -559990, -562010,
1043220ebbaSratchov 	-562826, -562490, -561055, -558571, -555090, -550664, -545344, -539181,
1053220ebbaSratchov 	-532225, -524527, -516137, -507102, -497472, -487294, -476613, -465477,
1063220ebbaSratchov 	-453930, -442015, -429775, -417252, -404485, -391515, -378378, -365111,
1073220ebbaSratchov 	-351750, -338329, -324880, -311434, -298021, -284670, -271407, -258259,
1083220ebbaSratchov 	-245249, -232401, -219735, -207271, -195029, -183025, -171276, -159795,
1093220ebbaSratchov 	-148596, -137692, -127092, -116806, -106843,  -97209,  -87911,  -78953,
1103220ebbaSratchov 	 -70339,  -62072,  -54153,  -46584,  -39364,  -32492,  -25967,  -19785,
1113220ebbaSratchov 	 -13944,   -8440,   -3267,    1580,    6105,   10317,   14222,   17827,
1123220ebbaSratchov 	  21140,   24169,   26923,   29411,   31641,   33623,   35366,   36881,
1133220ebbaSratchov 	  38176,   39261,   40147,   40842,   41358,   41704,   41890,   41925,
1143220ebbaSratchov 	  41819,   41582,   41223,   40750,   40174,   39502,   38744,   37908,
1153220ebbaSratchov 	  37001,   36033,   35009,   33938,   32826,   31681,   30509,   29315,
1163220ebbaSratchov 	  28106,   26888,   25665,   24443,   23226,   22018,   20824,   19647,
1173220ebbaSratchov 	  18491,   17359,   16253,   15178,   14133,   13123,   12148,   11210,
1183220ebbaSratchov 	  10311,    9451,    8632,    7853,    7116,    6420,    5766,    5154,
1193220ebbaSratchov 	   4582,    4051,    3560,    3107,    2693,    2316,    1974,    1666,
1203220ebbaSratchov 	   1392,    1148,     934,     749,     589,     454,     341,     248,
1213220ebbaSratchov 	    174,     116,      73,      42,      22,       9,       3,       0,
1223220ebbaSratchov 	      0
1233220ebbaSratchov };
1243220ebbaSratchov 
1253220ebbaSratchov 
12687bc9f6aSratchov /*
12787bc9f6aSratchov  * Generate a string corresponding to the encoding in par,
12887bc9f6aSratchov  * return the length of the resulting string.
12987bc9f6aSratchov  */
13087bc9f6aSratchov int
13187bc9f6aSratchov aparams_enctostr(struct aparams *par, char *ostr)
13287bc9f6aSratchov {
13387bc9f6aSratchov 	char *p = ostr;
13487bc9f6aSratchov 
13587bc9f6aSratchov 	*p++ = par->sig ? 's' : 'u';
13687bc9f6aSratchov 	if (par->bits > 9)
13787bc9f6aSratchov 		*p++ = '0' + par->bits / 10;
13887bc9f6aSratchov 	*p++ = '0' + par->bits % 10;
13987bc9f6aSratchov 	if (par->bps > 1) {
14087bc9f6aSratchov 		*p++ = par->le ? 'l' : 'b';
14187bc9f6aSratchov 		*p++ = 'e';
14287bc9f6aSratchov 		if (par->bps != APARAMS_BPS(par->bits) ||
14387bc9f6aSratchov 		    par->bits < par->bps * 8) {
14487bc9f6aSratchov 			*p++ = par->bps + '0';
14587bc9f6aSratchov 			if (par->bits < par->bps * 8) {
14687bc9f6aSratchov 				*p++ = par->msb ? 'm' : 'l';
14787bc9f6aSratchov 				*p++ = 's';
14887bc9f6aSratchov 				*p++ = 'b';
14987bc9f6aSratchov 			}
15087bc9f6aSratchov 		}
15187bc9f6aSratchov 	}
15287bc9f6aSratchov 	*p++ = '\0';
15387bc9f6aSratchov 	return p - ostr - 1;
15487bc9f6aSratchov }
15587bc9f6aSratchov 
15687bc9f6aSratchov /*
15787bc9f6aSratchov  * Parse an encoding string, examples: s8, u8, s16, s16le, s24be ...
15887bc9f6aSratchov  * set *istr to the char following the encoding. Return the number
15987bc9f6aSratchov  * of bytes consumed.
16087bc9f6aSratchov  */
16187bc9f6aSratchov int
16287bc9f6aSratchov aparams_strtoenc(struct aparams *par, char *istr)
16387bc9f6aSratchov {
16487bc9f6aSratchov 	char *p = istr;
16587bc9f6aSratchov 	int i, sig, bits, le, bps, msb;
16687bc9f6aSratchov 
16787bc9f6aSratchov #define IS_SEP(c)			\
16887bc9f6aSratchov 	(((c) < 'a' || (c) > 'z') &&	\
16987bc9f6aSratchov 	 ((c) < 'A' || (c) > 'Z') &&	\
17087bc9f6aSratchov 	 ((c) < '0' || (c) > '9'))
17187bc9f6aSratchov 
17287bc9f6aSratchov 	/*
17387bc9f6aSratchov 	 * get signedness
17487bc9f6aSratchov 	 */
17587bc9f6aSratchov 	if (*p == 's') {
17687bc9f6aSratchov 		sig = 1;
17787bc9f6aSratchov 	} else if (*p == 'u') {
17887bc9f6aSratchov 		sig = 0;
17987bc9f6aSratchov 	} else
18087bc9f6aSratchov 		return 0;
18187bc9f6aSratchov 	p++;
18287bc9f6aSratchov 
18387bc9f6aSratchov 	/*
18487bc9f6aSratchov 	 * get number of bits per sample
18587bc9f6aSratchov 	 */
18687bc9f6aSratchov 	bits = 0;
18787bc9f6aSratchov 	for (i = 0; i < 2; i++) {
18887bc9f6aSratchov 		if (*p < '0' || *p > '9')
18987bc9f6aSratchov 			break;
19087bc9f6aSratchov 		bits = (bits * 10) + *p - '0';
19187bc9f6aSratchov 		p++;
19287bc9f6aSratchov 	}
19387bc9f6aSratchov 	if (bits < BITS_MIN || bits > BITS_MAX)
19487bc9f6aSratchov 		return 0;
19587bc9f6aSratchov 	bps = APARAMS_BPS(bits);
19687bc9f6aSratchov 	msb = 1;
19787bc9f6aSratchov 	le = ADATA_LE;
19887bc9f6aSratchov 
19987bc9f6aSratchov 	/*
20087bc9f6aSratchov 	 * get (optional) endianness
20187bc9f6aSratchov 	 */
20287bc9f6aSratchov 	if (p[0] == 'l' && p[1] == 'e') {
20387bc9f6aSratchov 		le = 1;
20487bc9f6aSratchov 		p += 2;
20587bc9f6aSratchov 	} else if (p[0] == 'b' && p[1] == 'e') {
20687bc9f6aSratchov 		le = 0;
20787bc9f6aSratchov 		p += 2;
20887bc9f6aSratchov 	} else if (IS_SEP(*p)) {
20987bc9f6aSratchov 		goto done;
21087bc9f6aSratchov 	} else
21187bc9f6aSratchov 		return 0;
21287bc9f6aSratchov 
21387bc9f6aSratchov 	/*
21487bc9f6aSratchov 	 * get (optional) number of bytes
21587bc9f6aSratchov 	 */
21687bc9f6aSratchov 	if (*p >= '0' && *p <= '9') {
21787bc9f6aSratchov 		bps = *p - '0';
21887bc9f6aSratchov 		if (bps < (bits + 7) / 8 ||
21987bc9f6aSratchov 		    bps > (BITS_MAX + 7) / 8)
22087bc9f6aSratchov 			return 0;
22187bc9f6aSratchov 		p++;
22287bc9f6aSratchov 
22387bc9f6aSratchov 		/*
224c77ecc4eSnicm 		 * get (optional) alignment
22587bc9f6aSratchov 		 */
22687bc9f6aSratchov 		if (p[0] == 'm' && p[1] == 's' && p[2] == 'b') {
22787bc9f6aSratchov 			msb = 1;
22887bc9f6aSratchov 			p += 3;
22987bc9f6aSratchov 		} else if (p[0] == 'l' && p[1] == 's' && p[2] == 'b') {
23087bc9f6aSratchov 			msb = 0;
23187bc9f6aSratchov 			p += 3;
23287bc9f6aSratchov 		} else if (IS_SEP(*p)) {
23387bc9f6aSratchov 			goto done;
23487bc9f6aSratchov 		} else
23587bc9f6aSratchov 			return 0;
23687bc9f6aSratchov 	} else if (!IS_SEP(*p))
23787bc9f6aSratchov 		return 0;
23887bc9f6aSratchov 
23987bc9f6aSratchov done:
24087bc9f6aSratchov 	par->msb = msb;
24187bc9f6aSratchov 	par->sig = sig;
24287bc9f6aSratchov 	par->bits = bits;
24387bc9f6aSratchov 	par->bps = bps;
24487bc9f6aSratchov 	par->le = le;
24587bc9f6aSratchov 	return p - istr;
24687bc9f6aSratchov }
24787bc9f6aSratchov 
24887bc9f6aSratchov /*
24987bc9f6aSratchov  * Initialise parameters structure with the defaults natively supported
25087bc9f6aSratchov  * by the machine.
25187bc9f6aSratchov  */
25287bc9f6aSratchov void
25387bc9f6aSratchov aparams_init(struct aparams *par)
25487bc9f6aSratchov {
25587bc9f6aSratchov 	par->bps = sizeof(adata_t);
25687bc9f6aSratchov 	par->bits = ADATA_BITS;
25787bc9f6aSratchov 	par->le = ADATA_LE;
25887bc9f6aSratchov 	par->sig = 1;
25987bc9f6aSratchov 	par->msb = 0;
26087bc9f6aSratchov }
26187bc9f6aSratchov 
26287bc9f6aSratchov /*
26387bc9f6aSratchov  * return true if encoding corresponds to what we store in adata_t
26487bc9f6aSratchov  */
26587bc9f6aSratchov int
26687bc9f6aSratchov aparams_native(struct aparams *par)
26787bc9f6aSratchov {
26891f86958Sratchov 	return par->sig &&
26991f86958Sratchov 	    par->bps == sizeof(adata_t) &&
27091f86958Sratchov 	    par->bits == ADATA_BITS &&
27187bc9f6aSratchov 	    (par->bps == 1 || par->le == ADATA_LE) &&
27287bc9f6aSratchov 	    (par->bits == par->bps * 8 || !par->msb);
27387bc9f6aSratchov }
27487bc9f6aSratchov 
27587bc9f6aSratchov /*
276b47fb7daSratchov  * Return the number of input and output frame that would be consumed
277b47fb7daSratchov  * by resamp_do(p, *icnt, *ocnt).
27887bc9f6aSratchov  */
279be3cc2b4Sratchov void
280b47fb7daSratchov resamp_getcnt(struct resamp *p, int *icnt, int *ocnt)
281b47fb7daSratchov {
282b47fb7daSratchov 	long long idiff, odiff;
283b47fb7daSratchov 	int cdiff;
284b47fb7daSratchov 
285b47fb7daSratchov 	cdiff = p->oblksz - p->diff;
286b47fb7daSratchov 	idiff = (long long)*icnt * p->oblksz;
287b47fb7daSratchov 	odiff = (long long)*ocnt * p->iblksz;
288b47fb7daSratchov 	if (odiff - idiff >= cdiff)
289b47fb7daSratchov 		*ocnt = (idiff + cdiff + p->iblksz - 1) / p->iblksz;
290b47fb7daSratchov 	else
291b47fb7daSratchov 		*icnt = (odiff + p->diff) / p->oblksz;
292b47fb7daSratchov }
293b47fb7daSratchov 
294b47fb7daSratchov /*
295b47fb7daSratchov  * Resample the given number of frames. The number of output frames
296b47fb7daSratchov  * must match the corresponding number of input frames. Either always
297b47fb7daSratchov  * use icnt and ocnt such that:
298b47fb7daSratchov  *
299b47fb7daSratchov  *	 icnt * oblksz = ocnt * iblksz
300b47fb7daSratchov  *
301b47fb7daSratchov  * or use resamp_getcnt() to calculate the proper numbers.
302b47fb7daSratchov  */
303b47fb7daSratchov void
304b47fb7daSratchov resamp_do(struct resamp *p, adata_t *in, adata_t *out, int icnt, int ocnt)
30587bc9f6aSratchov {
30687bc9f6aSratchov 	unsigned int nch;
30787bc9f6aSratchov 	adata_t *idata;
30887bc9f6aSratchov 	unsigned int oblksz;
309b47fb7daSratchov 	unsigned int ifr;
31087bc9f6aSratchov 	int s, ds, diff;
31187bc9f6aSratchov 	adata_t *odata;
31287bc9f6aSratchov 	unsigned int iblksz;
313b47fb7daSratchov 	unsigned int ofr;
31487bc9f6aSratchov 	unsigned int c;
3153220ebbaSratchov 	int64_t f[NCHAN_MAX];
31687bc9f6aSratchov 	adata_t *ctxbuf, *ctx;
31787bc9f6aSratchov 	unsigned int ctx_start;
3183220ebbaSratchov 	int q, qi, qf, n;
31987bc9f6aSratchov 
32087bc9f6aSratchov 	/*
32187bc9f6aSratchov 	 * Partially copy structures into local variables, to avoid
32287bc9f6aSratchov 	 * unnecessary indirections; this also allows the compiler to
32387bc9f6aSratchov 	 * order local variables more "cache-friendly".
32487bc9f6aSratchov 	 */
32587bc9f6aSratchov 	idata = in;
32687bc9f6aSratchov 	odata = out;
327b47fb7daSratchov 	diff = p->diff;
32887bc9f6aSratchov 	iblksz = p->iblksz;
32987bc9f6aSratchov 	oblksz = p->oblksz;
33087bc9f6aSratchov 	ctxbuf = p->ctx;
33187bc9f6aSratchov 	ctx_start = p->ctx_start;
33287bc9f6aSratchov 	nch = p->nch;
333b47fb7daSratchov 	ifr = icnt;
334b47fb7daSratchov 	ofr = ocnt;
33587bc9f6aSratchov 
336b47fb7daSratchov 	/*
337b47fb7daSratchov 	 * Start conversion.
338b47fb7daSratchov 	 */
339b47fb7daSratchov #ifdef DEBUG
340*7b639200Sratchov 	logx(4, "resamp: copying %d -> %d frames, diff = %d", ifr, ofr, diff);
341b47fb7daSratchov #endif
34287bc9f6aSratchov 	for (;;) {
343be3cc2b4Sratchov 		if (diff >= oblksz) {
344b47fb7daSratchov 			if (ifr == 0)
34587bc9f6aSratchov 				break;
3463220ebbaSratchov 			ctx_start = (ctx_start - 1) & (RESAMP_NCTX - 1);
34787bc9f6aSratchov 			ctx = ctxbuf + ctx_start;
34887bc9f6aSratchov 			for (c = nch; c > 0; c--) {
34987bc9f6aSratchov 				*ctx = *idata++;
35087bc9f6aSratchov 				ctx += RESAMP_NCTX;
35187bc9f6aSratchov 			}
352be3cc2b4Sratchov 			diff -= oblksz;
353b47fb7daSratchov 			ifr--;
354be3cc2b4Sratchov 		} else {
355b47fb7daSratchov 			if (ofr == 0)
356b47fb7daSratchov 				break;
3573220ebbaSratchov 
35832ba4c83Sratchov 			for (c = 0; c < nch; c++)
3593220ebbaSratchov 				f[c] = 0;
3603220ebbaSratchov 
3613220ebbaSratchov 			q = diff * p->filt_step;
3623220ebbaSratchov 			n = ctx_start;
3633220ebbaSratchov 
3643220ebbaSratchov 			while (q < RESAMP_LENGTH) {
3653220ebbaSratchov 				qi = q >> RESAMP_STEP_BITS;
3663220ebbaSratchov 				qf = q & (RESAMP_STEP - 1);
3673220ebbaSratchov 				s = resamp_filt[qi];
3683220ebbaSratchov 				ds = resamp_filt[qi + 1] - s;
3693220ebbaSratchov 				s += (int64_t)qf * ds >> RESAMP_STEP_BITS;
37087bc9f6aSratchov 				ctx = ctxbuf;
37132ba4c83Sratchov 				for (c = 0; c < nch; c++) {
3723220ebbaSratchov 					f[c] += (int64_t)ctx[n] * s;
37387bc9f6aSratchov 					ctx += RESAMP_NCTX;
3743220ebbaSratchov 				}
3753220ebbaSratchov 				q += p->filt_cutoff;
3763220ebbaSratchov 				n = (n + 1) & (RESAMP_NCTX - 1);
3773220ebbaSratchov 			}
3783220ebbaSratchov 
37932ba4c83Sratchov 			for (c = 0; c < nch; c++) {
3803220ebbaSratchov 				s = f[c] >> RESAMP_BITS;
3813220ebbaSratchov 				s = (int64_t)s * p->filt_cutoff >> RESAMP_BITS;
3823220ebbaSratchov #if ADATA_BITS == 16
3833220ebbaSratchov 				/*
3843220ebbaSratchov 				 * In 16-bit mode, we've no room for filter
3853220ebbaSratchov 				 * overshoots, so we need to clip the signal
3863220ebbaSratchov 				 * to avoid 16-bit integers to wrap around.
3873220ebbaSratchov 				 * In 24-bit mode, samples may exceed the
3883220ebbaSratchov 				 * [-1:1] range. Later, cmap_add() will clip
3893220ebbaSratchov 				 * them, so no need to clip them here as well.
3903220ebbaSratchov 				 */
3913220ebbaSratchov 				if (s >= ADATA_UNIT)
3923220ebbaSratchov 					s = ADATA_UNIT - 1;
3933220ebbaSratchov 				else if (s < -ADATA_UNIT)
3943220ebbaSratchov 					s = -ADATA_UNIT;
3953220ebbaSratchov #endif
3963220ebbaSratchov 				*odata++ = s;
39787bc9f6aSratchov 			}
398b47fb7daSratchov 
399be3cc2b4Sratchov 			diff += iblksz;
400b47fb7daSratchov 			ofr--;
40187bc9f6aSratchov 		}
40287bc9f6aSratchov 	}
403b47fb7daSratchov 	p->diff = diff;
404b47fb7daSratchov 	p->ctx_start = ctx_start;
405b47fb7daSratchov #ifdef DEBUG
406b47fb7daSratchov 	if (ifr != 0) {
407*7b639200Sratchov 		logx(0, "resamp_do: %d: too many input frames", ifr);
408b47fb7daSratchov 		panic();
409b47fb7daSratchov 	}
410b47fb7daSratchov 	if (ofr != 0) {
411*7b639200Sratchov 		logx(0, "resamp_do: %d: too many output frames", ofr);
412b47fb7daSratchov 		panic();
413b47fb7daSratchov 	}
414b47fb7daSratchov #endif
415b47fb7daSratchov }
416be3cc2b4Sratchov 
417b47fb7daSratchov static unsigned int
418b47fb7daSratchov uint_gcd(unsigned int a, unsigned int b)
419b47fb7daSratchov {
420b47fb7daSratchov 	unsigned int r;
421b47fb7daSratchov 
422b47fb7daSratchov 	while (b > 0) {
423b47fb7daSratchov 		r = a % b;
424b47fb7daSratchov 		a = b;
425b47fb7daSratchov 		b = r;
426b47fb7daSratchov 	}
427b47fb7daSratchov 	return a;
42887bc9f6aSratchov }
42987bc9f6aSratchov 
43087bc9f6aSratchov /*
43187bc9f6aSratchov  * initialize resampler with ibufsz/obufsz factor and "nch" channels
43287bc9f6aSratchov  */
43387bc9f6aSratchov void
43426308fb1Sratchov resamp_init(struct resamp *p, unsigned int iblksz,
43526308fb1Sratchov     unsigned int oblksz, int nch)
43687bc9f6aSratchov {
437b47fb7daSratchov 	unsigned int g;
438b47fb7daSratchov 
439b47fb7daSratchov 	/*
440b47fb7daSratchov 	 * reduce iblksz/oblksz fraction
441b47fb7daSratchov 	 */
442b47fb7daSratchov 	g = uint_gcd(iblksz, oblksz);
443b47fb7daSratchov 	iblksz /= g;
444b47fb7daSratchov 	oblksz /= g;
445b47fb7daSratchov 
446b47fb7daSratchov 	/*
447b47fb7daSratchov 	 * ensure weird rates don't cause integer overflow
448b47fb7daSratchov 	 */
449b47fb7daSratchov 	while (iblksz > ADATA_UNIT || oblksz > ADATA_UNIT) {
450b47fb7daSratchov 		iblksz >>= 1;
451b47fb7daSratchov 		oblksz >>= 1;
452b47fb7daSratchov 	}
453b47fb7daSratchov 
45487bc9f6aSratchov 	p->iblksz = iblksz;
45587bc9f6aSratchov 	p->oblksz = oblksz;
456b47fb7daSratchov 	p->diff = 0;
45787bc9f6aSratchov 	p->nch = nch;
45887bc9f6aSratchov 	p->ctx_start = 0;
459ec714a7eSmiko 	memset(p->ctx, 0, sizeof(p->ctx));
4603220ebbaSratchov 	if (p->iblksz < p->oblksz) {
4613220ebbaSratchov 		p->filt_cutoff = RESAMP_UNIT;
4623220ebbaSratchov 		p->filt_step = RESAMP_UNIT / p->oblksz;
4633220ebbaSratchov 	} else {
4643220ebbaSratchov 		p->filt_cutoff = (int64_t)RESAMP_UNIT * p->oblksz / p->iblksz;
4653220ebbaSratchov 		p->filt_step = RESAMP_UNIT / p->iblksz;
4663220ebbaSratchov 	}
46787bc9f6aSratchov #ifdef DEBUG
468*7b639200Sratchov 	logx(3, "resamp_init: %u/%u", iblksz, oblksz);
46987bc9f6aSratchov #endif
47087bc9f6aSratchov }
47187bc9f6aSratchov 
47287bc9f6aSratchov /*
47387bc9f6aSratchov  * encode "todo" frames from native to foreign encoding
47487bc9f6aSratchov  */
47587bc9f6aSratchov void
47687bc9f6aSratchov enc_do(struct conv *p, unsigned char *in, unsigned char *out, int todo)
47787bc9f6aSratchov {
47887bc9f6aSratchov 	unsigned int f;
47987bc9f6aSratchov 	adata_t *idata;
4800569a3deSratchov 	unsigned int s;
48187bc9f6aSratchov 	unsigned int oshift;
4820569a3deSratchov 	unsigned int obias;
48387bc9f6aSratchov 	unsigned int obps;
48487bc9f6aSratchov 	unsigned int i;
48587bc9f6aSratchov 	unsigned char *odata;
48687bc9f6aSratchov 	int obnext;
48787bc9f6aSratchov 	int osnext;
48887bc9f6aSratchov 
48987bc9f6aSratchov #ifdef DEBUG
490*7b639200Sratchov 	logx(4, "enc: copying %u frames", todo);
49187bc9f6aSratchov #endif
49287bc9f6aSratchov 	/*
49387bc9f6aSratchov 	 * Partially copy structures into local variables, to avoid
49487bc9f6aSratchov 	 * unnecessary indirections; this also allows the compiler to
49587bc9f6aSratchov 	 * order local variables more "cache-friendly".
49687bc9f6aSratchov 	 */
49787bc9f6aSratchov 	idata = (adata_t *)in;
49887bc9f6aSratchov 	odata = out;
49987bc9f6aSratchov 	oshift = p->shift;
5000569a3deSratchov 	obias = p->bias;
50187bc9f6aSratchov 	obps = p->bps;
50287bc9f6aSratchov 	obnext = p->bnext;
50387bc9f6aSratchov 	osnext = p->snext;
50487bc9f6aSratchov 
50587bc9f6aSratchov 	/*
50687bc9f6aSratchov 	 * Start conversion.
50787bc9f6aSratchov 	 */
50887bc9f6aSratchov 	odata += p->bfirst;
50987bc9f6aSratchov 	for (f = todo * p->nch; f > 0; f--) {
5100569a3deSratchov 		/* convert adata to u32 */
5110569a3deSratchov 		s = (int)*idata++ + ADATA_UNIT;
51287bc9f6aSratchov 		s <<= 32 - ADATA_BITS;
5130569a3deSratchov 		/* convert u32 to uN */
51487bc9f6aSratchov 		s >>= oshift;
5150569a3deSratchov 		/* convert uN to sN */
5160569a3deSratchov 		s -= obias;
5170569a3deSratchov 		/* packetize sN */
51887bc9f6aSratchov 		for (i = obps; i > 0; i--) {
51987bc9f6aSratchov 			*odata = (unsigned char)s;
52087bc9f6aSratchov 			s >>= 8;
52187bc9f6aSratchov 			odata += obnext;
52287bc9f6aSratchov 		}
52387bc9f6aSratchov 		odata += osnext;
52487bc9f6aSratchov 	}
52587bc9f6aSratchov }
52687bc9f6aSratchov 
52787bc9f6aSratchov /*
52887bc9f6aSratchov  * store "todo" frames of silence in foreign encoding
52987bc9f6aSratchov  */
53087bc9f6aSratchov void
53187bc9f6aSratchov enc_sil_do(struct conv *p, unsigned char *out, int todo)
53287bc9f6aSratchov {
53387bc9f6aSratchov 	unsigned int f;
5340569a3deSratchov 	unsigned int s;
5350569a3deSratchov 	unsigned int oshift;
5360569a3deSratchov 	int obias;
53787bc9f6aSratchov 	unsigned int obps;
53887bc9f6aSratchov 	unsigned int i;
53987bc9f6aSratchov 	unsigned char *odata;
54087bc9f6aSratchov 	int obnext;
54187bc9f6aSratchov 	int osnext;
54287bc9f6aSratchov 
54387bc9f6aSratchov #ifdef DEBUG
544*7b639200Sratchov 	logx(4, "enc: silence %u frames", todo);
54587bc9f6aSratchov #endif
54687bc9f6aSratchov 	/*
54787bc9f6aSratchov 	 * Partially copy structures into local variables, to avoid
54887bc9f6aSratchov 	 * unnecessary indirections; this also allows the compiler to
54987bc9f6aSratchov 	 * order local variables more "cache-friendly".
55087bc9f6aSratchov 	 */
55187bc9f6aSratchov 	odata = out;
5520569a3deSratchov 	oshift = p->shift;
5530569a3deSratchov 	obias = p->bias;
55487bc9f6aSratchov 	obps = p->bps;
55587bc9f6aSratchov 	obnext = p->bnext;
55687bc9f6aSratchov 	osnext = p->snext;
55787bc9f6aSratchov 
55887bc9f6aSratchov 	/*
55987bc9f6aSratchov 	 * Start conversion.
56087bc9f6aSratchov 	 */
56187bc9f6aSratchov 	odata += p->bfirst;
56287bc9f6aSratchov 	for (f = todo * p->nch; f > 0; f--) {
5630569a3deSratchov 		s = ((1U << 31) >> oshift) - obias;
56487bc9f6aSratchov 		for (i = obps; i > 0; i--) {
56587bc9f6aSratchov 			*odata = (unsigned char)s;
56687bc9f6aSratchov 			s >>= 8;
56787bc9f6aSratchov 			odata += obnext;
56887bc9f6aSratchov 		}
56987bc9f6aSratchov 		odata += osnext;
57087bc9f6aSratchov 	}
57187bc9f6aSratchov }
57287bc9f6aSratchov 
57387bc9f6aSratchov /*
57487bc9f6aSratchov  * initialize encoder from native to foreign encoding
57587bc9f6aSratchov  */
57687bc9f6aSratchov void
57787bc9f6aSratchov enc_init(struct conv *p, struct aparams *par, int nch)
57887bc9f6aSratchov {
579*7b639200Sratchov #ifdef DEBUG
580*7b639200Sratchov 	char enc_str[ENCMAX];
581*7b639200Sratchov #endif
582*7b639200Sratchov 
58387bc9f6aSratchov 	p->nch = nch;
58487bc9f6aSratchov 	p->bps = par->bps;
58587bc9f6aSratchov 	if (par->msb) {
58687bc9f6aSratchov 		p->shift = 32 - par->bps * 8;
58787bc9f6aSratchov 	} else {
58887bc9f6aSratchov 		p->shift = 32 - par->bits;
58987bc9f6aSratchov 	}
5900569a3deSratchov 	if (par->sig) {
5910569a3deSratchov 		p->bias = (1U << 31) >> p->shift;
5920569a3deSratchov 	} else {
5930569a3deSratchov 		p->bias = 0;
5940569a3deSratchov 	}
59587bc9f6aSratchov 	if (!par->le) {
59687bc9f6aSratchov 		p->bfirst = par->bps - 1;
59787bc9f6aSratchov 		p->bnext = -1;
59887bc9f6aSratchov 		p->snext = 2 * par->bps;
59987bc9f6aSratchov 	} else {
60087bc9f6aSratchov 		p->bfirst = 0;
60187bc9f6aSratchov 		p->bnext = 1;
60287bc9f6aSratchov 		p->snext = 0;
60387bc9f6aSratchov 	}
60487bc9f6aSratchov #ifdef DEBUG
605*7b639200Sratchov 	logx(3, "enc: %s, %d channels",
606*7b639200Sratchov 	    (aparams_enctostr(par, enc_str), enc_str), p->nch);
60787bc9f6aSratchov #endif
60887bc9f6aSratchov }
60987bc9f6aSratchov 
61087bc9f6aSratchov /*
6117c71888cSratchov  * decode "todo" frames from foreign to native encoding
61287bc9f6aSratchov  */
61387bc9f6aSratchov void
61487bc9f6aSratchov dec_do(struct conv *p, unsigned char *in, unsigned char *out, int todo)
61587bc9f6aSratchov {
61687bc9f6aSratchov 	unsigned int f;
61787bc9f6aSratchov 	unsigned int ibps;
61887bc9f6aSratchov 	unsigned int i;
6190569a3deSratchov 	unsigned int s = 0xdeadbeef;
62087bc9f6aSratchov 	unsigned char *idata;
62187bc9f6aSratchov 	int ibnext;
62287bc9f6aSratchov 	int isnext;
6230569a3deSratchov 	unsigned int ibias;
62487bc9f6aSratchov 	unsigned int ishift;
62587bc9f6aSratchov 	adata_t *odata;
62687bc9f6aSratchov 
62787bc9f6aSratchov #ifdef DEBUG
628*7b639200Sratchov 	logx(4, "dec: copying %u frames", todo);
62987bc9f6aSratchov #endif
63087bc9f6aSratchov 	/*
63187bc9f6aSratchov 	 * Partially copy structures into local variables, to avoid
63287bc9f6aSratchov 	 * unnecessary indirections; this also allows the compiler to
63387bc9f6aSratchov 	 * order local variables more "cache-friendly".
63487bc9f6aSratchov 	 */
63587bc9f6aSratchov 	idata = in;
63687bc9f6aSratchov 	odata = (adata_t *)out;
63787bc9f6aSratchov 	ibps = p->bps;
63887bc9f6aSratchov 	ibnext = p->bnext;
6390569a3deSratchov 	ibias = p->bias;
64087bc9f6aSratchov 	ishift = p->shift;
64187bc9f6aSratchov 	isnext = p->snext;
64287bc9f6aSratchov 
64387bc9f6aSratchov 	/*
64487bc9f6aSratchov 	 * Start conversion.
64587bc9f6aSratchov 	 */
64687bc9f6aSratchov 	idata += p->bfirst;
64787bc9f6aSratchov 	for (f = todo * p->nch; f > 0; f--) {
64887bc9f6aSratchov 		for (i = ibps; i > 0; i--) {
64987bc9f6aSratchov 			s <<= 8;
65087bc9f6aSratchov 			s |= *idata;
65187bc9f6aSratchov 			idata += ibnext;
65287bc9f6aSratchov 		}
65387bc9f6aSratchov 		idata += isnext;
6540569a3deSratchov 		s += ibias;
65587bc9f6aSratchov 		s <<= ishift;
65687bc9f6aSratchov 		s >>= 32 - ADATA_BITS;
6570569a3deSratchov 		*odata++ = s - ADATA_UNIT;
65887bc9f6aSratchov 	}
65987bc9f6aSratchov }
66087bc9f6aSratchov 
66187bc9f6aSratchov /*
66287bc9f6aSratchov  * initialize decoder from foreign to native encoding
66387bc9f6aSratchov  */
66487bc9f6aSratchov void
66587bc9f6aSratchov dec_init(struct conv *p, struct aparams *par, int nch)
66687bc9f6aSratchov {
667*7b639200Sratchov #ifdef DEBUG
668*7b639200Sratchov 	char enc_str[ENCMAX];
669*7b639200Sratchov #endif
670*7b639200Sratchov 
67187bc9f6aSratchov 	p->bps = par->bps;
67287bc9f6aSratchov 	p->nch = nch;
67387bc9f6aSratchov 	if (par->msb) {
67487bc9f6aSratchov 		p->shift = 32 - par->bps * 8;
67587bc9f6aSratchov 	} else {
67687bc9f6aSratchov 		p->shift = 32 - par->bits;
67787bc9f6aSratchov 	}
6780569a3deSratchov 	if (par->sig) {
6790569a3deSratchov 		p->bias = (1U << 31) >> p->shift;
6800569a3deSratchov 	} else {
6810569a3deSratchov 		p->bias = 0;
6820569a3deSratchov 	}
68387bc9f6aSratchov 	if (par->le) {
68487bc9f6aSratchov 		p->bfirst = par->bps - 1;
68587bc9f6aSratchov 		p->bnext = -1;
68687bc9f6aSratchov 		p->snext = 2 * par->bps;
68787bc9f6aSratchov 	} else {
68887bc9f6aSratchov 		p->bfirst = 0;
68987bc9f6aSratchov 		p->bnext = 1;
69087bc9f6aSratchov 		p->snext = 0;
69187bc9f6aSratchov 	}
69287bc9f6aSratchov #ifdef DEBUG
693*7b639200Sratchov 	logx(3, "dec: %s, %d channels",
694*7b639200Sratchov 	    (aparams_enctostr(par, enc_str), enc_str), p->nch);
69587bc9f6aSratchov #endif
69687bc9f6aSratchov }
69787bc9f6aSratchov 
69887bc9f6aSratchov /*
69987bc9f6aSratchov  * mix "todo" input frames on the output with the given volume
70087bc9f6aSratchov  */
70187bc9f6aSratchov void
70287bc9f6aSratchov cmap_add(struct cmap *p, void *in, void *out, int vol, int todo)
70387bc9f6aSratchov {
70487bc9f6aSratchov 	adata_t *idata, *odata;
70587bc9f6aSratchov 	int i, j, nch, istart, inext, onext, ostart, y, v;
70687bc9f6aSratchov 
70787bc9f6aSratchov #ifdef DEBUG
708*7b639200Sratchov 	logx(4, "cmap: adding %d frames", todo);
70987bc9f6aSratchov #endif
71087bc9f6aSratchov 	idata = in;
71187bc9f6aSratchov 	odata = out;
71287bc9f6aSratchov 	ostart = p->ostart;
71387bc9f6aSratchov 	onext = p->onext;
71487bc9f6aSratchov 	istart = p->istart;
71587bc9f6aSratchov 	inext = p->inext;
71687bc9f6aSratchov 	nch = p->nch;
717b35d71a2Sratchov 	v = vol;
71887bc9f6aSratchov 
71987bc9f6aSratchov 	/*
72087bc9f6aSratchov 	 * map/mix input on the output
72187bc9f6aSratchov 	 */
72287bc9f6aSratchov 	for (i = todo; i > 0; i--) {
72387bc9f6aSratchov 		odata += ostart;
72487bc9f6aSratchov 		idata += istart;
72587bc9f6aSratchov 		for (j = nch; j > 0; j--) {
72687bc9f6aSratchov 			y = *odata + ADATA_MUL(*idata, v);
72787bc9f6aSratchov 			if (y >= ADATA_UNIT)
72887bc9f6aSratchov 				y = ADATA_UNIT - 1;
72987bc9f6aSratchov 			else if (y < -ADATA_UNIT)
73087bc9f6aSratchov 				y = -ADATA_UNIT;
73187bc9f6aSratchov 			*odata = y;
73287bc9f6aSratchov 			idata++;
73387bc9f6aSratchov 			odata++;
73487bc9f6aSratchov 		}
73587bc9f6aSratchov 		odata += onext;
73687bc9f6aSratchov 		idata += inext;
73787bc9f6aSratchov 	}
73887bc9f6aSratchov }
73987bc9f6aSratchov 
74087bc9f6aSratchov /*
7417c71888cSratchov  * overwrite output with "todo" input frames with the given volume
74287bc9f6aSratchov  */
74387bc9f6aSratchov void
74487bc9f6aSratchov cmap_copy(struct cmap *p, void *in, void *out, int vol, int todo)
74587bc9f6aSratchov {
74687bc9f6aSratchov 	adata_t *idata, *odata;
74787bc9f6aSratchov 	int i, j, nch, istart, inext, onext, ostart, v;
74887bc9f6aSratchov 
74987bc9f6aSratchov #ifdef DEBUG
750*7b639200Sratchov 	logx(4, "cmap: copying %d frames", todo);
75187bc9f6aSratchov #endif
75287bc9f6aSratchov 	idata = in;
75387bc9f6aSratchov 	odata = out;
75487bc9f6aSratchov 	ostart = p->ostart;
75587bc9f6aSratchov 	onext = p->onext;
75687bc9f6aSratchov 	istart = p->istart;
75787bc9f6aSratchov 	inext = p->inext;
75887bc9f6aSratchov 	nch = p->nch;
75987bc9f6aSratchov 	v = vol;
76087bc9f6aSratchov 
76187bc9f6aSratchov 	/*
76287bc9f6aSratchov 	 * copy to the output buffer
76387bc9f6aSratchov 	 */
76487bc9f6aSratchov 	for (i = todo; i > 0; i--) {
76587bc9f6aSratchov 		idata += istart;
76678dcdbbcSratchov 		odata += ostart;
76787bc9f6aSratchov 		for (j = nch; j > 0; j--) {
76887bc9f6aSratchov 			*odata = ADATA_MUL(*idata, v);
76987bc9f6aSratchov 			odata++;
77087bc9f6aSratchov 			idata++;
77187bc9f6aSratchov 		}
77278dcdbbcSratchov 		odata += onext;
77387bc9f6aSratchov 		idata += inext;
77487bc9f6aSratchov 	}
77587bc9f6aSratchov }
77687bc9f6aSratchov 
77787bc9f6aSratchov /*
77887bc9f6aSratchov  * initialize channel mapper, to map a subset of input channel range
77987bc9f6aSratchov  * into a subset of the output channel range
78087bc9f6aSratchov  */
78187bc9f6aSratchov void
78287bc9f6aSratchov cmap_init(struct cmap *p,
78387bc9f6aSratchov     int imin, int imax, int isubmin, int isubmax,
78487bc9f6aSratchov     int omin, int omax, int osubmin, int osubmax)
78587bc9f6aSratchov {
7865c89abe4Sratchov 	int inch, onch, nch;
78787bc9f6aSratchov 
7885c89abe4Sratchov 	/*
7895c89abe4Sratchov 	 * Ignore channels outside of the available sets
7905c89abe4Sratchov 	 */
7915c89abe4Sratchov 	if (isubmin < imin)
7925c89abe4Sratchov 		isubmin = imin;
7935c89abe4Sratchov 	if (isubmax > imax)
7945c89abe4Sratchov 		isubmax = imax;
7955c89abe4Sratchov 	if (osubmin < omin)
7965c89abe4Sratchov 		osubmin = omin;
7975c89abe4Sratchov 	if (osubmax > omax)
7985c89abe4Sratchov 		osubmax = omax;
79987bc9f6aSratchov 
8005c89abe4Sratchov 	/*
8015c89abe4Sratchov 	 * Shrink the input or the output subset to make both subsets of
8025c89abe4Sratchov 	 * the same size
8035c89abe4Sratchov 	 */
8045c89abe4Sratchov 	inch = isubmax - isubmin + 1;
8055c89abe4Sratchov 	onch = osubmax - osubmin + 1;
8065c89abe4Sratchov 	nch = (inch < onch) ? inch : onch;
8075c89abe4Sratchov 	isubmax = isubmin + nch - 1;
8085c89abe4Sratchov 	osubmax = osubmin + nch - 1;
80987bc9f6aSratchov 
8105c89abe4Sratchov 	p->ostart = osubmin - omin;
8115c89abe4Sratchov 	p->onext = omax - osubmax;
8125c89abe4Sratchov 	p->istart = isubmin - imin;
8135c89abe4Sratchov 	p->inext = imax - isubmax;
8145c89abe4Sratchov 	p->nch = nch;
81587bc9f6aSratchov #ifdef DEBUG
816*7b639200Sratchov 	logx(3, "%s: nch = %d, ostart = %d, onext = %d, istart = %d, inext = %d",
817*7b639200Sratchov 	    __func__, p->nch, p->ostart, p->onext, p->istart, p->inext);
81887bc9f6aSratchov #endif
81987bc9f6aSratchov }
820