CoreAudioFile fixes
parent
269cd05b5f
commit
5472794be8
|
@ -20,24 +20,22 @@
|
||||||
|
|
||||||
#import <Cocoa/Cocoa.h>
|
#import <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
#include <AudioToolbox/AudioFile.h>
|
#include <AudioToolbox/ExtendedAudioFile.h>
|
||||||
|
|
||||||
#import "SoundFile.h"
|
#import "SoundFile.h"
|
||||||
|
|
||||||
|
#define _USE_WRAPPER_
|
||||||
|
|
||||||
@interface CoreAudioFile : SoundFile
|
@interface CoreAudioFile : SoundFile
|
||||||
{
|
{
|
||||||
AudioFileID _in;
|
ExtAudioFileRef _in;
|
||||||
|
|
||||||
|
#ifdef _USE_WRAPPER_
|
||||||
|
FILE * _inFd;
|
||||||
|
AudioFileID _audioID;
|
||||||
|
|
||||||
SInt64 _packetCount;
|
|
||||||
SInt64 _totalPackets;
|
|
||||||
SInt64 _fileSize;
|
SInt64 _fileSize;
|
||||||
UInt32 _maxPacketSize;
|
#endif
|
||||||
UInt32 _framesPerPacket;
|
|
||||||
|
|
||||||
AudioConverterRef _converter;
|
|
||||||
void *_convBuf;
|
|
||||||
|
|
||||||
FILE *_inFd;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -21,16 +21,12 @@
|
||||||
#import "CoreAudioFile.h"
|
#import "CoreAudioFile.h"
|
||||||
|
|
||||||
@interface CoreAudioFile (Private)
|
@interface CoreAudioFile (Private)
|
||||||
- (BOOL) readInfoFromAudioFile;
|
- (BOOL) readInfoFromExtAudioFileRef;
|
||||||
- (BOOL) setupConverter: (AudioStreamBasicDescription *)inputFormat;
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation CoreAudioFile
|
@implementation CoreAudioFile
|
||||||
|
|
||||||
#define _USE_CALLBACKS_
|
#ifdef _USE_WRAPPER_
|
||||||
//#undef _USE_CALLBACKS_
|
|
||||||
|
|
||||||
#ifdef _USE_CALLBACKS_
|
|
||||||
OSStatus readFunc(void * inRefCon, SInt64 inPosition, ByteCount requestCount, void *buffer, ByteCount* actualCount)
|
OSStatus readFunc(void * inRefCon, SInt64 inPosition, ByteCount requestCount, void *buffer, ByteCount* actualCount)
|
||||||
{
|
{
|
||||||
CoreAudioFile *caf = (CoreAudioFile *)inRefCon;
|
CoreAudioFile *caf = (CoreAudioFile *)inRefCon;
|
||||||
|
@ -41,7 +37,9 @@ OSStatus readFunc(void * inRefCon, SInt64 inPosition, ByteCount requestCount, vo
|
||||||
*actualCount = fread(buffer, 1, requestCount, fd);
|
*actualCount = fread(buffer, 1, requestCount, fd);
|
||||||
|
|
||||||
if (*actualCount <= 0)
|
if (*actualCount <= 0)
|
||||||
|
{
|
||||||
return -1000; //Error?
|
return -1000; //Error?
|
||||||
|
}
|
||||||
|
|
||||||
return noErr;
|
return noErr;
|
||||||
}
|
}
|
||||||
|
@ -51,6 +49,7 @@ SInt64 getSizeFunc(void *inRefCon)
|
||||||
CoreAudioFile *caf = (CoreAudioFile *)inRefCon;
|
CoreAudioFile *caf = (CoreAudioFile *)inRefCon;
|
||||||
FILE *fd = caf->_inFd;
|
FILE *fd = caf->_inFd;
|
||||||
|
|
||||||
|
|
||||||
if (caf->_fileSize != 0)
|
if (caf->_fileSize != 0)
|
||||||
{
|
{
|
||||||
return caf->_fileSize;
|
return caf->_fileSize;
|
||||||
|
@ -58,8 +57,6 @@ SInt64 getSizeFunc(void *inRefCon)
|
||||||
|
|
||||||
long curPos;
|
long curPos;
|
||||||
|
|
||||||
NSLog(@"SIZE FUNC");
|
|
||||||
|
|
||||||
curPos = ftell(fd);
|
curPos = ftell(fd);
|
||||||
|
|
||||||
fseek(fd, 0, SEEK_END);
|
fseek(fd, 0, SEEK_END);
|
||||||
|
@ -73,73 +70,18 @@ SInt64 getSizeFunc(void *inRefCon)
|
||||||
|
|
||||||
OSStatus setSizeFunc(void * inRefCon, SInt64 inSize)
|
OSStatus setSizeFunc(void * inRefCon, SInt64 inSize)
|
||||||
{
|
{
|
||||||
|
NSLog(@"setsize FUNC");
|
||||||
|
|
||||||
return -1000; //Not supported at the moment
|
return -1000; //Not supported at the moment
|
||||||
}
|
}
|
||||||
|
|
||||||
OSStatus writeFunc(void * inRefCon, SInt64 inPosition, ByteCount requestCount, const void *buffer, ByteCount* actualCount)
|
OSStatus writeFunc(void * inRefCon, SInt64 inPosition, ByteCount requestCount, const void *buffer, ByteCount* actualCount)
|
||||||
{
|
{
|
||||||
|
NSLog(@"WRITE FUNC");
|
||||||
return -1000; //Not supported at the moment
|
return -1000; //Not supported at the moment
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
OSStatus ACInputProc(AudioConverterRef inAudioConverter, UInt32 *ioNumberDataPackets, AudioBufferList *ioData, AudioStreamPacketDescription **outDataPacketDescription, void *inUserData)
|
|
||||||
{
|
|
||||||
CoreAudioFile *caf = (CoreAudioFile *)inUserData;
|
|
||||||
OSStatus err = noErr;
|
|
||||||
UInt32 numBytes = 0;
|
|
||||||
|
|
||||||
if (caf->_packetCount + *ioNumberDataPackets > caf->_totalPackets)
|
|
||||||
{
|
|
||||||
*ioNumberDataPackets = caf->_totalPackets - caf->_packetCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*ioNumberDataPackets <= 0)
|
|
||||||
{
|
|
||||||
ioData->mBuffers[0].mData = NULL;
|
|
||||||
ioData->mBuffers[0].mDataByteSize = 0;
|
|
||||||
|
|
||||||
return noErr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (caf->_convBuf)
|
|
||||||
{
|
|
||||||
free(caf->_convBuf);
|
|
||||||
caf->_convBuf = NULL;
|
|
||||||
}
|
|
||||||
caf->_convBuf = malloc(*ioNumberDataPackets * caf->_maxPacketSize);
|
|
||||||
|
|
||||||
SInt64 localPacketCount;
|
|
||||||
|
|
||||||
localPacketCount = caf->_packetCount;
|
|
||||||
|
|
||||||
err = AudioFileReadPackets(caf->_in, false, &numBytes, NULL, localPacketCount, ioNumberDataPackets, caf->_convBuf);
|
|
||||||
if(err != noErr) {
|
|
||||||
NSLog(@"Error reading AudioFile: %i", err);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
caf->_packetCount += *ioNumberDataPackets;
|
|
||||||
|
|
||||||
ioData->mBuffers[0].mData = caf->_convBuf;
|
|
||||||
ioData->mBuffers[0].mDataByteSize = numBytes;
|
|
||||||
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (id)init
|
|
||||||
{
|
|
||||||
self = [super init];
|
|
||||||
if (self)
|
|
||||||
{
|
|
||||||
_packetCount = 0;
|
|
||||||
_convBuf = NULL;
|
|
||||||
_totalPackets = 0;
|
|
||||||
_maxPacketSize = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL) open:(const char *)filename
|
- (BOOL) open:(const char *)filename
|
||||||
{
|
{
|
||||||
return [self readInfo:filename];
|
return [self readInfo:filename];
|
||||||
|
@ -147,30 +89,24 @@ OSStatus ACInputProc(AudioConverterRef inAudioConverter, UInt32 *ioNumberDataPac
|
||||||
|
|
||||||
- (void) close
|
- (void) close
|
||||||
{
|
{
|
||||||
#ifdef _USE_CALLBACKS_
|
|
||||||
int err;
|
|
||||||
|
|
||||||
err = fclose(_inFd);
|
|
||||||
if(err != 0)
|
|
||||||
{
|
|
||||||
NSLog(@"Error closing AudioFile: %i", err);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
OSStatus err;
|
OSStatus err;
|
||||||
|
|
||||||
err = AudioFileClose(_in);
|
#ifdef _USE_WRAPPER_
|
||||||
if (err != noErr)
|
fclose(_inFd);
|
||||||
{
|
AudioFileClose(_audioID);
|
||||||
NSLog(@"Error closing AudioFile: %i", err);
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
err = ExtAudioFileDispose(_in);
|
||||||
|
if(noErr != err) {
|
||||||
|
NSLog(@"Error closing ExtAudioFile");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL) readInfo:(const char *)filename
|
- (BOOL) readInfo:(const char *)filename
|
||||||
{
|
{
|
||||||
OSStatus err;
|
OSStatus err;
|
||||||
|
|
||||||
#ifdef _USE_CALLBACKS_
|
#ifdef _USE_WRAPPER_
|
||||||
// Open the input file
|
// Open the input file
|
||||||
_inFd = fopen(filename, "r");
|
_inFd = fopen(filename, "r");
|
||||||
if (!_inFd)
|
if (!_inFd)
|
||||||
|
@ -180,85 +116,83 @@ OSStatus ACInputProc(AudioConverterRef inAudioConverter, UInt32 *ioNumberDataPac
|
||||||
}
|
}
|
||||||
|
|
||||||
//Using callbacks with fopen, ftell, fseek, fclose, because the default pread hangs when accessing the same file from multiple threads.
|
//Using callbacks with fopen, ftell, fseek, fclose, because the default pread hangs when accessing the same file from multiple threads.
|
||||||
err = AudioFileOpenWithCallbacks(self, readFunc, writeFunc, getSizeFunc, setSizeFunc, 0, &_in);
|
err = AudioFileOpenWithCallbacks(self, readFunc, writeFunc, getSizeFunc, setSizeFunc, 0, &_audioID);
|
||||||
if(noErr != err) {
|
if(noErr != err)
|
||||||
NSLog(@"Error opening AudioFile: %i", err);
|
{
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
FSRef ref;
|
FSRef ref;
|
||||||
|
fclose(_inFd);
|
||||||
|
|
||||||
err = FSPathMakeRef((const UInt8 *)filename, &ref, NULL);
|
err = FSPathMakeRef((const UInt8 *)filename, &ref, NULL);
|
||||||
if(noErr != err) {
|
if(noErr != err) {
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = AudioFileOpen(&ref, fsRdPerm, 0, &_in);
|
err = AudioFileOpen(&ref, fsRdPerm, 0, &_audioID);
|
||||||
|
if(noErr != err) {
|
||||||
|
NSLog(@"Error opening AudioFile: %i", (char *)&err);
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = ExtAudioFileWrapAudioFileID(_audioID, NO, &_in);
|
||||||
|
if(noErr != err) {
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
FSRef ref;
|
||||||
|
|
||||||
|
// Open the input file
|
||||||
|
err = FSPathMakeRef((const UInt8 *)filename, &ref, NULL);
|
||||||
|
if(noErr != err) {
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = ExtAudioFileOpen(&ref, &_in);
|
||||||
if(noErr != err) {
|
if(noErr != err) {
|
||||||
NSLog(@"Error opening AudioFile: %i", err);
|
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
return [self readInfoFromExtAudioFileRef];
|
||||||
return [self readInfoFromAudioFile];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL) readInfoFromAudioFile
|
- (BOOL) readInfoFromExtAudioFileRef
|
||||||
{
|
{
|
||||||
OSStatus err;
|
OSStatus err;
|
||||||
UInt32 size;
|
UInt32 size;
|
||||||
|
SInt64 totalFrames;
|
||||||
AudioStreamBasicDescription asbd;
|
AudioStreamBasicDescription asbd;
|
||||||
SInt64 totalBytes;
|
|
||||||
|
|
||||||
// Get input file information
|
// Get input file information
|
||||||
size = sizeof(asbd);
|
size = sizeof(asbd);
|
||||||
err = AudioFileGetProperty(_in, kAudioFilePropertyDataFormat, &size, &asbd);
|
err = ExtAudioFileGetProperty(_in, kExtAudioFileProperty_FileDataFormat, &size, &asbd);
|
||||||
if(err != noErr) {
|
if(err != noErr) {
|
||||||
[self close];
|
err = ExtAudioFileDispose(_in);
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
size = sizeof(_totalPackets);
|
size = sizeof(totalFrames);
|
||||||
err = AudioFileGetProperty(_in, kAudioFilePropertyAudioDataPacketCount, &size, &_totalPackets);
|
err = ExtAudioFileGetProperty(_in, kExtAudioFileProperty_FileLengthFrames, &size, &totalFrames);
|
||||||
if(err != noErr) {
|
if(err != noErr) {
|
||||||
[self close];
|
err = ExtAudioFileDispose(_in);
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
size = sizeof(totalBytes);
|
|
||||||
err = AudioFileGetProperty(_in, kAudioFilePropertyAudioDataByteCount, &size, &totalBytes);
|
|
||||||
if(err != noErr) {
|
|
||||||
[self close];
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
bitRate = ((totalBytes*8)/((_totalPackets * asbd.mFramesPerPacket)/asbd.mSampleRate))/1000.0;
|
|
||||||
// Set our properties
|
// Set our properties
|
||||||
bitsPerSample = asbd.mBitsPerChannel;
|
bitsPerSample = asbd.mBitsPerChannel;
|
||||||
channels = asbd.mChannelsPerFrame;
|
channels = asbd.mChannelsPerFrame;
|
||||||
frequency = asbd.mSampleRate;
|
frequency = asbd.mSampleRate;
|
||||||
|
|
||||||
_framesPerPacket = asbd.mFramesPerPacket;
|
|
||||||
|
|
||||||
// mBitsPerChannel will only be set for lpcm formats
|
// mBitsPerChannel will only be set for lpcm formats
|
||||||
if(0 == bitsPerSample) {
|
if(0 == bitsPerSample) {
|
||||||
bitsPerSample = 16;
|
bitsPerSample = 16;
|
||||||
}
|
}
|
||||||
|
|
||||||
totalSize = _totalPackets * asbd.mFramesPerPacket *channels * (bitsPerSample/8);
|
totalSize = totalFrames * channels * (bitsPerSample / 8);
|
||||||
|
bitRate = 0;
|
||||||
isBigEndian = YES;
|
|
||||||
isUnsigned = NO;
|
|
||||||
|
|
||||||
return [self setupConverter:&asbd];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)setupConverter: (AudioStreamBasicDescription *)inputFormat
|
|
||||||
{
|
|
||||||
OSStatus err;
|
|
||||||
UInt32 size;
|
|
||||||
AudioStreamBasicDescription result;
|
|
||||||
|
|
||||||
// Set output format
|
// Set output format
|
||||||
|
AudioStreamBasicDescription result;
|
||||||
|
|
||||||
bzero(&result, sizeof(AudioStreamBasicDescription));
|
bzero(&result, sizeof(AudioStreamBasicDescription));
|
||||||
|
|
||||||
|
@ -273,51 +207,15 @@ OSStatus ACInputProc(AudioConverterRef inAudioConverter, UInt32 *ioNumberDataPac
|
||||||
result.mFramesPerPacket = 1;
|
result.mFramesPerPacket = 1;
|
||||||
result.mBytesPerFrame = channels * (bitsPerSample / 8);
|
result.mBytesPerFrame = channels * (bitsPerSample / 8);
|
||||||
|
|
||||||
err = AudioConverterNew(inputFormat, &result, &_converter);
|
err = ExtAudioFileSetProperty(_in, kExtAudioFileProperty_ClientDataFormat, sizeof(result), &result);
|
||||||
if (err != noErr)
|
if(noErr != err) {
|
||||||
{
|
err = ExtAudioFileDispose(_in);
|
||||||
[self close];
|
|
||||||
|
|
||||||
NSLog(@"Error creating converter");
|
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = AudioFileGetPropertyInfo( _in,
|
// Further properties
|
||||||
kAudioFilePropertyMagicCookieData,
|
isBigEndian = YES;
|
||||||
&size,
|
isUnsigned = NO;
|
||||||
NULL);
|
|
||||||
|
|
||||||
if (err == noErr) //Some data can be read without magic cookies...
|
|
||||||
{
|
|
||||||
void *magicCookie = malloc (size);
|
|
||||||
//Get Magic Cookie data from Audio File
|
|
||||||
err = AudioFileGetProperty(_in,
|
|
||||||
kAudioFilePropertyMagicCookieData,
|
|
||||||
&size,
|
|
||||||
magicCookie);
|
|
||||||
|
|
||||||
// Give the AudioConverter the magic cookie decompression params if there are any
|
|
||||||
if (err == noErr)
|
|
||||||
{
|
|
||||||
err = AudioConverterSetProperty( _converter,
|
|
||||||
kAudioConverterDecompressionMagicCookie,
|
|
||||||
size,
|
|
||||||
magicCookie);
|
|
||||||
}
|
|
||||||
|
|
||||||
free(magicCookie);
|
|
||||||
}
|
|
||||||
|
|
||||||
size = sizeof(_maxPacketSize);
|
|
||||||
err = AudioFileGetProperty( _in,
|
|
||||||
kAudioFilePropertyMaximumPacketSize,
|
|
||||||
&size,
|
|
||||||
&_maxPacketSize);
|
|
||||||
if(err != noErr) {
|
|
||||||
err = AudioFileClose(_in);
|
|
||||||
NSLog(@"Error getting maximum packet size: %i", err);
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
@ -325,34 +223,35 @@ OSStatus ACInputProc(AudioConverterRef inAudioConverter, UInt32 *ioNumberDataPac
|
||||||
- (int) fillBuffer:(void *)buf ofSize:(UInt32)size
|
- (int) fillBuffer:(void *)buf ofSize:(UInt32)size
|
||||||
{
|
{
|
||||||
OSStatus err;
|
OSStatus err;
|
||||||
|
AudioBufferList bufferList;
|
||||||
UInt32 frameCount;
|
UInt32 frameCount;
|
||||||
AudioBufferList ioData;
|
|
||||||
|
|
||||||
ioData.mNumberBuffers = 1;
|
// Set up the AudioBufferList
|
||||||
ioData.mBuffers[0].mData = buf;
|
bufferList.mNumberBuffers = 1;
|
||||||
ioData.mBuffers[0].mDataByteSize = size;
|
bufferList.mBuffers[0].mNumberChannels = channels;
|
||||||
|
bufferList.mBuffers[0].mData = buf;
|
||||||
frameCount = size / (channels * (bitsPerSample / 8));
|
bufferList.mBuffers[0].mDataByteSize = size;
|
||||||
|
|
||||||
// Read a chunk of PCM input (converted from whatever format)
|
// Read a chunk of PCM input (converted from whatever format)
|
||||||
err = AudioConverterFillComplexBuffer(_converter, ACInputProc , self , &frameCount, &ioData, NULL);
|
frameCount = (size / (channels * (bitsPerSample / 8)));
|
||||||
|
err = ExtAudioFileRead(_in, &frameCount, &bufferList);
|
||||||
if(err != noErr) {
|
if(err != noErr) {
|
||||||
NSLog(@"Error reading converter: %i", err);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ioData.mBuffers[0].mDataByteSize;
|
return frameCount * (channels * (bitsPerSample / 8));
|
||||||
}
|
}
|
||||||
|
|
||||||
- (double) seekToTime:(double)milliseconds
|
- (double) seekToTime:(double)milliseconds
|
||||||
{
|
{
|
||||||
double newTime;
|
OSStatus err;
|
||||||
|
|
||||||
_packetCount = ((milliseconds / 1000.f) * frequency)/_framesPerPacket;
|
err = ExtAudioFileSeek(_in, ((milliseconds / 1000.f) * frequency));
|
||||||
|
if(noErr != err) {
|
||||||
|
return -1.f;
|
||||||
|
}
|
||||||
|
|
||||||
newTime = ((_packetCount * _framesPerPacket)/frequency)*1000.0;
|
return milliseconds;
|
||||||
|
|
||||||
return newTime;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
Loading…
Reference in New Issue