Unified · Split
| @@ -17,7 +17,7 @@ Mantainers: · 16 unmodified lines | |||
| 17 | EFFECTS: tempo, pad, bass, treble, delay, new reverb, new | 17 | EFFECTS: tempo, pad, bass, treble, delay, new reverb, new |
| 18 | flanger, soft-knee companding, speed via resampling, filters | 18 | flanger, soft-knee companding, speed via resampling, filters |
| 19 | makeover inc. gnuplot & octave plotting, splice, remix, norm, | 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 | new effects chain with buffering and any # channels. | 21 | new effects chain with buffering and any # channels. |
| 22 | OTHERS: open input files via URL, file merge, play | 22 | OTHERS: open input files via URL, file merge, play |
| 23 | multiple files with mixed format types, play with replay-gain, | 23 | multiple files with mixed format types, play with replay-gain, |
| @@ -44,7 +44,9 @@ File formats: · 43 unmodified lines | |||
| 44 | 44 | ||
| 45 | Effects: | 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 | o New -b option for the norm effect; can be used to fix stereo | 50 | o New -b option for the norm effect; can be used to fix stereo |
| 49 | imbalance. (robs) | 51 | imbalance. (robs) |
| 50 | o Change default settings for `rate' effect; add -s -L options to | 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 | o dcshift Apply or remove DC offset | 127 | o dcshift Apply or remove DC offset |
| 128 | o fade Apply a fade-in and/or fade-out to the audio | 128 | o fade Apply a fade-in and/or fade-out to the audio |
| 129 | o gain Apply gain or attenuation | 129 | o gain Apply gain or attenuation |
| 130 | o loudness Gain control with ISO 226 loudness compensation | ||
| 130 | o mcompand Multi-band compression/expansion/limiting | 131 | o mcompand Multi-band compression/expansion/limiting |
| 131 | o norm Normalise to 0dB (or other), or fix imbalance | 132 | o norm Normalise to 0dB (or other), or fix imbalance |
| 132 | o vol Adjust audio volume | 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 | and one audio output port can be used. If found, the environment varible | 652 | and one audio output port can be used. If found, the environment varible |
| 653 | LADSPA_PATH will be used as search path for plugins. | 653 | LADSPA_PATH will be used as search path for plugins. |
| 654 | .TP | 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 | \fBlowpass\fR [\fB\-1\fR|\fB\-2\fR] \fIfrequency\fR[\fBk\fR]\fR [\fRwidth\fR[\fBq\fR\^|\^\fBo\fR\^|\^\fBh\fR\^|\^\fBk\fR]] | 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 | Apply a low-pass filter. | 673 | Apply a low-pass filter. |
| 657 | See the description of the \fBhighpass\fR effect for details. | 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 | audio. If no quality option is given, the quality level used is `high'. | 984 | audio. If no quality option is given, the quality level used is `high'. |
| 968 | .SP | 985 | .SP |
| 969 | The `quick' algorithm uses cubic interpolation; all others use | 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 | algorithms have a `linear' phase response; for `medium', `high' and | 988 | algorithms have a `linear' phase response; for `medium', `high' and |
| 972 | `very high', the phase response is configurable (see below), but | 989 | `very high', the phase response is configurable (see below), but |
| 973 | defaults to `intermediate'. | 990 | defaults to `intermediate'. |
| @@ -1010,7 +1027,7 @@ lB lw52. · 36 unmodified lines | |||
| 1010 | Any phase response (0 = minimum, 25 = intermediate, 50 = linear, 100 = maximum) | 1027 | Any phase response (0 = minimum, 25 = intermediate, 50 = linear, 100 = maximum) |
| 1011 | T} | 1028 | T} |
| 1012 | \-s Steep filter (band-width = 99%) | 1029 | \-s Steep filter (band-width = 99%) |
| 1013 | \-b\ 74\-99.7 Any band-width % | 1030 | \-b\ 74\-99\*d7 Any band-width % |
| 1014 | \-a Allow aliasing above the pass-band | 1031 | \-a Allow aliasing above the pass-band |
| 1015 | .TE | 1032 | .TE |
| 1016 | .DT | 1033 | .DT |
| @@ -28,15 +28,16 @@ add_custom_command( · 27 unmodified lines | |||
| 28 | 28 | ||
| 29 | # Format with: !xargs echo|tr ' ' '\n'|sort|column|expand|sed 's/^/ /' | 29 | # Format with: !xargs echo|tr ' ' '\n'|sort|column|expand|sed 's/^/ /' |
| 30 | set(effects_srcs | 30 | set(effects_srcs |
| 31 | biquad earwax mixer polyphas speed | 31 | biquad echo noiseprof remix swap |
| 32 | biquads echo noiseprof rate splice | 32 | biquads echos noisered repeat synth |
| 33 | chorus echos noisered remix stat | 33 | chorus fade normalise resample tempo |
| 34 | compand fade normalise repeat swap | 34 | compand fft4g output reverb tremolo |
| 35 | compandt fft4g output resample synth | 35 | compandt filter pad reverse trim |
| 36 | contrast filter pad reverb tempo | 36 | contrast flanger pan silence vol |
| 37 | dcshift flanger pan reverse tremolo | 37 | dcshift input phaser skeleff |
| 38 | delay input phaser silence trim | 38 | delay loudness pitch speed |
| 39 | dither mcompand pitch skeleff vol | 39 | dither mcompand polyphas splice |
| 40 | earwax mixer rate stat | ||
| 40 | ) | 41 | ) |
| 41 | set(formats_srcs | 42 | set(formats_srcs |
| 42 | 8svx dat ima-fmt s3-fmt u4-fmt | 43 | 8svx dat ima-fmt s3-fmt u4-fmt |
| @@ -252,7 +252,7 @@ libsfx_la_SOURCES = \ · 251 unmodified lines | |||
| 252 | band.h biquad.c biquad.h biquads.c chorus.c compand.c compandt.c \ | 252 | band.h biquad.c biquad.h biquads.c chorus.c compand.c compandt.c \ |
| 253 | compandt.h contrast.c dcshift.c delay.c dither.c earwax.c echo.c \ | 253 | compandt.h contrast.c dcshift.c delay.c dither.c earwax.c echo.c \ |
| 254 | echos.c effects.c effects.h effects_i.c fade.c fft4g.c fft4g.h \ | 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 | mixer.c noiseprof.c noisered.c noisered.h normalise.c output.c pad.c \ | 256 | mixer.c noiseprof.c noisered.c noisered.h normalise.c output.c pad.c \ |
| 257 | pan.c phaser.c pitch.c polyphas.c rabbit.c rate.c \ | 257 | pan.c phaser.c pitch.c polyphas.c rabbit.c rate.c \ |
| 258 | rate_filters.h rate_half_fir.h rate_poly_fir0.h rate_poly_fir.h \ | 258 | rate_filters.h rate_half_fir.h rate_poly_fir0.h rate_poly_fir.h \ |
| @@ -41,6 +41,7 @@ · 40 unmodified lines | |||
| 41 | #ifdef HAVE_LADSPA_H | 41 | #ifdef HAVE_LADSPA_H |
| 42 | EFFECT(ladspa) | 42 | EFFECT(ladspa) |
| 43 | #endif | 43 | #endif |
| 44 | EFFECT(loudness) | ||
| 44 | EFFECT(lowpass) | 45 | EFFECT(lowpass) |
| 45 | EFFECT(mcompand) | 46 | EFFECT(mcompand) |
| 46 | EFFECT(mixer) | 47 | EFFECT(mixer) |
| @@ -68,6 +68,56 @@ unsigned lsx_lcm(unsigned a, unsigned b) · 67 unmodified lines | |||
| 68 | return a * (b / lsx_gcd(a, b)); | 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 | enum_item const lsx_wave_enum[] = { | 121 | enum_item const lsx_wave_enum[] = { |
| 72 | ENUM_ITEM(SOX_WAVE_,SINE) | 122 | ENUM_ITEM(SOX_WAVE_,SINE) |
| 73 | ENUM_ITEM(SOX_WAVE_,TRIANGLE) | 123 | ENUM_ITEM(SOX_WAVE_,TRIANGLE) |
| @@ -279,6 +329,15 @@ double lsx_bessel_I_0(double x) · 205 unmodified lines | |||
| 279 | return sum; | 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 | #include "fft4g.h" | 341 | #include "fft4g.h" |
| 283 | int * lsx_fft_br; | 342 | int * lsx_fft_br; |
| 284 | double * lsx_fft_sc; | 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 | double lsx_kaiser_beta(double att) | 464 | double lsx_kaiser_beta(double att) |
| 388 | { | 465 | { |
| 389 | if (att > 100 ) return .1117 * att - 1.11; | 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 | free(work); | 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 | static void half_band_filter_init(rate_shared_t * p, unsigned which, | 304 | static void half_band_filter_init(rate_shared_t * p, unsigned which, |
| 314 | int num_taps, sample_t const h[], double Fp, double atten, int multiplier, | 305 | int num_taps, sample_t const h[], double Fp, double atten, int multiplier, |
| 315 | double phase, sox_bool allow_aliasing) | 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 | if (f->num_taps) | 311 | if (f->num_taps) |
| 321 | return; | 312 | return; |
| 322 | if (h) { | 313 | if (h) { |
| 323 | dft_length = set_dft_length(num_taps); | 314 | dft_length = lsx_set_dft_length(num_taps); |
| 324 | f->coefs = calloc(dft_length, sizeof(*f->coefs)); | 315 | f->coefs = calloc(dft_length, sizeof(*f->coefs)); |
| 325 | for (i = 0; i < num_taps; ++i) | 316 | for (i = 0; i < num_taps; ++i) |
| 326 | f->coefs[(i + dft_length - num_taps + 1) & (dft_length - 1)] | 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 | fir_to_phase(&h, &num_taps, &f->post_peak, phase); | 328 | fir_to_phase(&h, &num_taps, &f->post_peak, phase); |
| 338 | else f->post_peak = num_taps / 2; | 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 | f->coefs = calloc(dft_length, sizeof(*f->coefs)); | 332 | f->coefs = calloc(dft_length, sizeof(*f->coefs)); |
| 342 | for (i = 0; i < num_taps; ++i) | 333 | for (i = 0; i < num_taps; ++i) |
| 343 | f->coefs[(i + dft_length - num_taps + 1) & (dft_length - 1)] | 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 | unsigned lsx_gcd(unsigned a, unsigned b); | 61 | unsigned lsx_gcd(unsigned a, unsigned b); |
| 62 | unsigned lsx_lcm(unsigned a, unsigned b); | 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 | double lsx_bessel_I_0(double x); | 69 | double lsx_bessel_I_0(double x); |
| 70 | int lsx_set_dft_length(int num_taps); | ||
| 65 | extern int * lsx_fft_br; | 71 | extern int * lsx_fft_br; |
| 66 | extern double * lsx_fft_sc; | 72 | extern double * lsx_fft_sc; |
| 67 | void lsx_safe_rdft(int len, int type, double * d); | 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 | void lsx_apply_hann(double h[], const int num_points); | 78 | void lsx_apply_hann(double h[], const int num_points); |
| 73 | void lsx_apply_hamming(double h[], const int num_points); | 79 | void lsx_apply_hamming(double h[], const int num_points); |
| 74 | void lsx_apply_bartlett(double h[], const int num_points); | 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 | double lsx_kaiser_beta(double att); | 83 | double lsx_kaiser_beta(double att); |
| 76 | void lsx_apply_kaiser(double h[], const int num_points, double beta); | 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 | # Create input file | 20 | # Create input file |
| 21 | $SOX -r $1 -n -twavpcm $IN synth 20 sin 0:`expr $1 / 2` gain -2 | 21 | $SOX -r $1 -n -twavpcm $IN synth 20 sin 0:`expr $1 / 2` gain -2 |
| 22 | for src in \ | 22 | for src in \ |
| 23 | "polyphase" \ | 23 | "rate -vsL" \ |
| 24 | "rabbit -c0" \ | ||
| 25 | "rabbit -c1" \ | ||
| 26 | "rate -h" \ | ||
| 27 | "rate -v" \ | ||
| 28 | "resample -q" \ | ||
| 29 | "resample -ql" \ | ||
| 30 | "ssrc" \ | ||
| 31 | "ssrc_hp" \ | ||
| 32 | ; do | 24 | ; do |
| 33 | echo $src | 25 | echo $src |
| 34 | case "$src" in | 26 | case "$src" in |