Unified · Split
| @@ -17,7 +17,7 @@ Mantainers: · 16 unmodified lines | ||
| 17 | 17 | EFFECTS: tempo, pad, bass, treble, delay, new reverb, new |
| 18 | 18 | flanger, soft-knee companding, speed via resampling, filters |
| 19 | 19 | makeover inc. gnuplot & octave plotting, splice, remix, norm, |
| 20 | − contrast, new rate, spectrogram, new pitch, riaa; | |
| 20 | + contrast, new rate, spectrogram, new pitch, riaa, loudness; | |
| 21 | 21 | new effects chain with buffering and any # channels. |
| 22 | 22 | OTHERS: open input files via URL, file merge, play |
| 23 | 23 | multiple files with mixed format types, play with replay-gain, |
| @@ -44,7 +44,9 @@ File formats: · 43 unmodified lines | ||
| 44 | 44 | |
| 45 | 45 | Effects: |
| 46 | 46 | |
| 47 | − o New `riaa' effect; RIAA vinyl playback EQ. (robs) | |
| 47 | + o New `riaa' effect: RIAA vinyl playback EQ. (robs) | |
| 48 | + o New `loudness' effect: gain control with ISO 226 loudness | |
| 49 | + compensation. (robs) | |
| 48 | 50 | o New -b option for the norm effect; can be used to fix stereo |
| 49 | 51 | imbalance. (robs) |
| 50 | 52 | o Change default settings for `rate' effect; add -s -L options to |
| @@ -127,6 +127,7 @@ The audio effects/tools included in this release are as follows: · 126 unmodified lines | ||
| 127 | 127 | o dcshift Apply or remove DC offset |
| 128 | 128 | o fade Apply a fade-in and/or fade-out to the audio |
| 129 | 129 | o gain Apply gain or attenuation |
| 130 | + o loudness Gain control with ISO 226 loudness compensation | |
| 130 | 131 | o mcompand Multi-band compression/expansion/limiting |
| 131 | 132 | o norm Normalise to 0dB (or other), or fix imbalance |
| 132 | 133 | o vol Adjust audio volume |
| @@ -652,6 +652,23 @@ default values if possible. Only plugins with at most one audio input · 651 unmodified lines | ||
| 652 | 652 | and one audio output port can be used. If found, the environment varible |
| 653 | 653 | LADSPA_PATH will be used as search path for plugins. |
| 654 | 654 | .TP |
| 655 | +\fBloudness [\fIgain\fR [\fIreference\fR]] | |
| 656 | +Loudness control\*msimilar to the | |
| 657 | +.B gain | |
| 658 | +effect, but provides equalisation for the human auditory system. See | |
| 659 | +http://en.wikipedia.org/wiki/Loudness for a detailed description of | |
| 660 | +loudness. The gain is adjusted by the given | |
| 661 | +.I gain | |
| 662 | +parameter (usually negative) and the signal equalised according to ISO | |
| 663 | +226 w.r.t. a reference level of 65dB, though an alternative | |
| 664 | +.I reference | |
| 665 | +level may be given if the original audio has been equalised for some | |
| 666 | +other optimal level. | |
| 667 | +.SP | |
| 668 | +See also the | |
| 669 | +.B gain | |
| 670 | +effect. | |
| 671 | +.TP | |
| 655 | 672 | \fBlowpass\fR [\fB\-1\fR|\fB\-2\fR] \fIfrequency\fR[\fBk\fR]\fR [\fRwidth\fR[\fBq\fR\^|\^\fBo\fR\^|\^\fBh\fR\^|\^\fBk\fR]] |
| 656 | 673 | Apply a low-pass filter. |
| 657 | 674 | See the description of the \fBhighpass\fR effect for details. |
| @@ -967,7 +984,7 @@ quality come at the expense of increasing amounts of time to process the · 309 unmodified lines | ||
| 967 | 984 | audio. If no quality option is given, the quality level used is `high'. |
| 968 | 985 | .SP |
| 969 | 986 | The `quick' algorithm uses cubic interpolation; all others use |
| 970 | −band-width limited interpolation. The `quick' and `low' quality | |
| 987 | +band-limited interpolation. The `quick' and `low' quality | |
| 971 | 988 | algorithms have a `linear' phase response; for `medium', `high' and |
| 972 | 989 | `very high', the phase response is configurable (see below), but |
| 973 | 990 | defaults to `intermediate'. |
| @@ -1010,7 +1027,7 @@ lB lw52. · 36 unmodified lines | ||
| 1010 | 1027 | Any phase response (0 = minimum, 25 = intermediate, 50 = linear, 100 = maximum) |
| 1011 | 1028 | T} |
| 1012 | 1029 | \-s Steep filter (band-width = 99%) |
| 1013 | −\-b\ 74\-99.7 Any band-width % | |
| 1030 | +\-b\ 74\-99\*d7 Any band-width % | |
| 1014 | 1031 | \-a Allow aliasing above the pass-band |
| 1015 | 1032 | .TE |
| 1016 | 1033 | .DT |
| @@ -28,15 +28,16 @@ add_custom_command( · 27 unmodified lines | ||
| 28 | 28 | |
| 29 | 29 | # Format with: !xargs echo|tr ' ' '\n'|sort|column|expand|sed 's/^/ /' |
| 30 | 30 | set(effects_srcs |
| 31 | − biquad earwax mixer polyphas speed | |
| 32 | − biquads echo noiseprof rate splice | |
| 33 | − chorus echos noisered remix stat | |
| 34 | − compand fade normalise repeat swap | |
| 35 | − compandt fft4g output resample synth | |
| 36 | − contrast filter pad reverb tempo | |
| 37 | − dcshift flanger pan reverse tremolo | |
| 38 | − delay input phaser silence trim | |
| 39 | − dither mcompand pitch skeleff vol | |
| 31 | + biquad echo noiseprof remix swap | |
| 32 | + biquads echos noisered repeat synth | |
| 33 | + chorus fade normalise resample tempo | |
| 34 | + compand fft4g output reverb tremolo | |
| 35 | + compandt filter pad reverse trim | |
| 36 | + contrast flanger pan silence vol | |
| 37 | + dcshift input phaser skeleff | |
| 38 | + delay loudness pitch speed | |
| 39 | + dither mcompand polyphas splice | |
| 40 | + earwax mixer rate stat | |
| 40 | 41 | ) |
| 41 | 42 | set(formats_srcs |
| 42 | 43 | 8svx dat ima-fmt s3-fmt u4-fmt |
| @@ -252,7 +252,7 @@ libsfx_la_SOURCES = \ · 251 unmodified lines | ||
| 252 | 252 | band.h biquad.c biquad.h biquads.c chorus.c compand.c compandt.c \ |
| 253 | 253 | compandt.h contrast.c dcshift.c delay.c dither.c earwax.c echo.c \ |
| 254 | 254 | echos.c effects.c effects.h effects_i.c fade.c fft4g.c fft4g.h \ |
| 255 | − fifo.h filter.c flanger.c input.c ladspa.c mcompand.c \ | |
| 255 | + fifo.h filter.c flanger.c input.c ladspa.c loudness.c mcompand.c \ | |
| 256 | 256 | mixer.c noiseprof.c noisered.c noisered.h normalise.c output.c pad.c \ |
| 257 | 257 | pan.c phaser.c pitch.c polyphas.c rabbit.c rate.c \ |
| 258 | 258 | rate_filters.h rate_half_fir.h rate_poly_fir0.h rate_poly_fir.h \ |
| @@ -41,6 +41,7 @@ · 40 unmodified lines | ||
| 41 | 41 | #ifdef HAVE_LADSPA_H |
| 42 | 42 | EFFECT(ladspa) |
| 43 | 43 | #endif |
| 44 | + EFFECT(loudness) | |
| 44 | 45 | EFFECT(lowpass) |
| 45 | 46 | EFFECT(mcompand) |
| 46 | 47 | EFFECT(mixer) |
| @@ -68,6 +68,56 @@ unsigned lsx_lcm(unsigned a, unsigned b) · 67 unmodified lines | ||
| 68 | 68 | return a * (b / lsx_gcd(a, b)); |
| 69 | 69 | } |
| 70 | 70 | |
| 71 | +/* Numerical Recipes cubic spline */ | |
| 72 | + | |
| 73 | +void lsx_prepare_spline3(double const * x, double const * y, int n, | |
| 74 | + double start_1d, double end_1d, double * y_2d) | |
| 75 | +{ | |
| 76 | + double p, qn, sig, un, * u = lsx_malloc((n - 1) * sizeof(*u)); | |
| 77 | + int i; | |
| 78 | + | |
| 79 | + if (start_1d == HUGE_VAL) | |
| 80 | + y_2d[0] = u[0] = 0; /* Start with natural spline or */ | |
| 81 | + else { /* set the start first derivative */ | |
| 82 | + y_2d[0] = -.5; | |
| 83 | + u[0] = (3 / (x[1] - x[0])) * ((y[1] - y[0]) / (x[1] - x[0]) - start_1d); | |
| 84 | + } | |
| 85 | + | |
| 86 | + for (i = 1; i < n - 1; ++i) { | |
| 87 | + sig = (x[i] - x[i - 1]) / (x[i + 1] - x[i - 1]); | |
| 88 | + p = sig * y_2d[i - 1] + 2; | |
| 89 | + y_2d[i] = (sig - 1) / p; | |
| 90 | + u[i] = (y[i + 1] - y[i]) / (x[i + 1] - x[i]) - | |
| 91 | + (y[i] - y[i - 1]) / (x[i] - x[i - 1]); | |
| 92 | + u[i] = (6 * u[i] / (x[i + 1] - x[i - 1]) - sig * u[i - 1]) / p; | |
| 93 | + } | |
| 94 | + if (end_1d == HUGE_VAL) | |
| 95 | + qn = un = 0; /* End with natural spline or */ | |
| 96 | + else { /* set the end first derivative */ | |
| 97 | + qn = .5; | |
| 98 | + un = 3 / (x[n - 1] - x[n - 2]) * (end_1d - (y[n - 1] - y[n - 2]) / (x[n - 1] - x[n - 2])); | |
| 99 | + } | |
| 100 | + y_2d[n - 1] = (un - qn * u[n - 2]) / (qn * y_2d[n - 2] + 1); | |
| 101 | + for (i = n - 2; i >= 0; --i) | |
| 102 | + y_2d[i] = y_2d[i] * y_2d[i + 1] + u[i]; | |
| 103 | + free(u); | |
| 104 | +} | |
| 105 | + | |
| 106 | +double lsx_spline3(double const * x, double const * y, double const * y_2d, | |
| 107 | + int n, double x1) | |
| 108 | +{ | |
| 109 | + int t, i[2] = {0, 0}; | |
| 110 | + double d, a, b; | |
| 111 | + | |
| 112 | + for (i[1] = n - 1; i[1] - i[0] > 1; t = (i[1] + i[0]) >> 1, i[x[t] > x1] = t); | |
| 113 | + d = x[i[1]] - x[i[0]]; | |
| 114 | + assert(d != 0); | |
| 115 | + a = (x[i[1]] - x1) / d; | |
| 116 | + b = (x1 - x[i[0]]) / d; | |
| 117 | + return a * y[i[0]] + b * y[i[1]] + | |
| 118 | + ((a * a * a - a) * y_2d[i[0]] + (b * b * b - b) * y_2d[i[1]]) * d * d / 6; | |
| 119 | +} | |
| 120 | + | |
| 71 | 121 | enum_item const lsx_wave_enum[] = { |
| 72 | 122 | ENUM_ITEM(SOX_WAVE_,SINE) |
| 73 | 123 | ENUM_ITEM(SOX_WAVE_,TRIANGLE) |
| @@ -279,6 +329,15 @@ double lsx_bessel_I_0(double x) · 205 unmodified lines | ||
| 279 | 329 | return sum; |
| 280 | 330 | } |
| 281 | 331 | |
| 332 | +int lsx_set_dft_length(int num_taps) /* Set to 4 x nearest power of 2 */ | |
| 333 | +{ | |
| 334 | + int result, n = num_taps; | |
| 335 | + for (result = 8; n > 2; result <<= 1, n >>= 1); | |
| 336 | + result = range_limit(result, 4096, 131072); | |
| 337 | + assert(num_taps * 2 < result); | |
| 338 | + return result; | |
| 339 | +} | |
| 340 | + | |
| 282 | 341 | #include "fft4g.h" |
| 283 | 342 | int * lsx_fft_br; |
| 284 | 343 | double * lsx_fft_sc; |
| @@ -384,6 +443,24 @@ void lsx_apply_bartlett(double h[], const int num_points) · 99 unmodified lines | ||
| 384 | 443 | } |
| 385 | 444 | } |
| 386 | 445 | |
| 446 | +void lsx_apply_blackman(double h[], const int num_points, double alpha) | |
| 447 | +{ | |
| 448 | + int i, m = num_points - 1; | |
| 449 | + for (i = 0; i < num_points; ++i) { | |
| 450 | + double x = 2 * M_PI * i / m; | |
| 451 | + h[i] *= (1 - alpha) *.5 - .5 * cos(x) + alpha * .5 * cos(2 * x); | |
| 452 | + } | |
| 453 | +} | |
| 454 | + | |
| 455 | +void lsx_apply_blackman_nutall(double h[], const int num_points) | |
| 456 | +{ | |
| 457 | + int i, m = num_points - 1; | |
| 458 | + for (i = 0; i < num_points; ++i) { | |
| 459 | + double x = 2 * M_PI * i / m; | |
| 460 | + h[i] *= .3635819 - .4891775 * cos(x) + .1365995 * cos(2 * x) - .0106411 * cos(3 * x); | |
| 461 | + } | |
| 462 | +} | |
| 463 | + | |
| 387 | 464 | double lsx_kaiser_beta(double att) |
| 388 | 465 | { |
| 389 | 466 | if (att > 100 ) return .1117 * att - 1.11; |
| @@ -0,0 +1,221 @@ | ||
| 1 | +/* Effect: loudness filter Copyright (c) 2008 robs@users.sourceforge.net | |
| 2 | + * | |
| 3 | + * This library is free software; you can redistribute it and/or modify it | |
| 4 | + * under the terms of the GNU Lesser General Public License as published by | |
| 5 | + * the Free Software Foundation; either version 2.1 of the License, or (at | |
| 6 | + * your option) any later version. | |
| 7 | + * | |
| 8 | + * This library is distributed in the hope that it will be useful, but | |
| 9 | + * WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 10 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser | |
| 11 | + * General Public License for more details. | |
| 12 | + * | |
| 13 | + * You should have received a copy of the GNU Lesser General Public License | |
| 14 | + * along with this library; if not, write to the Free Software Foundation, | |
| 15 | + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
| 16 | + */ | |
| 17 | + | |
| 18 | +#include "sox_i.h" | |
| 19 | +#include "fft4g.h" | |
| 20 | +#define FIFO_SIZE_T int | |
| 21 | +#include "fifo.h" | |
| 22 | +#include <string.h> | |
| 23 | + | |
| 24 | +typedef struct { | |
| 25 | + int dft_length, num_taps; | |
| 26 | + double * coefs; | |
| 27 | +} filter_t; | |
| 28 | + | |
| 29 | +typedef struct { | |
| 30 | + double delta, start; | |
| 31 | + int n; | |
| 32 | + size_t samples_in, samples_out; | |
| 33 | + fifo_t input_fifo, output_fifo; | |
| 34 | + filter_t filter, * filter_ptr; | |
| 35 | +} priv_t; | |
| 36 | + | |
| 37 | +static int create(sox_effect_t * effp, int argc, char **argv) | |
| 38 | +{ | |
| 39 | + priv_t * p = (priv_t *)effp->priv; | |
| 40 | + p->filter_ptr = &p->filter; | |
| 41 | + p->delta = -10; | |
| 42 | + p->start = 65; | |
| 43 | + p->n = 1023; | |
| 44 | + do { /* break-able block */ | |
| 45 | + NUMERIC_PARAMETER(delta,-50 , 15) | |
| 46 | + NUMERIC_PARAMETER(start, 50 , 75) | |
| 47 | + NUMERIC_PARAMETER(n ,127 ,2047) | |
| 48 | + } while (0); | |
| 49 | + p->n = 2 * p->n + 1; | |
| 50 | + return argc? lsx_usage(effp) : SOX_SUCCESS; | |
| 51 | +} | |
| 52 | + | |
| 53 | +static double * make_filter(int n, double start, double delta, double rate) | |
| 54 | +{ | |
| 55 | + static const struct {double f, af, lu, tf;} iso226_table[] = { | |
| 56 | + { 20,0.532,-31.6,78.5},{ 25,0.506,-27.2,68.7},{ 31.5,0.480,-23.0,59.5}, | |
| 57 | + { 40,0.455,-19.1,51.1},{ 50,0.432,-15.9,44.0},{ 63,0.409,-13.0,37.5}, | |
| 58 | + { 80,0.387,-10.3,31.5},{ 100,0.367, -8.1,26.5},{ 125,0.349, -6.2,22.1}, | |
| 59 | + { 160,0.330, -4.5,17.9},{ 200,0.315, -3.1,14.4},{ 250,0.301, -2.0,11.4}, | |
| 60 | + { 315,0.288, -1.1, 8.6},{ 400,0.276, -0.4, 6.2},{ 500,0.267, 0.0, 4.4}, | |
| 61 | + { 630,0.259, 0.3, 3.0},{ 800,0.253, 0.5, 2.2},{ 1000,0.250, 0.0, 2.4}, | |
| 62 | + { 1250,0.246, -2.7, 3.5},{ 1600,0.244, -4.1, 1.7},{ 2000,0.243, -1.0,-1.3}, | |
| 63 | + { 2500,0.243, 1.7,-4.2},{ 3150,0.243, 2.5,-6.0},{ 4000,0.242, 1.2,-5.4}, | |
| 64 | + { 5000,0.242, -2.1,-1.5},{ 6300,0.245, -7.1, 6.0},{ 8000,0.254,-11.2,12.6}, | |
| 65 | + {10000,0.271,-10.7,13.9},{12500,0.301, -3.1,12.3}, | |
| 66 | + }; | |
| 67 | + #define LEN (array_length(iso226_table) + 2) | |
| 68 | + #define SPL(phon, t) (10 / t.af * log10(4.47e-3 * (pow(10., .025 * (phon)) - \ | |
| 69 | + 1.15) + pow(.4 * pow(10., (t.tf + t.lu) / 10 - 9), t.af)) - t.lu + 94) | |
| 70 | + double fs[LEN], spl[LEN], d[LEN], * work, * h; | |
| 71 | + int i, work_len; | |
| 72 | + | |
| 73 | + fs[0] = log(1.); | |
| 74 | + spl[0] = delta * .2; | |
| 75 | + for (i = 0; i < (int)LEN - 2; ++i) { | |
| 76 | + spl[i + 1] = SPL(start + delta, iso226_table[i]) - | |
| 77 | + SPL(start , iso226_table[i]); | |
| 78 | + fs[i + 1] = log(iso226_table[i].f); | |
| 79 | + } | |
| 80 | + fs[i + 1] = log(100000.); | |
| 81 | + spl[i + 1] = spl[0]; | |
| 82 | + lsx_prepare_spline3(fs, spl, LEN, HUGE_VAL, HUGE_VAL, d); | |
| 83 | + | |
| 84 | + for (work_len = 8192; work_len < rate / 2; work_len <<= 1); | |
| 85 | + work = lsx_calloc(work_len, sizeof(*work)); | |
| 86 | + h = lsx_calloc(n, sizeof(*h)); | |
| 87 | + | |
| 88 | + for (i = 1; i <= work_len / 2; ++i) { | |
| 89 | + double f = rate * i / work_len; | |
| 90 | + double spl1 = f < 1? spl[0] : lsx_spline3(fs, spl, d, LEN, log(f)); | |
| 91 | + work[i < work_len / 2 ? 2 * i : 1] = dB_to_linear(spl1); | |
| 92 | + } | |
| 93 | + lsx_safe_rdft(work_len, -1, work); | |
| 94 | + for (i = 0; i < n; ++i) | |
| 95 | + h[i] = work[(work_len - n / 2 + i) % work_len] * 2. / work_len; | |
| 96 | + lsx_apply_kaiser(h, n, lsx_kaiser_beta(40 + 2./3 * fabs(delta))); | |
| 97 | + | |
| 98 | + free(work); | |
| 99 | + return h; | |
| 100 | + #undef SPL | |
| 101 | + #undef LEN | |
| 102 | +} | |
| 103 | + | |
| 104 | +static int start(sox_effect_t * effp) | |
| 105 | +{ | |
| 106 | + priv_t * p = (priv_t *) effp->priv; | |
| 107 | + int i, half = p->n / 2, dft_length = lsx_set_dft_length(p->n); | |
| 108 | + double * h; | |
| 109 | + | |
| 110 | + if (p->delta == 0) | |
| 111 | + return SOX_EFF_NULL; | |
| 112 | + | |
| 113 | + if (!p->filter_ptr->num_taps) { | |
| 114 | + h = make_filter(p->n, p->start, p->delta, effp->in_signal.rate); | |
| 115 | + p->filter_ptr->coefs = lsx_calloc(dft_length, sizeof(*p->filter_ptr->coefs)); | |
| 116 | + for (i = 0; i < p->n; ++i) | |
| 117 | + p->filter_ptr->coefs[(i + dft_length - p->n + 1) & (dft_length - 1)] | |
| 118 | + = h[i] / dft_length * 2; | |
| 119 | + free(h); | |
| 120 | + p->filter_ptr->num_taps = p->n; | |
| 121 | + p->filter_ptr->dft_length = dft_length; | |
| 122 | + lsx_safe_rdft(dft_length, 1, p->filter_ptr->coefs); | |
| 123 | + } | |
| 124 | + fifo_create(&p->input_fifo, (int)sizeof(double)); | |
| 125 | + memset(fifo_reserve(&p->input_fifo, half), 0, sizeof(double) * half); | |
| 126 | + fifo_create(&p->output_fifo, (int)sizeof(double)); | |
| 127 | + return SOX_SUCCESS; | |
| 128 | +} | |
| 129 | + | |
| 130 | +static void filter(priv_t * p) | |
| 131 | +{ | |
| 132 | + int i, num_in = max(0, fifo_occupancy(&p->input_fifo)); | |
| 133 | + filter_t const * f = p->filter_ptr; | |
| 134 | + int const overlap = f->num_taps - 1; | |
| 135 | + double * output; | |
| 136 | + | |
| 137 | + while (num_in >= f->dft_length) { | |
| 138 | + double const * input = fifo_read_ptr(&p->input_fifo); | |
| 139 | + fifo_read(&p->input_fifo, f->dft_length - overlap, NULL); | |
| 140 | + num_in -= f->dft_length - overlap; | |
| 141 | + | |
| 142 | + output = fifo_reserve(&p->output_fifo, f->dft_length); | |
| 143 | + fifo_trim_by(&p->output_fifo, overlap); | |
| 144 | + memcpy(output, input, f->dft_length * sizeof(*output)); | |
| 145 | + | |
| 146 | + lsx_rdft(f->dft_length, 1, output, lsx_fft_br, lsx_fft_sc); | |
| 147 | + output[0] *= f->coefs[0]; | |
| 148 | + output[1] *= f->coefs[1]; | |
| 149 | + for (i = 2; i < f->dft_length; i += 2) { | |
| 150 | + double tmp = output[i]; | |
| 151 | + output[i ] = f->coefs[i ] * tmp - f->coefs[i+1] * output[i+1]; | |
| 152 | + output[i+1] = f->coefs[i+1] * tmp + f->coefs[i ] * output[i+1]; | |
| 153 | + } | |
| 154 | + lsx_rdft(f->dft_length, -1, output, lsx_fft_br, lsx_fft_sc); | |
| 155 | + } | |
| 156 | +} | |
| 157 | + | |
| 158 | +static int flow(sox_effect_t * effp, const sox_sample_t * ibuf, | |
| 159 | + sox_sample_t * obuf, size_t * isamp, size_t * osamp) | |
| 160 | +{ | |
| 161 | + priv_t * p = (priv_t *)effp->priv; | |
| 162 | + size_t i, odone = min(*osamp, (size_t)fifo_occupancy(&p->output_fifo)); | |
| 163 | + double const * s = fifo_read(&p->output_fifo, (int)odone, NULL); | |
| 164 | + | |
| 165 | + for (i = 0; i < odone; ++i) | |
| 166 | + *obuf++ = SOX_FLOAT_64BIT_TO_SAMPLE(*s++, effp->clips); | |
| 167 | + p->samples_out += odone; | |
| 168 | + | |
| 169 | + if (*isamp && odone < *osamp) { | |
| 170 | + double * t = fifo_write(&p->input_fifo, (int)*isamp, NULL); | |
| 171 | + p->samples_in += (int)*isamp; | |
| 172 | + | |
| 173 | + for (i = *isamp; i; --i) | |
| 174 | + *t++ = SOX_SAMPLE_TO_FLOAT_64BIT(*ibuf++, effp->clips); | |
| 175 | + filter(p); | |
| 176 | + } | |
| 177 | + else *isamp = 0; | |
| 178 | + *osamp = odone; | |
| 179 | + return SOX_SUCCESS; | |
| 180 | +} | |
| 181 | + | |
| 182 | +static int drain(sox_effect_t * effp, sox_sample_t * obuf, size_t * osamp) | |
| 183 | +{ | |
| 184 | + priv_t * p = (priv_t *)effp->priv; | |
| 185 | + static size_t isamp = 0; | |
| 186 | + size_t samples_out = p->samples_in; | |
| 187 | + size_t remaining = samples_out - p->samples_out; | |
| 188 | + double * buff = lsx_calloc(1024, sizeof(*buff)); | |
| 189 | + | |
| 190 | + if ((int)remaining > 0) { | |
| 191 | + while ((size_t)fifo_occupancy(&p->output_fifo) < remaining) { | |
| 192 | + fifo_write(&p->input_fifo, 1024, buff); | |
| 193 | + p->samples_in += 1024; | |
| 194 | + filter(p); | |
| 195 | + } | |
| 196 | + fifo_trim_to(&p->output_fifo, (int)remaining); | |
| 197 | + p->samples_in = 0; | |
| 198 | + } | |
| 199 | + free(buff); | |
| 200 | + return flow(effp, 0, obuf, &isamp, osamp); | |
| 201 | +} | |
| 202 | + | |
| 203 | +static int stop(sox_effect_t * effp) | |
| 204 | +{ | |
| 205 | + priv_t * p = (priv_t *) effp->priv; | |
| 206 | + | |
| 207 | + fifo_delete(&p->input_fifo); | |
| 208 | + fifo_delete(&p->output_fifo); | |
| 209 | + free(p->filter_ptr->coefs); | |
| 210 | + memset(p->filter_ptr, 0, sizeof(*p->filter_ptr)); | |
| 211 | + return SOX_SUCCESS; | |
| 212 | +} | |
| 213 | + | |
| 214 | +sox_effect_handler_t const * sox_loudness_effect_fn(void) | |
| 215 | +{ | |
| 216 | + static sox_effect_handler_t handler = { | |
| 217 | + "loudness", "[gain [ref]]", 0, | |
| 218 | + create, start, flow, drain, stop, NULL, sizeof(priv_t) | |
| 219 | + }; | |
| 220 | + return &handler; | |
| 221 | +} | |
| @@ -301,15 +301,6 @@ static void fir_to_phase(double * * h, int * len, · 300 unmodified lines | ||
| 301 | 301 | free(work); |
| 302 | 302 | } |
| 303 | 303 | |
| 304 | −static int set_dft_length(int num_taps) /* Set to 4 x nearest power of 2 */ | |
| 305 | −{ | |
| 306 | − int result, n = num_taps; | |
| 307 | − for (result = 8; n > 2; result <<= 1, n >>= 1); | |
| 308 | − result = range_limit(result, 4096, 131072); | |
| 309 | − assert(num_taps * 2 < result); | |
| 310 | − return result; | |
| 311 | −} | |
| 312 | − | |
| 313 | 304 | static void half_band_filter_init(rate_shared_t * p, unsigned which, |
| 314 | 305 | int num_taps, sample_t const h[], double Fp, double atten, int multiplier, |
| 315 | 306 | double phase, sox_bool allow_aliasing) |
| @@ -320,7 +311,7 @@ static void half_band_filter_init(rate_shared_t * p, unsigned which, · 4 unmodified lines | ||
| 320 | 311 | if (f->num_taps) |
| 321 | 312 | return; |
| 322 | 313 | if (h) { |
| 323 | − dft_length = set_dft_length(num_taps); | |
| 314 | + dft_length = lsx_set_dft_length(num_taps); | |
| 324 | 315 | f->coefs = calloc(dft_length, sizeof(*f->coefs)); |
| 325 | 316 | for (i = 0; i < num_taps; ++i) |
| 326 | 317 | f->coefs[(i + dft_length - num_taps + 1) & (dft_length - 1)] |
| @@ -337,7 +328,7 @@ static void half_band_filter_init(rate_shared_t * p, unsigned which, · 10 unmodified lines | ||
| 337 | 328 | fir_to_phase(&h, &num_taps, &f->post_peak, phase); |
| 338 | 329 | else f->post_peak = num_taps / 2; |
| 339 | 330 | |
| 340 | − dft_length = set_dft_length(num_taps); | |
| 331 | + dft_length = lsx_set_dft_length(num_taps); | |
| 341 | 332 | f->coefs = calloc(dft_length, sizeof(*f->coefs)); |
| 342 | 333 | for (i = 0; i < num_taps; ++i) |
| 343 | 334 | f->coefs[(i + dft_length - num_taps + 1) & (dft_length - 1)] |
| @@ -61,7 +61,13 @@ double lsx_parse_frequency(char const * text, char * * end_ptr); · 60 unmodified lines | ||
| 61 | 61 | unsigned lsx_gcd(unsigned a, unsigned b); |
| 62 | 62 | unsigned lsx_lcm(unsigned a, unsigned b); |
| 63 | 63 | |
| 64 | +void lsx_prepare_spline3(double const * x, double const * y, int n, | |
| 65 | + double start_1d, double end_1d, double * y_2d); | |
| 66 | +double lsx_spline3(double const * x, double const * y, double const * y_2d, | |
| 67 | + int n, double x1); | |
| 68 | + | |
| 64 | 69 | double lsx_bessel_I_0(double x); |
| 70 | +int lsx_set_dft_length(int num_taps); | |
| 65 | 71 | extern int * lsx_fft_br; |
| 66 | 72 | extern double * lsx_fft_sc; |
| 67 | 73 | void lsx_safe_rdft(int len, int type, double * d); |
| @@ -72,6 +78,8 @@ void lsx_apply_hann_f(float h[], const int num_points); · 4 unmodified lines | ||
| 72 | 78 | void lsx_apply_hann(double h[], const int num_points); |
| 73 | 79 | void lsx_apply_hamming(double h[], const int num_points); |
| 74 | 80 | void lsx_apply_bartlett(double h[], const int num_points); |
| 81 | +void lsx_apply_blackman(double h[], const int num_points, double alpha); | |
| 82 | +void lsx_apply_blackman_nutall(double h[], const int num_points); | |
| 75 | 83 | double lsx_kaiser_beta(double att); |
| 76 | 84 | void lsx_apply_kaiser(double h[], const int num_points, double beta); |
| 77 | 85 | |
| @@ -20,15 +20,7 @@ test_converters () { · 19 unmodified lines | ||
| 20 | 20 | # Create input file |
| 21 | 21 | $SOX -r $1 -n -twavpcm $IN synth 20 sin 0:`expr $1 / 2` gain -2 |
| 22 | 22 | for src in \ |
| 23 | − "polyphase" \ | |
| 24 | − "rabbit -c0" \ | |
| 25 | − "rabbit -c1" \ | |
| 26 | − "rate -h" \ | |
| 27 | − "rate -v" \ | |
| 28 | − "resample -q" \ | |
| 29 | − "resample -ql" \ | |
| 30 | − "ssrc" \ | |
| 31 | − "ssrc_hp" \ | |
| 23 | + "rate -vsL" \ | |
| 32 | 24 | ; do |
| 33 | 25 | echo $src |
| 34 | 26 | case "$src" in |