src/io/source*: add _do_multi and _get_channels, really downmix apple_audio
[aubio.git] / src / io / source_apple_audio.c
index d0bc6b5496b7b7a7875fa97b49dfdcc9769ff81b..5040fe6f114524ced3126f0fd832f6b3c68fa027 100644 (file)
@@ -22,6 +22,7 @@
 #include "config.h"
 #include "aubio_priv.h"
 #include "fvec.h"
+#include "fmat.h"
 #include "io/source_apple_audio.h"
 
 // ExtAudioFileRef, AudioStreamBasicDescription, AudioBufferList, ...
@@ -36,7 +37,8 @@
 
 struct _aubio_source_apple_audio_t {
   uint_t channels;
-  uint_t samplerate;
+  uint_t samplerate;          //< requested samplerate
+  uint_t source_samplerate;   //< actual source samplerate
   uint_t block_size;
 
   char_t *path;
@@ -54,26 +56,11 @@ aubio_source_apple_audio_t * new_aubio_source_apple_audio(char_t * path, uint_t
   aubio_source_apple_audio_t * s = AUBIO_NEW(aubio_source_apple_audio_t);
 
   s->path = path;
-  s->samplerate = samplerate;
   s->block_size = block_size;
-  s->channels = 1;
 
   OSStatus err = noErr;
   UInt32 propSize;
 
-  AudioStreamBasicDescription clientFormat;
-  propSize = sizeof(clientFormat);
-  memset(&clientFormat, 0, sizeof(AudioStreamBasicDescription));
-  clientFormat.mFormatID         = kAudioFormatLinearPCM;
-  clientFormat.mSampleRate       = (Float64)(s->samplerate);
-  clientFormat.mFormatFlags      = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
-  clientFormat.mChannelsPerFrame = s->channels;
-  clientFormat.mBitsPerChannel   = sizeof(short) * 8;
-  clientFormat.mFramesPerPacket  = 1;
-  clientFormat.mBytesPerFrame    = clientFormat.mBitsPerChannel * clientFormat.mChannelsPerFrame / 8;
-  clientFormat.mBytesPerPacket   = clientFormat.mFramesPerPacket * clientFormat.mBytesPerFrame;
-  clientFormat.mReserved         = 0;
-
   // open the resource url
   CFURLRef fileURL = getURLFromPath(path);
   err = ExtAudioFileOpenURL(fileURL, &s->audioFile);
@@ -89,17 +76,33 @@ aubio_source_apple_audio_t * new_aubio_source_apple_audio(char_t * path, uint_t
       kExtAudioFileProperty_FileDataFormat, &propSize, &fileFormat);
   if (err) { AUBIO_ERROR("error in ExtAudioFileGetProperty, %d\n", (int)err); goto beach;}
 
-  if (s->samplerate == 1) {
-    clientFormat.mSampleRate = fileFormat.mSampleRate;
-    s->samplerate = fileFormat.mSampleRate;
+  if (samplerate == 0) {
+    samplerate = fileFormat.mSampleRate;
+    //AUBIO_DBG("sampling rate set to 0, automagically adjusting to %d\n", samplerate);
   }
+  s->samplerate = samplerate;
+  s->source_samplerate = fileFormat.mSampleRate;
+  s->channels = fileFormat.mChannelsPerFrame;
+
+  AudioStreamBasicDescription clientFormat;
+  propSize = sizeof(clientFormat);
+  memset(&clientFormat, 0, sizeof(AudioStreamBasicDescription));
+  clientFormat.mFormatID         = kAudioFormatLinearPCM;
+  clientFormat.mSampleRate       = (Float64)(s->samplerate);
+  clientFormat.mFormatFlags      = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
+  clientFormat.mChannelsPerFrame = s->channels;
+  clientFormat.mBitsPerChannel   = sizeof(short) * 8;
+  clientFormat.mFramesPerPacket  = 1;
+  clientFormat.mBytesPerFrame    = clientFormat.mBitsPerChannel * clientFormat.mChannelsPerFrame / 8;
+  clientFormat.mBytesPerPacket   = clientFormat.mFramesPerPacket * clientFormat.mBytesPerFrame;
+  clientFormat.mReserved         = 0;
 
   // 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",
@@ -116,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
+      goto beach;
+  }
 
   // compute the size of the segments needed to read the input file
   UInt32 samples = s->block_size * clientFormat.mChannelsPerFrame;
@@ -126,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 {
-    assert (segmentSize == samples );
+    assert ( segmentSize == samples );
     //AUBIO_DBG("not resampling, segmentSize %d, block_size %d\n", segmentSize, s->block_size);
   }
 
@@ -143,25 +148,55 @@ beach:
 void aubio_source_apple_audio_do(aubio_source_apple_audio_t *s, fvec_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("error in ExtAudioFileRead, %d\n", (int)err); goto beach;}
+  if (err) { AUBIO_ERROR("error in ExtAudioFileRead %s %d\n", s->path, (int)err); goto beach;}
+
+  short *data = (short*)s->bufferList.mBuffers[0].mData;
 
   smpl_t *buf = read_to->data;
 
+  for (v = 0; v < loadedPackets; v++) {
+    buf[v] = 0.;
+    for (c = 0; c < s->channels; c++) {
+      buf[v] += SHORT_TO_FLOAT(data[ v * s->channels + c]);
+    }
+    buf[v] /= (smpl_t)s->channels;
+  }
+  // short read, fill with zeros
+  if (loadedPackets < s->block_size) {
+    for (v = loadedPackets; v < s->block_size; v++) {
+      buf[v] = 0.;
+    }
+  }
+
+  *read = (uint_t)loadedPackets;
+  return;
+beach:
+  *read = 0;
+  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;
 
-  if (buf) {
+  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++) {
-          for (v = 0; v < s->block_size; v++) {
-              if (v < loadedPackets) {
-                  buf[v * s->channels + c] =
-                      SHORT_TO_FLOAT(data[ v * s->channels + c]);
-              } else {
-                  buf[v * s->channels + c] = 0.f;
-              }
-          }
+        buf[c][v] = 0.;
       }
+    }
   }
-  //if (loadedPackets < s->block_size) return EOF;
   *read = (uint_t)loadedPackets;
   return;
 beach:
@@ -180,8 +215,19 @@ void del_aubio_source_apple_audio(aubio_source_apple_audio_t * s){
   return;
 }
 
+uint_t aubio_source_apple_audio_seek (aubio_source_apple_audio_t * s, uint_t 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;
+}
+
 uint_t aubio_source_apple_audio_get_samplerate(aubio_source_apple_audio_t * s) {
   return s->samplerate;
 }
 
+uint_t aubio_source_apple_audio_get_channels(aubio_source_apple_audio_t * s) {
+  return s->channels;
+}
+
 #endif /* __APPLE__ */