ref: 59aa96942d2bdf6b7ece3f510a6da5e052ea3d3e
parent: 48a6aa0295d1285696bb19589c318c80e86f972f
author: robs <robs>
date: Mon Feb 2 04:43:36 EST 2009
improvements to intermediate-phase algorithm
--- a/configure.ac
+++ b/configure.ac
@@ -1,6 +1,6 @@
dnl Process this file with autoconf to produce a configure script.
-AC_INIT(SoX, 14.3.0, sox-devel@lists.sourceforge.net)
+AC_INIT(SoX, 14.3.0α, sox-devel@lists.sourceforge.net)
m4_ifdef([AC_CONFIG_MACRO_DIR], [AC_CONFIG_MACRO_DIR([m4])])
--- a/src/effects_i_dsp.c
+++ b/src/effects_i_dsp.c
@@ -304,21 +304,6 @@
return lsx_make_lpf(*num_taps, (Fc - tr_bw) / k, beta, (double)k, sox_true);
}
-#if 0
-static void printf_vector(double h[], int num_points)
-{
- int i;
- printf(
- "# name: b\n"
- "# type: matrix\n"
- "# rows: %i\n"
- "# columns: 1\n", num_points / 2);
- for (i = 0; i < num_points; i += 2)
- printf("%24.16e\n", h[i + 1]);
- exit(0);
-}
-#endif
-
static double safe_log(double x)
{
assert(x >= 0);
@@ -328,25 +313,44 @@
return -26;
}
-void lsx_fir_to_phase(double * * h, int * len,
- int * post_len, double phase0)
+void lsx_fir_to_phase(double * * h, int * len, int * post_len, double phase)
{
- double * work, phase = (phase0 > 50 ? 100 - phase0 : phase0) / 50;
- int work_len, begin, end, abs_peak = 0, peak = 0, i = *len;
- double sum = 0, peak_sum = 0;
+ double * pi_wraps, * work, phase1 = (phase > 50 ? 100 - phase : phase) / 50;
+ int i, work_len, begin, end, imp_peak = 0, peak = 0;
+ double imp_sum = 0, peak_imp_sum = 0;
+ double prev_angle2 = 0, cum_2pi = 0, prev_angle1 = 0, cum_1pi = 0;
- for (work_len = 32; i > 1; work_len <<= 1, i >>= 1);
- work = calloc((size_t)work_len /* + 2 */, sizeof(*work)); /* +2: (UN)PACK */
- for (i = 0; i < *len; ++i) work[i] = (*h)[i];
+ for (i = *len, work_len = 2 * 2 * 8; i > 1; work_len <<= 1, i >>= 1);
+ work = lsx_calloc((size_t)work_len + 2, sizeof(*work)); /* +2: (UN)PACK */
+ pi_wraps = lsx_malloc((((size_t)work_len + 2) / 2) * sizeof(*pi_wraps));
+
+ memcpy(work, *h, *len * sizeof(*work));
lsx_safe_rdft(work_len, 1, work); /* Cepstral: */
- work[0] = safe_log(fabs(work[0])), work[1] = safe_log(fabs(work[1]));
- for (i = 2; i < work_len; i += 2) {
+ LSX_UNPACK(work, work_len);
+
+ for (i = 0; i <= work_len; i += 2) {
+ double angle = atan2(work[i + 1], work[i]);
+ double detect = 2 * M_PI;
+ double delta = angle - prev_angle2;
+ double adjust = detect * ((delta < -detect * .7) - (delta > detect * .7));
+ prev_angle2 = angle;
+ cum_2pi += adjust;
+ angle += cum_2pi;
+ detect = M_PI;
+ delta = angle - prev_angle1;
+ adjust = detect * ((delta < -detect * .7) - (delta > detect * .7));
+ prev_angle1 = angle;
+ cum_1pi += fabs(adjust); /* fabs for when 2pi and 1pi have combined */
+ pi_wraps[i >> 1] = cum_1pi;
+
work[i] = safe_log(sqrt(sqr(work[i]) + sqr(work[i + 1])));
work[i + 1] = 0;
}
+ LSX_PACK(work, work_len);
lsx_safe_rdft(work_len, -1, work);
for (i = 0; i < work_len; ++i) work[i] *= 2. / work_len;
+
for (i = 1; i < work_len / 2; ++i) { /* Window to reject acausal components */
work[i] *= 2;
work[i + work_len / 2] = 0;
@@ -353,18 +357,10 @@
}
lsx_safe_rdft(work_len, 1, work);
- /* Some filters require phase unwrapping at this point. Ours give dis-
- * continuities only in the stop band, so no need to unwrap in this case. */
-#if 0
- LSX_UNPACK(work, work_len);
- unwrap_phase(work, work_len);
- printf_vector(work, work_len + 2);
- LSX_PACK(work, work_len);
-#endif
-
for (i = 2; i < work_len; i += 2) /* Interpolate between linear & min phase */
- work[i + 1] = phase * M_PI * .5 * i + (1 - phase) * work[i + 1];
-
+ work[i + 1] = phase1 * i / work_len * pi_wraps[work_len >> 1] +
+ (1 - phase1) * (work[i + 1] + pi_wraps[i >> 1]) - pi_wraps[i >> 1];
+
work[0] = exp(work[0]), work[1] = exp(work[1]);
for (i = 2; i < work_len; i += 2) {
double x = exp(work[i]);
@@ -371,43 +367,43 @@
work[i ] = x * cos(work[i + 1]);
work[i + 1] = x * sin(work[i + 1]);
}
+
lsx_safe_rdft(work_len, -1, work);
for (i = 0; i < work_len; ++i) work[i] *= 2. / work_len;
- for (i = 0; i < work_len; ++i) { /* Find peak pos. */
- sum += work[i];
- if (fabs(sum) > peak_sum) {
- peak_sum = fabs(sum);
+ /* Find peak pos. */
+ for (i = 0; i <= (int)(pi_wraps[work_len >> 1] / M_PI + .5); ++i) {
+ imp_sum += work[i];
+ if (fabs(imp_sum) > fabs(peak_imp_sum)) {
+ peak_imp_sum = imp_sum;
peak = i;
}
- if (work[i] > work[abs_peak]) /* For debug check only */
- abs_peak = i;
+ if (work[i] > work[imp_peak]) /* For debug check only */
+ imp_peak = i;
}
- while (fabs(work[peak-1]) > fabs(work[peak]) && work[peak-1] * work[peak] > 0)
+ while (peak && fabs(work[peak-1]) > fabs(work[peak]) && work[peak-1] * work[peak] > 0)
--peak;
- lsx_debug("peak: sum@work[%i]=%g (val@work[%i]=%g)",
- peak, peak_sum, abs_peak, work[abs_peak]);
- if (phase == 0)
+
+ if (!phase1)
begin = 0;
- else if (phase == 1)
- begin = 1 + (work_len - *len) / 2;
+ else if (phase1 == 1)
+ begin = peak - *len / 2;
else {
- if (peak < work_len / 4) { /* Low phases can wrap impulse, so unwrap: */
- memmove(work + work_len / 4, work, work_len / 2 * sizeof(*work));
- memmove(work, work + work_len * 3 / 4, work_len / 4 * sizeof(*work));
- peak += work_len / 4;
- }
- begin = (.997 - (2 - phase) * .22) * *len + .5;
- end = (.997 + (0 - phase) * .22) * *len + .5;
+ begin = (.997 - (2 - phase1) * .22) * *len + .5;
+ end = (.997 + (0 - phase1) * .22) * *len + .5;
begin = peak - begin - (begin & 1);
end = peak + 1 + end + (end & 1);
*len = end - begin;
*h = realloc(*h, *len * sizeof(**h));
}
- for (i = 0; i < *len; ++i)
- (*h)[i] = work[begin + (phase0 > 50 ? *len - 1 - i : i)];
- *post_len = phase0 > 50 ? peak - begin : begin + *len - (peak + 1);
- free(work);
+ for (i = 0; i < *len; ++i) (*h)[i] =
+ work[(begin + (phase > 50 ? *len - 1 - i : i) + work_len) & (work_len - 1)];
+ *post_len = phase > 50 ? peak - begin : begin + *len - (peak + 1);
+
+ lsx_debug("nPI=%g peak-sum@%i=%g (val@%i=%g); len=%i post=%i (%g%%)",
+ pi_wraps[work_len >> 1] / M_PI, peak, peak_imp_sum, imp_peak,
+ work[imp_peak], *len, *post_len, 100 - 100. * *post_len / (*len - 1));
+ free(pi_wraps), free(work);
}
void lsx_plot_fir(double * h, int num_points, sox_rate_t rate, sox_plot_t type, char const * title, double y1, double y2)
--- a/src/rate.c
+++ b/src/rate.c
@@ -188,7 +188,7 @@
}
static void half_band_filter_init(rate_shared_t * p, unsigned which,
- int num_taps, sample_t const h[], double Fp, double atten, int multiplier,
+ int num_taps, sample_t const h[], double Fp, double att, int multiplier,
double phase, sox_bool allow_aliasing)
{
half_band_t * f = &p->half_band[which];
@@ -205,8 +205,6 @@
f->post_peak = num_taps / 2;
}
else {
- /* Adjustment to negate att degradation with intermediate phase */
- double att = phase && phase != 50 && phase != 100? atten * (34./33) : atten;
double * h = lsx_design_lpf(Fp, 1., 2., allow_aliasing, att, &num_taps, 0);
if (phase != 50)
@@ -223,8 +221,8 @@
assert(num_taps & 1);
f->num_taps = num_taps;
f->dft_length = dft_length;
- lsx_debug("fir_len=%i dft_length=%i Fp=%g atten=%g mult=%i",
- num_taps, dft_length, Fp, atten, multiplier);
+ lsx_debug("fir_len=%i dft_length=%i Fp=%g att=%g mult=%i",
+ num_taps, dft_length, Fp, att, multiplier);
lsx_safe_rdft(dft_length, 1, f->coefs);
}
--- a/src/sinc.c
+++ b/src/sinc.c
@@ -77,7 +77,7 @@
h[(n - 1) / 2] += 1;
}
-static double * lpf(double Fn, double Fc, double tbw, int * num_taps, double att, double * beta, double phase, sox_bool round)
+static double * lpf(double Fn, double Fc, double tbw, int * num_taps, double att, double * beta, sox_bool round)
{
if ((Fc /= Fn) <= 0 || Fc >= 1) {
*num_taps = 0;
@@ -84,7 +84,6 @@
return NULL;
}
att = att? att : 120;
- att = phase && phase != 50 && phase != 100? 34./33 * att : att;
*beta = *beta < 0? lsx_kaiser_beta(att) : *beta;
if (!*num_taps) {
int n = lsx_lpf_num_taps(att, (tbw? tbw / Fn : .05) * .5, 0);
@@ -93,7 +92,7 @@
*num_taps = 1 + 2 * (int)((int)((*num_taps / 2) * Fc + .5) / Fc + .5);
lsx_report("num taps = %i (from %i)", *num_taps, n);
}
- return lsx_make_lpf(*num_taps | 1, Fc, *beta, 1., sox_false);
+ return lsx_make_lpf(*num_taps |= 1, Fc, *beta, 1., sox_false);
}
static int start(sox_effect_t * effp)
@@ -110,26 +109,29 @@
lsx_fail("filter frequency must be less than sample-rate / 2");
return SOX_EOF;
}
- h[0] = lpf(Fn, p->Fc0, p->tbw0, &p->num_taps[0], p->att, &p->beta, p->phase, p->round);
+ h[0] = lpf(Fn, p->Fc0, p->tbw0, &p->num_taps[0], p->att, &p->beta,p->round);
if (h[0]) invert(h[0], p->num_taps[0]);
- h[1] = lpf(Fn, p->Fc1, p->tbw1, &p->num_taps[1], p->att, &p->beta, p->phase, p->round);
+ h[1] = lpf(Fn, p->Fc1, p->tbw1, &p->num_taps[1], p->att, &p->beta,p->round);
+
longer = p->num_taps[1] > p->num_taps[0];
f->num_taps = p->num_taps[longer];
if (h[0] && h[1]) {
for (i = 0; i < p->num_taps[!longer]; ++i)
h[longer][i + (f->num_taps - p->num_taps[!longer])/2] += h[!longer][i];
- free(h[!longer]);
+
if (p->Fc0 < p->Fc1)
invert(h[longer], f->num_taps);
+
+ free(h[!longer]);
}
if (p->phase != 50)
lsx_fir_to_phase(&h[longer], &f->num_taps, &f->post_peak, p->phase);
else f->post_peak = f->num_taps / 2;
- lsx_debug("%i %i %g%%", f->num_taps, f->post_peak,
- 100 - 100. * f->post_peak / (f->num_taps - 1));
+
if (effp->global_info->plot != sox_plot_off) {
char title[100];
- sprintf(title, "SoX effect: sinc filter freq=%g-%g", p->Fc0, p->Fc1? p->Fc1 : Fn);
+ sprintf(title, "SoX effect: sinc filter freq=%g-%g",
+ p->Fc0, p->Fc1? p->Fc1 : Fn);
lsx_plot_fir(h[longer], f->num_taps, effp->in_signal.rate,
effp->global_info->plot, title, -p->beta * 10 - 25, 5.);
return SOX_EOF;
--- a/src/soxconfig.h.cmake
+++ b/src/soxconfig.h.cmake
@@ -1,4 +1,4 @@
-#define PACKAGE_VERSION "14.3.0"
+#define PACKAGE_VERSION "14.3.0α"
#cmakedefine EXTERNAL_GSM 1
#cmakedefine HAVE_ALSA 1