src/io/source*: add _do_multi and _get_channels, really downmix apple_audio
authorPaul Brossier <piem@piem.org>
Fri, 22 Mar 2013 01:29:19 +0000 (20:29 -0500)
committerPaul Brossier <piem@piem.org>
Fri, 22 Mar 2013 01:29:19 +0000 (20:29 -0500)
src/io/source.c
src/io/source.h
src/io/source_apple_audio.c
src/io/source_apple_audio.h
src/io/source_sndfile.c
src/io/source_sndfile.h
tests/src/io/test-source.c
tests/src/io/test-source_multi.c [new file with mode: 0644]

index 5e932913dfb5be7cfaa63aecbd79667a45632c0f..7bce2e0c395207867a5ea09b8024cfa1abced007 100644 (file)
@@ -21,6 +21,7 @@
 #include "config.h"
 #include "aubio_priv.h"
 #include "fvec.h"
 #include "config.h"
 #include "aubio_priv.h"
 #include "fvec.h"
+#include "fmat.h"
 #include "io/source.h"
 #ifdef __APPLE__
 #include "io/source_apple_audio.h"
 #include "io/source.h"
 #ifdef __APPLE__
 #include "io/source_apple_audio.h"
@@ -59,6 +60,16 @@ void aubio_source_do(aubio_source_t * s, fvec_t * data, uint_t * read) {
 #endif /* __APPLE__ */
 }
 
 #endif /* __APPLE__ */
 }
 
