Index: src/ai/conv1d.c
===================================================================
--- src/ai/conv1d.c	(revision d0ef4b7f97434666595dcfb02effc0ebaee2c87f)
+++ src/ai/conv1d.c	(revision d0ef4b7f97434666595dcfb02effc0ebaee2c87f)
@@ -0,0 +1,282 @@
+/*
+  Copyright (C) 2018 Paul Brossier <piem@aubio.org>
+
+  This file is part of aubio.
+
+  aubio is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  aubio is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with aubio.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+
+#include "aubio_priv.h"
+#include "fmat.h"
+#include "tensor.h"
+#include "conv1d.h"
+
+typedef enum
+{
+  PAD_SAME = 0,
+  PAD_VALID = 1,
+  PAD_CAUSAL = 2, // TODO (1d only, for dilated convolution)
+} aubio_conv1d_padding_type;
+
+struct _aubio_conv1d_t {
+  // define internals here
+  uint_t n_filters;
+  uint_t kernel_shape;     // kernel sizes
+  uint_t stride_shape;     // stride sizes
+
+  aubio_conv1d_padding_type padding_mode;
+
+  // these will be set after calling get_output_shape
+  aubio_tensor_t *kernel;
+  fvec_t *bias;
+  uint_t output_shape[2];     // shape of output
+  uint_t padding_start;    // {top, left} padding
+};
+
+static void aubio_conv1d_debug(aubio_conv1d_t *c, aubio_tensor_t *input_tensor);
+
+aubio_conv1d_t *new_aubio_conv1d(uint_t n_filters, uint_t kernel_shape[1])
+{
+  aubio_conv1d_t *c = AUBIO_NEW(aubio_conv1d_t);
+
+  // validate input parameters
+  AUBIO_GOTO_FAILURE((sint_t)n_filters >= 1);
+  AUBIO_GOTO_FAILURE((sint_t)kernel_shape[0] >= 1);
+
+  // set internal variables
+  c->n_filters = n_filters;
+  c->kernel_shape = kernel_shape[0];
+
+  // default to padding_mode="valid"
+  c->padding_mode = PAD_VALID;
+  // set default stride_shape to (1)
+  uint_t stride_shape[1] = {1};
+  aubio_conv1d_set_stride(c, stride_shape);
+
+  return c;
+
+failure:
+  del_aubio_conv1d(c);
+  return NULL;
+}
+
+void del_aubio_conv1d(aubio_conv1d_t *c)
+{
+  AUBIO_ASSERT(c);
+  // destroy internals here
+  if (c->kernel) {
+    del_aubio_tensor(c->kernel);
+  }
+  if (c->bias)
+    del_fvec(c->bias);
+  AUBIO_FREE(c);
+}
+
+
+uint_t aubio_conv1d_set_stride(aubio_conv1d_t *c, uint_t stride[1])
+{
+  if ((sint_t)stride[0] < 1) return AUBIO_FAIL;
+  c->stride_shape = stride[0];
+  return AUBIO_OK;
+}
+
+uint_t aubio_conv1d_get_stride(aubio_conv1d_t *c)
+{
+  return c->stride_shape;
+}
+
+uint_t aubio_conv1d_get_output_shape(aubio_conv1d_t *c,
+    aubio_tensor_t *input_tensor,
+    uint_t *shape)
+{
+  uint_t output_shape[2] = {0, c->n_filters};
+  uint_t padding_start = 0;
+
+  // check input parameters
+  AUBIO_ASSERT(input_tensor);
+  AUBIO_ASSERT(shape);
+
+  // reset output array
+  shape[0] = 0;
+  shape[1] = 0;
+
+  switch (c->padding_mode) {
+    case PAD_SAME:
+      // compute output shape
+      output_shape[0] = (uint_t)CEIL(input_tensor->dims[0]
+          / (smpl_t)c->stride_shape);
+
+      uint_t padding_shape;  // total amount of padding
+      padding_shape = (output_shape[0] - 1) * c->stride_shape +
+        c->kernel_shape - input_tensor->dims[0];
+
+      padding_start = FLOOR(padding_shape / 2);
+      break;
+    case PAD_VALID:
+      output_shape[0] = (input_tensor->dims[0] - c->kernel_shape + 1)
+        / c->stride_shape;
+
+      padding_start = 0;
+      break;
+    case PAD_CAUSAL:
+      // TODO
+      return AUBIO_FAIL;
+    default:
+      return AUBIO_FAIL;
+  }
+
+  uint_t kernel_dims[3];
+  kernel_dims[0] = c->kernel_shape; // filter length
+  kernel_dims[1] = input_tensor->dims[1]; // channels
+  kernel_dims[2] = c->n_filters; // outputs
+
+  if (c->kernel) del_aubio_tensor(c->kernel);
+  if (c->bias) del_fvec(c->bias);
+
+  c->kernel = new_aubio_tensor(3, kernel_dims);
+  if (!c->kernel) return AUBIO_FAIL;
+  c->bias = new_fvec(c->n_filters);
+
+  // set internals upon success
+  c->output_shape[0] = output_shape[0];
+  c->output_shape[1] = output_shape[1];
+
+  c->padding_start = padding_start;
+
+  // set output
+  shape[0] = output_shape[0];
+  shape[1] = output_shape[1];
+
+  aubio_conv1d_debug(c, input_tensor);
+
+  return AUBIO_OK;
+}
+
+void aubio_conv1d_debug(aubio_conv1d_t *c, aubio_tensor_t *input_tensor)
+{
+  // print some info
+  AUBIO_ASSERT(c);
+  uint_t n_params = (c->kernel->dims[0] * c->kernel->dims[2] + 1)
+    * c->kernel->dims[1] * c->kernel->dims[3];
+  AUBIO_DBG("conv1d: input (%d, %d) ¤ conv1d (%d, %d, %d)"
+      " : (%d, %d)"
+      " (%d params, stride (%d), pad_start [%d])\n",
+    input_tensor->dims[0], input_tensor->dims[1],
+    c->kernel->dims[0], c->kernel->dims[1], c->kernel->dims[2],
+    c->output_shape[0], c->output_shape[1],
+    n_params,
+    c->stride_shape,
+    -c->padding_start);
+}
+
+uint_t aubio_conv1d_check_output_shape(aubio_conv1d_t *c,
+    aubio_tensor_t *input_tensor,
+    aubio_tensor_t *activations)
+{
+  // fetch output_shape if it hasn't been done before
+  if (c->output_shape[0] == 0 ||
+      c->output_shape[1] == 0) {
+    if (!aubio_conv1d_get_output_shape(c, input_tensor, c->output_shape)) {
+      return AUBIO_FAIL;
+    }
+  }
+
+  // check we have as many filters as expected activation outputs
+  if (activations->dims[1] != c->n_filters) return AUBIO_FAIL;
+  if (activations->dims[1] != c->kernel->dims[2]) return AUBIO_FAIL;
+  if (input_tensor->dims[1] != c->kernel->dims[1]) return AUBIO_FAIL;
+
+  // check tensor activations has the expected sizes
+  if (c->output_shape[0] != activations->dims[0]) return AUBIO_FAIL;
+  if (c->output_shape[1] != activations->dims[1]) return AUBIO_FAIL;
+  return AUBIO_OK;
+}
+
+void aubio_conv1d_do(aubio_conv1d_t *c, aubio_tensor_t *input_tensor,
+    aubio_tensor_t *activations)
+{
+  uint_t i, j, k, a;
+  uint_t stride_a, kk;
+  sint_t x;
+  smpl_t s, w, bias, acc;
+
+  AUBIO_ASSERT(c && input_tensor && activations);
+  // check we have the correct output activation sizes
+  if (aubio_conv1d_check_output_shape(c, input_tensor, activations))
+  {
+    AUBIO_ERR("conv1d: check_output_shape failed\n");
+    return;
+  }
+
+  // for each kernel filter k
+  for (i = 0; i < activations->dims[1]; i++) {
+    // get bias
+    bias = c->bias->data[i];
+    stride_a = 0; // k * c->stride_shape
+    // for each output
+    for (j = 0; j < activations->dims[0]; j++) {
+      // reset output
+      acc = 0;
+      // compute convolution for one kernel
+      for (a = 0; a < c->kernel_shape; a++) {
+        x = stride_a + a - c->padding_start;
+        if ((x > -1) && (x < (sint_t)input_tensor->dims[0])) {
+          kk = 0;
+          // for each input channel
+          for (k = 0; k < input_tensor->dims[1]; k++) {
+            // get kernel weight
+            w = c->kernel->data[a][kk + i];
+            // get input sample
+            s = input_tensor->data[x][k];
+            acc += w * s;
+            kk += c->kernel->dims[2];
+          }
+        }
+      }
+      stride_a += c->stride_shape;
+      // apply bias
+      acc += bias;
+      // compute RELU
+      activations->data[j][i] = MAX(acc, 0);
+    }
+  }
+}
+
+uint_t aubio_conv1d_set_padding_mode(aubio_conv1d_t *c,
+    const char_t *padding_mode)
+{
+  AUBIO_ASSERT(c && padding_mode);
+  if (strncmp(padding_mode, "same", PATH_MAX) == 0) {
+    c->padding_mode = PAD_SAME;
+  } else if (strncmp(padding_mode, "valid", PATH_MAX) == 0) {
+    c->padding_mode = PAD_VALID;
+  } else {
+    return AUBIO_FAIL;
+  }
+  return AUBIO_OK;
+}
+
+aubio_tensor_t *aubio_conv1d_get_kernel(aubio_conv1d_t* c)
+{
+  AUBIO_ASSERT(c && c->kernel);
+  return c->kernel;
+}
+
+fvec_t *aubio_conv1d_get_bias(aubio_conv1d_t* c)
+{
+  AUBIO_ASSERT(c && c->bias);
+  return c->bias;
+}
Index: src/ai/conv1d.h
===================================================================
--- src/ai/conv1d.h	(revision d0ef4b7f97434666595dcfb02effc0ebaee2c87f)
+++ src/ai/conv1d.h	(revision d0ef4b7f97434666595dcfb02effc0ebaee2c87f)
@@ -0,0 +1,61 @@
+/*
+  Copyright (C) 2018 Paul Brossier <piem@aubio.org>
+
+  This file is part of aubio.
+
+  aubio is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  aubio is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with aubio.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef AUBIO_CONV1D_H
+#define AUBIO_CONV1D_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct _aubio_conv1d_t aubio_conv1d_t;
+
+/** create a new conv1d layer */
+aubio_conv1d_t *new_aubio_conv1d(uint_t filters, uint_t kernel_shape[1]);
+
+/** perform forward 1D convolution */
+void aubio_conv1d_do(aubio_conv1d_t *t, aubio_tensor_t *input_tensor,
+        aubio_tensor_t *activations);
+
+/** TODO: implement */
+void aubio_conv1d_train(aubio_conv1d_t *t, aubio_tensor_t *input_tensor);
+
+/** get conv1d weights */
+aubio_tensor_t *aubio_conv1d_get_kernel(aubio_conv1d_t *t);
+
+/** get conv1d biases */
+fvec_t *aubio_conv1d_get_bias(aubio_conv1d_t *t);
+
+/** set conv1d stride */
+uint_t aubio_conv1d_set_stride(aubio_conv1d_t *c, uint_t stride[1]);
+
+uint_t aubio_conv1d_set_padding_mode(aubio_conv1d_t *c,
+    const char_t *padding_mode);
+
+uint_t aubio_conv1d_get_output_shape(aubio_conv1d_t *t,
+        aubio_tensor_t *input_tensor, uint_t *shape);
+
+void del_aubio_conv1d(aubio_conv1d_t *t);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_CONV1D_H */
Index: src/ai/maxpool1d.c
===================================================================
--- src/ai/maxpool1d.c	(revision d0ef4b7f97434666595dcfb02effc0ebaee2c87f)
+++ src/ai/maxpool1d.c	(revision d0ef4b7f97434666595dcfb02effc0ebaee2c87f)
@@ -0,0 +1,98 @@
+/*
+  Copyright (C) 2018 Paul Brossier <piem@aubio.org>
+
+  This file is part of aubio.
+
+  aubio is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  aubio is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with aubio.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "aubio_priv.h"
+#include "fmat.h"
+#include "tensor.h"
+#include "maxpool1d.h"
+
+#include <float.h> // FLT_MAX
+
+struct _aubio_maxpool1d_t {
+  uint_t pool_size;
+  uint_t stride;
+};
+
+static void aubio_maxpool1d_debug(aubio_maxpool1d_t *c,
+    aubio_tensor_t *input_tensor);
+
+aubio_maxpool1d_t *new_aubio_maxpool1d(uint_t pool_size[1])
+{
+  aubio_maxpool1d_t *c = AUBIO_NEW(aubio_maxpool1d_t);
+
+  AUBIO_GOTO_FAILURE((sint_t)pool_size[0] > 0);
+
+  c->pool_size = pool_size[0];
+
+  c->stride = 1;
+
+  return c;
+
+failure:
+  del_aubio_maxpool1d(c);
+  return NULL;
+}
+
+void del_aubio_maxpool1d(aubio_maxpool1d_t* c) {
+  AUBIO_ASSERT(c);
+  AUBIO_FREE(c);
+}
+
+void aubio_maxpool1d_debug(aubio_maxpool1d_t *c, aubio_tensor_t *input_tensor)
+{
+  AUBIO_DBG("maxpool1d: input (%d, %d) ¤ maxpool1d (pool_size = (%d)) ->"
+      " (%d, %d) (no params)\n",
+      input_tensor->dims[0],
+      input_tensor->dims[1],
+      c->pool_size,
+      input_tensor->dims[0] / c->pool_size,
+      input_tensor->dims[1]);
+}
+
+uint_t aubio_maxpool1d_get_output_shape(aubio_maxpool1d_t *c,
+    aubio_tensor_t *input, uint_t *shape)
+{
+  AUBIO_ASSERT(c);
+  AUBIO_ASSERT(shape && sizeof(shape) == 2*sizeof(uint_t));
+  AUBIO_ASSERT(input);
+  shape[0] = input->dims[0] / c->pool_size;
+  shape[1] = input->dims[1];
+
+  aubio_maxpool1d_debug(c, input);
+
+  return AUBIO_OK;
+}
+
+void aubio_maxpool1d_do(aubio_maxpool1d_t *c, aubio_tensor_t *input_tensor,
+    aubio_tensor_t *output_tensor)
+{
+  uint_t i, j, a;
+  AUBIO_ASSERT(c && input_tensor && output_tensor);
+
+  for (j = 0; j < output_tensor->dims[1]; j++) {
+    for (i = 0; i < output_tensor->dims[0]; i++) {
+      smpl_t m = -FLT_MAX;
+      for (a = 0; a < c->pool_size; a++) {
+        m = MAX(m, input_tensor->data[i * c->pool_size + a][j]);
+      }
+      output_tensor->data[i][j] = m;
+    }
+  }
+}
Index: src/ai/maxpool1d.h
===================================================================
--- src/ai/maxpool1d.h	(revision d0ef4b7f97434666595dcfb02effc0ebaee2c87f)
+++ src/ai/maxpool1d.h	(revision d0ef4b7f97434666595dcfb02effc0ebaee2c87f)
@@ -0,0 +1,45 @@
+/*
+  Copyright (C) 2018 Paul Brossier <piem@aubio.org>
+
+  This file is part of aubio.
+
+  aubio is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  aubio is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with aubio.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef AUBIO_MAXPOOL1D_H
+#define AUBIO_MAXPOOL1D_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct _aubio_maxpool1d_t aubio_maxpool1d_t;
+
+aubio_maxpool1d_t *new_aubio_maxpool1d(uint_t pool_size[1]);
+
+uint_t aubio_maxpool1d_get_output_shape(aubio_maxpool1d_t *t,
+        aubio_tensor_t *input, uint_t *shape);
+
+void aubio_maxpool1d_do(aubio_maxpool1d_t *t,
+        aubio_tensor_t *input_tensor,
+        aubio_tensor_t *activations);
+
+void del_aubio_maxpool1d(aubio_maxpool1d_t *t);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_MAXPOOL1D_H */
Index: src/ai/tensor.c
===================================================================
--- src/ai/tensor.c	(revision d0ef4b7f97434666595dcfb02effc0ebaee2c87f)
+++ src/ai/tensor.c	(revision d0ef4b7f97434666595dcfb02effc0ebaee2c87f)
@@ -0,0 +1,95 @@
+#include "aubio_priv.h"
+#include "fmat.h"
+#include "tensor.h"
+
+aubio_tensor_t *new_aubio_tensor(uint_t n_dims, uint_t *dims)
+{
+  aubio_tensor_t *c = AUBIO_NEW(aubio_tensor_t);
+  uint_t i;
+
+  if ((sint_t)n_dims <= 0) goto failure;
+  for (i = 0; i < n_dims; i++) {
+    if ((sint_t)dims[i] <= 0) goto failure;
+  }
+
+  c->n_dims = n_dims;
+  c->items_per_row = 1;
+  //c->dims = AUBIO_ARRAY(uint_t, n_dims);
+  c->dims[0] = dims[0];
+  for (i = 1; i < n_dims; i++) {
+    c->dims[i] = dims[i];
+    c->items_per_row *= dims[i];
+  }
+  c->n_items = c->items_per_row * dims[0];
+  c->data = AUBIO_ARRAY(smpl_t*, dims[0]);
+  c->data[0] = AUBIO_ARRAY(smpl_t, c->n_items);
+  for (i = 1; i < c->dims[0]; i++) {
+    c->data[i] = c->data[0] + i * c->items_per_row;
+  }
+
+  return c;
+
+failure:
+  del_aubio_tensor(c);
+  return NULL;
+}
+
+void del_aubio_tensor(aubio_tensor_t *c)
+{
+  AUBIO_ASSERT(c);
+  if (c->data) {
+    if (c->data[0]) {
+      AUBIO_FREE(c->data[0]);
+    }
+    AUBIO_FREE(c->data);
+  }
+  //if (c->dims)
+  //  AUBIO_FREE(c->dims);
+  AUBIO_FREE(c);
+}
+
+uint_t aubio_tensor_as_fvec(aubio_tensor_t *c, fvec_t *o) {
+  if (c->n_dims  != 1) return AUBIO_FAIL;
+  if (c->dims[0] <= 0) return AUBIO_FAIL;
+  o->length = c->dims[0];
+  o->data = c->data[0];
+  return AUBIO_OK;
+}
+
+uint_t aubio_fvec_as_tensor(fvec_t *o, aubio_tensor_t *c) {
+  if (o == NULL) return AUBIO_FAIL;
+  c->n_dims = 1;
+  c->dims[0] = o->length;
+  c->data = &o->data;
+  return AUBIO_OK;
+}
+
+uint_t aubio_tensor_as_fmat(aubio_tensor_t *c, fmat_t *o) {
+  if (c->n_dims  != 2) return AUBIO_FAIL;
+  if (c->dims[0] <= 0) return AUBIO_FAIL;
+  if (c->dims[1] <= 0) return AUBIO_FAIL;
+  o->height = c->dims[0];
+  o->length = c->dims[1];
+  o->data = c->data;
+  return AUBIO_OK;
+}
+
+uint_t aubio_fmat_as_tensor(fmat_t *o, aubio_tensor_t *c) {
+  if (o == NULL) return AUBIO_FAIL;
+  if (c == NULL) return AUBIO_FAIL;
+  c->n_dims = 2;
+  c->dims[0] = o->height;
+  c->dims[1] = o->length;
+  c->data = o->data;
+  return AUBIO_OK;
+}
+
+smpl_t aubio_tensor_max(aubio_tensor_t *t)
+{
+  uint_t i;
+  smpl_t max = -1000000;
+  for (i = 0; i < t->n_items; i++) {
+    max = MAX(t->data[0][i], max);
+  }
+  return max;
+}
Index: src/ai/tensor.h
===================================================================
--- src/ai/tensor.h	(revision d0ef4b7f97434666595dcfb02effc0ebaee2c87f)
+++ src/ai/tensor.h	(revision d0ef4b7f97434666595dcfb02effc0ebaee2c87f)
@@ -0,0 +1,60 @@
+/*
+  Copyright (C) 2018 Paul Brossier <piem@aubio.org>
+
+  This file is part of aubio.
+
+  aubio is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  aubio is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with aubio.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef AUBIO_TENSOR_H
+#define AUBIO_TENSOR_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+  uint_t n_dims;
+  uint_t dims[8];
+  smpl_t **data;
+  uint_t n_items;
+  uint_t items_per_row;
+} aubio_tensor_t;
+
+aubio_tensor_t *new_aubio_tensor(uint_t n_dims, uint_t *dims);
+
+void del_aubio_tensor(aubio_tensor_t *c);
+
+uint_t aubio_tensor_as_fvec(aubio_tensor_t *c, fvec_t *o);
+uint_t aubio_fvec_as_tensor(fvec_t *o, aubio_tensor_t *c);
+
+uint_t aubio_tensor_as_fmat(aubio_tensor_t *c, fmat_t *o);
+uint_t aubio_fmat_as_tensor(fmat_t *o, aubio_tensor_t *c);
+
+smpl_t aubio_tensor_max(aubio_tensor_t *t);
+
+#define AUBIO_ASSERT_EQUAL_SHAPE(t1, t2) { \
+    AUBIO_ASSERT(t1 && t2); \
+    AUBIO_ASSERT(t1->n_dims == t2->n_dims); \
+    uint_t nn; \
+    for (nn = 0; nn < t1->n_dims; nn++) \
+      AUBIO_ASSERT(t1->dims[nn] == t2->dims[nn]); \
+    }
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_TENSOR_H */
Index: src/aubio_priv.h
===================================================================
--- src/aubio_priv.h	(revision dc7362fd01ba34189e434f396729ff0c12c36e50)
+++ src/aubio_priv.h	(revision d0ef4b7f97434666595dcfb02effc0ebaee2c87f)
@@ -397,3 +397,6 @@
 #endif /* DEBUG */
 
