1 From 5cd668c98c9e1b48a04109a1c36356ec324a7e62 Mon Sep 17 00:00:00 2001
2 From: CHAD RICHARD HANNA <crh184@psu.edu>
3 Date: Wed, 11 Feb 2015 17:56:36 -0500
4 Subject: [PATCH 1/8] gstlal_interpolator: first commit
7 gstlal/gst/lal/Makefile.am | 1 +
8 gstlal/gst/lal/gstlal.c | 2 +
9 gstlal/gst/lal/gstlal_interpolator.c | 631 +++++++++++++++++++++++++++++++++++
10 gstlal/gst/lal/gstlal_interpolator.h | 127 +++++++
11 4 files changed, 761 insertions(+)
12 create mode 100644 gstlal/gst/lal/gstlal_interpolator.c
13 create mode 100644 gstlal/gst/lal/gstlal_interpolator.h
15 diff --git a/gstlal/gst/lal/Makefile.am b/gstlal/gst/lal/Makefile.am
16 index 81d8ffb..ad98219 100644
17 --- a/gstlal/gst/lal/Makefile.am
18 +++ b/gstlal/gst/lal/Makefile.am
19 @@ -10,6 +10,7 @@ libgstlal_la_SOURCES = \
20 gstlal_drop.h gstlal_drop.c \
21 gstlal_firbank.h gstlal_firbank.c \
22 gstlal_gate.h gstlal_gate.c \
23 + gstlal_interpolator.h gstlal_interpolator.c \
24 gstlal_matrixmixer.h gstlal_matrixmixer.c \
25 gstlal_nofakedisconts.h gstlal_nofakedisconts.c \
26 gstlal_nxydump.h gstlal_nxydump.c \
27 diff --git a/gstlal/gst/lal/gstlal.c b/gstlal/gst/lal/gstlal.c
28 index 8832ed7..d492df9 100644
29 --- a/gstlal/gst/lal/gstlal.c
30 +++ b/gstlal/gst/lal/gstlal.c
32 #include <gstlal_drop.h>
33 #include <gstlal_firbank.h>
34 #include <gstlal_gate.h>
35 +#include <gstlal_interpolator.h>
36 #include <gstlal_matrixmixer.h>
37 #include <gstlal_nofakedisconts.h>
38 #include <gstlal_nxydump.h>
39 @@ -92,6 +93,7 @@
static gboolean plugin_init(GstPlugin *plugin)
40 {
"lal_drop", GSTLAL_DROP_TYPE},
41 {
"lal_firbank", GSTLAL_FIRBANK_TYPE},
42 {
"lal_gate", GSTLAL_GATE_TYPE},
43 + {
"lal_interpolator", GSTLAL_INTERPOLATOR_TYPE},
44 {
"lal_matrixmixer", GSTLAL_MATRIXMIXER_TYPE},
45 {
"lal_nofakedisconts", GSTLAL_NOFAKEDISCONTS_TYPE},
46 {
"lal_nxydump", GST_TSVENC_TYPE},
47 diff --git a/gstlal/gst/lal/gstlal_interpolator.c b/gstlal/gst/lal/gstlal_interpolator.c
49 index 0000000..731d161
51 +++ b/gstlal/gst/lal/gstlal_interpolator.c
94 +#include <glib/gprintf.h>
96 +#include <gst/base/gstbasetransform.h>
97 +#include <gst/base/gstadapter.h>
106 +#include <gstlal/gstlal.h>
107 +#include <gstlal/gstlal_debug.h>
108 +#include <gstlal/gstaudioadapter.h>
109 +#include <gstlal_interpolator.h>
115 +#define PI 3.141592653589793
117 +
static float* taperup(
int samps) {
119 +
float *out = (
float *) calloc(samps,
sizeof(
float));
120 +
for (
int i = 0; i < samps; i++) {
121 + x = cos(PI / 2. * (
float) i / samps);
122 + out[i] = 1. - x * x;
127 +
static float* taperdown(
int samps) {
129 +
float *out = (
float *) calloc(samps,
sizeof(
float));
130 +
for (
int i = 0; i < samps; i++) {
131 + x = cos(PI / 2. * (
float) i / samps);
137 +
static int applytaper(
float *in,
int end,
float *taper) {
138 +
for (
int i = 0; i < end; i++) {
144 +
static int blend(
float *in1,
float *in2,
int start,
int end) {
145 +
for (
int i = start; i < end; i++)
155 +#define GST_CAT_DEFAULT gstlal_interpolator_debug
156 +GST_DEBUG_CATEGORY_STATIC(GST_CAT_DEFAULT);
158 +
static void additional_initializations(GType type)
160 + GST_DEBUG_CATEGORY_INIT(GST_CAT_DEFAULT,
"lal_interpolator", 0,
"lal_interpolator element");
163 +GST_BOILERPLATE_FULL(
164 + GSTLALInterpolator,
165 + gstlal_interpolator,
167 + GST_TYPE_BASE_TRANSFORM,
168 + additional_initializations
171 +
static void gstlal_interpolator_base_init(gpointer klass){}
175 +
static GstStaticPadTemplate sink_template =
176 + GST_STATIC_PAD_TEMPLATE (
"sink",
179 + GST_STATIC_CAPS (
"audio/x-raw-float, "
180 +
"endianness = (int) BYTE_ORDER, "
181 +
"width = (int) 32, "
182 +
"rate = (int) {4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768}, "
183 +
"channels = (int) [1, MAX]")
186 +
static GstStaticPadTemplate src_template =
187 + GST_STATIC_PAD_TEMPLATE (
"src",
190 + GST_STATIC_CAPS (
"audio/x-raw-float, "
191 +
"endianness = (int) BYTE_ORDER, "
192 +
"width = (int) 32, "
193 +
"rate = (int) {4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768}, "
194 +
"channels = (int) [1, MAX]")
201 +
static void finalize(GObject *
object);
202 +
static gboolean get_unit_size(GstBaseTransform *trans, GstCaps *caps, guint *size);
203 +
static gboolean set_caps (GstBaseTransform * base, GstCaps * incaps, GstCaps * outcaps);
204 +
static GstFlowReturn transform(GstBaseTransform *trans, GstBuffer *inbuf, GstBuffer *outbuf);
205 +
static GstCaps* transform_caps (GstBaseTransform *trans, GstPadDirection direction, GstCaps *caps);
206 +
static gboolean transform_size(GstBaseTransform *trans, GstPadDirection direction, GstCaps *caps, guint size, GstCaps *othercaps, guint *othersize);
207 +
static gboolean start(GstBaseTransform *trans);
208 +
static gboolean stop(GstBaseTransform *trans);
217 + GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
218 + GstElementClass *element_class = GST_ELEMENT_CLASS(klass);
219 + GstBaseTransformClass *transform_class = GST_BASE_TRANSFORM_CLASS(klass);
221 + gst_element_class_set_details_simple(element_class,
"Interpolator",
"Filter/Audio",
"Interpolates multichannel audio data using FFTs",
"Chad Hanna <chad.hanna@ligo.org>");
223 + gobject_class->finalize = GST_DEBUG_FUNCPTR(finalize);
224 + transform_class->get_unit_size = GST_DEBUG_FUNCPTR(get_unit_size);
225 + transform_class->set_caps = GST_DEBUG_FUNCPTR(set_caps);
226 + transform_class->transform = GST_DEBUG_FUNCPTR(transform);
227 + transform_class->transform_caps = GST_DEBUG_FUNCPTR(transform_caps);
228 + transform_class->transform_size = GST_DEBUG_FUNCPTR(transform_size);
229 + transform_class->start = GST_DEBUG_FUNCPTR(start);
230 + transform_class->stop = GST_DEBUG_FUNCPTR(stop);
232 + gst_element_class_add_pad_template(element_class, gst_static_pad_template_get(&src_template));
233 + gst_element_class_add_pad_template(element_class, gst_static_pad_template_get(&sink_template));
239 + gst_base_transform_set_gap_aware(GST_BASE_TRANSFORM(element), TRUE);
242 + element->inrate = 0;
243 + element->outrate = 0;
247 + element->nrout = 0;
248 + element->ncout = 0;
249 + element->tapersampsin = 0;
250 + element->tapersampsout = 0;
251 + element->up = NULL;
252 + element->down = NULL;
253 + element->last = NULL;
254 + element->rin = NULL;
255 + element->cin = NULL;
256 + element->rout = NULL;
257 + element->cout = NULL;
258 + element->data = NULL;
260 + element->adapter = g_object_new(GST_TYPE_AUDIOADAPTER, NULL);
263 +
static GstCaps* transform_caps (GstBaseTransform *trans, GstPadDirection direction, GstCaps *caps) {
269 + GstStructure *capsstruct;
271 + capsstruct = gst_caps_get_structure (caps, 0);
272 +
char capsstr[256] = {0};
274 +
if (direction == GST_PAD_SINK && gst_structure_get_int (capsstruct,
"channels", &channels)) {
275 + sprintf(capsstr,
"audio/x-raw-float, endianness = (int) BYTE_ORDER, width = (int) 32, rate = (int) {4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768}, channels = (int) %d", channels);
276 +
return gst_caps_from_string(capsstr);
279 +
return gst_caps_from_string(
"audio/x-raw-float, endianness = (int) BYTE_ORDER, width = (int) 32, rate = (int) {4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768}, channels = (int) [1, MAX]");
283 +
static gboolean set_caps (GstBaseTransform * base, GstCaps * incaps, GstCaps * outcaps) {
284 + GSTLALInterpolator *element = GSTLAL_INTERPOLATOR (base);
285 + GstStructure *instruct, *outstruct;
286 + gint inchannels, inrate, outchannels, outrate;
288 + instruct = gst_caps_get_structure (incaps, 0);
289 + outstruct = gst_caps_get_structure (outcaps, 0);
290 + g_return_val_if_fail(gst_structure_get_int (instruct,
"channels", &inchannels), FALSE);
291 + g_return_val_if_fail(gst_structure_get_int (instruct,
"rate", &inrate), FALSE);
292 + g_return_val_if_fail(gst_structure_get_int (outstruct,
"channels", &outchannels), FALSE);
293 + g_return_val_if_fail(gst_structure_get_int (outstruct,
"rate", &outrate), FALSE);
295 + g_return_val_if_fail(inchannels == outchannels, FALSE);
296 + g_return_val_if_fail(outrate >= inrate, FALSE);
297 + g_return_val_if_fail(outrate % inrate == 0, FALSE);
299 + element->inrate = inrate;
300 + element->outrate = outrate;
301 + element->channels = inchannels;
305 + element->t0 = GST_CLOCK_TIME_NONE;
306 + element->offset0 = GST_BUFFER_OFFSET_NONE;
307 + element->next_input_offset = GST_BUFFER_OFFSET_NONE;
308 + element->next_output_offset = GST_BUFFER_OFFSET_NONE;
309 + element->need_discont = TRUE;
316 + element->nrin = inrate;
317 + element->ncin = element->nrin / 2 + 1;
318 + element->nrout = outrate;
319 + element->ncout = element->nrout / 2 + 1;
321 + element->tapersampsin = element->nrin / 4;
322 + element->tapersampsout = element->nrout / 4;
323 + element->blocksampsin = element->nrin - element->tapersampsin;
324 + element->blocksampsout = element->nrout - element->tapersampsout;
328 + element->up = taperup(element->tapersampsin);
331 + free(element->down);
332 + element->down = taperdown(element->tapersampsin);
335 + free(element->last);
336 + element->last = (
float *) fftw_alloc_real(element->tapersampsout * element->channels);
337 + memset(element->last, 0,
sizeof(
float) * element->tapersampsout * element->channels);
339 +
if (!element->data)
340 + free(element->data);
341 + element->data = (
float*) fftwf_alloc_real(element->nrin * element->channels);
344 + fftwf_free(element->rin);
345 + element->rin = (
float*) fftwf_alloc_real(element->nrin);
348 + fftwf_free(element->cin);
349 + element->cin = (fftwf_complex*) fftwf_alloc_complex(element->ncin);
352 + fftwf_free(element->rout);
353 + element->rout = (
float*) fftwf_alloc_real(element->nrout);
356 + fftwf_free(element->cout);
357 + element->cout = (fftwf_complex*) fftwf_alloc_complex(element->ncout);
359 + gstlal_fftw_lock();
360 + element->fwdplan_in = fftwf_plan_dft_r2c_1d(element->nrin, element->rin, element->cin, FFTW_PATIENT);
361 + element->revplan_out = fftwf_plan_dft_c2r_1d(element->nrout, element->cout, element->rout, FFTW_PATIENT);
362 + gstlal_fftw_unlock();
382 +
static gboolean get_unit_size(GstBaseTransform *trans, GstCaps *caps, guint *size)
384 + GSTLALInterpolator *element = GSTLAL_INTERPOLATOR(trans);
386 + gint width, channels;
387 + gboolean success = TRUE;
389 + str = gst_caps_get_structure(caps, 0);
390 + success &= gst_structure_get_int(str,
"channels", &channels);
391 + success &= gst_structure_get_int(str,
"width", &width);
395 + *size = width / 8 * channels;
396 + element->unitsize = *size;
397 + g_object_set(element->adapter,
"unit-size", *size, NULL);
398 + GST_INFO_OBJECT(element,
"get_unit_size(): channels %d, width %d", channels, width);
401 + GST_WARNING_OBJECT(trans,
"unable to parse channels from %" GST_PTR_FORMAT, caps);
406 +
static guint minimum_input_length(GSTLALInterpolator *element, guint samps) {
407 +
return ceil(samps / element->blocksampsin) * element->blocksampsin + element->tapersampsin;
410 +
static guint minimum_input_size(GSTLALInterpolator *element, guint size) {
411 +
return minimum_input_length(element, size / element->unitsize) * element->unitsize;
414 +
static guint64 get_available_samples(GSTLALInterpolator *element)
418 + g_object_get(element->adapter,
"size", &size, NULL);
422 +
static guint get_output_length(GSTLALInterpolator *element, guint samps) {
424 + guint numinsamps = get_available_samples(element) + samps;
425 +
if (numinsamps == 0)
427 + guint numoutsamps = numinsamps * element->outrate / element->inrate;
428 + guint numblocks = numoutsamps / element->blocksampsout;
429 +
if (numblocks != 0)
430 + remainder = numoutsamps % numblocks;
432 + remainder = numoutsamps;
433 +
if ((remainder < element->tapersampsout) && (numblocks > 0))
435 +
return numblocks * element->blocksampsout;
438 +
static guint get_output_size(GSTLALInterpolator *element, guint size) {
439 +
return get_output_length(element, size / element->unitsize) * element->unitsize;
442 +
static gboolean transform_size(GstBaseTransform *trans, GstPadDirection direction, GstCaps *caps, guint size, GstCaps *othercaps, guint *othersize)
444 + GSTLALInterpolator *element = GSTLAL_INTERPOLATOR(trans);
446 + guint other_unit_size;
447 + gboolean success = TRUE;
449 +
if(!get_unit_size(trans, caps, &unit_size))
451 +
if(size % unit_size) {
452 + GST_ERROR_OBJECT(element,
"size not a multiple of %u", unit_size);
455 +
if(!get_unit_size(trans, othercaps, &other_unit_size))
458 +
switch(direction) {
464 + *othersize = minimum_input_size(element, size);
465 + GST_INFO_OBJECT(element,
"transform_size() producing %d (bytes) buffer for request on src pad", *othersize);
474 + *othersize = get_output_size(element, size);
475 + GST_INFO_OBJECT(element,
"transform_size() SINK pad buffer of size %d (bytes) %d (samples) provided. Transforming to size %d (bytes) %d (samples).", size, size / element->unitsize, *othersize, *othersize / element->unitsize);
478 +
case GST_PAD_UNKNOWN:
479 + GST_ELEMENT_ERROR(trans, CORE, NEGOTIATION, (NULL), (
"invalid direction GST_PAD_UNKNOWN"));
487 +
static gboolean start(GstBaseTransform *trans)
489 + GSTLALInterpolator *element = GSTLAL_INTERPOLATOR(trans);
490 + element->t0 = GST_CLOCK_TIME_NONE;
491 + element->offset0 = GST_BUFFER_OFFSET_NONE;
492 + element->next_input_offset = GST_BUFFER_OFFSET_NONE;
493 + element->next_output_offset = GST_BUFFER_OFFSET_NONE;
494 + element->need_discont = TRUE;
499 +
static gboolean stop(GstBaseTransform *trans)
501 + GSTLALInterpolator *element = GSTLAL_INTERPOLATOR(trans);
502 + g_object_unref(element->adapter);
503 + element->adapter = NULL;
507 +
static void flush_history(GSTLALInterpolator *element) {
508 + GST_INFO_OBJECT(element,
"flushing adapter contents");
509 + gst_audioadapter_clear(element->adapter);
512 +
static void set_metadata(GSTLALInterpolator *element, GstBuffer *buf, guint64 outsamples, gboolean gap)
514 + GST_BUFFER_OFFSET(buf) = element->next_output_offset;
515 + element->next_output_offset += outsamples;
516 + GST_BUFFER_OFFSET_END(buf) = element->next_output_offset;
517 + GST_BUFFER_TIMESTAMP(buf) = element->t0 + gst_util_uint64_scale_int_round(GST_BUFFER_OFFSET(buf) - element->offset0, GST_SECOND, element->outrate);
518 + GST_BUFFER_DURATION(buf) = element->t0 + gst_util_uint64_scale_int_round(GST_BUFFER_OFFSET_END(buf) - element->offset0, GST_SECOND, element->outrate) - GST_BUFFER_TIMESTAMP(buf);
519 +
if(G_UNLIKELY(element->need_discont)) {
520 + GST_BUFFER_FLAG_SET(buf, GST_BUFFER_FLAG_DISCONT);
521 + element->need_discont = FALSE;
524 + GST_BUFFER_FLAG_SET(buf, GST_BUFFER_FLAG_GAP);
526 + GST_BUFFER_FLAG_UNSET(buf, GST_BUFFER_FLAG_GAP);
527 + GST_INFO_OBJECT(element,
"set_metadata() %s%s output buffer %p spans %" GST_BUFFER_BOUNDARIES_FORMAT, gap ?
"gap" :
"nongap", GST_BUFFER_FLAG_IS_SET(buf, GST_BUFFER_FLAG_DISCONT) ?
"+discont" :
"", buf, GST_BUFFER_BOUNDARIES_ARGS(buf));
531 +
static GstFlowReturn transform(GstBaseTransform *trans, GstBuffer *inbuf, GstBuffer *outbuf)
534 + GSTLALInterpolator *element = GSTLAL_INTERPOLATOR(trans);
535 + guint expected_output_length, expected_output_size;
536 + GstFlowReturn result = GST_FLOW_OK;
538 + g_assert(GST_BUFFER_TIMESTAMP_IS_VALID(inbuf));
539 + g_assert(GST_BUFFER_DURATION_IS_VALID(inbuf));
540 + g_assert(GST_BUFFER_OFFSET_IS_VALID(inbuf));
541 + g_assert(GST_BUFFER_OFFSET_END_IS_VALID(inbuf));
543 +
if(G_UNLIKELY(GST_BUFFER_IS_DISCONT(inbuf) || GST_BUFFER_OFFSET(inbuf) != element->next_input_offset || !GST_CLOCK_TIME_IS_VALID(element->t0))) {
548 + flush_history(element);
554 + element->t0 = GST_BUFFER_TIMESTAMP(inbuf);
555 + element->offset0 = GST_BUFFER_OFFSET(inbuf);
556 + element->next_output_offset = element->offset0 + get_output_length(element, GST_BUFFER_SIZE(inbuf) / element->unitsize);
562 + element->need_discont = TRUE;
563 + GST_INFO_OBJECT(element,
"transform() A discontinuity was detected. The offset has been reset to %" G_GUINT64_FORMAT
" and the timestamp has been reset to %" GST_TIME_SECONDS_FORMAT, element->offset0, element->t0);
566 + g_assert_cmpuint(GST_BUFFER_TIMESTAMP(inbuf), ==, gst_audioadapter_expected_timestamp(element->adapter));
568 + element->next_input_offset = GST_BUFFER_OFFSET_END(inbuf);
577 + GST_INFO_OBJECT(element,
"transform() pushing %d (bytes) %d (samples) sample buffer into adapter with size %d (samples)", GST_BUFFER_SIZE(inbuf), GST_BUFFER_SIZE(inbuf) / element->unitsize, get_available_samples(element));
579 + gst_buffer_ref(inbuf);
580 + gst_audioadapter_push(element->adapter, inbuf);
581 + GST_INFO_OBJECT(element,
"transform() adapter size is now %d (samples)", get_available_samples(element));
583 + expected_output_length = get_output_length(element, 0);
584 + expected_output_size = get_output_size(element, 0);
585 + GST_INFO_OBJECT(element,
"transform() expect an output buffer with size %d (%d samples): got one with size %d", expected_output_length, expected_output_size, GST_BUFFER_SIZE(outbuf));
586 + g_assert_cmpuint(expected_output_size, ==, GST_BUFFER_SIZE(outbuf));
593 +
if (GST_BUFFER_SIZE(outbuf) == 0)
594 + set_metadata(element, outbuf, 0, FALSE);
597 + guint processed = 0;
598 +
float *last = NULL;
599 +
float *output = (
float *) GST_BUFFER_DATA(outbuf);
602 +
while ((get_available_samples(element) >= element->nrin) && (processed < expected_output_length)) {
605 + gst_audioadapter_copy_samples(element->adapter, element->data, element->nrin, NULL, NULL);
608 +
for (guint i = 0; i < element->channels; i++) {
610 + last = element->last + i * element->tapersampsout;
616 +
for (guint j = 0; j < element->nrin; j++) {
617 + element->rin[j] = element->data[i+j*element->channels];
620 + memset(element->cout, 0,
sizeof(fftwf_complex) * element->ncout);
623 + applytaper(element->rin, element->tapersampsin, element->up);
624 + applytaper(element->rin + element->nrin - element->tapersampsin, element->tapersampsin, element->down);
627 + fftwf_execute(element->fwdplan_in);
628 + memcpy(element->cout, element->cin,
sizeof(fftwf_complex) * element->ncin);
629 + fftwf_execute(element->revplan_out);
632 + blend(element->rout, last, 0, element->tapersampsout);
633 + memcpy(last, element->rout + (element->nrout - element->tapersampsout),
sizeof(*last) * element->tapersampsout);
639 +
for (guint j = 0; j < element->nrout-element->tapersampsout; j++) {
640 + output[i+j*element->channels] = element->rout[j] / element->nrin;
646 + gst_audioadapter_flush_samples(element->adapter, element->nrin - element->tapersampsin);
647 + flushed += element->nrin - element->tapersampsin;
648 + processed += element->nrout - element->tapersampsout;
650 + output = (
float *) GST_BUFFER_DATA(outbuf) + processed * element->channels;
652 + GST_INFO_OBJECT(element,
"flushed %d processed %d expected output length %d", flushed, processed, expected_output_length);
653 + set_metadata(element, outbuf, expected_output_length, FALSE);
660 +
static void finalize(GObject *
object)
662 + GSTLALInterpolator *element = GSTLAL_INTERPOLATOR(
object);
669 + free(element->down);
670 + free(element->last);
671 + fftwf_free(element->rin);
672 + fftwf_free(element->cin);
673 + fftwf_free(element->rout);
674 + fftwf_free(element->cout);
675 + fftwf_free(element->data);
681 + G_OBJECT_CLASS(parent_class)->finalize(
object);
684 diff --git a/gstlal/gst/lal/gstlal_interpolator.h b/gstlal/gst/lal/gstlal_interpolator.h
686 index 0000000..e8be6cc
688 +++ b/gstlal/gst/lal/gstlal_interpolator.h
717 +#ifndef __GSTLAL_INTERPOLATOR_H__
718 +#define __GSTLAL_INTERPOLATOR_H__
722 +#include <gst/gst.h>
723 +#include <gst/base/gstadapter.h>
724 +#include <gst/base/gstbasetransform.h>
727 +#include <gstlal/gstlal.h>
728 +#include <gstlal/gstaudioadapter.h>
733 +#define GSTLAL_INTERPOLATOR_TYPE \
734 + (gstlal_interpolator_get_type())
736 +#define GSTLAL_INTERPOLATOR(obj) \
737 + (G_TYPE_CHECK_INSTANCE_CAST((obj), GSTLAL_INTERPOLATOR_TYPE, GSTLALInterpolator))
739 +#define GSTLAL_INTERPOLATOR_CLASS(klass) \
742 +#define GST_IS_GSTLAL_INTERPOLATOR(obj) \
743 + (G_TYPE_CHECK_INSTANCE_TYPE((obj), GSTLAL_INTERPOLATOR_TYPE))
745 +#define GST_IS_GSTLAL_INTERPOLATOR_CLASS(klass) \
746 + (G_TYPE_CHECK_CLASS_TYPE((klass), GSTLAL_INTERPOLATOR_TYPE))
759 + GstBaseTransform element;
764 + GstAudioAdapter *adapter;
769 + guint64 next_input_offset;
770 + GstClockTime next_input_timestamp;
771 + guint64 next_output_offset;
772 + GstClockTime next_output_timestamp;
773 + gboolean need_discont;
780 + guint tapersampsin;
781 + guint tapersampsout;
782 + guint blocksampsin;
783 + guint blocksampsout;
791 + fftwf_complex *cin;
793 + fftwf_complex *cout;
794 + fftwf_plan fwdplan_in;
795 + fftwf_plan revplan_out;
806 + GstBaseTransformClass parent_class;
810 +GType gstlal_interpolator_get_type(
void);
821 From 044e38137c40e312f798f60294acfebc422f7f8d Mon Sep 17 00:00:00 2001
822 From: CHAD RICHARD HANNA <crh184@psu.edu>
823 Date: Thu, 26 Feb 2015 16:23:20 -0500
824 Subject: [PATCH 2/8] update interpolator to time domain
827 gstlal/gst/lal/gstlal_interpolator.c | 335 +++++++++++++++--------------------
828 1 file changed, 138 insertions(+), 197 deletions(-)
830 diff --git a/gstlal/gst/lal/gstlal_interpolator.c b/gstlal/gst/lal/gstlal_interpolator.c
831 index 731d161..b4d9980 100644
832 --- a/gstlal/gst/lal/gstlal_interpolator.c
833 +++ b/gstlal/gst/lal/gstlal_interpolator.c
919 GstElementClass *element_class = GST_ELEMENT_CLASS(klass);
920 GstBaseTransformClass *transform_class = GST_BASE_TRANSFORM_CLASS(klass);
922 - gst_element_class_set_details_simple(element_class, "Interpolator", "Filter/Audio", "Interpolates multichannel audio data using FFTs", "Chad Hanna <chad.hanna@ligo.org>");
923 + gst_element_class_set_details_simple(element_class, "Interpolator", "Filter/Audio", "Interpolates multichannel audio data using FFTs", "Chad Hanna <chad.hanna@ligo.org>, Patrick Brockill <brockill@uwm.edu>");
925 gobject_class->finalize = GST_DEBUG_FUNCPTR(finalize);
926 transform_class->get_unit_size = GST_DEBUG_FUNCPTR(get_unit_size);
927 @@ -190,20 +200,17 @@ static
void gstlal_interpolator_init(GSTLALInterpolator *element, GSTLALInterpol
929 element->outrate = 0;
933 - element->nrout = 0;
934 - element->ncout = 0;
935 - element->tapersampsin = 0;
936 - element->tapersampsout = 0;
937 - element->up = NULL;
938 - element->down = NULL;
939 - element->last = NULL;
940 - element->rin = NULL;
941 - element->cin = NULL;
942 - element->rout = NULL;
943 - element->cout = NULL;
944 - element->data = NULL;
945 + element->factor = 0;
946 + element->kernel = NULL;
947 + element->workspace = NULL;
950 + element->half_length = 8;
951 + element->kernel_length = element->half_length * 2 + 1;
954 + element->need_discont = TRUE;
955 + element->need_pretend = TRUE;
957 element->adapter = g_object_new(GST_TYPE_AUDIOADAPTER, NULL);
959 @@ -247,6 +254,7 @@ static gboolean set_caps (GstBaseTransform * base, GstCaps * incaps, GstCaps * o
960 element->inrate = inrate;
961 element->outrate = outrate;
962 element->channels = inchannels;
963 + element->factor = outrate / inrate;
967 @@ -255,59 +263,24 @@ static gboolean set_caps (GstBaseTransform * base, GstCaps * incaps, GstCaps * o
968 element->next_input_offset = GST_BUFFER_OFFSET_NONE;
969 element->next_output_offset = GST_BUFFER_OFFSET_NONE;
970 element->need_discont = TRUE;
971 + element->need_pretend = TRUE;
977 + if (element->kernel)
978 + free(element->kernel);
979 + element->kernel = kernel(element->half_length, element->factor);
981 - element->nrin = inrate;
982 - element->ncin = element->nrin / 2 + 1;
983 - element->nrout = outrate;
984 - element->ncout = element->nrout / 2 + 1;
986 + element->blockstridein = 128;
987 + element->blocksampsin = element->blockstridein + element->kernel_length;
988 + element->blockstrideout = element->blockstridein * element->factor;
989 + element->blocksampsout = element->blockstrideout + (element->kernel_length) * element->factor;
991 - element->tapersampsin = element->nrin / 4;
992 - element->tapersampsout = element->nrout / 4;
993 - element->blocksampsin = element->nrin - element->tapersampsin;
994 - element->blocksampsout = element->nrout - element->tapersampsout;
995 + GST_INFO_OBJECT(element, "blocksampsin %d, blocksampsout %d, blockstridein %d, blockstrideout %d", element->blocksampsin, element->blocksampsout, element->blockstridein, element->blockstrideout);
999 - element->up = taperup(element->tapersampsin);
1001 - if (element->down)
1002 - free(element->down);
1003 - element->down = taperdown(element->tapersampsin);
1005 - if (element->last)
1006 - free(element->last);
1007 - element->last = (
float *) fftw_alloc_real(element->tapersampsout * element->channels);
1008 - memset(element->last, 0, sizeof(
float) * element->tapersampsout * element->channels);
1010 - if (!element->data)
1011 - free(element->data);
1012 - element->data = (
float*) fftwf_alloc_real(element->nrin * element->channels);
1015 - fftwf_free(element->rin);
1016 - element->rin = (
float*) fftwf_alloc_real(element->nrin);
1019 - fftwf_free(element->cin);
1020 - element->cin = (fftwf_complex*) fftwf_alloc_complex(element->ncin);
1022 - if (element->rout)
1023 - fftwf_free(element->rout);
1024 - element->rout = (
float*) fftwf_alloc_real(element->nrout);
1026 - if (element->cout)
1027 - fftwf_free(element->cout);
1028 - element->cout = (fftwf_complex*) fftwf_alloc_complex(element->ncout);
1030 - gstlal_fftw_lock();
1031 - element->fwdplan_in = fftwf_plan_dft_r2c_1d(element->nrin, element->rin, element->cin, FFTW_PATIENT);
1032 - element->revplan_out = fftwf_plan_dft_c2r_1d(element->nrout, element->cout, element->rout, FFTW_PATIENT);
1033 - gstlal_fftw_unlock();
1034 + if (element->workspace)
1035 + free(element->workspace);
1036 + element->workspace = (
float *) fftw_alloc_real(element->blocksampsin * element->channels);
1037 + memset(element->workspace, 0, sizeof(
float) * element->blocksampsin * element->channels);
1041 @@ -343,7 +316,7 @@ static gboolean get_unit_size(GstBaseTransform *trans, GstCaps *caps, guint *siz
1042 *size = width / 8 * channels;
1043 element->unitsize = *size;
1044 g_object_set(element->adapter, "unit-size", *size, NULL);
1045 - GST_INFO_OBJECT(element, "get_unit_size(): channels %d, width %d", channels, width);
1046 + GST_INFO_OBJECT(element, "channels %d, width %d", channels, width);
1049 GST_WARNING_OBJECT(trans, "unable to parse channels from %" GST_PTR_FORMAT, caps);
1050 @@ -351,14 +324,6 @@ static gboolean get_unit_size(GstBaseTransform *trans, GstCaps *caps, guint *siz
1054 -static guint minimum_input_length(GSTLALInterpolator *element, guint samps) {
1055 -
return ceil(samps / element->blocksampsin) * element->blocksampsin + element->tapersampsin;
1058 -
static guint minimum_input_size(GSTLALInterpolator *element, guint size) {
1059 -
return minimum_input_length(element, size / element->unitsize) * element->unitsize;
1062 static guint64 get_available_samples(GSTLALInterpolator *element)
1065 @@ -367,20 +332,25 @@
static guint64 get_available_samples(GSTLALInterpolator *element)
1070 +
static guint minimum_input_length(GSTLALInterpolator *element, guint samps) {
1071 +
return samps / element->factor + element->kernel_length;
1074 +
static guint minimum_input_size(GSTLALInterpolator *element, guint size) {
1075 +
return minimum_input_length(element, size / element->unitsize) * element->unitsize;
1078 static guint get_output_length(GSTLALInterpolator *element, guint samps) {
1080 - guint numinsamps = get_available_samples(element) + samps;
1081 -
if (numinsamps == 0)
1083 + guint pretend_samps = element->need_pretend ? element->half_length : 0;
1084 + guint numinsamps = get_available_samples(element) + samps + pretend_samps;
1085 +
if (numinsamps <= element->kernel_length)
1087 - guint numoutsamps = numinsamps * element->outrate / element->inrate;
1088 - guint numblocks = numoutsamps / element->blocksampsout;
1089 -
if (numblocks != 0)
1090 - remainder = numoutsamps % numblocks;
1092 - remainder = numoutsamps;
1093 -
if ((remainder < element->tapersampsout) && (numblocks > 0))
1095 -
return numblocks * element->blocksampsout;
1096 + guint numoutsamps = (numinsamps - element->kernel_length) * element->factor;
1097 + guint numblocks = numoutsamps / element->blockstrideout;
1099 +
return numblocks * element->blockstrideout;
1102 static guint get_output_size(GSTLALInterpolator *element, guint size) {
1103 @@ -410,7 +380,7 @@
static gboolean transform_size(GstBaseTransform *trans, GstPadDirection directio
1104 * buffer of (at least) the requested size
1106 *othersize = minimum_input_size(element, size);
1107 - GST_INFO_OBJECT(element,
"transform_size() producing %d (bytes) buffer for request on src pad", *othersize);
1108 + GST_INFO_OBJECT(element,
"producing %d (bytes) buffer for request on SRC pad", *othersize);
1112 @@ -420,7 +390,7 @@
static gboolean transform_size(GstBaseTransform *trans, GstPadDirection directio
1115 *othersize = get_output_size(element, size);
1116 - GST_INFO_OBJECT(element,
"transform_size() SINK pad buffer of size %d (bytes) %d (samples) provided. Transforming to size %d (bytes) %d (samples).", size, size / element->unitsize, *othersize, *othersize / element->unitsize);
1117 + GST_INFO_OBJECT(element,
"SINK pad buffer of size %d (bytes) %d (samples) provided. Transforming to size %d (bytes) %d (samples).", size, size / element->unitsize, *othersize, *othersize / element->unitsize);
1120 case GST_PAD_UNKNOWN:
1121 @@ -440,15 +410,17 @@
static gboolean start(GstBaseTransform *trans)
1122 element->next_input_offset = GST_BUFFER_OFFSET_NONE;
1123 element->next_output_offset = GST_BUFFER_OFFSET_NONE;
1124 element->need_discont = TRUE;
1126 + element->need_pretend = TRUE;
1132 static gboolean stop(GstBaseTransform *trans)
1134 - GSTLALInterpolator *element = GSTLAL_INTERPOLATOR(trans);
1135 - g_object_unref(element->adapter);
1136 - element->adapter = NULL;
1137 + GSTLALInterpolator *element = GSTLAL_INTERPOLATOR(trans);
1138 + g_object_unref(element->adapter);
1139 + element->adapter = NULL;
1143 @@ -472,22 +444,21 @@
static void set_metadata(GSTLALInterpolator *element, GstBuffer *buf, guint64 ou
1144 GST_BUFFER_FLAG_SET(buf, GST_BUFFER_FLAG_GAP);
1146 GST_BUFFER_FLAG_UNSET(buf, GST_BUFFER_FLAG_GAP);
1147 - GST_INFO_OBJECT(element,
"set_metadata() %s%s output buffer %p spans %" GST_BUFFER_BOUNDARIES_FORMAT, gap ?
"gap" :
"nongap", GST_BUFFER_FLAG_IS_SET(buf, GST_BUFFER_FLAG_DISCONT) ?
"+discont" :
"", buf, GST_BUFFER_BOUNDARIES_ARGS(buf));
1148 + GST_INFO_OBJECT(element,
"%s%s output_buffer %p spans %" GST_BUFFER_BOUNDARIES_FORMAT, gap ?
"gap" :
"nongap", GST_BUFFER_FLAG_IS_SET(buf, GST_BUFFER_FLAG_DISCONT) ?
"+discont" :
"", buf, GST_BUFFER_BOUNDARIES_ARGS(buf));
1152 static GstFlowReturn transform(GstBaseTransform *trans, GstBuffer *inbuf, GstBuffer *outbuf)
1155 GSTLALInterpolator *element = GSTLAL_INTERPOLATOR(trans);
1156 - guint expected_output_length, expected_output_size;
1157 + guint input_length, output_length, expected_output_size;
1158 GstFlowReturn result = GST_FLOW_OK;
1160 g_assert(GST_BUFFER_TIMESTAMP_IS_VALID(inbuf));
1161 g_assert(GST_BUFFER_DURATION_IS_VALID(inbuf));
1162 g_assert(GST_BUFFER_OFFSET_IS_VALID(inbuf));
1163 g_assert(GST_BUFFER_OFFSET_END_IS_VALID(inbuf));
1166 if(G_UNLIKELY(GST_BUFFER_IS_DISCONT(inbuf) || GST_BUFFER_OFFSET(inbuf) != element->next_input_offset || !GST_CLOCK_TIME_IS_VALID(element->t0))) {
1180 element->need_discont = TRUE;
1181 - GST_INFO_OBJECT(element,
"transform() A discontinuity was detected. The offset has been reset to %" G_GUINT64_FORMAT
" and the timestamp has been reset to %" GST_TIME_SECONDS_FORMAT, element->offset0, element->t0);
1182 + element->need_pretend = TRUE;
1183 + GST_INFO_OBJECT(element,
"A discontinuity was detected. The offset has been reset to %" G_GUINT64_FORMAT
" and the timestamp has been reset to %" GST_TIME_SECONDS_FORMAT, element->offset0, element->t0);
1188 g_assert_cmpuint(GST_BUFFER_TIMESTAMP(inbuf), ==, gst_audioadapter_expected_timestamp(element->adapter));
1192 element->next_input_offset = GST_BUFFER_OFFSET_END(inbuf);
1200 + GST_INFO_OBJECT(element,
"%s input_buffer %p spans %" GST_BUFFER_BOUNDARIES_FORMAT, GST_BUFFER_FLAG_IS_SET(inbuf, GST_BUFFER_FLAG_DISCONT) ?
"+discont" :
"", inbuf, GST_BUFFER_BOUNDARIES_ARGS(inbuf));
1202 - GST_INFO_OBJECT(element,
"transform() pushing %d (bytes) %d (samples) sample buffer into adapter with size %d (samples)", GST_BUFFER_SIZE(inbuf), GST_BUFFER_SIZE(inbuf) / element->unitsize, get_available_samples(element));
1203 + GST_INFO_OBJECT(element,
"pushing %d (bytes) %d (samples) sample buffer into adapter with size %d (samples)", GST_BUFFER_SIZE(inbuf), GST_BUFFER_SIZE(inbuf) / element->unitsize, get_available_samples(element));
1205 gst_buffer_ref(inbuf);
1206 gst_audioadapter_push(element->adapter, inbuf);
1207 - GST_INFO_OBJECT(element,
"transform() adapter size is now %d (samples)", get_available_samples(element));
1209 - expected_output_length = get_output_length(element, 0);
1210 - expected_output_size = get_output_size(element, 0);
1211 - GST_INFO_OBJECT(element,
"transform() expect an output buffer with size %d (%d samples): got one with size %d", expected_output_length, expected_output_size, GST_BUFFER_SIZE(outbuf));
1212 - g_assert_cmpuint(expected_output_size, ==, GST_BUFFER_SIZE(outbuf));
1214 + GST_INFO_OBJECT(element,
"adapter_size %d (samples)", get_available_samples(element));
1222 + output_length = GST_BUFFER_SIZE(outbuf) / element->unitsize;
1224 if (GST_BUFFER_SIZE(outbuf) == 0)
1225 set_metadata(element, outbuf, 0, FALSE);
1230 guint processed = 0;
1231 -
float *last = NULL;
1232 + gint input_offset;
1233 + gint kernel_offset;
1234 + gint output_offset;
1237 float *output = (
float *) GST_BUFFER_DATA(outbuf);
1238 + memset(GST_BUFFER_DATA(outbuf), 0, GST_BUFFER_SIZE(outbuf));
1241 -
while ((get_available_samples(element) >= element->nrin) && (processed < expected_output_length)) {
1244 - gst_audioadapter_copy_samples(element->adapter, element->data, element->nrin, NULL, NULL);
1247 -
for (guint i = 0; i < element->channels; i++) {
1249 - last = element->last + i * element->tapersampsout;
1255 -
for (guint j = 0; j < element->nrin; j++) {
1256 - element->rin[j] = element->data[i+j*element->channels];
1259 - memset(element->cout, 0,
sizeof(fftwf_complex) * element->ncout);
1262 - applytaper(element->rin, element->tapersampsin, element->up);
1263 - applytaper(element->rin + element->nrin - element->tapersampsin, element->tapersampsin, element->down);
1266 - fftwf_execute(element->fwdplan_in);
1267 - memcpy(element->cout, element->cin,
sizeof(fftwf_complex) * element->ncin);
1268 - fftwf_execute(element->revplan_out);
1271 - blend(element->rout, last, 0, element->tapersampsout);
1272 - memcpy(last, element->rout + (element->nrout - element->tapersampsout),
sizeof(*last) * element->tapersampsout);
1278 -
for (guint j = 0; j < element->nrout-element->tapersampsout; j++) {
1279 - output[i+j*element->channels] = element->rout[j] / element->nrin;
1282 + GST_INFO_OBJECT(element,
"Processing a %d sample output buffer from %d input", output_length);
1284 +
while (processed < output_length) {
1286 + memset(element->workspace, 0,
sizeof(
float) * element->blocksampsin * element->channels);
1290 - gst_audioadapter_flush_samples(element->adapter, element->nrin - element->tapersampsin);
1291 - flushed += element->nrin - element->tapersampsin;
1292 - processed += element->nrout - element->tapersampsout;
1294 - output = (
float *) GST_BUFFER_DATA(outbuf) + processed * element->channels;
1296 +
if (element->need_pretend)
1297 + gst_audioadapter_copy_samples(element->adapter, element->workspace + (element->half_length) * element->channels, element->blocksampsin - element->half_length, NULL, NULL);
1299 + gst_audioadapter_copy_samples(element->adapter, element->workspace, element->blocksampsin, NULL, NULL);
1301 + resample(output, element->kernel, element->workspace, element->kernel_length, element->factor, element->channels, element->blockstrideout);
1303 +
if (element->need_pretend) {
1304 + element->need_pretend = FALSE;
1305 + gst_audioadapter_flush_samples(element->adapter, element->blockstridein - element->half_length);
1308 + gst_audioadapter_flush_samples(element->adapter, element->blockstridein);
1309 + output += element->blockstrideout * element->channels;
1310 + processed += element->blockstrideout;
1312 - GST_INFO_OBJECT(element,
"flushed %d processed %d expected output length %d", flushed, processed, expected_output_length);
1313 - set_metadata(element, outbuf, expected_output_length, FALSE);
1314 + GST_INFO_OBJECT(element,
"Processed a %d samples", processed);
1315 + set_metadata(element, outbuf, output_length, FALSE);
1319 @@ -613,14 +560,8 @@
static void finalize(GObject *
object)
1323 - free(element->up);
1324 - free(element->down);
1325 - free(element->last);
1326 - fftwf_free(element->rin);
1327 - fftwf_free(element->cin);
1328 - fftwf_free(element->rout);
1329 - fftwf_free(element->cout);
1330 - fftwf_free(element->data);
1331 + free(element->kernel);
1332 + free(element->workspace);
1367 guint64 next_output_offset;
1368 GstClockTime next_output_timestamp;
1369 gboolean need_discont;
1370 + gboolean need_pretend;
1377 - guint tapersampsin;
1378 - guint tapersampsout;
1381 guint blocksampsout;
1389 - fftwf_complex *cin;
1391 - fftwf_complex *cout;
1392 - fftwf_plan fwdplan_in;
1393 - fftwf_plan revplan_out;
1394 + guint blockstridein;
1395 + guint blockstrideout;
1397 + guint half_length;
1398 + guint kernel_length;
1408 From 2a5224390fa5ebef5e680891eb979bbad882452e Mon Sep 17 00:00:00 2001
1409 From: CHAD RICHARD HANNA <crh184@psu.edu>
1410 Date: Fri, 27 Feb 2015 14:09:35 -0500
1411 Subject: [PATCH 4/8] gstlal_interpolator: additional vectorization
1414 gstlal/gst/lal/gstlal_interpolator.c | 97 +++++++++++++++++++-----------------
1415 1 file changed, 52 insertions(+), 45 deletions(-)
1417 diff --git a/gstlal/gst/lal/gstlal_interpolator.c b/gstlal/gst/lal/gstlal_interpolator.c
1418 index b4d9980..97741ab 100644
1419 --- a/gstlal/gst/lal/gstlal_interpolator.c
1420 +++ b/gstlal/gst/lal/gstlal_interpolator.c
1425 +#include <gsl/gsl_matrix.h>
1426 +#include <gsl/gsl_blas.h>
1584 - free(element->kernel);
1585 - free(element->workspace);
1587 +
for (guint i = 0; i < element->factor; i++)
1588 + gsl_vector_float_free(element->kernel[i]);
1589 + gsl_matrix_float_free(element->workspace);