src/io/ioutils.h: add functions to check samplerate and channels, use in sink_*.c
[aubio.git] / src / io / sink_wavwrite.c
index 5c1f380..79ae402 100644 (file)
 #ifdef HAVE_WAVWRITE
 
 #include "aubio_priv.h"
-#include "sink_wavwrite.h"
 #include "fvec.h"
+#include "fmat.h"
+#include "io/sink_wavwrite.h"
+#include "io/ioutils.h"
 
 #include <errno.h>
 
 #elif defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
 #define HTOLES(x) x
 #else
+#ifdef HAVE_WIN_HACKS
+#define HTOLES(x) x
+#else
 #define HTOLES(x) SWAPS(htons(x))
 #endif
+#endif
+
+uint_t aubio_sink_wavwrite_open(aubio_sink_wavwrite_t *s);
 
 struct _aubio_sink_wavwrite_t {
   char_t *path;
@@ -61,8 +69,12 @@ struct _aubio_sink_wavwrite_t {
   unsigned short *scratch_data;
 };
 
-unsigned char *write_little_endian (unsigned int s, unsigned char *str, unsigned int length);
-unsigned char *write_little_endian (unsigned int s, unsigned char *str, unsigned int length) {
+static unsigned char *write_little_endian (unsigned int s, unsigned char *str,
+    unsigned int length);
+
+static unsigned char *write_little_endian (unsigned int s, unsigned char *str,
+    unsigned int length)
+{
   uint_t i;
   for (i = 0; i < length; i++) {
     str[i] = s >> (i * 8);
@@ -70,10 +82,8 @@ unsigned char *write_little_endian (unsigned int s, unsigned char *str, unsigned
   return str;
 }
 
-aubio_sink_wavwrite_t * new_aubio_sink_wavwrite(char_t * path, uint_t samplerate) {
+aubio_sink_wavwrite_t * new_aubio_sink_wavwrite(const char_t * path, uint_t samplerate) {
   aubio_sink_wavwrite_t * s = AUBIO_NEW(aubio_sink_wavwrite_t);
-  unsigned char buf[5];
-  uint_t byterate, blockalign;
 
   if (path == NULL) {
     AUBIO_ERR("sink_wavwrite: Aborted opening null path\n");
@@ -84,15 +94,84 @@ aubio_sink_wavwrite_t * new_aubio_sink_wavwrite(char_t * path, uint_t samplerate
     goto beach;
   }
 
-  s->path = path;
-  s->samplerate = samplerate;
+  if (s->path) AUBIO_FREE(s->path);
+  s->path = AUBIO_ARRAY(char_t, strnlen(path, PATH_MAX) + 1);
+  strncpy(s->path, path, strnlen(path, PATH_MAX) + 1);
+
   s->max_size = MAX_SIZE;
-  s->channels = 1;
   s->bitspersample = 16;
   s->total_frames_written = 0;
 
-  /* set output format */
-  s->fid = fopen((const char *)path, "wb");
+  s->samplerate = 0;
+  s->channels = 0;
+
+  // zero samplerate given. do not open yet
+  if ((sint_t)samplerate == 0) {
+    return s;
+  }
+  // invalid samplerate given, abort
+  if (aubio_io_validate_samplerate("sink_wavwrite", s->path, samplerate)) {
+    goto beach;
+  }
+
+  s->samplerate = samplerate;
+  s->channels = 1;
+
+  if (aubio_sink_wavwrite_open(s) != AUBIO_OK) {
+    // open failed, abort
+    goto beach;
+  }
+
+  return s;
+beach:
+  //AUBIO_ERR("sink_wavwrite: failed creating %s with samplerate %dHz\n",
+  //    s->path, s->samplerate);
+  del_aubio_sink_wavwrite(s);
+  return NULL;
+}
+
+uint_t aubio_sink_wavwrite_preset_samplerate(aubio_sink_wavwrite_t *s, uint_t samplerate)
+{
+  if (aubio_io_validate_samplerate("sink_wavwrite", s->path, samplerate)) {
+    return AUBIO_FAIL;
+  }
+  s->samplerate = samplerate;
+  // automatically open when both samplerate and channels have been set
+  if (s->samplerate != 0 && s->channels != 0) {
+    return aubio_sink_wavwrite_open(s);
+  }
+  return AUBIO_OK;
+}
+
+uint_t aubio_sink_wavwrite_preset_channels(aubio_sink_wavwrite_t *s, uint_t channels)
+{
+  if (aubio_io_validate_channels("sink_wavwrite", s->path, channels)) {
+    return AUBIO_FAIL;
+  }
+  s->channels = channels;
+  // automatically open when both samplerate and channels have been set
+  if (s->samplerate != 0 && s->channels != 0) {
+    return aubio_sink_wavwrite_open(s);
+  }
+  return AUBIO_OK;
+}
+
+uint_t aubio_sink_wavwrite_get_samplerate(const aubio_sink_wavwrite_t *s)
+{
+  return s->samplerate;
+}
+
+uint_t aubio_sink_wavwrite_get_channels(const aubio_sink_wavwrite_t *s)
+{
+  return s->channels;
+}
+
+uint_t aubio_sink_wavwrite_open(aubio_sink_wavwrite_t *s) {
+  unsigned char buf[5];
+  uint_t byterate, blockalign;
+
+  /* open output file */
+  s->fid = fopen((const char *)s->path, "wb");
   if (!s->fid) {
     AUBIO_ERR("sink_wavwrite: could not open %s (%s)\n", s->path, strerror(errno));
     goto beach;
@@ -142,20 +221,16 @@ aubio_sink_wavwrite_t * new_aubio_sink_wavwrite(char_t * path, uint_t samplerate
   s->scratch_size = s->max_size * s->channels;
   /* allocate data for de/interleaving reallocated when needed. */
   if (s->scratch_size >= MAX_SIZE * MAX_CHANNELS) {
-    AUBIO_ERR("sink_wavwrite: %d x %d exceeds maximum buffer size %d\n",
-        s->max_size, s->channels, MAX_CHANNELS * MAX_CHANNELS);
-    AUBIO_FREE(s);
-    return NULL;
+    AUBIO_ERR("sink_wavwrite: %d x %d exceeds SIZE maximum buffer size %d\n",
+        s->max_size, s->channels, MAX_SIZE * MAX_CHANNELS);
+    goto beach;
   }
   s->scratch_data = AUBIO_ARRAY(unsigned short,s->scratch_size);
 
-  return s;
+  return AUBIO_OK;
 
 beach:
-  AUBIO_ERR("sink_wavwrite: can not write %s at samplerate %dHz\n",
-      s->path, s->samplerate);
-  del_aubio_sink_wavwrite(s);
-  return NULL;
+  return AUBIO_FAIL;
 }
 
 
@@ -181,10 +256,34 @@ void aubio_sink_wavwrite_do(aubio_sink_wavwrite_t *s, fvec_t * write_data, uint_
   return;
 }
 
-void aubio_sink_wavwrite_close(aubio_sink_wavwrite_t * s) {
+void aubio_sink_wavwrite_do_multi(aubio_sink_wavwrite_t *s, fmat_t * write_data, uint_t write){
+  uint_t c = 0, i = 0, written_frames = 0;
+
+  if (write > s->max_size) {
+    AUBIO_WRN("sink_wavwrite: trying to write %d frames to %s, "
+        "but only %d can be written at a time\n", write, s->path, s->max_size);
+    write = s->max_size;
+  }
+
+  for (c = 0; c < s->channels; c++) {
+    for (i = 0; i < write; i++) {
+      s->scratch_data[i * s->channels + c] = HTOLES(FLOAT_TO_SHORT(write_data->data[c][i]));
+    }
+  }
+  written_frames = fwrite(s->scratch_data, 2, write * s->channels, s->fid);
+
+  if (written_frames != write * s->channels) {
+    AUBIO_WRN("sink_wavwrite: trying to write %d frames to %s, "
+        "but only %d could be written\n", write, s->path, written_frames / s->channels);
+  }
+  s->total_frames_written += written_frames;
+  return;
+}
+
+uint_t aubio_sink_wavwrite_close(aubio_sink_wavwrite_t * s) {
   uint_t data_size = s->total_frames_written * s->bitspersample * s->channels / 8;
   unsigned char buf[5];
-  if (!s->fid) return;
+  if (!s->fid) return AUBIO_FAIL;
   // ChunkSize
   fseek(s->fid, 4, SEEK_SET);
   fwrite(write_little_endian(data_size + 36, buf, 4), 4, 1, s->fid);
@@ -196,11 +295,13 @@ void aubio_sink_wavwrite_close(aubio_sink_wavwrite_t * s) {
     AUBIO_ERR("sink_wavwrite: Error closing file %s (%s)\n", s->path, strerror(errno));
   }
   s->fid = NULL;
+  return AUBIO_OK;
 }
 
 void del_aubio_sink_wavwrite(aubio_sink_wavwrite_t * s){
   if (!s) return;
   aubio_sink_wavwrite_close(s);
+  if (s->path) AUBIO_FREE(s->path);
   AUBIO_FREE(s->scratch_data);
   AUBIO_FREE(s);
 }