src/io/source_apple_audio.{c,h}: added simple file read using ExtAudioFile
authorPaul Brossier <piem@piem.org>
Fri, 13 Jul 2012 21:28:43 +0000 (15:28 -0600)
committerPaul Brossier <piem@piem.org>
Fri, 13 Jul 2012 21:28:43 +0000 (15:28 -0600)
src/io/source.c
src/io/source.h
src/io/source_apple_audio.c [new file with mode: 0644]
src/io/source_apple_audio.h [new file with mode: 0644]

index 9f0a40eab4355ddf60d2064b9577607e79974262..dd8e0728c66d67fa217506ce49da552573d8d8d0 100644 (file)
 #include "aubio_priv.h"
 #include "fvec.h"
 #include "io/source.h"
+#ifdef __APPLE__
+#include "io/source_apple_audio_file.h"
+#endif /* __APPLE__ */
 
 struct _aubio_source_t { 
-  uint_t hopsize;
-  uint_t samplerate;
+  void *source;
 };
 
 aubio_source_t * new_aubio_source(char_t * uri, uint_t hop_size, uint_t samplerate) {
-  return NULL;
+  aubio_source_t * s = AUBIO_NEW(aubio_source_t);
+#ifdef __APPLE__
+  s->source= (void *)new_aubio_source_apple_audio(uri, hop_size, samplerate);
+#endif /* __APPLE__ */
+  if (s->source == NULL) return NULL;
+  return s;
 }
 
