gstlal-inspiral  0.4.2
 All Classes Namespaces Files Functions Variables Pages
interp.patch
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
5 
6 ---
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
14 
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
31 @@ -57,6 +57,7 @@
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
48 new file mode 100644
49 index 0000000..731d161
50 --- /dev/null
51 +++ b/gstlal/gst/lal/gstlal_interpolator.c
52 @@ -0,0 +1,631 @@
53 +/*
54 + * An interpolator element
55 + *
56 + * Copyright (C) 2011 Chad Hanna, Kipp Cannon
57 + *
58 + * This program is free software; you can redistribute it and/or modify
59 + * it under the terms of the GNU General Public License as published by
60 + * the Free Software Foundation; either version 2 of the License, or
61 + * (at your option) any later version.
62 + *
63 + * This program is distributed in the hope that it will be useful,
64 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
65 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
66 + * GNU General Public License for more details.
67 + *
68 + * You should have received a copy of the GNU General Public License along
69 + * with this program; if not, write to the Free Software Foundation, Inc.,
70 + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
71 + */
72 +
73 +
74 +/*
75 + * ========================================================================
76 + *
77 + * Preamble
78 + *
79 + * ========================================================================
80 + */
81 +
82 +
83 +/*
84 + * struff from the C library
85 + */
86 +
87 +
88 +/*
89 + * stuff from glib/gstreamer
90 + */
91 +
92 +
93 +#include <glib.h>
94 +#include <glib/gprintf.h>
95 +#include <gst/gst.h>
96 +#include <gst/base/gstbasetransform.h>
97 +#include <gst/base/gstadapter.h>
98 +#include <math.h>
99 +#include <string.h>
100 +#include <fftw3.h>
101 +
102 +/*
103 + * our own stuff
104 + */
105 +
106 +#include <gstlal/gstlal.h>
107 +#include <gstlal/gstlal_debug.h>
108 +#include <gstlal/gstaudioadapter.h>
109 +#include <gstlal_interpolator.h>
110 +
111 +/*
112 + * Utility functions for tapering the FFT buffers
113 + */
114 +
115 +#define PI 3.141592653589793
116 +
117 +static float* taperup(int samps) {
118 + float x;
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;
123 + }
124 + return out;
125 +}
126 +
127 +static float* taperdown(int samps) {
128 + float x;
129 + float *out = (float *) calloc(samps, sizeof(float));
130 + for (int i = 0; i < samps; i++) {
131 + x = cos(PI / 2. * (float) i / samps);
132 + out[i] = x * x;
133 + }
134 + return out;
135 +}
136 +
137 +static int applytaper(float *in, int end, float *taper) {
138 + for (int i = 0; i < end; i++) {
139 + in[i] *= taper[i];
140 + }
141 + return 0;
142 +}
143 +
144 +static int blend(float *in1, float *in2, int start, int end) {
145 + for (int i = start; i < end; i++)
146 + in1[i] += in2[i];
147 + return 0;
148 +}
149 +
150 +
151 +/*
152 + * gstreamer boiler plate
153 + */
154 +
155 +#define GST_CAT_DEFAULT gstlal_interpolator_debug
156 +GST_DEBUG_CATEGORY_STATIC(GST_CAT_DEFAULT);
157 +
158 +static void additional_initializations(GType type)
159 +{
160 + GST_DEBUG_CATEGORY_INIT(GST_CAT_DEFAULT, "lal_interpolator", 0, "lal_interpolator element");
161 +}
162 +
163 +GST_BOILERPLATE_FULL(
164 + GSTLALInterpolator,
165 + gstlal_interpolator,
166 + GstBaseTransform,
167 + GST_TYPE_BASE_TRANSFORM,
168 + additional_initializations
169 +);
170 +
171 +static void gstlal_interpolator_base_init(gpointer klass){}
172 +
173 +/* Pads */
174 +
175 +static GstStaticPadTemplate sink_template =
176 + GST_STATIC_PAD_TEMPLATE ("sink",
177 + GST_PAD_SINK,
178 + GST_PAD_ALWAYS,
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]")
184 + );
185 +
186 +static GstStaticPadTemplate src_template =
187 + GST_STATIC_PAD_TEMPLATE ("src",
188 + GST_PAD_SRC,
189 + GST_PAD_ALWAYS,
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]")
195 + );
196 +
197 +/*
198 + * Virtual method protototypes
199 + */
200 +
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);
209 +
210 +/*
211 + * class_init()
212 + */
213 +
214 +static void gstlal_interpolator_class_init(GSTLALInterpolatorClass *klass)
215 +{
216 +
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);
220 +
221 + gst_element_class_set_details_simple(element_class, "Interpolator", "Filter/Audio", "Interpolates multichannel audio data using FFTs", "Chad Hanna <chad.hanna@ligo.org>");
222 +
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);
231 +
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));
234 +}
235 +
236 +
237 +static void gstlal_interpolator_init(GSTLALInterpolator *element, GSTLALInterpolatorClass *klass)
238 +{
239 + gst_base_transform_set_gap_aware(GST_BASE_TRANSFORM(element), TRUE);
240 +
241 + /* internal data */
242 + element->inrate = 0;
243 + element->outrate = 0;
244 +
245 + element->nrin = 0; // size of real input to FFT
246 + element->ncin = 0; // size of complex input to FFFT
247 + element->nrout = 0; // size of real output to FFT
248 + element->ncout = 0; // size of complex output to FFT
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;
259 +
260 + element->adapter = g_object_new(GST_TYPE_AUDIOADAPTER, NULL);
261 +}
262 +
263 +static GstCaps* transform_caps (GstBaseTransform *trans, GstPadDirection direction, GstCaps *caps) {
264 +
265 + /*
266 + * FIXME actually pull out the allowed rates so that we can prevent
267 + * downsampling at the negotiation stage
268 + */
269 + GstStructure *capsstruct;
270 + gint channels;
271 + capsstruct = gst_caps_get_structure (caps, 0);
272 + char capsstr[256] = {0};
273 +
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);
277 + }
278 +
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]");
280 +
281 +}
282 +
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;
287 +
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);
294 +
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);
298 +
299 + element->inrate = inrate;
300 + element->outrate = outrate;
301 + element->channels = inchannels;
302 +
303 + /* Timestamp and offset bookeeping */
304 +
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;
310 +
311 + /*
312 + * NOTE: This element hardcodes transform sizes to be 1 second so we
313 + * can set up a lot of stuff right now. Might as well.
314 + */
315 +
316 + element->nrin = inrate;
317 + element->ncin = element->nrin / 2 + 1; // FFTW documentation for complex size
318 + element->nrout = outrate;
319 + element->ncout = element->nrout / 2 + 1; // FFTW documentation for complex size
320 +
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;
325 +
326 + if (element->up)
327 + free(element->up);
328 + element->up = taperup(element->tapersampsin);
329 +
330 + if (element->down)
331 + free(element->down);
332 + element->down = taperdown(element->tapersampsin);
333 +
334 + if (element->last)
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);
338 +
339 + if (!element->data)
340 + free(element->data);
341 + element->data = (float*) fftwf_alloc_real(element->nrin * element->channels);
342 +
343 + if (element->rin)
344 + fftwf_free(element->rin);
345 + element->rin = (float*) fftwf_alloc_real(element->nrin);
346 +
347 + if (element->cin)
348 + fftwf_free(element->cin);
349 + element->cin = (fftwf_complex*) fftwf_alloc_complex(element->ncin);
350 +
351 + if (element->rout)
352 + fftwf_free(element->rout);
353 + element->rout = (float*) fftwf_alloc_real(element->nrout);
354 +
355 + if (element->cout)
356 + fftwf_free(element->cout);
357 + element->cout = (fftwf_complex*) fftwf_alloc_complex(element->ncout);
358 +
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();
363 +
364 + return TRUE;
365 +}
366 +
367 +
368 +/*
369 + * ============================================================================
370 + *
371 + * GstBaseTransform Method Overrides
372 + *
373 + * ============================================================================
374 + */
375 +
376 +
377 +/*
378 + * get_unit_size()
379 + */
380 +
381 +
382 +static gboolean get_unit_size(GstBaseTransform *trans, GstCaps *caps, guint *size)
383 +{
384 + GSTLALInterpolator *element = GSTLAL_INTERPOLATOR(trans);
385 + GstStructure *str;
386 + gint width, channels;
387 + gboolean success = TRUE;
388 +
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);
392 +
393 +
394 + if(success) {
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);
399 + }
400 + else
401 + GST_WARNING_OBJECT(trans, "unable to parse channels from %" GST_PTR_FORMAT, caps);
402 +
403 + return success;
404 +}
405 +
406 +static guint minimum_input_length(GSTLALInterpolator *element, guint samps) {
407 + return ceil(samps / element->blocksampsin) * element->blocksampsin + element->tapersampsin;
408 +}
409 +
410 +static guint minimum_input_size(GSTLALInterpolator *element, guint size) {
411 + return minimum_input_length(element, size / element->unitsize) * element->unitsize;
412 +}
413 +
414 +static guint64 get_available_samples(GSTLALInterpolator *element)
415 +{
416 + //FIXME is size here really samples, I guess so??
417 + guint size;
418 + g_object_get(element->adapter, "size", &size, NULL);
419 + return size;
420 +}
421 +
422 +static guint get_output_length(GSTLALInterpolator *element, guint samps) {
423 + guint remainder;
424 + guint numinsamps = get_available_samples(element) + samps;
425 + if (numinsamps == 0)
426 + return 0;
427 + guint numoutsamps = numinsamps * element->outrate / element->inrate;
428 + guint numblocks = numoutsamps / element->blocksampsout; //truncation
429 + if (numblocks != 0)
430 + remainder = numoutsamps % numblocks; // what doesn't fit into a multiple of block sizes
431 + else
432 + remainder = numoutsamps;
433 + if ((remainder < element->tapersampsout) && (numblocks > 0)) // we can't actually produce output for the last tapersampsout worth of samples since those will be blended
434 + numblocks -= 1;
435 + return numblocks * element->blocksampsout; // Could be zero
436 +}
437 +
438 +static guint get_output_size(GSTLALInterpolator *element, guint size) {
439 + return get_output_length(element, size / element->unitsize) * element->unitsize;
440 +}
441 +
442 +static gboolean transform_size(GstBaseTransform *trans, GstPadDirection direction, GstCaps *caps, guint size, GstCaps *othercaps, guint *othersize)
443 +{
444 + GSTLALInterpolator *element = GSTLAL_INTERPOLATOR(trans);
445 + guint unit_size;
446 + guint other_unit_size;
447 + gboolean success = TRUE;
448 +
449 + if(!get_unit_size(trans, caps, &unit_size))
450 + return FALSE;
451 + if(size % unit_size) {
452 + GST_ERROR_OBJECT(element, "size not a multiple of %u", unit_size);
453 + return FALSE;
454 + }
455 + if(!get_unit_size(trans, othercaps, &other_unit_size))
456 + return FALSE;
457 +
458 + switch(direction) {
459 + case GST_PAD_SRC:
460 + /*
461 + * number of input bytes required to produce an output
462 + * buffer of (at least) the requested size
463 + */
464 + *othersize = minimum_input_size(element, size);
465 + GST_INFO_OBJECT(element, "transform_size() producing %d (bytes) buffer for request on src pad", *othersize);
466 + break;
467 +
468 + case GST_PAD_SINK:
469 + /*
470 + * number of output bytes to be generated by the receipt of
471 + * an input buffer of the given size.
472 + */
473 +
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);
476 + break;
477 +
478 + case GST_PAD_UNKNOWN:
479 + GST_ELEMENT_ERROR(trans, CORE, NEGOTIATION, (NULL), ("invalid direction GST_PAD_UNKNOWN"));
480 + success = FALSE;
481 + break;
482 + }
483 +
484 + return success;
485 +}
486 +
487 +static gboolean start(GstBaseTransform *trans)
488 +{
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;
495 + //element->need_new_segment = TRUE;
496 + return TRUE;
497 +}
498 +
499 +static gboolean stop(GstBaseTransform *trans)
500 +{
501 + GSTLALInterpolator *element = GSTLAL_INTERPOLATOR(trans);
502 + g_object_unref(element->adapter);
503 + element->adapter = NULL;
504 + return TRUE;
505 +}
506 +
507 +static void flush_history(GSTLALInterpolator *element) {
508 + GST_INFO_OBJECT(element, "flushing adapter contents");
509 + gst_audioadapter_clear(element->adapter);
510 +}
511 +
512 +static void set_metadata(GSTLALInterpolator *element, GstBuffer *buf, guint64 outsamples, gboolean gap)
513 +{
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;
522 + }
523 + if(gap)
524 + GST_BUFFER_FLAG_SET(buf, GST_BUFFER_FLAG_GAP);
525 + else
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));
528 +}
529 +
530 +
531 +static GstFlowReturn transform(GstBaseTransform *trans, GstBuffer *inbuf, GstBuffer *outbuf)
532 +{
533 +// FIXME, finish this. It is just (partially) copied from firbank
534 + GSTLALInterpolator *element = GSTLAL_INTERPOLATOR(trans);
535 + guint expected_output_length, expected_output_size;
536 + GstFlowReturn result = GST_FLOW_OK;
537 +
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));
542 +
543 + if(G_UNLIKELY(GST_BUFFER_IS_DISCONT(inbuf) || GST_BUFFER_OFFSET(inbuf) != element->next_input_offset || !GST_CLOCK_TIME_IS_VALID(element->t0))) {
544 + /*
545 + * flush any previous history and clear the adapter
546 + */
547 +
548 + flush_history(element);
549 +
550 + /*
551 + * (re)sync timestamp and offset book-keeping
552 + */
553 +
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);
557 +
558 + /*
559 + * be sure to flag the next output buffer as a discontinuity
560 + */
561 +
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);
564 +
565 + } else
566 + g_assert_cmpuint(GST_BUFFER_TIMESTAMP(inbuf), ==, gst_audioadapter_expected_timestamp(element->adapter));
567 +
568 + element->next_input_offset = GST_BUFFER_OFFSET_END(inbuf);
569 +
570 + /*
571 + * Put the input buffer into the adapter first
572 + * Then check the output buffer size that was expected.
573 + * Note that the transform size function tells you what you can produce
574 + * *after* receiving the next input buffer so this order is important
575 + */
576 +
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));
578 +
579 + gst_buffer_ref(inbuf); /* don't let calling code free buffer */
580 + gst_audioadapter_push(element->adapter, inbuf);
581 + GST_INFO_OBJECT(element, "transform() adapter size is now %d (samples)", get_available_samples(element));
582 +
583 + expected_output_length = get_output_length(element, 0); // just check the output length based on what we have in the adapter already
584 + expected_output_size = get_output_size(element, 0); // Ditto here
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));
587 +
588 +
589 + /*
590 + * Handle the different possiblilities
591 + */
592 +
593 + if (GST_BUFFER_SIZE(outbuf) == 0)
594 + set_metadata(element, outbuf, 0, FALSE);
595 + else {
596 + guint flushed = 0;
597 + guint processed = 0;
598 + float *last = NULL;
599 + float *output = (float *) GST_BUFFER_DATA(outbuf);
600 +
601 + // FIXME actually handle gaps properly
602 + while ((get_available_samples(element) >= element->nrin) && (processed < expected_output_length)) {
603 +
604 + /* First copy the data we need */
605 + gst_audioadapter_copy_samples(element->adapter, element->data, element->nrin, NULL, NULL);
606 +
607 + /* Resample each channel */
608 + for (guint i = 0; i < element->channels; i++) {
609 +
610 + last = element->last + i * element->tapersampsout; // get a pointer to the history for this channel
611 +
612 + /* Adapt output for FFTW FIXME FIXME FIXME we
613 + * need to avoid this copying around by making use of the advanced FFTW
614 + * interface
615 + */
616 + for (guint j = 0; j < element->nrin; j++) {
617 + element->rin[j] = element->data[i+j*element->channels];
618 + }
619 + /* Clear the output */
620 + memset(element->cout, 0, sizeof(fftwf_complex) * element->ncout);
621 +
622 + /* taper */
623 + applytaper(element->rin, element->tapersampsin, element->up);
624 + applytaper(element->rin + element->nrin - element->tapersampsin, element->tapersampsin, element->down);
625 +
626 + /* resample */
627 + fftwf_execute(element->fwdplan_in);
628 + memcpy(element->cout, element->cin, sizeof(fftwf_complex) * element->ncin);
629 + fftwf_execute(element->revplan_out);
630 +
631 + /* Blend the outputs */
632 + blend(element->rout, last, 0, element->tapersampsout);
633 + memcpy(last, element->rout + (element->nrout - element->tapersampsout), sizeof(*last) * element->tapersampsout);
634 +
635 + /* Adapt output for FFTW FIXME FIXME FIXME we
636 + * need to avoid this copying around by making use of the advanced FFTW
637 + * interface
638 + */
639 + for (guint j = 0; j < element->nrout-element->tapersampsout; j++) {
640 + output[i+j*element->channels] = element->rout[j] / element->nrin;
641 + }
642 + }
643 +
644 + /* Then flush the data we will never need again */
645 + // FIXME add a check that we have processed the correct number of samples
646 + gst_audioadapter_flush_samples(element->adapter, element->nrin - element->tapersampsin);
647 + flushed += element->nrin - element->tapersampsin;
648 + processed += element->nrout - element->tapersampsout;
649 + // Dont forget to increase the output pointer
650 + output = (float *) GST_BUFFER_DATA(outbuf) + processed * element->channels;
651 + }
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);
654 +
655 + }
656 + return result;
657 +}
658 +
659 +
660 +static void finalize(GObject *object)
661 +{
662 + GSTLALInterpolator *element = GSTLAL_INTERPOLATOR(object);
663 +
664 + /*
665 + * free resources
666 + */
667 +
668 + free(element->up);
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);
676 +
677 + /*
678 + * chain to parent class' finalize() method
679 + */
680 +
681 + G_OBJECT_CLASS(parent_class)->finalize(object);
682 +}
683 +
684 diff --git a/gstlal/gst/lal/gstlal_interpolator.h b/gstlal/gst/lal/gstlal_interpolator.h
685 new file mode 100644
686 index 0000000..e8be6cc
687 --- /dev/null
688 +++ b/gstlal/gst/lal/gstlal_interpolator.h
689 @@ -0,0 +1,127 @@
690 +/*
691 + * Copyright (C) 2011 Chad Hanna <chad.hanna@ligo.org>
692 + *
693 + * Permission is hereby granted, free of charge, to any person obtaining a
694 + * copy of this software and associated documentation files (the
695 + * "Software"), to deal in the Software without restriction, including
696 + * without limitation the rights to use, copy, modify, merge, publish,
697 + * distribute, sublicense, and/or sell copies of the Software, and to
698 + * permit persons to whom the Software is furnished to do so, subject to
699 + * the following conditions:
700 + *
701 + * The above copyright notice and this permission notice shall be included
702 + * in all copies or substantial portions of the Software.
703 + *
704 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
705 + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
706 + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
707 + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
708 + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
709 + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
710 + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
711 + *
712 + * You should have received a copy of the GNU General Public License along
713 + * with this program; if not, write to the Free Software Foundation, Inc.,
714 + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
715 + */
716 +
717 +#ifndef __GSTLAL_INTERPOLATOR_H__
718 +#define __GSTLAL_INTERPOLATOR_H__
719 +
720 +
721 +#include <glib.h>
722 +#include <gst/gst.h>
723 +#include <gst/base/gstadapter.h>
724 +#include <gst/base/gstbasetransform.h>
725 +#include <fftw3.h>
726 +
727 +#include <gstlal/gstlal.h>
728 +#include <gstlal/gstaudioadapter.h>
729 +
730 +G_BEGIN_DECLS
731 +
732 +
733 +#define GSTLAL_INTERPOLATOR_TYPE \
734 + (gstlal_interpolator_get_type())
735 +
736 +#define GSTLAL_INTERPOLATOR(obj) \
737 + (G_TYPE_CHECK_INSTANCE_CAST((obj), GSTLAL_INTERPOLATOR_TYPE, GSTLALInterpolator))
738 +
739 +#define GSTLAL_INTERPOLATOR_CLASS(klass) \
740 + (G_TYPE_CHECK_CLASS_CAST((klass), GSTLAL_INTERPOLATOR_TYPE, GSTLALInterpolatorClass))
741 +
742 +#define GST_IS_GSTLAL_INTERPOLATOR(obj) \
743 + (G_TYPE_CHECK_INSTANCE_TYPE((obj), GSTLAL_INTERPOLATOR_TYPE))
744 +
745 +#define GST_IS_GSTLAL_INTERPOLATOR_CLASS(klass) \
746 + (G_TYPE_CHECK_CLASS_TYPE((klass), GSTLAL_INTERPOLATOR_TYPE))
747 +
748 +
749 +typedef struct _GSTLALInterpolator GSTLALInterpolator;
751 +
752 +
753 +
756 +
757 +
759 + GstBaseTransform element;
760 +
761 + gint inrate;
762 + gint outrate;
763 + guint channels;
764 + GstAudioAdapter *adapter;
765 +
766 + /* Timestamp and offset bookeeping */
767 + guint64 t0;
768 + guint64 offset0;
769 + guint64 next_input_offset;
770 + GstClockTime next_input_timestamp;
771 + guint64 next_output_offset;
772 + GstClockTime next_output_timestamp;
773 + gboolean need_discont;
774 +
775 + /* Variables to control the size of transforms */
776 + guint nrin;
777 + guint ncin;
778 + guint nrout;
779 + guint ncout;
780 + guint tapersampsin;
781 + guint tapersampsout;
782 + guint blocksampsin;
783 + guint blocksampsout;
784 + guint unitsize;
785 +
786 + float *data;
787 + float *up;
788 + float *down;
789 + float *last;
790 + float *rin;
791 + fftwf_complex *cin;
792 + float *rout;
793 + fftwf_complex *cout;
794 + fftwf_plan fwdplan_in;
795 + fftwf_plan revplan_out;
796 +};
797 +
798 +
799 +
803 +
804 +
806 + GstBaseTransformClass parent_class;
807 +};
808 +
809 +
810 +GType gstlal_interpolator_get_type(void);
811 +
812 +
813 +G_END_DECLS
814 +
815 +
816 +#endif /* __GSTLAL_INTERPOLATOR_H__ */
817 --
818 1.8.3.2
819 
820 
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
825 
826 ---
827  gstlal/gst/lal/gstlal_interpolator.c | 335 +++++++++++++++--------------------
828  1 file changed, 138 insertions(+), 197 deletions(-)
829 
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
834 @@ -1,7 +1,7 @@
835  /*
836  * An interpolator element
837  *
838 - * Copyright (C) 2011 Chad Hanna, Kipp Cannon
839 + * Copyright (C) 2015 Chad Hanna, Kipp Cannon
840  *
841  * This program is free software; you can redistribute it and/or modify
842  * it under the terms of the GNU General Public License as published by
843 @@ -62,40 +62,50 @@
844 
845  #define PI 3.141592653589793
846 
847 -static float* taperup(int samps) {
848 - float x;
849 - float *out = (float *) calloc(samps, sizeof(float));
850 - for (int i = 0; i < samps; i++) {
851 - x = cos(PI / 2. * (float) i / samps);
852 - out[i] = 1. - x * x;
853 +static float* kernel(int half_length, int factor) {
854 + int kernel_length = (2 * half_length + 1) * factor;
855 + int domain = kernel_length / 2; // kernel length is gauranteed to be even
856 + float *out = fftwf_alloc_real(kernel_length + 1);
857 + float norm = 0.;
858 +
859 + for (int j = 0; j < kernel_length + 1; j++) {
860 + float x = j - domain;
861 + if (j == domain)
862 + out[j] = 1.;
863 + else
864 + out[j] = sin(PI * x / factor) / (PI * x / factor) * (1. - x*x / domain / domain);
865  }
866 - return out;
867 -}
868 
869 -static float* taperdown(int samps) {
870 - float x;
871 - float *out = (float *) calloc(samps, sizeof(float));
872 - for (int i = 0; i < samps; i++) {
873 - x = cos(PI / 2. * (float) i / samps);
874 - out[i] = x * x;
875 - }
876 + for (int i = 0; i < kernel_length + 1; i++)
877 + norm += out[i] * out[i];
878 +
879 + for (int i = 0; i < kernel_length + 1; i++)
880 + out[i] /= sqrt(norm / factor);
881 +
882  return out;
883  }
884 
885 -static int applytaper(float *in, int end, float *taper) {
886 - for (int i = 0; i < end; i++) {
887 - in[i] *= taper[i];
888 +void convolve(float *output, float *thiskernel, float *input, guint kernel_length, guint factor, guint channels) {
889 + for (guint i = 1; i < kernel_length; i++) {
890 + *output += (*thiskernel) * (*input);
891 + input += channels;
892 + thiskernel += factor;
893  }
894 - return 0;
895 + return;
896  }
897 
898 -static int blend(float *in1, float *in2, int start, int end) {
899 - for (int i = start; i < end; i++)
900 - in1[i] += in2[i];
901 - return 0;
902 +void resample(float *output, float *thiskernel, float *input, guint kernel_length, guint factor, guint channels, guint blockstrideout) {
903 + guint kernel_offset, output_offset, input_offset;
904 + for (gint samp = 0; samp < blockstrideout; samp++) {
905 + kernel_offset = factor - samp % factor + factor / 2;
906 + output_offset = samp * channels;
907 + input_offset = (samp / factor) * channels; // first input sample
908 + for (gint chan = 0; chan < channels; chan++)
909 + convolve(output + output_offset + chan, thiskernel + kernel_offset, input + input_offset + chan + channels, kernel_length, factor, channels);
910 + }
911 + return;
912  }
913 
914 -
915  /*
916  * gstreamer boiler plate
917  */
918 @@ -166,7 +176,7 @@ static void gstlal_interpolator_class_init(GSTLALInterpolatorClass *klass)
919  GstElementClass *element_class = GST_ELEMENT_CLASS(klass);
920  GstBaseTransformClass *transform_class = GST_BASE_TRANSFORM_CLASS(klass);
921 
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>");
924 
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
928  element->inrate = 0;
929  element->outrate = 0;
930 
931 - element->nrin = 0; // size of real input to FFT
932 - element->ncin = 0; // size of complex input to FFFT
933 - element->nrout = 0; // size of real output to FFT
934 - element->ncout = 0; // size of complex output to FFT
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; // size of complex output to FFT
946 + element->kernel = NULL;
947 + element->workspace = NULL;
948 +
949 + // hardcoded kernel size
950 + element->half_length = 8;
951 + element->kernel_length = element->half_length * 2 + 1;
952 +
953 + // Always initialize with a discont
954 + element->need_discont = TRUE;
955 + element->need_pretend = TRUE;
956 
957  element->adapter = g_object_new(GST_TYPE_AUDIOADAPTER, NULL);
958  }
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;
964 
965  /* Timestamp and offset bookeeping */
966 
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;
972 
973 - /*
974 - * NOTE: This element hardcodes transform sizes to be 1 second so we
975 - * can set up a lot of stuff right now. Might as well.
976 - */
977 + if (element->kernel)
978 + free(element->kernel);
979 + element->kernel = kernel(element->half_length, element->factor);
980 
981 - element->nrin = inrate;
982 - element->ncin = element->nrin / 2 + 1; // FFTW documentation for complex size
983 - element->nrout = outrate;
984 - element->ncout = element->nrout / 2 + 1; // FFTW documentation for complex size
985 + // Assume that we process inrate worth of samples at a time (e.g. 1s stride)
986 + element->blockstridein = 128;//element->inrate;
987 + element->blocksampsin = element->blockstridein + element->kernel_length;
988 + element->blockstrideout = element->blockstridein * element->factor;//element->outrate;
989 + element->blocksampsout = element->blockstrideout + (element->kernel_length) * element->factor;
990 
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);
996 
997 - if (element->up)
998 - free(element->up);
999 - element->up = taperup(element->tapersampsin);
1000 -
1001 - if (element->down)
1002 - free(element->down);
1003 - element->down = taperdown(element->tapersampsin);
1004 -
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);
1009 -
1010 - if (!element->data)
1011 - free(element->data);
1012 - element->data = (float*) fftwf_alloc_real(element->nrin * element->channels);
1013 -
1014 - if (element->rin)
1015 - fftwf_free(element->rin);
1016 - element->rin = (float*) fftwf_alloc_real(element->nrin);
1017 -
1018 - if (element->cin)
1019 - fftwf_free(element->cin);
1020 - element->cin = (fftwf_complex*) fftwf_alloc_complex(element->ncin);
1021 -
1022 - if (element->rout)
1023 - fftwf_free(element->rout);
1024 - element->rout = (float*) fftwf_alloc_real(element->nrout);
1025 -
1026 - if (element->cout)
1027 - fftwf_free(element->cout);
1028 - element->cout = (fftwf_complex*) fftwf_alloc_complex(element->ncout);
1029 -
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);
1038 
1039  return TRUE;
1040  }
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);
1047  }
1048  else
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
1051  return success;
1052  }
1053 
1054 -static guint minimum_input_length(GSTLALInterpolator *element, guint samps) {
1055 - return ceil(samps / element->blocksampsin) * element->blocksampsin + element->tapersampsin;
1056 -}
1057 -
1058 -static guint minimum_input_size(GSTLALInterpolator *element, guint size) {
1059 - return minimum_input_length(element, size / element->unitsize) * element->unitsize;
1060 -}
1061 -
1062  static guint64 get_available_samples(GSTLALInterpolator *element)
1063  {
1064  //FIXME is size here really samples, I guess so??
1065 @@ -367,20 +332,25 @@ static guint64 get_available_samples(GSTLALInterpolator *element)
1066  return size;
1067  }
1068 
1069 +
1070 +static guint minimum_input_length(GSTLALInterpolator *element, guint samps) {
1071 + return samps / element->factor + element->kernel_length; // FIXME check this
1072 +}
1073 +
1074 +static guint minimum_input_size(GSTLALInterpolator *element, guint size) {
1075 + return minimum_input_length(element, size / element->unitsize) * element->unitsize;
1076 +}
1077 +
1078  static guint get_output_length(GSTLALInterpolator *element, guint samps) {
1079 - guint remainder;
1080 - guint numinsamps = get_available_samples(element) + samps;
1081 - if (numinsamps == 0)
1082 + // Pretend that we have a half_length set of samples if we are at a discont
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)
1086  return 0;
1087 - guint numoutsamps = numinsamps * element->outrate / element->inrate;
1088 - guint numblocks = numoutsamps / element->blocksampsout; //truncation
1089 - if (numblocks != 0)
1090 - remainder = numoutsamps % numblocks; // what doesn't fit into a multiple of block sizes
1091 - else
1092 - remainder = numoutsamps;
1093 - if ((remainder < element->tapersampsout) && (numblocks > 0)) // we can't actually produce output for the last tapersampsout worth of samples since those will be blended
1094 - numblocks -= 1;
1095 - return numblocks * element->blocksampsout; // Could be zero
1096 + guint numoutsamps = (numinsamps - element->kernel_length) * element->factor; // FIXME check this
1097 + guint numblocks = numoutsamps / element->blockstrideout; //truncation
1098 +
1099 + return numblocks * element->blockstrideout; // Could be zero
1100  }
1101 
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
1105  */
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);
1109  break;
1110 
1111  case GST_PAD_SINK:
1112 @@ -420,7 +390,7 @@ static gboolean transform_size(GstBaseTransform *trans, GstPadDirection directio
1113  */
1114 
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);
1118  break;
1119 
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;
1125 - //element->need_new_segment = TRUE;
1126 + element->need_pretend = TRUE;
1127 + // FIXME properly handle segments
1128 + // element->need_new_segment = TRUE;
1129  return TRUE;
1130  }
1131 
1132  static gboolean stop(GstBaseTransform *trans)
1133  {
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;
1140  return TRUE;
1141  }
1142 
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);
1145  else
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));
1149  }
1150 
1151 
1152  static GstFlowReturn transform(GstBaseTransform *trans, GstBuffer *inbuf, GstBuffer *outbuf)
1153  {
1154 -// FIXME, finish this. It is just (partially) copied from firbank
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;
1159 
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));
1164 -
1165 +
1166  if(G_UNLIKELY(GST_BUFFER_IS_DISCONT(inbuf) || GST_BUFFER_OFFSET(inbuf) != element->next_input_offset || !GST_CLOCK_TIME_IS_VALID(element->t0))) {
1167  /*
1168  * flush any previous history and clear the adapter
1169 @@ -501,104 +472,80 @@ static GstFlowReturn transform(GstBaseTransform *trans, GstBuffer *inbuf, GstBuf
1170 
1171  element->t0 = GST_BUFFER_TIMESTAMP(inbuf);
1172  element->offset0 = GST_BUFFER_OFFSET(inbuf);
1173 - element->next_output_offset = element->offset0 + get_output_length(element, GST_BUFFER_SIZE(inbuf) / element->unitsize);
1174 + element->next_output_offset = element->offset0;
1175 
1176  /*
1177  * be sure to flag the next output buffer as a discontinuity
1178  */
1179 
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);
1184 
1185 - } else
1186 + }
1187 + else {
1188  g_assert_cmpuint(GST_BUFFER_TIMESTAMP(inbuf), ==, gst_audioadapter_expected_timestamp(element->adapter));
1189 + }
1190 +
1191 
1192  element->next_input_offset = GST_BUFFER_OFFSET_END(inbuf);
1193 
1194 - /*
1195 - * Put the input buffer into the adapter first
1196 - * Then check the output buffer size that was expected.
1197 - * Note that the transform size function tells you what you can produce
1198 - * *after* receiving the next input buffer so this order is important
1199 - */
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));
1201 
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));
1204 
1205  gst_buffer_ref(inbuf); /* don't let calling code free buffer */
1206  gst_audioadapter_push(element->adapter, inbuf);
1207 - GST_INFO_OBJECT(element, "transform() adapter size is now %d (samples)", get_available_samples(element));
1208 -
1209 - expected_output_length = get_output_length(element, 0); // just check the output length based on what we have in the adapter already
1210 - expected_output_size = get_output_size(element, 0); // Ditto here
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));
1213 -
1214 + GST_INFO_OBJECT(element, "adapter_size %d (samples)", get_available_samples(element));
1215 +
1216 + // FIXME check the sanity of the output buffer
1217 
1218  /*
1219  * Handle the different possiblilities
1220  */
1221 
1222 + output_length = GST_BUFFER_SIZE(outbuf) / element->unitsize;
1223 +
1224  if (GST_BUFFER_SIZE(outbuf) == 0)
1225  set_metadata(element, outbuf, 0, FALSE);
1226  else {
1227 +
1228 +
1229  guint flushed = 0;
1230  guint processed = 0;
1231 - float *last = NULL;
1232 + gint input_offset;
1233 + gint kernel_offset;
1234 + gint output_offset;
1235 + gint f;
1236 + gint i;
1237  float *output = (float *) GST_BUFFER_DATA(outbuf);
1238 + memset(GST_BUFFER_DATA(outbuf), 0, GST_BUFFER_SIZE(outbuf)); // FIXME necesary?
1239 
1240 - // FIXME actually handle gaps properly
1241 - while ((get_available_samples(element) >= element->nrin) && (processed < expected_output_length)) {
1242 -
1243 - /* First copy the data we need */
1244 - gst_audioadapter_copy_samples(element->adapter, element->data, element->nrin, NULL, NULL);
1245 -
1246 - /* Resample each channel */
1247 - for (guint i = 0; i < element->channels; i++) {
1248 -
1249 - last = element->last + i * element->tapersampsout; // get a pointer to the history for this channel
1250 -
1251 - /* Adapt output for FFTW FIXME FIXME FIXME we
1252 - * need to avoid this copying around by making use of the advanced FFTW
1253 - * interface
1254 - */
1255 - for (guint j = 0; j < element->nrin; j++) {
1256 - element->rin[j] = element->data[i+j*element->channels];
1257 - }
1258 - /* Clear the output */
1259 - memset(element->cout, 0, sizeof(fftwf_complex) * element->ncout);
1260 -
1261 - /* taper */
1262 - applytaper(element->rin, element->tapersampsin, element->up);
1263 - applytaper(element->rin + element->nrin - element->tapersampsin, element->tapersampsin, element->down);
1264 -
1265 - /* resample */
1266 - fftwf_execute(element->fwdplan_in);
1267 - memcpy(element->cout, element->cin, sizeof(fftwf_complex) * element->ncin);
1268 - fftwf_execute(element->revplan_out);
1269 -
1270 - /* Blend the outputs */
1271 - blend(element->rout, last, 0, element->tapersampsout);
1272 - memcpy(last, element->rout + (element->nrout - element->tapersampsout), sizeof(*last) * element->tapersampsout);
1273 -
1274 - /* Adapt output for FFTW FIXME FIXME FIXME we
1275 - * need to avoid this copying around by making use of the advanced FFTW
1276 - * interface
1277 - */
1278 - for (guint j = 0; j < element->nrout-element->tapersampsout; j++) {
1279 - output[i+j*element->channels] = element->rout[j] / element->nrin;
1280 - }
1281 - }
1282 + GST_INFO_OBJECT(element, "Processing a %d sample output buffer from %d input", output_length);
1283 +
1284 + while (processed < output_length) {
1285 +
1286 + memset(element->workspace, 0, sizeof(float) * element->blocksampsin * element->channels); // FIXME necessary?
1287 
1288 - /* Then flush the data we will never need again */
1289 - // FIXME add a check that we have processed the correct number of samples
1290 - gst_audioadapter_flush_samples(element->adapter, element->nrin - element->tapersampsin);
1291 - flushed += element->nrin - element->tapersampsin;
1292 - processed += element->nrout - element->tapersampsout;
1293 - // Dont forget to increase the output pointer
1294 - output = (float *) GST_BUFFER_DATA(outbuf) + processed * element->channels;
1295 + // Special case to handle discontinuities: effectively zero pad. FIXME make this more elegant
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);
1298 + else
1299 + gst_audioadapter_copy_samples(element->adapter, element->workspace, element->blocksampsin, NULL, NULL);
1300 +
1301 + resample(output, element->kernel, element->workspace, element->kernel_length, element->factor, element->channels, element->blockstrideout);
1302 +
1303 + if (element->need_pretend) {
1304 + element->need_pretend = FALSE;
1305 + gst_audioadapter_flush_samples(element->adapter, element->blockstridein - element->half_length);
1306 + }
1307 + else
1308 + gst_audioadapter_flush_samples(element->adapter, element->blockstridein);
1309 + output += element->blockstrideout * element->channels;
1310 + processed += element->blockstrideout;
1311  }
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);
1316 
1317  }
1318  return result;
1319 @@ -613,14 +560,8 @@ static void finalize(GObject *object)
1320  * free resources
1321  */
1322 
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);
1333 
1334  /*
1335  * chain to parent class' finalize() method
1336 --
1337 1.8.3.2
1338 
1339 
1340 From 74a62f546d2e895a908d7acba4ffc560cdd9134b Mon Sep 17 00:00:00 2001
1341 From: CHAD RICHARD HANNA <crh184@psu.edu>
1342 Date: Thu, 26 Feb 2015 16:23:22 -0500
1343 Subject: [PATCH 3/8] update interpolator to time domain
1344 
1345 ---
1346  gstlal/gst/lal/gstlal_interpolator.h | 30 +++++++++++-------------------
1347  1 file changed, 11 insertions(+), 19 deletions(-)
1348 
1349 diff --git a/gstlal/gst/lal/gstlal_interpolator.h b/gstlal/gst/lal/gstlal_interpolator.h
1350 index e8be6cc..4860c79 100644
1351 --- a/gstlal/gst/lal/gstlal_interpolator.h
1352 +++ b/gstlal/gst/lal/gstlal_interpolator.h
1353 @@ -69,10 +69,11 @@ typedef struct _GSTLALInterpolatorClass GSTLALInterpolatorClass;
1354  struct _GSTLALInterpolator {
1355  GstBaseTransform element;
1356 
1357 + GstAudioAdapter *adapter;
1358 +
1359  gint inrate;
1360  gint outrate;
1361  guint channels;
1362 - GstAudioAdapter *adapter;
1363 
1364  /* Timestamp and offset bookeeping */
1365  guint64 t0;
1366 @@ -82,28 +83,19 @@ struct _GSTLALInterpolator {
1367  guint64 next_output_offset;
1368  GstClockTime next_output_timestamp;
1369  gboolean need_discont;
1370 + gboolean need_pretend;
1371 
1372  /* Variables to control the size of transforms */
1373 - guint nrin;
1374 - guint ncin;
1375 - guint nrout;
1376 - guint ncout;
1377 - guint tapersampsin;
1378 - guint tapersampsout;
1379 + guint unitsize;
1380  guint blocksampsin;
1381  guint blocksampsout;
1382 - guint unitsize;
1383 -
1384 - float *data;
1385 - float *up;
1386 - float *down;
1387 - float *last;
1388 - float *rin;
1389 - fftwf_complex *cin;
1390 - float *rout;
1391 - fftwf_complex *cout;
1392 - fftwf_plan fwdplan_in;
1393 - fftwf_plan revplan_out;
1394 + guint blockstridein;
1395 + guint blockstrideout;
1396 + guint factor;
1397 + guint half_length;
1398 + guint kernel_length;
1399 + float *kernel;
1400 + float *workspace;
1401  };
1402 
1403 
1404 --
1405 1.8.3.2
1406 
1407 
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
1412 
1413 ---
1414  gstlal/gst/lal/gstlal_interpolator.c | 97 +++++++++++++++++++-----------------
1415  1 file changed, 52 insertions(+), 45 deletions(-)
1416 
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
1421 @@ -46,6 +46,8 @@
1422  #include <math.h>
1423  #include <string.h>
1424  #include <fftw3.h>
1425 +#include <gsl/gsl_matrix.h>
1426 +#include <gsl/gsl_blas.h>
1427 
1428  /*
1429  * our own stuff
1430 @@ -62,46 +64,56 @@
1431 
1432  #define PI 3.141592653589793
1433 
1434 -static float* kernel(int half_length, int factor) {
1435 +gsl_vector_float** kernel(int half_length, int factor) {
1436  int kernel_length = (2 * half_length + 1) * factor;
1437  int domain = kernel_length / 2; // kernel length is gauranteed to be even
1438 - float *out = fftwf_alloc_real(kernel_length + 1);
1439 +
1440 + gsl_vector_float **vecs = malloc(sizeof(gsl_vector_float *) * factor);
1441 + for (int i = 0; i < factor; i++)
1442 + vecs[i] = gsl_vector_float_calloc(2 * half_length + 1);
1443 +
1444 + float *out = fftwf_malloc(sizeof(float) * (kernel_length + factor / 2));
1445 + memset(out, 0, (kernel_length + factor / 2) * sizeof(float));
1446 +
1447  float norm = 0.;
1448 
1449 - for (int j = 0; j < kernel_length + 1; j++) {
1450 - float x = j - domain;
1451 - if (j == domain)
1452 - out[j] = 1.;
1453 - else
1454 - out[j] = sin(PI * x / factor) / (PI * x / factor) * (1. - x*x / domain / domain);
1455 + for (int j = 0; j < 2 * half_length + 1; j++) {
1456 + for (int i = 0; i < factor; i++) {
1457 + int x = j * factor + i - domain;
1458 + if (x == 0)
1459 + out[x + domain] = 1.;
1460 + else
1461 + out[x + domain] = sin(PI * x / factor) / (PI * x / factor) * (1. - (float) x*x / domain / domain);
1462 + norm += out[x + domain] * out[x + domain];
1463 + }
1464  }
1465 
1466 - for (int i = 0; i < kernel_length + 1; i++)
1467 - norm += out[i] * out[i];
1468 -
1469 - for (int i = 0; i < kernel_length + 1; i++)
1470 - out[i] /= sqrt(norm / factor);
1471 + for (int i = 0; i < 2 * half_length+1; i++) {
1472 + for (int j = 0; j < factor; j++) {
1473 + int index = i * factor + j + factor / 2; //FIXME FIXME FIXME this offset belongs above
1474 + gsl_vector_float_set(vecs[factor - j - 1], i, out[index] / sqrt(norm / factor));
1475 + }
1476 + }
1477 
1478 - return out;
1479 + free(out);
1480 + return vecs;
1481  }
1482 
1483 -void convolve(float *output, float *thiskernel, float *input, guint kernel_length, guint factor, guint channels) {
1484 - for (guint i = 1; i < kernel_length; i++) {
1485 - *output += (*thiskernel) * (*input);
1486 - input += channels;
1487 - thiskernel += factor;
1488 - }
1489 +void convolve(float *output, gsl_vector_float *thiskernel, float *input, guint kernel_length, guint factor, guint channels) {
1490 + gsl_vector_float_view output_vector = gsl_vector_float_view_array(output, channels);
1491 + gsl_matrix_float_view input_matrix = gsl_matrix_float_view_array(input, kernel_length, channels);
1492 + gsl_blas_sgemv (CblasTrans, 1.0, &(input_matrix.matrix), thiskernel, 0, &(output_vector.vector));
1493  return;
1494  }
1495 
1496 -void resample(float *output, float *thiskernel, float *input, guint kernel_length, guint factor, guint channels, guint blockstrideout) {
1497 +void resample(float *output, gsl_vector_float **thiskernel, float *input, guint kernel_length, guint factor, guint channels, guint blockstrideout) {
1498  guint kernel_offset, output_offset, input_offset;
1499 - for (gint samp = 0; samp < blockstrideout; samp++) {
1500 - kernel_offset = factor - samp % factor + factor / 2;
1501 + for (guint samp = 0; samp < blockstrideout; samp++) {
1502 + kernel_offset = samp % factor;
1503  output_offset = samp * channels;
1504  input_offset = (samp / factor) * channels; // first input sample
1505 - for (gint chan = 0; chan < channels; chan++)
1506 - convolve(output + output_offset + chan, thiskernel + kernel_offset, input + input_offset + chan + channels, kernel_length, factor, channels);
1507 + // FIXME FIXME FIXME should this + channels really be there??
1508 + convolve(output + output_offset, thiskernel[kernel_offset], input + input_offset + channels, kernel_length, factor, channels);
1509  }
1510  return;
1511  }
1512 @@ -270,7 +282,7 @@ static gboolean set_caps (GstBaseTransform * base, GstCaps * incaps, GstCaps * o
1513  element->kernel = kernel(element->half_length, element->factor);
1514 
1515  // Assume that we process inrate worth of samples at a time (e.g. 1s stride)
1516 - element->blockstridein = 128;//element->inrate;
1517 + element->blockstridein = element->inrate;
1518  element->blocksampsin = element->blockstridein + element->kernel_length;
1519  element->blockstrideout = element->blockstridein * element->factor;//element->outrate;
1520  element->blocksampsout = element->blockstrideout + (element->kernel_length) * element->factor;
1521 @@ -278,9 +290,8 @@ static gboolean set_caps (GstBaseTransform * base, GstCaps * incaps, GstCaps * o
1522  GST_INFO_OBJECT(element, "blocksampsin %d, blocksampsout %d, blockstridein %d, blockstrideout %d", element->blocksampsin, element->blocksampsout, element->blockstridein, element->blockstrideout);
1523 
1524  if (element->workspace)
1525 - free(element->workspace);
1526 - element->workspace = (float *) fftw_alloc_real(element->blocksampsin * element->channels);
1527 - memset(element->workspace, 0, sizeof(float) * element->blocksampsin * element->channels);
1528 + gsl_matrix_float_free(element->workspace);
1529 + element->workspace = gsl_matrix_float_calloc (element->blocksampsin, element->channels);
1530 
1531  return TRUE;
1532  }
1533 @@ -451,7 +462,7 @@ static void set_metadata(GSTLALInterpolator *element, GstBuffer *buf, guint64 ou
1534  static GstFlowReturn transform(GstBaseTransform *trans, GstBuffer *inbuf, GstBuffer *outbuf)
1535  {
1536  GSTLALInterpolator *element = GSTLAL_INTERPOLATOR(trans);
1537 - guint input_length, output_length, expected_output_size;
1538 + guint output_length;
1539  GstFlowReturn result = GST_FLOW_OK;
1540 
1541  g_assert(GST_BUFFER_TIMESTAMP_IS_VALID(inbuf));
1542 @@ -511,29 +522,24 @@ static GstFlowReturn transform(GstBaseTransform *trans, GstBuffer *inbuf, GstBuf
1543  else {
1544 
1545 
1546 - guint flushed = 0;
1547  guint processed = 0;
1548 - gint input_offset;
1549 - gint kernel_offset;
1550 - gint output_offset;
1551 - gint f;
1552 - gint i;
1553  float *output = (float *) GST_BUFFER_DATA(outbuf);
1554 - memset(GST_BUFFER_DATA(outbuf), 0, GST_BUFFER_SIZE(outbuf)); // FIXME necesary?
1555 + //memset(GST_BUFFER_DATA(outbuf), 0, GST_BUFFER_SIZE(outbuf)); // FIXME necesary?
1556 
1557  GST_INFO_OBJECT(element, "Processing a %d sample output buffer from %d input", output_length);
1558 
1559  while (processed < output_length) {
1560 
1561 - memset(element->workspace, 0, sizeof(float) * element->blocksampsin * element->channels); // FIXME necessary?
1562 
1563  // Special case to handle discontinuities: effectively zero pad. FIXME make this more elegant
1564 - if (element->need_pretend)
1565 - gst_audioadapter_copy_samples(element->adapter, element->workspace + (element->half_length) * element->channels, element->blocksampsin - element->half_length, NULL, NULL);
1566 + if (element->need_pretend) {
1567 + memset(element->workspace->data, 0, sizeof(float) * element->workspace->size1 * element->workspace->size2); // FIXME necessary?
1568 + gst_audioadapter_copy_samples(element->adapter, element->workspace->data + (element->half_length) * element->channels, element->blocksampsin - element->half_length, NULL, NULL);
1569 + }
1570  else
1571 - gst_audioadapter_copy_samples(element->adapter, element->workspace, element->blocksampsin, NULL, NULL);
1572 + gst_audioadapter_copy_samples(element->adapter, element->workspace->data, element->blocksampsin, NULL, NULL);
1573 
1574 - resample(output, element->kernel, element->workspace, element->kernel_length, element->factor, element->channels, element->blockstrideout);
1575 + resample(output, element->kernel, element->workspace->data, element->kernel_length, element->factor, element->channels, element->blockstrideout);
1576 
1577  if (element->need_pretend) {
1578  element->need_pretend = FALSE;
1579 @@ -559,9 +565,10 @@ static void finalize(GObject *object)
1580  /*
1581  * free resources
1582  */
1583 -
1584 - free(element->kernel);
1585 - free(element->workspace);
1586 +
1587 + for (guint i = 0; i < element->factor; i++)
1588 + gsl_vector_float_free(element->kernel[i]);
1589 + gsl_matrix_float_free(element->workspace);
1590 
1591  /*
1592  * chain to parent class' finalize() method
1593 --
1594 1.8.3.2
1595 
1596 
1597 From dec37f9ffa00c2d4fc86b2ffeaea76ef228f94b4 Mon Sep 17 00:00:00 2001
1598 From: CHAD RICHARD HANNA <crh184@psu.edu>
1599 Date: Fri, 27 Feb 2015 14:09:36 -0500
1600 Subject: [PATCH 5/8] gstlal_interpolator: additional vectorization
1601 
1602 ---
1603  gstlal/gst/lal/gstlal_interpolator.h | 6 ++++--
1604  1 file changed, 4 insertions(+), 2 deletions(-)
1605 
1606 diff --git a/gstlal/gst/lal/gstlal_interpolator.h b/gstlal/gst/lal/gstlal_interpolator.h
1607 index 4860c79..2d28cfa 100644
1608 --- a/gstlal/gst/lal/gstlal_interpolator.h
1609 +++ b/gstlal/gst/lal/gstlal_interpolator.h
1610 @@ -34,6 +34,7 @@
1611  #include <gst/base/gstadapter.h>
1612  #include <gst/base/gstbasetransform.h>
1613  #include <fftw3.h>
1614 +#include <gsl/gsl_matrix.h>
1615 
1616  #include <gstlal/gstlal.h>
1617  #include <gstlal/gstaudioadapter.h>
1618 @@ -94,8 +95,9 @@ struct _GSTLALInterpolator {
1619  guint factor;
1620  guint half_length;
1621  guint kernel_length;
1622 - float *kernel;
1623 - float *workspace;
1624 + //float *kernel;
1625 + gsl_vector_float **kernel;
1626 + gsl_matrix_float *workspace;
1627  };
1628 
1629 
1630 --
1631 1.8.3.2
1632 
1633 
1634 From edd27dd3429ab1f7382227bdf2853b2b0fa6c488 Mon Sep 17 00:00:00 2001
1635 From: CHAD RICHARD HANNA <crh184@psu.edu>
1636 Date: Fri, 27 Feb 2015 15:09:35 -0500
1637 Subject: [PATCH 6/8] lal_interpolator: fix off by one
1638 
1639 ---
1640  gstlal/gst/lal/gstlal_interpolator.c | 9 ++++++---
1641  1 file changed, 6 insertions(+), 3 deletions(-)
1642 
1643 diff --git a/gstlal/gst/lal/gstlal_interpolator.c b/gstlal/gst/lal/gstlal_interpolator.c
1644 index 97741ab..1c4dee8 100644
1645 --- a/gstlal/gst/lal/gstlal_interpolator.c
1646 +++ b/gstlal/gst/lal/gstlal_interpolator.c
1647 @@ -88,9 +88,11 @@ gsl_vector_float** kernel(int half_length, int factor) {
1648  }
1649  }
1650 
1651 - for (int i = 0; i < 2 * half_length+1; i++) {
1652 + for (int i = 1; i < 2 * half_length+1; i++) {
1653  for (int j = 0; j < factor; j++) {
1654 - int index = i * factor + j + factor / 2; //FIXME FIXME FIXME this offset belongs above
1655 + int index = i * factor + j - factor / 2; //FIXME FIXME FIXME this offset belongs above
1656 + if (factor > 1)
1657 + index += 1;
1658  gsl_vector_float_set(vecs[factor - j - 1], i, out[index] / sqrt(norm / factor));
1659  }
1660  }
1661 @@ -113,7 +115,8 @@ void resample(float *output, gsl_vector_float **thiskernel, float *input, guint
1662  output_offset = samp * channels;
1663  input_offset = (samp / factor) * channels; // first input sample
1664  // FIXME FIXME FIXME should this + channels really be there??
1665 - convolve(output + output_offset, thiskernel[kernel_offset], input + input_offset + channels, kernel_length, factor, channels);
1666 + //convolve(output + output_offset, thiskernel[kernel_offset], input + input_offset + channels, kernel_length, factor, channels);
1667 + convolve(output + output_offset, thiskernel[kernel_offset], input + input_offset, kernel_length, factor, channels);
1668  }
1669  return;
1670  }
1671 --
1672 1.8.3.2
1673 
1674 
1675 From 84bee4ed8256f7054bf40c687c5ea4ea7a8bac1a Mon Sep 17 00:00:00 2001
1676 From: CHAD RICHARD HANNA <crh184@psu.edu>
1677 Date: Sat, 28 Feb 2015 09:12:37 -0500
1678 Subject: [PATCH 7/8] gstlal_interpolator: add minimal gap support
1679 
1680 ---
1681  gstlal/gst/lal/gstlal_interpolator.c | 13 ++++++++-----
1682  1 file changed, 8 insertions(+), 5 deletions(-)
1683 
1684 diff --git a/gstlal/gst/lal/gstlal_interpolator.c b/gstlal/gst/lal/gstlal_interpolator.c
1685 index 1c4dee8..c099256 100644
1686 --- a/gstlal/gst/lal/gstlal_interpolator.c
1687 +++ b/gstlal/gst/lal/gstlal_interpolator.c
1688 @@ -108,14 +108,16 @@ void convolve(float *output, gsl_vector_float *thiskernel, float *input, guint k
1689  return;
1690  }
1691 
1692 -void resample(float *output, gsl_vector_float **thiskernel, float *input, guint kernel_length, guint factor, guint channels, guint blockstrideout) {
1693 +void resample(float *output, gsl_vector_float **thiskernel, float *input, guint kernel_length, guint factor, guint channels, guint blockstrideout, gboolean nongap) {
1694 + if (!nongap) {
1695 + memset(output, 0, sizeof(float) * blockstrideout * channels);
1696 + return;
1697 + }
1698  guint kernel_offset, output_offset, input_offset;
1699  for (guint samp = 0; samp < blockstrideout; samp++) {
1700  kernel_offset = samp % factor;
1701  output_offset = samp * channels;
1702  input_offset = (samp / factor) * channels; // first input sample
1703 - // FIXME FIXME FIXME should this + channels really be there??
1704 - //convolve(output + output_offset, thiskernel[kernel_offset], input + input_offset + channels, kernel_length, factor, channels);
1705  convolve(output + output_offset, thiskernel[kernel_offset], input + input_offset, kernel_length, factor, channels);
1706  }
1707  return;
1708 @@ -467,6 +469,7 @@ static GstFlowReturn transform(GstBaseTransform *trans, GstBuffer *inbuf, GstBuf
1709  GSTLALInterpolator *element = GSTLAL_INTERPOLATOR(trans);
1710  guint output_length;
1711  GstFlowReturn result = GST_FLOW_OK;
1712 + gboolean copied_nongap;
1713 
1714  g_assert(GST_BUFFER_TIMESTAMP_IS_VALID(inbuf));
1715  g_assert(GST_BUFFER_DURATION_IS_VALID(inbuf));
1716 @@ -537,12 +540,12 @@ static GstFlowReturn transform(GstBaseTransform *trans, GstBuffer *inbuf, GstBuf
1717  // Special case to handle discontinuities: effectively zero pad. FIXME make this more elegant
1718  if (element->need_pretend) {
1719  memset(element->workspace->data, 0, sizeof(float) * element->workspace->size1 * element->workspace->size2); // FIXME necessary?
1720 - gst_audioadapter_copy_samples(element->adapter, element->workspace->data + (element->half_length) * element->channels, element->blocksampsin - element->half_length, NULL, NULL);
1721 + gst_audioadapter_copy_samples(element->adapter, element->workspace->data + (element->half_length) * element->channels, element->blocksampsin - element->half_length, NULL, &copied_nongap);
1722  }
1723  else
1724  gst_audioadapter_copy_samples(element->adapter, element->workspace->data, element->blocksampsin, NULL, NULL);
1725 
1726 - resample(output, element->kernel, element->workspace->data, element->kernel_length, element->factor, element->channels, element->blockstrideout);
1727 + resample(output, element->kernel, element->workspace->data, element->kernel_length, element->factor, element->channels, element->blockstrideout, copied_nongap);
1728 
1729  if (element->need_pretend) {
1730  element->need_pretend = FALSE;
1731 --
1732 1.8.3.2
1733 
1734 
1735 From 816cab915aeaff7ceca017c299eda894fde92432 Mon Sep 17 00:00:00 2001
1736 From: CHAD RICHARD HANNA <crh184@psu.edu>
1737 Date: Sat, 28 Feb 2015 10:01:15 -0500
1738 Subject: [PATCH 8/8] gstlal_interpolator: actually allow output buffers to be
1739  marked as gap
1740 
1741 ---
1742  gstlal/gst/lal/gstlal_interpolator.c | 7 ++++---
1743  1 file changed, 4 insertions(+), 3 deletions(-)
1744 
1745 diff --git a/gstlal/gst/lal/gstlal_interpolator.c b/gstlal/gst/lal/gstlal_interpolator.c
1746 index c099256..c091d3e 100644
1747 --- a/gstlal/gst/lal/gstlal_interpolator.c
1748 +++ b/gstlal/gst/lal/gstlal_interpolator.c
1749 @@ -286,8 +286,9 @@ static gboolean set_caps (GstBaseTransform * base, GstCaps * incaps, GstCaps * o
1750  free(element->kernel);
1751  element->kernel = kernel(element->half_length, element->factor);
1752 
1753 - // Assume that we process inrate worth of samples at a time (e.g. 1s stride)
1754 - element->blockstridein = element->inrate;
1755 + // Keep blockstride small to prevent GAPS from growing to be large
1756 + // FIXME probably this should be decoupled
1757 + element->blockstridein = 32;//element->inrate;
1758  element->blocksampsin = element->blockstridein + element->kernel_length;
1759  element->blockstrideout = element->blockstridein * element->factor;//element->outrate;
1760  element->blocksampsout = element->blockstrideout + (element->kernel_length) * element->factor;
1761 @@ -557,7 +558,7 @@ static GstFlowReturn transform(GstBaseTransform *trans, GstBuffer *inbuf, GstBuf
1762  processed += element->blockstrideout;
1763  }
1764  GST_INFO_OBJECT(element, "Processed a %d samples", processed);
1765 - set_metadata(element, outbuf, output_length, FALSE);
1766 + set_metadata(element, outbuf, output_length, !copied_nongap);
1767 
1768  }
1769  return result;
1770 --
1771 1.8.3.2
1772