CoreAudioFile fixes

CQTexperiment
vspader 2006-05-13 04:50:06 +00:00
parent 269cd05b5f
commit 5472794be8
2 changed files with 98 additions and 201 deletions

View File

@ -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

View File

@ -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