+void aubio_source_do_multi(aubio_source_t * s, fmat_t * data, uint_t * read) {
+#ifdef __APPLE__
+  aubio_source_apple_audio_do_multi((aubio_source_apple_audio_t *)s->source, data, read);
+#else /* __APPLE__ */
+#if HAVE_SNDFILE
+  aubio_source_sndfile_do_multi((aubio_source_sndfile_t *)s->source, data, read);
+#endif /* HAVE_SNDFILE */
+#endif /* __APPLE__ */
+}
+
 void del_aubio_source(aubio_source_t * s) {
   if (!s) return;
 #ifdef __APPLE__
 void del_aubio_source(aubio_source_t * s) {
   if (!s) return;
 #ifdef __APPLE__
@@ -81,6 +92,16 @@ uint_t aubio_source_get_samplerate(aubio_source_t * s) {
 #endif /* __APPLE__ */
 }
 
 #endif /* __APPLE__ */
 }
 
+uint_t aubio_source_get_channels(aubio_source_t * s) {
+#ifdef __APPLE__
+  return aubio_source_apple_audio_get_channels((aubio_source_apple_audio_t *)s->source);
+#else /* __APPLE__ */
+#if HAVE_SNDFILE
+  return aubio_source_sndfile_get_channels((aubio_source_sndfile_t *)s->source);
+#endif /* HAVE_SNDFILE */
+#endif /* __APPLE__ */
+}
+
 uint_t aubio_source_seek (aubio_source_t * s, uint_t seek ) {
 #ifdef __APPLE__
   return aubio_source_apple_audio_seek ((aubio_source_apple_audio_t *)s->source, seek);
 uint_t aubio_source_seek (aubio_source_t * s, uint_t seek ) {
 #ifdef __APPLE__
   return aubio_source_apple_audio_seek ((aubio_source_apple_audio_t *)s->source, seek);
index d8ef74ece6f0acfa9eb787c768c46e5953b8b02d..c07bf1e5eed06d0009e911f6616427bd2c89c211 100644 (file)
@@ -67,6 +67,20 @@ aubio_source_t * new_aubio_source(char_t * uri, uint_t samplerate, uint_t hop_si
 */
 void aubio_source_do(aubio_source_t * s, fvec_t * read_to, uint_t * read);
 
 */
 void aubio_source_do(aubio_source_t * s, fvec_t * read_to, uint_t * read);
 
+/**
+
+  read polyphonic vector of length hop_size from source object
+
+  \param s source object, created with ::new_aubio_source
+  \param read_to ::fmat_t of data to read to
+  \param read upon returns, equals to number of frames actually read
+
+  Upon returns, `read` contains the number of frames actually read from the
+  source. `hop_size` if enough frames could be read, less otherwise.
+
+*/
+void aubio_source_do_multi(aubio_source_t * s, fmat_t * read_to, uint_t * read);
+
 /**
 
   get samplerate of source object
 /**
 
   get samplerate of source object
@@ -77,6 +91,16 @@ void aubio_source_do(aubio_source_t * s, fvec_t * read_to, uint_t * read);
 */
 uint_t aubio_source_get_samplerate(aubio_source_t * s);
 
 */
 uint_t aubio_source_get_samplerate(aubio_source_t * s);
 
+/**
+
+  get channels of source object
+
+  \param s source object, created with ::new_aubio_source
+  \return channels
+
+*/
+uint_t aubio_source_get_channels (aubio_source_t * s);
+
 /**
 
   seek source object
 /**
 
   seek source object
index fb310bfd46d150f8fa3c62368d4192ce2e2ee3fa..5040fe6f114524ced3126f0fd832f6b3c68fa027 100644 (file)
@@ -22,6 +22,7 @@
 #include "config.h"
 #include "aubio_priv.h"
 #include "fvec.h"
 #include "config.h"
 #include "aubio_priv.h"
 #include "fvec.h"
+#include "fmat.h"
 #include "io/source_apple_audio.h"
 
 // ExtAudioFileRef, AudioStreamBasicDescription, AudioBufferList, ...
 #include "io/source_apple_audio.h"
 
 // ExtAudioFileRef, AudioStreamBasicDescription, AudioBufferList, ...
@@ -56,7 +57,6 @@ aubio_source_apple_audio_t * new_aubio_source_apple_audio(char_t * path, uint_t
 
   s->path = path;
   s->block_size = block_size;
 
   s->path = path;
   s->block_size = block_size;
-  s->channels = 1;
 
   OSStatus err = noErr;
   UInt32 propSize;
 
   OSStatus err = noErr;
   UInt32 propSize;
@@ -82,6 +82,7 @@ aubio_source_apple_audio_t * new_aubio_source_apple_audio(char_t * path, uint_t
   }
   s->samplerate = samplerate;
   s->source_samplerate = fileFormat.mSampleRate;
   }
   s->samplerate = samplerate;
   s->source_samplerate = fileFormat.mSampleRate;
+  s->channels = fileFormat.mChannelsPerFrame;
 
   AudioStreamBasicDescription clientFormat;
   propSize = sizeof(clientFormat);
 
   AudioStreamBasicDescription clientFormat;
   propSize = sizeof(clientFormat);
@@ -99,9 +100,9 @@ aubio_source_apple_audio_t * new_aubio_source_apple_audio(char_t * path, uint_t
   // set the client format description
   err = ExtAudioFileSetProperty(s->audioFile, kExtAudioFileProperty_ClientDataFormat,
       propSize, &clientFormat);
   // set the client format description
   err = ExtAudioFileSetProperty(s->audioFile, kExtAudioFileProperty_ClientDataFormat,
       propSize, &clientFormat);
-  if (err) { AUBIO_ERROR("error in ExtAudioFileSetProperty, %d\n", (int)err); goto beach;}
-
-#if 0
+  if (err) {
+      AUBIO_ERROR("error in ExtAudioFileSetProperty, %d\n", (int)err);
+#if 1
   // print client and format descriptions
   AUBIO_DBG("Opened %s\n", s->path);
   AUBIO_DBG("file/client Format.mFormatID:        : %3c%c%c%c / %c%c%c%c\n",
   // print client and format descriptions
   AUBIO_DBG("Opened %s\n", s->path);
   AUBIO_DBG("file/client Format.mFormatID:        : %3c%c%c%c / %c%c%c%c\n",
@@ -118,6 +119,8 @@ aubio_source_apple_audio_t * new_aubio_source_apple_audio(char_t * path, uint_t
   AUBIO_DBG("file/client Format.mBytesPerPacket   : %6d / %d\n",    (int)fileFormat.mBytesPerPacket  , (int)clientFormat.mBytesPerPacket);
   AUBIO_DBG("file/client Format.mReserved         : %6d / %d\n",    (int)fileFormat.mReserved        , (int)clientFormat.mReserved);
 #endif
   AUBIO_DBG("file/client Format.mBytesPerPacket   : %6d / %d\n",    (int)fileFormat.mBytesPerPacket  , (int)clientFormat.mBytesPerPacket);
   AUBIO_DBG("file/client Format.mReserved         : %6d / %d\n",    (int)fileFormat.mReserved        , (int)clientFormat.mReserved);
 #endif
+      goto beach;
+  }
 
   // compute the size of the segments needed to read the input file
   UInt32 samples = s->block_size * clientFormat.mChannelsPerFrame;
 
   // compute the size of the segments needed to read the input file
   UInt32 samples = s->block_size * clientFormat.mChannelsPerFrame;
@@ -128,7 +131,7 @@ aubio_source_apple_audio_t * new_aubio_source_apple_audio(char_t * path, uint_t
   } else if (rateRatio > 1.) {
     AUBIO_WRN("up-sampling %s from %0.2fHz to %0.2fHz\n", s->path, fileFormat.mSampleRate, clientFormat.mSampleRate);
   } else {
   } else if (rateRatio > 1.) {
     AUBIO_WRN("up-sampling %s from %0.2fHz to %0.2fHz\n", s->path, fileFormat.mSampleRate, clientFormat.mSampleRate);
   } else {
-    assert (segmentSize == samples );
+    assert ( segmentSize == samples );
     //AUBIO_DBG("not resampling, segmentSize %d, block_size %d\n", segmentSize, s->block_size);
   }
 
     //AUBIO_DBG("not resampling, segmentSize %d, block_size %d\n", segmentSize, s->block_size);
   }
 
@@ -172,6 +175,35 @@ beach:
   return;
 }
 
   return;
 }
 
+void aubio_source_apple_audio_do_multi(aubio_source_apple_audio_t *s, fmat_t * read_to, uint_t * read) {
+  UInt32 c, v, loadedPackets = s->block_size;
+  OSStatus err = ExtAudioFileRead(s->audioFile, &loadedPackets, &s->bufferList);
+  if (err) { AUBIO_ERROR("source_apple_audio: error in ExtAudioFileRead, %d\n", (int)err); goto beach;}
+
+  short *data = (short*)s->bufferList.mBuffers[0].mData;
+
+  smpl_t **buf = read_to->data;
+
+  for (v = 0; v < loadedPackets; v++) {
+    for (c = 0; c < s->channels; c++) {
+      buf[c][v] = SHORT_TO_FLOAT(data[ v * s->channels + c]);
+    }
+  }
+  // short read, fill with zeros
+  if (loadedPackets < s->block_size) {
+    for (v = loadedPackets; v < s->block_size; v++) {
+      for (c = 0; c < s->channels; c++) {
+        buf[c][v] = 0.;
+      }
+    }
+  }
+  *read = (uint_t)loadedPackets;
+  return;
+beach:
+  *read = 0;
+  return;
+}
+
 void del_aubio_source_apple_audio(aubio_source_apple_audio_t * s){
   OSStatus err = noErr;
   if (!s || !s->audioFile) { return; }
 void del_aubio_source_apple_audio(aubio_source_apple_audio_t * s){
   OSStatus err = noErr;
   if (!s || !s->audioFile) { return; }
@@ -184,8 +216,8 @@ void del_aubio_source_apple_audio(aubio_source_apple_audio_t * s){
 }
 
 uint_t aubio_source_apple_audio_seek (aubio_source_apple_audio_t * s, uint_t pos) {
 }
 
 uint_t aubio_source_apple_audio_seek (aubio_source_apple_audio_t * s, uint_t pos) {
-  Float64 ratio = (Float64)(s->source_samplerate) / (Float64)(s->samplerate);
-  OSStatus err = ExtAudioFileSeek(s->audioFile, pos);
+  SInt64 resampled_pos = (SInt64)ROUND( pos * s->source_samplerate * 1. / s->samplerate );
+  OSStatus err = ExtAudioFileSeek(s->audioFile, resampled_pos);
   if (err) AUBIO_ERROR("source_apple_audio: error in ExtAudioFileSeek (%d)\n", (int)err);
   return err;
 }
   if (err) AUBIO_ERROR("source_apple_audio: error in ExtAudioFileSeek (%d)\n", (int)err);
   return err;
 }
@@ -194,4 +226,8 @@ uint_t aubio_source_apple_audio_get_samplerate(aubio_source_apple_audio_t * s) {
   return s->samplerate;
 }
 
   return s->samplerate;
 }
 
+uint_t aubio_source_apple_audio_get_channels(aubio_source_apple_audio_t * s) {
+  return s->channels;
+}
+
 #endif /* __APPLE__ */
 #endif /* __APPLE__ */
index ee2c625bed595f90888d6e1b3aac6cd5183d3329..03ed750dd97be78a77a2ac6ae772e8ffffdb64a0 100644 (file)
@@ -73,6 +73,20 @@ aubio_source_apple_audio_t * new_aubio_source_apple_audio(char_t * uri, uint_t s
 */
 void aubio_source_apple_audio_do(aubio_source_apple_audio_t * s, fvec_t * read_to, uint_t * read);
 
 */
 void aubio_source_apple_audio_do(aubio_source_apple_audio_t * s, fvec_t * read_to, uint_t * read);
 
+/**
+
+  read polyphonic vector of length hop_size from source object
+
+  \param s source object, created with ::new_aubio_source_apple_audio
+  \param read_to ::fmat_t of data to read to
+  \param read upon returns, equals to number of frames actually read
+
+  Upon returns, `read` contains the number of frames actually read from the
+  source. `hop_size` if enough frames could be read, less otherwise.
+
+*/
+void aubio_source_apple_audio_do_multi(aubio_source_apple_audio_t * s, fmat_t * read_to, uint_t * read);
+
 /**
 
   get samplerate of source object
 /**
 
   get samplerate of source object
@@ -83,6 +97,16 @@ void aubio_source_apple_audio_do(aubio_source_apple_audio_t * s, fvec_t * read_t
 */
 uint_t aubio_source_apple_audio_get_samplerate(aubio_source_apple_audio_t * s);
 
 */
 uint_t aubio_source_apple_audio_get_samplerate(aubio_source_apple_audio_t * s);
 
+/**
+
+  get channels of source object
+
+  \param s source object, created with ::new_aubio_source_apple_audio
+  \return number of channels
+
+*/
+uint_t aubio_source_apple_audio_get_channels(aubio_source_apple_audio_t * s);
+
 /**
 
   seek source object
 /**
 
   seek source object
index a21cf60678f4b10f74153f713d64e38e5cfb7666..cbd682b29ed111486a8ef91b06a83ae3199a4c4d 100644 (file)
@@ -158,7 +158,7 @@ void aubio_source_sndfile_do(aubio_source_sndfile_t * s, fvec_t * read_data, uin
   for (j = 0; j < read_samples / input_channels; j++) {
     data[j] = 0;
     for (i = 0; i < input_channels; i++) {
   for (j = 0; j < read_samples / input_channels; j++) {
     data[j] = 0;
     for (i = 0; i < input_channels; i++) {
-      data[j] += (smpl_t)s->scratch_data[input_channels*j+i];
+      data[j] += s->scratch_data[input_channels*j+i];
     }
     data[j] /= (smpl_t)input_channels;
   }
     }
     data[j] /= (smpl_t)input_channels;
   }
@@ -172,10 +172,48 @@ void aubio_source_sndfile_do(aubio_source_sndfile_t * s, fvec_t * read_data, uin
   *read = (int)FLOOR(s->ratio * read_samples / input_channels + .5);
 }
 
   *read = (int)FLOOR(s->ratio * read_samples / input_channels + .5);
 }
 
+void aubio_source_sndfile_do_multi(aubio_source_sndfile_t * s, fmat_t * read_data, uint_t * read){
+  uint_t i,j, input_channels = s->input_channels;
+  /* do actual reading */
+  sf_count_t read_samples = sf_read_float (s->handle, s->scratch_data, s->scratch_size);
+
+  smpl_t **data;
+
+#ifdef HAVE_SAMPLERATE
+  if (s->ratio != 1) {
+    AUBIO_ERR("source_sndfile: no multi channel resampling yet");
+    return;
+    data = s->input_data->data;
+  } else
+#endif /* HAVE_SAMPLERATE */
+  {
+    data = read_data->data;
+  }
+
+  /* de-interleaving data */
+  for (j = 0; j < read_samples / input_channels; j++) {
+    for (i = 0; i < input_channels; i++) {
+      data[i][j] = (smpl_t)s->scratch_data[input_channels*j+i];
+    }
+  }
+
+#ifdef HAVE_SAMPLERATE
+  if (s->resampler) {
+    aubio_resampler_do(s->resampler, s->input_data, read_data);
+  }
+#endif /* HAVE_SAMPLERATE */
+
+  *read = (int)FLOOR(s->ratio * read_samples / input_channels + .5);
+}
+
 uint_t aubio_source_sndfile_get_samplerate(aubio_source_sndfile_t * s) {
   return s->samplerate;
 }
 
 uint_t aubio_source_sndfile_get_samplerate(aubio_source_sndfile_t * s) {
   return s->samplerate;
 }
 
+uint_t aubio_source_sndfile_get_channels(aubio_source_sndfile_t * s) {
+  return s->input_channels;
+}
+
 uint_t aubio_source_sndfile_seek (aubio_source_sndfile_t * s, uint_t pos) {
   uint_t resampled_pos = (uint_t)ROUND(pos * s->input_samplerate * 1. / s->samplerate);
   return sf_seek (s->handle, resampled_pos, SEEK_SET);
 uint_t aubio_source_sndfile_seek (aubio_source_sndfile_t * s, uint_t pos) {
   uint_t resampled_pos = (uint_t)ROUND(pos * s->input_samplerate * 1. / s->samplerate);
   return sf_seek (s->handle, resampled_pos, SEEK_SET);
index 3aec329109ee7685b05f3ff49237049c70c015a6..8dd10ac9bd6f6797adf74ab2cf551a3170154314 100644 (file)
@@ -82,6 +82,16 @@ void aubio_source_sndfile_do(aubio_source_sndfile_t * s, fvec_t * read_to, uint_
 */
 uint_t aubio_source_sndfile_get_samplerate(aubio_source_sndfile_t * s);
 
 */
 uint_t aubio_source_sndfile_get_samplerate(aubio_source_sndfile_t * s);
 
+/**
+
+  get number of channels of source object
+
+  \param s source object, created with ::new_aubio_source_sndfile
+  \return number of channels
+
+*/
+uint_t aubio_source_sndfile_get_channels (aubio_source_sndfile_t * s);
+
 /**
 
   seek source object
 /**
 
   seek source object
index 342ef406bcecb6899657a22ad4e1b6c261432df7..76747e2d45cf05983f07d75c59b09ff50c63beee 100644 (file)
@@ -36,7 +36,7 @@ int main (int argc, char **argv)
 
   do {
     aubio_source_do(s, vec, &read);
 
   do {
     aubio_source_do(s, vec, &read);
-    // fvec_print (vec);
+    fvec_print (vec);
     n_frames += read;
   } while ( read == hop_size );
 
     n_frames += read;
   } while ( read == hop_size );
 
diff --git a/tests/src/io/test-source_multi.c b/tests/src/io/test-source_multi.c
new file mode 100644 (file)
index 0000000..a1a72ec
--- /dev/null
@@ -0,0 +1,51 @@
+#include <aubio.h>
+#include "utils_tests.h"
+
+int main (int argc, char **argv)
+{
+  sint_t err = 0;
+  if (argc < 2) {
+    err = -2;
+    PRINT_ERR("not enough arguments\n");
+    PRINT_MSG("read a wave file as a mono vector\n");
+    PRINT_MSG("usage: %s <source_path> [samplerate] [hop_size]\n", argv[0]);
+    PRINT_MSG("examples:\n");
+    PRINT_MSG(" - read file.wav at original samplerate\n");
+    PRINT_MSG("       %s file.wav\n", argv[0]);
+    PRINT_MSG(" - read file.wav at 32000Hz\n");
+    PRINT_MSG("       %s file.aif 32000\n", argv[0]);
+    PRINT_MSG(" - read file.wav at original samplerate with 4096 blocks\n");
+    PRINT_MSG("       %s file.wav 0 4096 \n", argv[0]);
+    return err;
+  }
+
+  uint_t samplerate = 0;
+  uint_t hop_size = 256;
+  uint_t n_frames = 0, read = 0;
+  if ( argc == 3 ) samplerate = atoi(argv[2]);
+  if ( argc == 4 ) hop_size = atoi(argv[3]);
+
+  char_t *source_path = argv[1];
+
+  aubio_source_t* s = new_aubio_source(source_path, samplerate, hop_size);
+  if (!s) { err = -1; goto beach; }
+
+  if (samplerate == 0 ) samplerate = aubio_source_get_samplerate(s);
+
+  fmat_t *mat = new_fmat(hop_size, aubio_source_get_channels(s) );
+
+  do {
+    aubio_source_do_multi (s, mat, &read);
+    fmat_print (mat);
+    n_frames += read;
+  } while ( read == hop_size );
+
+  PRINT_MSG("read %d frames at %dHz (%d blocks) from %s\n", n_frames, samplerate,
+    n_frames / hop_size, source_path);
+
+  del_aubio_source (s);
+beach:
+  del_fmat (mat);
+
+  return err;
+}