static void gst_audio_iir_filter_update_coefficients (GstAudioIIRFilter * self, GValueArray * va, GValueArray * vb) { gdouble *a = NULL, *b = NULL; guint i; if (va) { if (self->a) g_value_array_free (self->a); self->a = va; } if (vb) { if (self->b) g_value_array_free (self->b); self->b = vb; } if (self->a && self->a->n_values > 0) { a = g_new (gdouble, self->a->n_values); for (i = 0; i < self->a->n_values; i++) { GValue *v = g_value_array_get_nth (self->a, i); a[i] = g_value_get_double (v); } } if (self->b && self->b->n_values > 0) { b = g_new (gdouble, self->b->n_values); for (i = 0; i < self->b->n_values; i++) { GValue *v = g_value_array_get_nth (self->b, i); b[i] = g_value_get_double (v); } } gst_audio_fx_base_iir_filter_set_coefficients (GST_AUDIO_FX_BASE_IIR_FILTER (self), a, (self->a) ? self->a->n_values : 0, b, (self->b) ? self->b->n_values : 0); }
static void generate_coefficients (GstAudioChebBand * filter) { if (GST_AUDIO_FILTER (filter)->format.rate == 0) { gdouble *a = g_new0 (gdouble, 1); a[0] = 1.0; gst_audio_fx_base_iir_filter_set_coefficients (GST_AUDIO_FX_BASE_IIR_FILTER (filter), a, 1, NULL, 0); GST_LOG_OBJECT (filter, "rate was not set yet"); return; } if (filter->upper_frequency <= filter->lower_frequency) { gdouble *a = g_new0 (gdouble, 1); a[0] = (filter->mode == MODE_BAND_PASS) ? 0.0 : 1.0; gst_audio_fx_base_iir_filter_set_coefficients (GST_AUDIO_FX_BASE_IIR_FILTER (filter), a, 1, NULL, 0); GST_LOG_OBJECT (filter, "frequency band had no or negative dimension"); return; } if (filter->upper_frequency > GST_AUDIO_FILTER (filter)->format.rate / 2) { filter->upper_frequency = GST_AUDIO_FILTER (filter)->format.rate / 2; GST_LOG_OBJECT (filter, "clipped upper frequency to nyquist frequency"); } if (filter->lower_frequency < 0.0) { filter->lower_frequency = 0.0; GST_LOG_OBJECT (filter, "clipped lower frequency to 0.0"); } /* Calculate coefficients for the chebyshev filter */ { gint np = filter->poles; gdouble *a, *b; gint i, p; a = g_new0 (gdouble, np + 5); b = g_new0 (gdouble, np + 5); /* Calculate transfer function coefficients */ a[4] = 1.0; b[4] = 1.0; for (p = 1; p <= np / 4; p++) { gdouble a0, a1, a2, a3, a4, b1, b2, b3, b4; gdouble *ta = g_new0 (gdouble, np + 5); gdouble *tb = g_new0 (gdouble, np + 5); generate_biquad_coefficients (filter, p, &a0, &a1, &a2, &a3, &a4, &b1, &b2, &b3, &b4); memcpy (ta, a, sizeof (gdouble) * (np + 5)); memcpy (tb, b, sizeof (gdouble) * (np + 5)); /* add the new coefficients for the new two poles * to the cascade by multiplication of the transfer * functions */ for (i = 4; i < np + 5; i++) { a[i] = a0 * ta[i] + a1 * ta[i - 1] + a2 * ta[i - 2] + a3 * ta[i - 3] + a4 * ta[i - 4]; b[i] = tb[i] - b1 * tb[i - 1] - b2 * tb[i - 2] - b3 * tb[i - 3] - b4 * tb[i - 4]; } g_free (ta); g_free (tb); } /* Move coefficients to the beginning of the array * and multiply the b coefficients with -1 to move from * the transfer function's coefficients to the difference * equation's coefficients */ b[4] = 0.0; for (i = 0; i <= np; i++) { a[i] = a[i + 4]; b[i] = -b[i + 4]; } /* Normalize to unity gain at frequency 0 and frequency * 0.5 for bandreject and unity gain at band center frequency * for bandpass */ if (filter->mode == MODE_BAND_REJECT) { /* gain is sqrt(H(0)*H(0.5)) */ gdouble gain1 = gst_audio_fx_base_iir_filter_calculate_gain (a, np + 1, b, np + 1, 1.0, 0.0); gdouble gain2 = gst_audio_fx_base_iir_filter_calculate_gain (a, np + 1, b, np + 1, -1.0, 0.0); gain1 = sqrt (gain1 * gain2); for (i = 0; i <= np; i++) { a[i] /= gain1; } } else { /* gain is H(wc), wc = center frequency */ gdouble w1 = 2.0 * G_PI * (filter->lower_frequency / GST_AUDIO_FILTER (filter)->format.rate); gdouble w2 = 2.0 * G_PI * (filter->upper_frequency / GST_AUDIO_FILTER (filter)->format.rate); gdouble w0 = (w2 + w1) / 2.0; gdouble zr = cos (w0), zi = sin (w0); gdouble gain = gst_audio_fx_base_iir_filter_calculate_gain (a, np + 1, b, np + 1, zr, zi); for (i = 0; i <= np; i++) { a[i] /= gain; } } gst_audio_fx_base_iir_filter_set_coefficients (GST_AUDIO_FX_BASE_IIR_FILTER (filter), a, np + 1, b, np + 1); GST_LOG_OBJECT (filter, "Generated IIR coefficients for the Chebyshev filter"); GST_LOG_OBJECT (filter, "mode: %s, type: %d, poles: %d, lower-frequency: %.2f Hz, upper-frequency: %.2f Hz, ripple: %.2f dB", (filter->mode == MODE_BAND_PASS) ? "band-pass" : "band-reject", filter->type, filter->poles, filter->lower_frequency, filter->upper_frequency, filter->ripple); GST_LOG_OBJECT (filter, "%.2f dB gain @ 0Hz", 20.0 * log10 (gst_audio_fx_base_iir_filter_calculate_gain (a, np + 1, b, np + 1, 1.0, 0.0))); { gdouble w1 = 2.0 * G_PI * (filter->lower_frequency / GST_AUDIO_FILTER (filter)->format.rate); gdouble w2 = 2.0 * G_PI * (filter->upper_frequency / GST_AUDIO_FILTER (filter)->format.rate); gdouble w0 = (w2 + w1) / 2.0; gdouble zr, zi; zr = cos (w1); zi = sin (w1); GST_LOG_OBJECT (filter, "%.2f dB gain @ %dHz", 20.0 * log10 (gst_audio_fx_base_iir_filter_calculate_gain (a, np + 1, b, np + 1, zr, zi)), (int) filter->lower_frequency); zr = cos (w0); zi = sin (w0); GST_LOG_OBJECT (filter, "%.2f dB gain @ %dHz", 20.0 * log10 (gst_audio_fx_base_iir_filter_calculate_gain (a, np + 1, b, np + 1, zr, zi)), (int) ((filter->lower_frequency + filter->upper_frequency) / 2.0)); zr = cos (w2); zi = sin (w2); GST_LOG_OBJECT (filter, "%.2f dB gain @ %dHz", 20.0 * log10 (gst_audio_fx_base_iir_filter_calculate_gain (a, np + 1, b, np + 1, zr, zi)), (int) filter->upper_frequency); } GST_LOG_OBJECT (filter, "%.2f dB gain @ %dHz", 20.0 * log10 (gst_audio_fx_base_iir_filter_calculate_gain (a, np + 1, b, np + 1, -1.0, 0.0)), GST_AUDIO_FILTER (filter)->format.rate / 2); } }