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