You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
159 lines
3.9 KiB
159 lines
3.9 KiB
//
|
|
// AudioFile.m
|
|
// SpectogramPrototype
|
|
//
|
|
// Created by Joshua Moerman on 28/12/13.
|
|
// Copyright (c) 2013 Joshua Moerman. All rights reserved.
|
|
//
|
|
|
|
#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
|
|
|
|
#pragma mark
|
|
#pragma mark Creation
|
|
|
|
- (id)initWithExtAudioFileRef:(ExtAudioFileRef) af{
|
|
if(self = [super init]){
|
|
audioFile = af;
|
|
buffers = [[NSMutableArray alloc] init];
|
|
[self setupFormat];
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (void)setupFormat{
|
|
format.mSampleRate = 44100.0f;
|
|
format.mFormatID = kAudioFormatLinearPCM;
|
|
format.mFormatFlags = kLinearPCMFormatFlagIsPacked | kLinearPCMFormatFlagIsSignedInteger;
|
|
format.mBytesPerPacket = 4;
|
|
format.mFramesPerPacket = 1;
|
|
format.mBytesPerFrame = 4;
|
|
format.mChannelsPerFrame = 2;
|
|
format.mBitsPerChannel = 16;
|
|
format.mReserved = 0;
|
|
|
|
UInt32 size = sizeof(format);
|
|
OSStatus err = ExtAudioFileSetProperty(audioFile, kExtAudioFileProperty_ClientDataFormat, size, &format);
|
|
assert(err == 0);
|
|
}
|
|
|
|
- (void)dealloc {
|
|
OSStatus err = ExtAudioFileDispose(audioFile);
|
|
assert(err == 0);
|
|
}
|
|
|
|
+ (AudioFile *)audioFileFromURL:(NSURL *)url{
|
|
ExtAudioFileRef audioFile = NULL;
|
|
OSStatus err = ExtAudioFileOpenURL((__bridge CFURLRef) url, &audioFile);
|
|
assert(err == 0 && audioFile);
|
|
|
|
return [[AudioFile alloc] initWithExtAudioFileRef:audioFile];
|
|
}
|
|
|
|
- (Buffer *)getBufferForSample:(NSUInteger)sample{
|
|
for (Buffer * b in buffers) {
|
|
if(NSLocationInRange(sample, b->range)){
|
|
return b;
|
|
}
|
|
}
|
|
|
|
|
|
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 = buffer_size * format.mBytesPerFrame;
|
|
bufferList.mBuffers[0].mData = calloc(bufferList.mBuffers[0].mDataByteSize, 1);
|
|
|
|
UInt32 nFrames = buffer_size;
|
|
OSStatus err = ExtAudioFileRead(audioFile, &nFrames, &bufferList);
|
|
assert(err == 0);
|
|
|
|
short * buffer = bufferList.mBuffers[0].mData;
|
|
|
|
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;
|
|
}
|
|
|
|
// assume left and right are of the same size
|
|
while(left != leftEnd){
|
|
*left++ = 0;
|
|
*right++ = 0;
|
|
}
|
|
|
|
b->range.length = nFrames;
|
|
|
|
free(bufferList.mBuffers[0].mData);
|
|
|
|
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
|
|
|