From: Paul Brossier Date: Fri, 13 Jul 2012 21:28:43 +0000 (-0600) Subject: src/io/source_apple_audio.{c,h}: added simple file read using ExtAudioFile X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=3504dfe767149b9ce2f36b39c83f89d37e20931d;p=aubio.git src/io/source_apple_audio.{c,h}: added simple file read using ExtAudioFile --- diff --git a/src/io/source.c b/src/io/source.c index 9f0a40ea..dd8e0728 100644 --- a/src/io/source.c +++ b/src/io/source.c @@ -22,21 +22,33 @@ #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); } diff --git a/src/io/source.h b/src/io/source.h index 16cc839d..8f931809 100644 --- a/src/io/source.h +++ b/src/io/source.h @@ -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 index 00000000..475838c5 --- /dev/null +++ b/src/io/source_apple_audio.c @@ -0,0 +1,208 @@ +/* + Copyright (C) 2012 Paul Brossier + + 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 . + +*/ + +#ifdef __APPLE__ +#include "config.h" +#include "aubio_priv.h" +#include "fvec.h" +#include "io/source_apple_audio.h" + +// CFURLRef, CFURLCreateWithFileSystemPath, ... +#include +// ExtAudioFileRef, AudioStreamBasicDescription, AudioBufferList, ... +#include + +#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 index 00000000..39e47dff --- /dev/null +++ b/src/io/source_apple_audio.h @@ -0,0 +1,29 @@ +/* + Copyright (C) 2012 Paul Brossier + + 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 . + +*/ + +#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 */