+// goto to failure if condition x is not true
+#define AUBIO_GOTO_FAILURE(x) if (!(x)) goto failure
+
 #endif /* AUBIO_PRIV_H */
Index: src/fmat.c
===================================================================
--- src/fmat.c	(revision dc7362fd01ba34189e434f396729ff0c12c36e50)
+++ src/fmat.c	(revision d0ef4b7f97434666595dcfb02effc0ebaee2c87f)
@@ -24,5 +24,5 @@
 fmat_t * new_fmat (uint_t height, uint_t length) {
   fmat_t * s;
-  uint_t i,j;
+  uint_t i;
   if ((sint_t)length <= 0 || (sint_t)height <= 0 ) {
     return NULL;
@@ -32,9 +32,7 @@
   s->length = length;
   s->data = AUBIO_ARRAY(smpl_t*,s->height);
-  for (i=0; i< s->height; i++) {
-    s->data[i] = AUBIO_ARRAY(smpl_t, s->length);
-    for (j=0; j< s->length; j++) {
-      s->data[i][j]=0.;
-    }
+  s->data[0] = AUBIO_ARRAY(smpl_t, s->length * s->height);
+  for (i=1; i< s->height; i++) {
+    s->data[i] = s->data[0] + i * s->length;
   }
   return s;
@@ -42,9 +40,9 @@
 
 void del_fmat (fmat_t *s) {
-  uint_t i;
-  for (i=0; i<s->height; i++) {
-    AUBIO_FREE(s->data[i]);
-  }
-  AUBIO_FREE(s->data);
+  AUBIO_ASSERT(s);
+  if (s->data[0])
+    AUBIO_FREE(s->data[0]);
+  if (s->data)
+    AUBIO_FREE(s->data);
   AUBIO_FREE(s);
 }
