|
|
@ -9,12 +9,29 @@ |
|
|
|
#import "AudioFile.h" |
|
|
|
@import AudioToolbox.ExtendedAudioFile; |
|
|
|
|
|
|
|
static const size_t buffer_size = 1 << 12; |
|
|
|
|
|
|
|
@interface Buffer : NSObject { |
|
|
|
@public |
|
|
|
float left[buffer_size]; |
|
|
|
float right[buffer_size]; |
|
|
|
NSRange range; |
|
|
|
} |
|
|
|
@end |
|
|
|
|
|
|
|
@implementation Buffer |
|
|
|
@end |
|
|
|
|
|
|
|
|
|
|
|
@interface AudioFile (){ |
|
|
|
ExtAudioFileRef audioFile; |
|
|
|
AudioStreamBasicDescription format; |
|
|
|
NSMutableArray * buffers; |
|
|
|
} |
|
|
|
- (id)initWithExtAudioFileRef:(ExtAudioFileRef) audioFile; |
|
|
|
- (void)setupFormat; |
|
|
|
- (Buffer*)getBufferForSample:(NSUInteger) sample; |
|
|
|
- (Buffer*)appendBuffer; |
|
|
|
@end |
|
|
|
|
|
|
|
@implementation AudioFile |
|
|
@ -25,6 +42,7 @@ |
|
|
|
- (id)initWithExtAudioFileRef:(ExtAudioFileRef) af{ |
|
|
|
if(self = [super init]){ |
|
|
|
audioFile = af; |
|
|
|
buffers = [[NSMutableArray alloc] init]; |
|
|
|
[self setupFormat]; |
|
|
|
} |
|
|
|
return self; |
|
|
@ -59,22 +77,45 @@ |
|
|
|
return [[AudioFile alloc] initWithExtAudioFileRef:audioFile]; |
|
|
|
} |
|
|
|
|
|
|
|
#pragma mark |
|
|
|
#pragma mark Usage |
|
|
|
- (Buffer *)getBufferForSample:(NSUInteger)sample{ |
|
|
|
for (Buffer * b in buffers) { |
|
|
|
if(NSLocationInRange(sample, b->range)){ |
|
|
|
return b; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
- (unsigned int)fillLeft:(float *)left andRight:(float *)right withNumberOfSamples:(unsigned int)nSamples { |
|
|
|
AudioBufferList bufferList; |
|
|
|
while(1){ |
|
|
|
Buffer * b = [self appendBuffer]; |
|
|
|
if(!b) return nil; |
|
|
|
if(NSLocationInRange(sample, b->range)) return b; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
- (Buffer *)appendBuffer{ |
|
|
|
Buffer * b = [[Buffer alloc] init]; |
|
|
|
Buffer * last = [buffers lastObject]; |
|
|
|
if(last){ |
|
|
|
b->range.location = last->range.location + last->range.length; |
|
|
|
} else { |
|
|
|
b->range.location = 0; |
|
|
|
} |
|
|
|
|
|
|
|
AudioBufferList bufferList; |
|
|
|
bufferList.mNumberBuffers = 1; |
|
|
|
bufferList.mBuffers[0].mNumberChannels = 2; |
|
|
|
bufferList.mBuffers[0].mDataByteSize = nSamples * format.mBytesPerFrame; |
|
|
|
bufferList.mBuffers[0].mDataByteSize = buffer_size * format.mBytesPerFrame; |
|
|
|
bufferList.mBuffers[0].mData = calloc(bufferList.mBuffers[0].mDataByteSize, 1); |
|
|
|
|
|
|
|
UInt32 nFrames = nSamples; |
|
|
|
UInt32 nFrames = buffer_size; |
|
|
|
OSStatus err = ExtAudioFileRead(audioFile, &nFrames, &bufferList); |
|
|
|
assert(err == 0); |
|
|
|
|
|
|
|
short * buffer = bufferList.mBuffers[0].mData; |
|
|
|
float * leftEnd = left + nSamples; |
|
|
|
|
|
|
|
float * left = b->left; |
|
|
|
float * right = b->right; |
|
|
|
float * leftEnd = left + buffer_size; |
|
|
|
for(unsigned int i = 0; i < nFrames; ++i){ |
|
|
|
*left++ = *buffer++ / 32768.0f; |
|
|
|
*right++ = *buffer++ / 32768.0f; |
|
|
@ -85,10 +126,34 @@ |
|
|
|
*left++ = 0; |
|
|
|
*right++ = 0; |
|
|
|
} |
|
|
|
|
|
|
|
b->range.length = nFrames; |
|
|
|
|
|
|
|
free(bufferList.mBuffers[0].mData); |
|
|
|
|
|
|
|
return nFrames; |
|
|
|
|
|
|
|
if(!nFrames) return nil; |
|
|
|
[buffers addObject:b]; |
|
|
|
return b; |
|
|
|
} |
|
|
|
|
|
|
|
#pragma mark |
|
|
|
#pragma mark Usage |
|
|
|
|
|
|
|
- (BOOL)fillLeft:(float *)left andRight:(float *)right forRange:(NSRange)range{ |
|
|
|
NSUInteger n = range.length; |
|
|
|
|
|
|
|
Buffer * b = nil; |
|
|
|
while ((b = [self getBufferForSample:range.location])) { |
|
|
|
while(range.length && NSLocationInRange(range.location, b->range)){ |
|
|
|
*left++ = b->left[range.location - b->range.location]; |
|
|
|
*right++ = b->right[range.location - b->range.location]; |
|
|
|
range.location++; |
|
|
|
range.length--; |
|
|
|
} |
|
|
|
if(range.length == 0) break; |
|
|
|
} |
|
|
|
|
|
|
|
return range.length < n; |
|
|
|
} |
|
|
|
|
|
|
|
@end |
|
|
|