static void gst_audio_fx_base_iir_filter_finalize (GObject * object) { GstAudioFXBaseIIRFilter *filter = GST_AUDIO_FX_BASE_IIR_FILTER (object); if (filter->a) { g_free (filter->a); filter->a = NULL; } if (filter->b) { g_free (filter->b); filter->b = NULL; } if (filter->channels) { GstAudioFXBaseIIRFilterChannelCtx *ctx; guint i; for (i = 0; i < filter->nchannels; i++) { ctx = &filter->channels[i]; g_free (ctx->x); g_free (ctx->y); } g_free (filter->channels); filter->channels = NULL; } g_mutex_clear (&filter->lock); G_OBJECT_CLASS (parent_class)->finalize (object); }
static gboolean gst_audio_fx_base_iir_filter_setup (GstAudioFilter * base, const GstAudioInfo * info) { GstAudioFXBaseIIRFilter *filter = GST_AUDIO_FX_BASE_IIR_FILTER (base); gboolean ret = TRUE; gint channels; g_mutex_lock (&filter->lock); switch (GST_AUDIO_INFO_FORMAT (info)) { case GST_AUDIO_FORMAT_F32: filter->process = (GstAudioFXBaseIIRFilterProcessFunc) process_32; break; case GST_AUDIO_FORMAT_F64: filter->process = (GstAudioFXBaseIIRFilterProcessFunc) process_64; break; default: ret = FALSE; break; } channels = GST_AUDIO_INFO_CHANNELS (info); if (channels != filter->nchannels) { guint i; GstAudioFXBaseIIRFilterChannelCtx *ctx; if (filter->channels) { for (i = 0; i < filter->nchannels; i++) { ctx = &filter->channels[i]; g_free (ctx->x); g_free (ctx->y); } g_free (filter->channels); } filter->channels = g_new0 (GstAudioFXBaseIIRFilterChannelCtx, channels); for (i = 0; i < channels; i++) { ctx = &filter->channels[i]; ctx->x = g_new0 (gdouble, filter->nb); ctx->y = g_new0 (gdouble, filter->na); } filter->nchannels = channels; } g_mutex_unlock (&filter->lock); return ret; }
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 gboolean gst_audio_fx_base_iir_filter_stop (GstBaseTransform * base) { GstAudioFXBaseIIRFilter *filter = GST_AUDIO_FX_BASE_IIR_FILTER (base); guint channels = filter->nchannels; GstAudioFXBaseIIRFilterChannelCtx *ctx; guint i; /* Reset the history of input and output values if * already existing */ if (channels && filter->channels) { for (i = 0; i < channels; i++) { ctx = &filter->channels[i]; g_free (ctx->x); g_free (ctx->y); } g_free (filter->channels); } filter->channels = NULL; filter->nchannels = 0; return TRUE; }
/* GstBaseTransform vmethod implementations */ static GstFlowReturn gst_audio_fx_base_iir_filter_transform_ip (GstBaseTransform * base, GstBuffer * buf) { GstAudioFXBaseIIRFilter *filter = GST_AUDIO_FX_BASE_IIR_FILTER (base); guint num_samples; GstClockTime timestamp, stream_time; GstMapInfo map; timestamp = GST_BUFFER_TIMESTAMP (buf); stream_time = gst_segment_to_stream_time (&base->segment, GST_FORMAT_TIME, timestamp); GST_DEBUG_OBJECT (filter, "sync to %" GST_TIME_FORMAT, GST_TIME_ARGS (timestamp)); if (GST_CLOCK_TIME_IS_VALID (stream_time)) gst_object_sync_values (GST_OBJECT (filter), stream_time); gst_buffer_map (buf, &map, GST_MAP_READWRITE); num_samples = map.size / GST_AUDIO_FILTER_BPS (filter); g_mutex_lock (&filter->lock); if (filter->a == NULL || filter->b == NULL) { g_warn_if_fail (filter->a != NULL && filter->b != NULL); gst_buffer_unmap (buf, &map); g_mutex_unlock (&filter->lock); return GST_FLOW_ERROR; } filter->process (filter, map.data, num_samples); g_mutex_unlock (&filter->lock); gst_buffer_unmap (buf, &map); return GST_FLOW_OK; }
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); } }