The following variants are implemented: lipshitz noise shaping dither shibata noise shaping dither low shibata noise shaping dither high shibata noise shaping dither f-weighted noise shaping dither modified-e-weighted noise shaping dither improved-e-weighted noise shaping dither Data tables taken from SOX Signed-off-by: Michael Niedermayer <michaelni@gmx.at>tags/n1.2
| @@ -21,6 +21,8 @@ | |||||
| #include "libavutil/avassert.h" | #include "libavutil/avassert.h" | ||||
| #include "swresample_internal.h" | #include "swresample_internal.h" | ||||
| #include "noise_shaping_data.c" | |||||
| void swri_get_dither(SwrContext *s, void *dst, int len, unsigned seed, enum AVSampleFormat out_fmt, enum AVSampleFormat in_fmt) { | void swri_get_dither(SwrContext *s, void *dst, int len, unsigned seed, enum AVSampleFormat out_fmt, enum AVSampleFormat in_fmt) { | ||||
| double scale = 0; | double scale = 0; | ||||
| #define TMP_EXTRA 2 | #define TMP_EXTRA 2 | ||||
| @@ -41,19 +43,37 @@ void swri_get_dither(SwrContext *s, void *dst, int len, unsigned seed, enum AVSa | |||||
| scale *= s->dither_scale; | scale *= s->dither_scale; | ||||
| s->ns_pos = 0; | |||||
| s->ns_scale = scale; | |||||
| s->ns_scale_1 = 1/scale; | |||||
| memset(s->ns_errors, 0, sizeof(s->ns_errors)); | |||||
| for (i=0; filters[i].coefs; i++) { | |||||
| const filter_t *f = &filters[i]; | |||||
| if (fabs(s->out_sample_rate - f->rate) / f->rate <= .05 && f->name == s->dither_method) { | |||||
| int j; | |||||
| s->ns_taps = f->len; | |||||
| for (j=0; j<f->len; j++) | |||||
| s->ns_coeffs[j] = f->coefs[j]; | |||||
| break; | |||||
| } | |||||
| } | |||||
| if (!filters[i].coefs && s->dither_method > SWR_DITHER_NS) { | |||||
| av_log(s, AV_LOG_WARNING, "Requested noise shaping dither not available at this sampling rate, using triangular hp dither\n"); | |||||
| s->dither_method = SWR_DITHER_TRIANGULAR_HIGHPASS; | |||||
| } | |||||
| for(i=0; i<len + TMP_EXTRA; i++){ | for(i=0; i<len + TMP_EXTRA; i++){ | ||||
| double v; | double v; | ||||
| seed = seed* 1664525 + 1013904223; | seed = seed* 1664525 + 1013904223; | ||||
| switch(s->dither_method){ | switch(s->dither_method){ | ||||
| case SWR_DITHER_RECTANGULAR: v= ((double)seed) / UINT_MAX - 0.5; break; | case SWR_DITHER_RECTANGULAR: v= ((double)seed) / UINT_MAX - 0.5; break; | ||||
| case SWR_DITHER_TRIANGULAR : | |||||
| case SWR_DITHER_TRIANGULAR_HIGHPASS : | |||||
| default: | |||||
| av_assert0(s->dither_method < SWR_DITHER_NB); | |||||
| v = ((double)seed) / UINT_MAX; | v = ((double)seed) / UINT_MAX; | ||||
| seed = seed*1664525 + 1013904223; | seed = seed*1664525 + 1013904223; | ||||
| v-= ((double)seed) / UINT_MAX; | v-= ((double)seed) / UINT_MAX; | ||||
| break; | break; | ||||
| default: av_assert0(0); | |||||
| } | } | ||||
| tmp[i] = v; | tmp[i] = v; | ||||
| } | } | ||||
| @@ -62,14 +82,13 @@ void swri_get_dither(SwrContext *s, void *dst, int len, unsigned seed, enum AVSa | |||||
| double v; | double v; | ||||
| switch(s->dither_method){ | switch(s->dither_method){ | ||||
| case SWR_DITHER_RECTANGULAR: | |||||
| case SWR_DITHER_TRIANGULAR : | |||||
| default: | |||||
| av_assert0(s->dither_method < SWR_DITHER_NB); | |||||
| v = tmp[i]; | v = tmp[i]; | ||||
| break; | break; | ||||
| case SWR_DITHER_TRIANGULAR_HIGHPASS : | case SWR_DITHER_TRIANGULAR_HIGHPASS : | ||||
| v = (- tmp[i] + 2*tmp[i+1] - tmp[i+2]) / sqrt(6); | v = (- tmp[i] + 2*tmp[i+1] - tmp[i+2]) / sqrt(6); | ||||
| break; | break; | ||||
| default: av_assert0(0); | |||||
| } | } | ||||
| v*= scale; | v*= scale; | ||||
| @@ -85,3 +104,19 @@ void swri_get_dither(SwrContext *s, void *dst, int len, unsigned seed, enum AVSa | |||||
| av_free(tmp); | av_free(tmp); | ||||
| } | } | ||||
| #define TEMPLATE_DITHER_S16 | |||||
| #include "dither_template.c" | |||||
| #undef TEMPLATE_DITHER_S16 | |||||
| #define TEMPLATE_DITHER_S32 | |||||
| #include "dither_template.c" | |||||
| #undef TEMPLATE_DITHER_S32 | |||||
| #define TEMPLATE_DITHER_FLT | |||||
| #include "dither_template.c" | |||||
| #undef TEMPLATE_DITHER_FLT | |||||
| #define TEMPLATE_DITHER_DBL | |||||
| #include "dither_template.c" | |||||
| #undef TEMPLATE_DITHER_DBL | |||||
| @@ -0,0 +1,53 @@ | |||||
| #if defined(TEMPLATE_DITHER_DBL) | |||||
| # define RENAME(N) N ## _double | |||||
| # define DELEM double | |||||
| # define CLIP(v) | |||||
| #elif defined(TEMPLATE_DITHER_FLT) | |||||
| # define RENAME(N) N ## _float | |||||
| # define DELEM float | |||||
| # define CLIP(v) | |||||
| #elif defined(TEMPLATE_DITHER_S32) | |||||
| # define RENAME(N) N ## _int32 | |||||
| # define DELEM int32_t | |||||
| # define CLIP(v) v = FFMAX(FFMIN(v, INT32_MAX), INT32_MIN) | |||||
| #elif defined(TEMPLATE_DITHER_S16) | |||||
| # define RENAME(N) N ## _int16 | |||||
| # define DELEM int16_t | |||||
| # define CLIP(v) v = FFMAX(FFMIN(v, INT16_MAX), INT16_MIN) | |||||
| #else | |||||
| ERROR | |||||
| #endif | |||||
| void RENAME(swri_noise_shaping)(SwrContext *s, AudioData *srcs, AudioData *noises, int count){ | |||||
| int i, j, pos, ch; | |||||
| int taps = s->ns_taps; | |||||
| float S = s->ns_scale; | |||||
| float S_1 = s->ns_scale_1; | |||||
| for (ch=0; ch<srcs->ch_count; ch++) { | |||||
| const float *noise = ((const float *)noises->ch[ch]) + s->dither_pos; | |||||
| DELEM *data = (DELEM*)srcs->ch[ch]; | |||||
| pos = s->ns_pos; | |||||
| for (i=0; i<count; i++) { | |||||
| double d1, d = data[i]; | |||||
| for(j=0; j<taps; j++) | |||||
| d -= s->ns_coeffs[j] * s->ns_errors[ch][pos + j]; | |||||
| pos = pos ? pos - 1 : pos - 1 + taps; | |||||
| d1 = rint((d + noise[i]) * S_1)*S; | |||||
| s->ns_errors[ch][pos + taps] = s->ns_errors[ch][pos] = d1 - d; | |||||
| CLIP(d1); | |||||
| data[i] = d1; | |||||
| } | |||||
| } | |||||
| s->ns_pos = pos; | |||||
| } | |||||
| #undef RENAME | |||||
| #undef DELEM | |||||
| #undef CLIP | |||||
| @@ -0,0 +1,223 @@ | |||||
| /* Effect: dither/noise-shape Copyright (c) 2008-9 robs@users.sourceforge.net | |||||
| * | |||||
| * This library is free software; you can redistribute it and/or modify it | |||||
| * under the terms of the GNU Lesser General Public License as published by | |||||
| * the Free Software Foundation; either version 2.1 of the License, or (at | |||||
| * your option) any later version. | |||||
| * | |||||
| * This library is distributed in the hope that it will be useful, but | |||||
| * WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser | |||||
| * General Public License for more details. | |||||
| * | |||||
| * You should have received a copy of the GNU Lesser General Public License | |||||
| * along with this library; if not, write to the Free Software Foundation, | |||||
| * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |||||
| */ | |||||
| typedef struct { | |||||
| int rate; | |||||
| enum {fir, iir} type; | |||||
| size_t len; | |||||
| int gain_cB; /* Chosen so clips are few if any, but not guaranteed none. */ | |||||
| double const * coefs; | |||||
| enum SwrDitherType name; | |||||
| } filter_t; | |||||
| static double const lip44[] = {2.033, -2.165, 1.959, -1.590, .6149}; | |||||
| static double const fwe44[] = { | |||||
| 2.412, -3.370, 3.937, -4.174, 3.353, -2.205, 1.281, -.569, .0847}; | |||||
| static double const mew44[] = { | |||||
| 1.662, -1.263, .4827, -.2913, .1268, -.1124, .03252, -.01265, -.03524}; | |||||
| static double const iew44[] = { | |||||
| 2.847, -4.685, 6.214, -7.184, 6.639, -5.032, 3.263, -1.632, .4191}; | |||||
| static double const ges44[] = { | |||||
| 2.2061, -.4706, -.2534, -.6214, 1.0587, .0676, -.6054, -.2738}; | |||||
| static double const ges48[] = { | |||||
| 2.2374, -.7339, -.1251, -.6033, .903, .0116, -.5853, -.2571}; | |||||
| static double const shi48[] = { | |||||
| 2.8720729351043701172, -5.0413231849670410156, 6.2442994117736816406, | |||||
| -5.8483986854553222656, 3.7067542076110839844, -1.0495119094848632812, | |||||
| -1.1830236911773681641, 2.1126792430877685547, -1.9094531536102294922, | |||||
| 0.99913084506988525391, -0.17090806365013122559, -0.32615602016448974609, | |||||
| 0.39127644896507263184, -0.26876461505889892578, 0.097676105797290802002, | |||||
| -0.023473845794796943665, | |||||
| }; | |||||
| static double const shi44[] = { | |||||
| 2.6773197650909423828, -4.8308925628662109375, 6.570110321044921875, | |||||
| -7.4572014808654785156, 6.7263274192810058594, -4.8481650352478027344, | |||||
| 2.0412089824676513672, 0.7006359100341796875, -2.9537565708160400391, | |||||
| 4.0800385475158691406, -4.1845216751098632812, 3.3311812877655029297, | |||||
| -2.1179926395416259766, 0.879302978515625, -0.031759146600961685181, | |||||
| -0.42382788658142089844, 0.47882103919982910156, -0.35490813851356506348, | |||||
| 0.17496839165687561035, -0.060908168554306030273, | |||||
| }; | |||||
| static double const shi38[] = { | |||||
| 1.6335992813110351562, -2.2615492343902587891, 2.4077029228210449219, | |||||
| -2.6341717243194580078, 2.1440362930297851562, -1.8153258562088012695, | |||||
| 1.0816224813461303711, -0.70302653312683105469, 0.15991993248462677002, | |||||
| 0.041549518704414367676, -0.29416576027870178223, 0.2518316805362701416, | |||||
| -0.27766478061676025391, 0.15785403549671173096, -0.10165894031524658203, | |||||
| 0.016833892092108726501, | |||||
| }; | |||||
| static double const shi32[] = | |||||
| { /* dmaker 32000: bestmax=4.99659 (inverted) */ | |||||
| 0.82118552923202515, | |||||
| -1.0063692331314087, | |||||
| 0.62341964244842529, | |||||
| -1.0447187423706055, | |||||
| 0.64532512426376343, | |||||
| -0.87615132331848145, | |||||
| 0.52219754457473755, | |||||
| -0.67434263229370117, | |||||
| 0.44954317808151245, | |||||
| -0.52557498216629028, | |||||
| 0.34567299485206604, | |||||
| -0.39618203043937683, | |||||
| 0.26791760325431824, | |||||
| -0.28936097025871277, | |||||
| 0.1883765310049057, | |||||
| -0.19097308814525604, | |||||
| 0.10431359708309174, | |||||
| -0.10633844882249832, | |||||
| 0.046832218766212463, | |||||
| -0.039653312414884567, | |||||
| }; | |||||
| static double const shi22[] = | |||||
| { /* dmaker 22050: bestmax=5.77762 (inverted) */ | |||||
| 0.056581053882837296, | |||||
| -0.56956905126571655, | |||||
| -0.40727734565734863, | |||||
| -0.33870288729667664, | |||||
| -0.29810553789138794, | |||||
| -0.19039161503314972, | |||||
| -0.16510021686553955, | |||||
| -0.13468159735202789, | |||||
| -0.096633769571781158, | |||||
| -0.081049129366874695, | |||||
| -0.064953058958053589, | |||||
| -0.054459091275930405, | |||||
| -0.043378707021474838, | |||||
| -0.03660014271736145, | |||||
| -0.026256965473294258, | |||||
| -0.018786206841468811, | |||||
| -0.013387725688517094, | |||||
| -0.0090983230620622635, | |||||
| -0.0026585909072309732, | |||||
| -0.00042083300650119781, | |||||
| }; | |||||
| static double const shi16[] = | |||||
| { /* dmaker 16000: bestmax=5.97128 (inverted) */ | |||||
| -0.37251132726669312, | |||||
| -0.81423574686050415, | |||||
| -0.55010956525802612, | |||||
| -0.47405767440795898, | |||||
| -0.32624706625938416, | |||||
| -0.3161766529083252, | |||||
| -0.2286367267370224, | |||||
| -0.22916607558727264, | |||||
| -0.19565616548061371, | |||||
| -0.18160104751586914, | |||||
| -0.15423151850700378, | |||||
| -0.14104481041431427, | |||||
| -0.11844276636838913, | |||||
| -0.097583092749118805, | |||||
| -0.076493598520755768, | |||||
| -0.068106919527053833, | |||||
| -0.041881654411554337, | |||||
| -0.036922425031661987, | |||||
| -0.019364040344953537, | |||||
| -0.014994367957115173, | |||||
| }; | |||||
| static double const shi11[] = | |||||
| { /* dmaker 11025: bestmax=5.9406 (inverted) */ | |||||
| -0.9264228343963623, | |||||
| -0.98695987462997437, | |||||
| -0.631156325340271, | |||||
| -0.51966935396194458, | |||||
| -0.39738872647285461, | |||||
| -0.35679301619529724, | |||||
| -0.29720726609230042, | |||||
| -0.26310476660728455, | |||||
| -0.21719355881214142, | |||||
| -0.18561814725399017, | |||||
| -0.15404847264289856, | |||||
| -0.12687471508979797, | |||||
| -0.10339745879173279, | |||||
| -0.083688631653785706, | |||||
| -0.05875682458281517, | |||||
| -0.046893671154975891, | |||||
| -0.027950936928391457, | |||||
| -0.020740609616041183, | |||||
| -0.009366452693939209, | |||||
| -0.0060260160826146603, | |||||
| }; | |||||
| static double const shi08[] = | |||||
| { /* dmaker 8000: bestmax=5.56234 (inverted) */ | |||||
| -1.202863335609436, | |||||
| -0.94103097915649414, | |||||
| -0.67878556251525879, | |||||
| -0.57650017738342285, | |||||
| -0.50004476308822632, | |||||
| -0.44349345564842224, | |||||
| -0.37833768129348755, | |||||
| -0.34028723835945129, | |||||
| -0.29413089156150818, | |||||
| -0.24994957447052002, | |||||
| -0.21715600788593292, | |||||
| -0.18792112171649933, | |||||
| -0.15268312394618988, | |||||
| -0.12135542929172516, | |||||
| -0.099610626697540283, | |||||
| -0.075273610651493073, | |||||
| -0.048787496984004974, | |||||
| -0.042586319148540497, | |||||
| -0.028991291299462318, | |||||
| -0.011869125068187714, | |||||
| }; | |||||
| static double const shl48[] = { | |||||
| 2.3925774097442626953, -3.4350297451019287109, 3.1853709220886230469, | |||||
| -1.8117271661758422852, -0.20124770700931549072, 1.4759907722473144531, | |||||
| -1.7210904359817504883, 0.97746700048446655273, -0.13790138065814971924, | |||||
| -0.38185903429985046387, 0.27421241998672485352, 0.066584214568138122559, | |||||
| -0.35223302245140075684, 0.37672343850135803223, -0.23964276909828186035, | |||||
| 0.068674825131893157959, | |||||
| }; | |||||
| static double const shl44[] = { | |||||
| 2.0833916664123535156, -3.0418450832366943359, 3.2047898769378662109, | |||||
| -2.7571926116943359375, 1.4978630542755126953, -0.3427594602108001709, | |||||
| -0.71733748912811279297, 1.0737057924270629883, -1.0225815773010253906, | |||||
| 0.56649994850158691406, -0.20968692004680633545, -0.065378531813621520996, | |||||
| 0.10322438180446624756, -0.067442022264003753662, -0.00495197344571352005, | |||||
| }; | |||||
| static double const shh44[] = { | |||||
| 3.0259189605712890625, -6.0268716812133789062, 9.195003509521484375, | |||||
| -11.824929237365722656, 12.767142295837402344, -11.917946815490722656, | |||||
| 9.1739168167114257812, -5.3712320327758789062, 1.1393624544143676758, | |||||
| 2.4484779834747314453, -4.9719839096069335938, 6.0392003059387207031, | |||||
| -5.9359521865844726562, 4.903278350830078125, -3.5527443885803222656, | |||||
| 2.1909697055816650391, -1.1672389507293701172, 0.4903914332389831543, | |||||
| -0.16519790887832641602, 0.023217858746647834778, | |||||
| }; | |||||
| static const filter_t filters[] = { | |||||
| {44100, fir, 5, 210, lip44, SWR_DITHER_NS_LIPSHITZ}, | |||||
| {46000, fir, 9, 276, fwe44, SWR_DITHER_NS_F_WEIGHTED}, | |||||
| {46000, fir, 9, 160, mew44, SWR_DITHER_NS_MODIFIED_E_WEIGHTED}, | |||||
| {46000, fir, 9, 321, iew44, SWR_DITHER_NS_IMPROVED_E_WEIGHTED}, | |||||
| // {48000, iir, 4, 220, ges48, SWR_DITHER_NS_GESEMANN}, | |||||
| // {44100, iir, 4, 230, ges44, SWR_DITHER_NS_GESEMANN}, | |||||
| {48000, fir, 16, 301, shi48, SWR_DITHER_NS_SHIBATA}, | |||||
| {44100, fir, 20, 333, shi44, SWR_DITHER_NS_SHIBATA}, | |||||
| {37800, fir, 16, 240, shi38, SWR_DITHER_NS_SHIBATA}, | |||||
| {32000, fir, 20, 240/*TBD*/, shi32, SWR_DITHER_NS_SHIBATA}, | |||||
| {22050, fir, 20, 240/*TBD*/, shi22, SWR_DITHER_NS_SHIBATA}, | |||||
| {16000, fir, 20, 240/*TBD*/, shi16, SWR_DITHER_NS_SHIBATA}, | |||||
| {11025, fir, 20, 240/*TBD*/, shi11, SWR_DITHER_NS_SHIBATA}, | |||||
| { 8000, fir, 20, 240/*TBD*/, shi08, SWR_DITHER_NS_SHIBATA}, | |||||
| {48000, fir, 16, 250, shl48, SWR_DITHER_NS_LOW_SHIBATA}, | |||||
| {44100, fir, 15, 250, shl44, SWR_DITHER_NS_LOW_SHIBATA}, | |||||
| {44100, fir, 20, 383, shh44, SWR_DITHER_NS_HIGH_SHIBATA}, | |||||
| { 0, fir, 0, 0, NULL, SWR_DITHER_NONE}, | |||||
| }; | |||||
| @@ -78,7 +78,14 @@ static const AVOption options[]={ | |||||
| {"dither_method" , "set dither method" , OFFSET(dither_method ), AV_OPT_TYPE_INT , {.i64=0 }, 0 , SWR_DITHER_NB-1, PARAM, "dither_method"}, | {"dither_method" , "set dither method" , OFFSET(dither_method ), AV_OPT_TYPE_INT , {.i64=0 }, 0 , SWR_DITHER_NB-1, PARAM, "dither_method"}, | ||||
| {"rectangular" , "select rectangular dither" , 0 , AV_OPT_TYPE_CONST, {.i64=SWR_DITHER_RECTANGULAR}, INT_MIN, INT_MAX , PARAM, "dither_method"}, | {"rectangular" , "select rectangular dither" , 0 , AV_OPT_TYPE_CONST, {.i64=SWR_DITHER_RECTANGULAR}, INT_MIN, INT_MAX , PARAM, "dither_method"}, | ||||
| {"triangular" , "select triangular dither" , 0 , AV_OPT_TYPE_CONST, {.i64=SWR_DITHER_TRIANGULAR }, INT_MIN, INT_MAX , PARAM, "dither_method"}, | {"triangular" , "select triangular dither" , 0 , AV_OPT_TYPE_CONST, {.i64=SWR_DITHER_TRIANGULAR }, INT_MIN, INT_MAX , PARAM, "dither_method"}, | ||||
| {"triangular_hp" , "select triangular dither with high pass" , 0 , AV_OPT_TYPE_CONST, {.i64=SWR_DITHER_TRIANGULAR_HIGHPASS }, INT_MIN, INT_MAX, PARAM, "dither_method"}, | |||||
| {"triangular_hp" , "select triangular dither with high pass" , 0 , AV_OPT_TYPE_CONST, {.i64=SWR_DITHER_TRIANGULAR_HIGHPASS }, INT_MIN, INT_MAX, PARAM, "dither_method"}, | |||||
| {"lipshitz" , "select lipshitz noise shaping dither" , 0 , AV_OPT_TYPE_CONST, {.i64=SWR_DITHER_NS_LIPSHITZ}, INT_MIN, INT_MAX, PARAM, "dither_method"}, | |||||
| {"shibata" , "select shibata noise shaping dither" , 0 , AV_OPT_TYPE_CONST, {.i64=SWR_DITHER_NS_SHIBATA }, INT_MIN, INT_MAX, PARAM, "dither_method"}, | |||||
| {"low_shibata" , "select low shibata noise shaping dither" , 0 , AV_OPT_TYPE_CONST, {.i64=SWR_DITHER_NS_LOW_SHIBATA }, INT_MIN, INT_MAX, PARAM, "dither_method"}, | |||||
| {"high_shibata" , "select high shibata noise shaping dither" , 0 , AV_OPT_TYPE_CONST, {.i64=SWR_DITHER_NS_HIGH_SHIBATA }, INT_MIN, INT_MAX, PARAM, "dither_method"}, | |||||
| {"f_weighted" , "select f-weighted noise shaping dither" , 0 , AV_OPT_TYPE_CONST, {.i64=SWR_DITHER_NS_F_WEIGHTED }, INT_MIN, INT_MAX, PARAM, "dither_method"}, | |||||
| {"modified_e_weighted" , "select modified-e-weighted noise shaping dither" , 0 , AV_OPT_TYPE_CONST, {.i64=SWR_DITHER_NS_MODIFIED_E_WEIGHTED }, INT_MIN, INT_MAX, PARAM, "dither_method"}, | |||||
| {"improved_e_weighted" , "select improved-e-weighted noise shaping dither" , 0 , AV_OPT_TYPE_CONST, {.i64=SWR_DITHER_NS_IMPROVED_E_WEIGHTED }, INT_MIN, INT_MAX, PARAM, "dither_method"}, | |||||
| {"filter_size" , "set swr resampling filter size", OFFSET(filter_size) , AV_OPT_TYPE_INT , {.i64=32 }, 0 , INT_MAX , PARAM }, | {"filter_size" , "set swr resampling filter size", OFFSET(filter_size) , AV_OPT_TYPE_INT , {.i64=32 }, 0 , INT_MAX , PARAM }, | ||||
| {"phase_shift" , "set swr resampling phase shift", OFFSET(phase_shift) , AV_OPT_TYPE_INT , {.i64=10 }, 0 , 30 , PARAM }, | {"phase_shift" , "set swr resampling phase shift", OFFSET(phase_shift) , AV_OPT_TYPE_INT , {.i64=10 }, 0 , 30 , PARAM }, | ||||
| @@ -637,7 +644,7 @@ static int swr_convert_internal(struct SwrContext *s, AudioData *out, int out_co | |||||
| if(preout != out && out_count){ | if(preout != out && out_count){ | ||||
| if(s->dither_method){ | if(s->dither_method){ | ||||
| int ch; | |||||
| int ch, len1; | |||||
| int dither_count= FFMAX(out_count, 1<<16); | int dither_count= FFMAX(out_count, 1<<16); | ||||
| av_assert0(preout != in); | av_assert0(preout != in); | ||||
| @@ -651,19 +658,28 @@ static int swr_convert_internal(struct SwrContext *s, AudioData *out, int out_co | |||||
| if(s->dither_pos + out_count > s->dither.count) | if(s->dither_pos + out_count > s->dither.count) | ||||
| s->dither_pos = 0; | s->dither_pos = 0; | ||||
| if (s->mix_2_1_simd) { | |||||
| int len1= out_count&~15; | |||||
| int off = len1 * preout->bps; | |||||
| if(len1) | |||||
| for(ch=0; ch<preout->ch_count; ch++) | |||||
| s->mix_2_1_simd(preout->ch[ch], preout->ch[ch], s->dither.ch[ch] + s->dither.bps * s->dither_pos, s->native_one, 0, 0, len1); | |||||
| if(out_count != len1) | |||||
| if (s->dither_method < SWR_DITHER_NS){ | |||||
| if (s->mix_2_1_simd) { | |||||
| int len1= out_count&~15; | |||||
| int off = len1 * preout->bps; | |||||
| if(len1) | |||||
| for(ch=0; ch<preout->ch_count; ch++) | |||||
| s->mix_2_1_simd(preout->ch[ch], preout->ch[ch], s->dither.ch[ch] + s->dither.bps * s->dither_pos, s->native_one, 0, 0, len1); | |||||
| if(out_count != len1) | |||||
| for(ch=0; ch<preout->ch_count; ch++) | |||||
| s->mix_2_1_f(preout->ch[ch] + off, preout->ch[ch] + off, s->dither.ch[ch] + s->dither.bps * s->dither_pos + off + len1, s->native_one, 0, 0, out_count - len1); | |||||
| } else { | |||||
| for(ch=0; ch<preout->ch_count; ch++) | for(ch=0; ch<preout->ch_count; ch++) | ||||
| s->mix_2_1_f(preout->ch[ch] + off, preout->ch[ch] + off, s->dither.ch[ch] + s->dither.bps * s->dither_pos + off + len1, s->native_one, 0, 0, out_count - len1); | |||||
| s->mix_2_1_f(preout->ch[ch], preout->ch[ch], s->dither.ch[ch] + s->dither.bps * s->dither_pos, s->native_one, 0, 0, out_count); | |||||
| } | |||||
| } else { | } else { | ||||
| for(ch=0; ch<preout->ch_count; ch++) | |||||
| s->mix_2_1_f(preout->ch[ch], preout->ch[ch], s->dither.ch[ch] + s->dither.bps * s->dither_pos, s->native_one, 0, 0, out_count); | |||||
| switch(s->int_sample_fmt) { | |||||
| case AV_SAMPLE_FMT_S16P :swri_noise_shaping_int16(s, preout, &s->dither, out_count); break; | |||||
| case AV_SAMPLE_FMT_S32P :swri_noise_shaping_int32(s, preout, &s->dither, out_count); break; | |||||
| case AV_SAMPLE_FMT_FLTP :swri_noise_shaping_float(s, preout, &s->dither, out_count); break; | |||||
| case AV_SAMPLE_FMT_DBLP :swri_noise_shaping_double(s,preout, &s->dither, out_count); break; | |||||
| } | |||||
| } | } | ||||
| s->dither_pos += out_count; | s->dither_pos += out_count; | ||||
| } | } | ||||
| @@ -111,6 +111,15 @@ enum SwrDitherType { | |||||
| SWR_DITHER_RECTANGULAR, | SWR_DITHER_RECTANGULAR, | ||||
| SWR_DITHER_TRIANGULAR, | SWR_DITHER_TRIANGULAR, | ||||
| SWR_DITHER_TRIANGULAR_HIGHPASS, | SWR_DITHER_TRIANGULAR_HIGHPASS, | ||||
| SWR_DITHER_NS = 64, ///< not part of API/ABI | |||||
| SWR_DITHER_NS_LIPSHITZ, | |||||
| SWR_DITHER_NS_F_WEIGHTED, | |||||
| SWR_DITHER_NS_MODIFIED_E_WEIGHTED, | |||||
| SWR_DITHER_NS_IMPROVED_E_WEIGHTED, | |||||
| SWR_DITHER_NS_SHIBATA, | |||||
| SWR_DITHER_NS_LOW_SHIBATA, | |||||
| SWR_DITHER_NS_HIGH_SHIBATA, | |||||
| SWR_DITHER_NB, ///< not part of API/ABI | SWR_DITHER_NB, ///< not part of API/ABI | ||||
| }; | }; | ||||
| @@ -27,6 +27,8 @@ | |||||
| #define SQRT3_2 1.22474487139158904909 /* sqrt(3/2) */ | #define SQRT3_2 1.22474487139158904909 /* sqrt(3/2) */ | ||||
| #define NS_TAPS 20 | |||||
| #if ARCH_X86_64 | #if ARCH_X86_64 | ||||
| typedef int64_t integer; | typedef int64_t integer; | ||||
| #else | #else | ||||
| @@ -71,6 +73,13 @@ struct SwrContext { | |||||
| enum SwrDitherType dither_method; | enum SwrDitherType dither_method; | ||||
| int dither_pos; | int dither_pos; | ||||
| float dither_scale; | float dither_scale; | ||||
| int ns_taps; ///< Noise shaping dither taps | |||||
| float ns_scale; ///< Noise shaping dither scale | |||||
| float ns_scale_1; ///< Noise shaping dither scale^-1 | |||||
| int ns_pos; ///< Noise shaping dither position | |||||
| float ns_coeffs[NS_TAPS]; ///< Noise shaping filter coefficients | |||||
| float ns_errors[SWR_CH_MAX][2*NS_TAPS]; | |||||
| int filter_size; /**< length of each FIR filter in the resampling filterbank relative to the cutoff frequency */ | int filter_size; /**< length of each FIR filter in the resampling filterbank relative to the cutoff frequency */ | ||||
| int phase_shift; /**< log2 of the number of entries in the resampling polyphase filterbank */ | int phase_shift; /**< log2 of the number of entries in the resampling polyphase filterbank */ | ||||
| int linear_interp; /**< if 1 then the resampling FIR filter will be linearly interpolated */ | int linear_interp; /**< if 1 then the resampling FIR filter will be linearly interpolated */ | ||||
| @@ -152,6 +161,11 @@ int swri_resample_int32(struct ResampleContext *c, int32_t *dst, const int32_t * | |||||
| int swri_resample_float(struct ResampleContext *c, float *dst, const float *src, int *consumed, int src_size, int dst_size, int update_ctx); | int swri_resample_float(struct ResampleContext *c, float *dst, const float *src, int *consumed, int src_size, int dst_size, int update_ctx); | ||||
| int swri_resample_double(struct ResampleContext *c,double *dst, const double *src, int *consumed, int src_size, int dst_size, int update_ctx); | int swri_resample_double(struct ResampleContext *c,double *dst, const double *src, int *consumed, int src_size, int dst_size, int update_ctx); | ||||
| void swri_noise_shaping_int16 (SwrContext *s, AudioData *srcs, AudioData *noises, int count); | |||||
| void swri_noise_shaping_int32 (SwrContext *s, AudioData *srcs, AudioData *noises, int count); | |||||
| void swri_noise_shaping_float (SwrContext *s, AudioData *srcs, AudioData *noises, int count); | |||||
| void swri_noise_shaping_double(SwrContext *s, AudioData *srcs, AudioData *noises, int count); | |||||
| int swri_rematrix_init(SwrContext *s); | int swri_rematrix_init(SwrContext *s); | ||||
| void swri_rematrix_free(SwrContext *s); | void swri_rematrix_free(SwrContext *s); | ||||
| int swri_rematrix(SwrContext *s, AudioData *out, AudioData *in, int len, int mustcopy); | int swri_rematrix(SwrContext *s, AudioData *out, AudioData *in, int len, int mustcopy); | ||||