//
//  MP3Decoder.m
//  Ensemble2
//
//  Created by Tom Lemberg on 5/9/10.
//  Copyright 2010 __MyCompanyName__. All rights reserved.
//

#import "MP3Decoder.h"

AudioFileID input;
AudioFileID output;

SInt64 inputIndex;
SInt64 outputIndex;
UInt8 *buffer;

UInt32 maxPacketSize;
UInt64 packetCount;

AudioStreamPacketDescription *packetDescription;

id selfRef;

void decode(CFURLRef inputURL, CFURLRef outputURL);
OSStatus fillBuffer(AudioConverterRef converter, UInt32 *nPackets, AudioBufferList *bufferList, AudioStreamPacketDescription **outputPacketFormat, void *inputData);

@implementation MP3Decoder

- (void)decode:(NSString *)filename withCallback:(SEL)updateCallback caller:(Ensemble2ViewController *)callerObject{
	
	MP3Decoder *genericDecoder = [[MP3Decoder alloc] init];
	selfRef = genericDecoder;
	
	input = NULL;
	output = NULL;
	inputIndex = 0;
	outputIndex = 0;
	buffer = NULL;
	maxPacketSize = 0;
	packetCount = 0;
	packetDescription = NULL;
	
	update = updateCallback;
	caller = callerObject;
	
	NSString *inputPath = [FileUtility pathToFile:filename ofType:@"mp3"];
	CFURLRef inputURL = (CFURLRef)[NSURL fileURLWithPath:inputPath isDirectory:NO];
	
	NSString *outputPath = [FileUtility pathToFile:filename ofType:@"aiff"];
	NSFileManager *manager = [NSFileManager defaultManager];
	[manager createFileAtPath:outputPath contents:nil attributes:nil];
	CFURLRef outputURL = (CFURLRef)[NSURL fileURLWithPath:outputPath isDirectory:NO];
	
	NSLog(inputPath);
	NSLog(outputPath);
	
	decode(inputURL, outputURL);
	
}

void decode(CFURLRef inputURL, CFURLRef outputURL) {
	
	AudioFileOpenURL(inputURL, kAudioFileReadPermission, kAudioFileMP3Type, &input);
	
	UInt32 size;
	UInt32 writable;
	
	AudioStreamBasicDescription inputFormat;
	AudioFileGetPropertyInfo(input, kAudioFilePropertyDataFormat, &size, &writable);
	AudioFileGetProperty(input, kAudioFilePropertyDataFormat, &size, &inputFormat);
	
	AudioFileGetPropertyInfo(input, kAudioFilePropertyAudioDataPacketCount, &size, &writable);
	AudioFileGetProperty(input, kAudioFilePropertyAudioDataPacketCount, &size, &packetCount);
	
	AudioFileGetPropertyInfo(input, kAudioFilePropertyMaximumPacketSize, &size, &writable);
	AudioFileGetProperty(input, kAudioFilePropertyMaximumPacketSize, &size, &maxPacketSize);
	
	AudioStreamBasicDescription outputFormat;
	
	outputFormat.mSampleRate = 44100;
	outputFormat.mFormatID = kAudioFormatLinearPCM;
	outputFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked | kLinearPCMFormatFlagIsBigEndian;
	outputFormat.mBytesPerPacket = 4;
	outputFormat.mFramesPerPacket = 1;
	outputFormat.mBytesPerFrame = 4;
	outputFormat.mChannelsPerFrame = 2;
	outputFormat.mBitsPerChannel = 16;
	
	AudioFileCreateWithURL(outputURL, kAudioFileAIFFType, &outputFormat, kAudioFileFlags_EraseFile, &output);
	
	AudioStreamBasicDescription testFMT;
	AudioFileGetPropertyInfo(output, kAudioFilePropertyDataFormat, &size, &writable);
	AudioFileGetProperty(output, kAudioFilePropertyDataFormat, &size, &testFMT);
	
	AudioConverterRef converter;
	AudioConverterNew(&inputFormat, &outputFormat, &converter);
	
	UInt32 nPackets = 512;
	
	AudioBufferList *bufferList = (AudioBufferList *)calloc(1, sizeof(AudioBufferList));
	bufferList->mNumberBuffers = 1;
	
	bufferList->mBuffers[0].mNumberChannels = 2;
	bufferList->mBuffers[0].mDataByteSize = 2048;
	bufferList->mBuffers[0].mData = calloc(1, 2048);
	
	packetDescription = (AudioStreamPacketDescription *)calloc(sizeof(AudioStreamPacketDescription), nPackets);
	
	while(nPackets == 512){
				
		AudioConverterFillComplexBuffer(converter, fillBuffer, NULL, &nPackets, bufferList, packetDescription);
		
		AudioFileWritePackets(output, FALSE, bufferList->mBuffers[0].mDataByteSize, NULL, outputIndex, &nPackets, bufferList->mBuffers[0].mData);
		outputIndex += nPackets;
		
	}
	
	AudioFileClose(input);
	AudioFileClose(output);
	
}

OSStatus fillBuffer(AudioConverterRef converter, UInt32 *nPackets, AudioBufferList *bufferList, AudioStreamPacketDescription **outPacketDescription, void *inputData){
	
	UInt32 nBytes;
	
	bufferList->mBuffers[0].mDataByteSize = 0;
	bufferList->mBuffers[0].mData = NULL;
	
	if(buffer != NULL){
		free(buffer);
		buffer = NULL;
	}
	
	buffer = (UInt8 *)calloc(1, *nPackets * maxPacketSize);
	
	AudioFileReadPackets(input, FALSE, &nBytes, packetDescription, inputIndex, nPackets, buffer);
	*outPacketDescription = packetDescription;
	inputIndex += *nPackets;
	
	bufferList->mBuffers[0].mDataByteSize = nBytes;
	bufferList->mBuffers[0].mData = buffer;
	
	[selfRef doUpdate];
	
	return noErr;
	
}

- (void)doUpdate {
	
	//NSNumber *packets = [NSNumber numberWithLongLong:inputIndex];
	//NSNumber *total = [NSNumber numberWithUnsignedLongLong:packetCount];
	[caller performSelector:update];
	
}

@end
