Index: src/io/sink.c
===================================================================
--- src/io/sink.c	(revision c21553d9684c83ee03cea11f10c14a751d6e6c4b)
+++ src/io/sink.c	(revision 4ed4b1f010a68edc99c5edaf7e77f3135cead02c)
@@ -1,4 +1,4 @@
 /*
-  Copyright (C) 2012 Paul Brossier <piem@aubio.org>
+  Copyright (C) 2012-2014 Paul Brossier <piem@aubio.org>
 
   This file is part of aubio.
@@ -22,4 +22,5 @@
 #include "aubio_priv.h"
 #include "fvec.h"
+#include "fmat.h"
 #include "io/sink.h"
 #ifdef __APPLE__
@@ -34,9 +35,9 @@
 
 typedef void (*aubio_sink_do_t)(aubio_sink_t * s, fvec_t * data, uint_t write);
-#if 0
-typedef void (*aubio_sink_do_multi_t)(aubio_sink_t * s, fmat_t * data, uint_t * read);
+typedef void (*aubio_sink_do_multi_t)(aubio_sink_t * s, fmat_t * data, uint_t write);
+typedef uint_t (*aubio_sink_preset_samplerate_t)(aubio_sink_t * s, uint_t samplerate);
+typedef uint_t (*aubio_sink_preset_channels_t)(aubio_sink_t * s, uint_t channels);
 typedef uint_t (*aubio_sink_get_samplerate_t)(aubio_sink_t * s);
 typedef uint_t (*aubio_sink_get_channels_t)(aubio_sink_t * s);
-#endif
 typedef uint_t (*aubio_sink_close_t)(aubio_sink_t * s);
 typedef void (*del_aubio_sink_t)(aubio_sink_t * s);
@@ -45,9 +46,9 @@
   void *sink;
   aubio_sink_do_t s_do;
-#if 0
   aubio_sink_do_multi_t s_do_multi;
+  aubio_sink_preset_samplerate_t s_preset_samplerate;
+  aubio_sink_preset_channels_t s_preset_channels;
   aubio_sink_get_samplerate_t s_get_samplerate;
   aubio_sink_get_channels_t s_get_channels;
-#endif
   aubio_sink_close_t s_close;
   del_aubio_sink_t s_del;
@@ -60,4 +61,9 @@
   if (s->sink) {
     s->s_do = (aubio_sink_do_t)(aubio_sink_apple_audio_do);
+    s->s_do_multi = (aubio_sink_do_multi_t)(aubio_sink_apple_audio_do_multi);
+    s->s_preset_samplerate = (aubio_sink_preset_samplerate_t)(aubio_sink_apple_audio_preset_samplerate);
+    s->s_preset_channels = (aubio_sink_preset_channels_t)(aubio_sink_apple_audio_preset_channels);
+    s->s_get_samplerate = (aubio_sink_get_samplerate_t)(aubio_sink_apple_audio_get_samplerate);
+    s->s_get_channels = (aubio_sink_get_channels_t)(aubio_sink_apple_audio_get_channels);
     s->s_close = (aubio_sink_close_t)(aubio_sink_apple_audio_close);
     s->s_del = (del_aubio_sink_t)(del_aubio_sink_apple_audio);
@@ -69,4 +75,9 @@
   if (s->sink) {
     s->s_do = (aubio_sink_do_t)(aubio_sink_sndfile_do);
+    s->s_do_multi = (aubio_sink_do_multi_t)(aubio_sink_sndfile_do_multi);
+    s->s_preset_samplerate = (aubio_sink_preset_samplerate_t)(aubio_sink_sndfile_preset_samplerate);
+    s->s_preset_channels = (aubio_sink_preset_channels_t)(aubio_sink_sndfile_preset_channels);
+    s->s_get_samplerate = (aubio_sink_get_samplerate_t)(aubio_sink_sndfile_get_samplerate);
+    s->s_get_channels = (aubio_sink_get_channels_t)(aubio_sink_sndfile_get_channels);
     s->s_close = (aubio_sink_close_t)(aubio_sink_sndfile_close);
     s->s_del = (del_aubio_sink_t)(del_aubio_sink_sndfile);
@@ -78,4 +89,9 @@
   if (s->sink) {
     s->s_do = (aubio_sink_do_t)(aubio_sink_wavwrite_do);
+    s->s_do_multi = (aubio_sink_do_multi_t)(aubio_sink_wavwrite_do_multi);
+    s->s_preset_samplerate = (aubio_sink_preset_samplerate_t)(aubio_sink_wavwrite_preset_samplerate);
+    s->s_preset_channels = (aubio_sink_preset_channels_t)(aubio_sink_wavwrite_preset_channels);
+    s->s_get_samplerate = (aubio_sink_get_samplerate_t)(aubio_sink_wavwrite_get_samplerate);
+    s->s_get_channels = (aubio_sink_get_channels_t)(aubio_sink_wavwrite_get_channels);
     s->s_close = (aubio_sink_close_t)(aubio_sink_wavwrite_close);
     s->s_del = (del_aubio_sink_t)(del_aubio_sink_wavwrite);
@@ -93,4 +109,24 @@
 }
 
+void aubio_sink_do_multi(aubio_sink_t * s, fmat_t * write_data, uint_t write) {
+  s->s_do_multi((void *)s->sink, write_data, write);
+}
+
+uint_t aubio_sink_preset_samplerate(aubio_sink_t * s, uint_t samplerate) {
+  return s->s_preset_samplerate((void *)s->sink, samplerate);
+}
+
+uint_t aubio_sink_preset_channels(aubio_sink_t * s, uint_t channels) {
+  return s->s_preset_channels((void *)s->sink, channels);
+}
+
+uint_t aubio_sink_get_samplerate(aubio_sink_t * s) {
+  return s->s_get_samplerate((void *)s->sink);
+}
+
+uint_t aubio_sink_get_channels(aubio_sink_t * s) {
+  return s->s_get_channels((void *)s->sink);
+}
+
 uint_t aubio_sink_close(aubio_sink_t *s) {
   return s->s_close((void *)s->sink);
Index: src/io/sink.h
===================================================================
--- src/io/sink.h	(revision c21553d9684c83ee03cea11f10c14a751d6e6c4b)
+++ src/io/sink.h	(revision 4ed4b1f010a68edc99c5edaf7e77f3135cead02c)
@@ -1,4 +1,4 @@
 /*
-  Copyright (C) 2012-2013 Paul Brossier <piem@aubio.org>
+  Copyright (C) 2012-2014 Paul Brossier <piem@aubio.org>
 
   This file is part of aubio.
@@ -26,4 +26,6 @@
   Media sink to write blocks of consecutive audio samples to file.
 
+  To read from file, use ::aubio_source_t.
+
   \example io/test-sink.c
 
@@ -48,6 +50,64 @@
   Creates a new sink object.
 
+  If samplerate is set to 0, the creation of the file will be delayed until
+  both ::aubio_sink_preset_samplerate and ::aubio_sink_preset_channels have
+  been called.
+
 */
 aubio_sink_t * new_aubio_sink(char_t * uri, uint_t samplerate);