-fvec_t * aubio_source_do(aubio_source_t * s, fvec_t * write_data) {
-  return NULL;
+void aubio_source_do(aubio_source_t * s, fvec_t * data, uint_t * read) {
+#ifdef __APPLE__
+  aubio_source_apple_audio_do((aubio_source_apple_audio_t *)s->source, data, read);
+#endif /* __APPLE__ */
 }
 
 void del_aubio_source(aubio_source_t * s) {
-  return;
+#ifdef __APPLE__
+  del_aubio_source_apple_audio((aubio_source_apple_audio_t *)s->source);
+#endif /* __APPLE__ */
+  AUBIO_FREE(s);
 }
 
index 16cc839d7b5133a7dd04b69e463cb314952b205a..8f9318096d76076d995d74be621ade856ab5a202 100644 (file)
@@ -32,8 +32,8 @@ extern "C" {
 */
 
 typedef struct _aubio_source_t aubio_source_t;
-aubio_source_t * new_aubio_source(char_t * uri, uint_t hop_size, uint_t samplerate);
-fvec_t * aubio_source_do(aubio_source_t * s);
+aubio_source_t * new_aubio_source(char_t * method, uint_t hop_size, uint_t samplerate);
+void aubio_source_do(aubio_source_t * s, fvec_t * read_data, uint_t * read);
 void del_aubio_source(aubio_source_t * s);
 
 #ifdef __cplusplus
diff --git a/src/io/source_apple_audio.c b/src/io/source_apple_audio.c
new file mode 100644 (file)
index 0000000..475838c
--- /dev/null
@@ -0,0 +1,208 @@
+/*
+  Copyright (C) 2012 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/>.
+
+*/
+
+#ifdef __APPLE__
+#include "config.h"
+#include "aubio_priv.h"
+#include "fvec.h"
+#include "io/source_apple_audio.h"
+
+// CFURLRef, CFURLCreateWithFileSystemPath, ...
+#include <CoreFoundation/CoreFoundation.h>
+// ExtAudioFileRef, AudioStreamBasicDescription, AudioBufferList, ...
+#include <AudioToolbox/AudioToolbox.h>
+
+#define RT_BYTE1( a )      ( (a) & 0xff )
+#define RT_BYTE2( a )      ( ((a) >> 8) & 0xff )
+#define RT_BYTE3( a )      ( ((a) >> 16) & 0xff )
+#define RT_BYTE4( a )      ( ((a) >> 24) & 0xff )
+
+#define SHORT_TO_FLOAT(x) (smpl_t)(x * 3.0517578125e-05)
+
+struct _aubio_source_apple_audio_t {
+  uint_t channels;
+  uint_t samplerate;
+  uint_t block_size;
+
+  char_t *path;
+
+  ExtAudioFileRef audioFile;
+  AudioStreamBasicDescription fileFormat;
+  AudioBufferList bufferList;
+};
+
+static int createAubioBufferList(AudioBufferList *bufferList, int channels, int segmentSize);
+static void freeAudioBufferList(AudioBufferList *bufferList);
+static CFURLRef getURLFromPath(const char * path);
+
+aubio_source_apple_audio_t * new_aubio_source_apple_audio(char_t * path, uint_t samplerate, uint_t block_size)
+{
+  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);
+  if (err) { AUBIO_ERR("error when trying to access %s, in ExtAudioFileOpenURL, %d\n", s->path, (int)err); goto beach;}
+
+  // create an empty AudioStreamBasicDescription
+  AudioStreamBasicDescription fileFormat;
+  propSize = sizeof(fileFormat);
+  memset(&fileFormat, 0, sizeof(AudioStreamBasicDescription));
+
+  // fill it with the file description
+  err = ExtAudioFileGetProperty(s->audioFile,
+      kExtAudioFileProperty_FileDataFormat, &propSize, &fileFormat);
+  if (err) { AUBIO_ERROR("error in ExtAudioFileGetProperty, %d\n", (int)err); goto beach;}
+
+  // set the client format description
+  err = ExtAudioFileSetProperty(s->audioFile, kExtAudioFileProperty_ClientDataFormat,
+      propSize, &clientFormat);
+  if (err) { fprintf(stderr, "error in ExtAudioFileSetProperty, %d\n", (int)err); goto beach;}
+
+  // 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",
+      (int)RT_BYTE4(fileFormat.mFormatID),   (int)RT_BYTE3(fileFormat.mFormatID),   (int)RT_BYTE2(fileFormat.mFormatID),   (int)RT_BYTE1(fileFormat.mFormatID),
+      (int)RT_BYTE4(clientFormat.mFormatID), (int)RT_BYTE3(clientFormat.mFormatID), (int)RT_BYTE2(clientFormat.mFormatID), (int)RT_BYTE1(clientFormat.mFormatID)
+      );
+
+  AUBIO_DBG("file/client Format.mSampleRate       : %6.0f / %.0f\n",     fileFormat.mSampleRate      ,      clientFormat.mSampleRate);
+  AUBIO_DBG("file/client Format.mFormatFlags      : %6d / %d\n",    (int)fileFormat.mFormatFlags     , (int)clientFormat.mFormatFlags);
+  AUBIO_DBG("file/client Format.mChannelsPerFrame : %6d / %d\n",    (int)fileFormat.mChannelsPerFrame, (int)clientFormat.mChannelsPerFrame);
+  AUBIO_DBG("file/client Format.mBitsPerChannel   : %6d / %d\n",    (int)fileFormat.mBitsPerChannel  , (int)clientFormat.mBitsPerChannel);
+  AUBIO_DBG("file/client Format.mFramesPerPacket  : %6d / %d\n",    (int)fileFormat.mFramesPerPacket , (int)clientFormat.mFramesPerPacket);
+  AUBIO_DBG("file/client Format.mBytesPerFrame    : %6d / %d\n",    (int)fileFormat.mBytesPerFrame   , (int)clientFormat.mBytesPerFrame);
+  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);
+
+  // compute the size of the segments needed to read the input file
+  UInt32 samples = s->block_size * clientFormat.mChannelsPerFrame;
+  Float64 rateRatio = clientFormat.mSampleRate / fileFormat.mSampleRate;
+  uint_t segmentSize= (uint_t)(samples * rateRatio + .5);
+  if (rateRatio < 1.) {
+    segmentSize = (uint_t)(samples / rateRatio + .5);
+  } 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 );
+    //AUBIO_DBG("not resampling, segmentSize %d, block_size %d\n", segmentSize, s->block_size);
+  }
+
+  // allocate the AudioBufferList
+  if (createAubioBufferList(&s->bufferList, s->channels, segmentSize)) err = -1;
+
+  return s;
+beach:
+  AUBIO_FREE(s);
+  return NULL;
+}
+
+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;}
+
+  smpl_t *buf = read_to->data;
+
+  short *data = (short*)s->bufferList.mBuffers[0].mData;
+
+  if (buf) {
+      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;
+              }
+          }
+      }
+  }
+  //if (loadedPackets < s->block_size) return EOF;
+  *read = (uint_t)loadedPackets;
+  return;
+beach:
+  *read = 0;
+  return;
+}
+
+static int createAubioBufferList(AudioBufferList * bufferList, int channels, int segmentSize) {
+  bufferList->mNumberBuffers = 1;
+  bufferList->mBuffers[0].mNumberChannels = channels;
+  bufferList->mBuffers[0].mData = (short *)malloc(segmentSize * sizeof(short));
+  bufferList->mBuffers[0].mDataByteSize = segmentSize * sizeof(short);
+  return 0;
+}
+
+static void freeAudioBufferList(AudioBufferList *bufferList) {
+  UInt32 i = 0;
+  if (!bufferList) return;
+  for (i = 0; i < bufferList->mNumberBuffers; i++) {
+    if (bufferList->mBuffers[i].mData) {
+      free (bufferList->mBuffers[i].mData);
+      bufferList->mBuffers[i].mData = NULL;
+    }
+  }
+  bufferList = NULL;
+}
+
+static CFURLRef getURLFromPath(const char * path) {
+  CFStringRef cfTotalPath = CFStringCreateWithCString (kCFAllocatorDefault,
+      path, kCFStringEncodingUTF8);
+
+  return CFURLCreateWithFileSystemPath(kCFAllocatorDefault, cfTotalPath,
+      kCFURLPOSIXPathStyle, false);
+}
+
+
+void del_aubio_source_apple_audio(aubio_source_apple_audio_t * s){
+  OSStatus err = noErr;
+  if (!s || !s->audioFile) { return; }
+  err = ExtAudioFileDispose(s->audioFile);
+  if (err) AUBIO_ERROR("error in ExtAudioFileDispose, %d\n", (int)err);
+  s->audioFile = NULL;
+  freeAudioBufferList(&s->bufferList);
+  AUBIO_FREE(s);
+  return;
+}
+
+#endif /* __APPLE__ */
diff --git a/src/io/source_apple_audio.h b/src/io/source_apple_audio.h
new file mode 100644 (file)
index 0000000..39e47df
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+  Copyright (C) 2012 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_SOURCE_APPLE_AUDIO_H
+#define _AUBIO_SOURCE_APPLE_AUDIO_H
+
+typedef struct _aubio_source_apple_audio_t aubio_source_apple_audio_t;
+aubio_source_apple_audio_t * new_aubio_source_apple_audio(char_t * path, uint_t samplerate, uint_t block_size);
+void aubio_source_apple_audio_do(aubio_source_apple_audio_t * s, fvec_t * read_to, uint_t * read);
+void del_aubio_source_apple_audio(aubio_source_apple_audio_t * s);
+
+#endif /* _AUBIO_SOURCE_APPLE_AUDIO_H */