+
+/**
+
+  preset sink samplerate
+
+  \param s sink, created with ::new_aubio_sink
+  \param samplerate samplerate to preset the sink to, in Hz
+
+  \return 0 on success, 1 on error
+
+  Preset the samplerate of the sink. The file should have been created using a
+  samplerate of 0.
+
+  The file will be opened only when both samplerate and channels have been set.
+
+*/
+uint_t aubio_sink_preset_samplerate(aubio_sink_t *s, uint_t samplerate);
+
+/**
+
+  preset sink channels
+
+  \param s sink, created with ::new_aubio_sink
+  \param channels number of channels to preset the sink to
+
+  \return 0 on success, 1 on error
+
+  Preset the samplerate of the sink. The file should have been created using a
+  samplerate of 0.
+
+  The file will be opened only when both samplerate and channels have been set.
+
+*/
+uint_t aubio_sink_preset_channels(aubio_sink_t *s, uint_t channels);
+
+/**
+
+  get samplerate of sink object
+
+  \param s sink object, created with ::new_aubio_sink
+  \return samplerate, in Hz
+
+*/
+uint_t aubio_sink_get_samplerate(aubio_sink_t *s);
+
+/**
+
+  get channels of sink object
+
+  \param s sink object, created with ::new_aubio_sink
+  \return number of channels
+
+*/
+uint_t aubio_sink_get_channels(aubio_sink_t *s);
 
 /**
@@ -61,4 +121,15 @@
 */
 void aubio_sink_do(aubio_sink_t * s, fvec_t * write_data, uint_t write);
+
+/**
+
+  write polyphonic vector of length hop_size to sink
+
+  \param s sink, created with ::new_aubio_sink
+  \param write_data ::fmat_t samples to write to sink
+  \param write number of frames to write
+
+*/
+void aubio_sink_do_multi(aubio_sink_t * s, fmat_t * write_data, uint_t write);
 
 /**
Index: tests/src/io/test-sink-multi.c
===================================================================
--- tests/src/io/test-sink-multi.c	(revision 4ed4b1f010a68edc99c5edaf7e77f3135cead02c)
+++ tests/src/io/test-sink-multi.c	(revision 4ed4b1f010a68edc99c5edaf7e77f3135cead02c)
@@ -0,0 +1,73 @@
+#define AUBIO_UNSTABLE 1
+#include <aubio.h>
+#include "utils_tests.h"
+
+// this file uses the unstable aubio api, please use aubio_sink instead
+// see src/io/sink.h and tests/src/sink/test-sink.c
+
+int main (int argc, char **argv)
+{
+  sint_t err = 0;
+
+  if (argc < 3) {
+    err = 2;
+    PRINT_ERR("not enough arguments\n");
+    PRINT_MSG("usage: %s <input_path> <output_path> [samplerate] [channels] [hop_size]\n", argv[0]);
+    return err;
+  }
+
+  uint_t samplerate = 0;
+  uint_t channels = 0;
+  uint_t hop_size = 512;
+  uint_t n_frames = 0, read = 0;
+
+  char_t *source_path = argv[1];
+  char_t *sink_path = argv[2];
+
+  if ( argc >= 4 ) samplerate = atoi(argv[3]);
+  if ( argc >= 5 ) channels = atoi(argv[4]);
+  if ( argc >= 6 ) hop_size = atoi(argv[5]);
+  if ( argc >= 7 ) {
+    err = 2;
+    PRINT_ERR("too many arguments\n");
+    return err;
+  }
+
+  aubio_source_t *i = new_aubio_source(source_path, samplerate, hop_size);
+  if (!i) { err = 1; goto beach_source; }
+
+  if (samplerate == 0 ) samplerate = aubio_source_get_samplerate(i);
+  if (channels == 0 ) channels = aubio_source_get_channels(i);
+
+  fmat_t *mat = new_fmat(channels, hop_size);
+  if (!mat) { err = 1; goto beach_fmat; }
+
+  aubio_sink_t *o = new_aubio_sink(sink_path, 0);
+  if (!o) { err = 1; goto beach_sink; }
+  err = aubio_sink_preset_samplerate(o, samplerate);
+  if (err) { goto beach; }
+  err = aubio_sink_preset_channels(o, channels);
+  if (err) { goto beach; }
+
+  do {
+    aubio_source_do_multi(i, mat, &read);
+    aubio_sink_do_multi(o, mat, read);
+    n_frames += read;
+  } while ( read == hop_size );
+
+  PRINT_MSG("read %d frames at %dHz in %d channels (%d blocks) from %s written to %s\n",
+      n_frames, samplerate, channels, n_frames / hop_size,
+      source_path, sink_path);
+  PRINT_MSG("wrote %s with %dHz in %d channels\n", sink_path,
+      aubio_sink_get_samplerate(o),
+      aubio_sink_get_channels(o) );
+
+beach:
+  del_aubio_sink(o);
+beach_sink:
+  del_fmat(mat);
+beach_fmat:
+  del_aubio_source(i);
+beach_source:
+  return err;
+}
