diff --git a/OrigamiEngine/Plugins/CoreAudioDecoder.m b/OrigamiEngine/Plugins/CoreAudioDecoder.m index 87c9abf..d8f2175 100644 --- a/OrigamiEngine/Plugins/CoreAudioDecoder.m +++ b/OrigamiEngine/Plugins/CoreAudioDecoder.m @@ -29,13 +29,13 @@ @interface CoreAudioDecoder () { id _source; AudioFileID _audioFile; - ExtAudioFileRef _in; - - int bitrate; - int bitsPerSample; - int channels; - float frequency; - long totalFrames; + ExtAudioFileRef _in; + + int bitrate; + int bitsPerSample; + int channels; + float frequency; + long totalFrames; } @property (retain, nonatomic) NSMutableDictionary *metadata; @end @@ -51,22 +51,21 @@ - (void)dealloc { #pragma mark - ORGMDecoder + (NSArray *)fileTypes { - OSStatus err; - UInt32 size; - NSArray *sAudioExtensions; - - size = sizeof(sAudioExtensions); - err = AudioFileGetGlobalInfo(kAudioFileGlobalInfo_AllExtensions, 0, NULL, - &size, &sAudioExtensions); - if(noErr != err) { - return nil; - } - - return [sAudioExtensions autorelease]; + OSStatus err; + UInt32 size; + NSArray *sAudioExtensions; + + size = sizeof(sAudioExtensions); + err = AudioFileGetGlobalInfo(kAudioFileGlobalInfo_AllExtensions, 0, NULL, &size, &sAudioExtensions); + if (noErr != err) { + return nil; + } + + return [sAudioExtensions autorelease]; } - (NSDictionary *)properties { - return [NSDictionary dictionaryWithObjectsAndKeys: + return [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithInt:channels], @"channels", [NSNumber numberWithInt:bitsPerSample], @"bitsPerSample", [NSNumber numberWithInt:bitrate], @"bitrate", @@ -82,52 +81,52 @@ - (NSMutableDictionary *)metadata { } - (int)readAudio:(void *)buf frames:(UInt32)frames { - OSStatus err; - AudioBufferList bufferList; - UInt32 frameCount; - - bufferList.mNumberBuffers = 1; - bufferList.mBuffers[0].mNumberChannels = channels; - bufferList.mBuffers[0].mData = buf; - bufferList.mBuffers[0].mDataByteSize = frames * channels * (bitsPerSample/8); - - frameCount = frames; - err = ExtAudioFileRead(_in, &frameCount, &bufferList); - if(err != noErr) { - return 0; - } - - return frameCount; + OSStatus err; + AudioBufferList bufferList; + UInt32 frameCount; + + bufferList.mNumberBuffers = 1; + bufferList.mBuffers[0].mNumberChannels = channels; + bufferList.mBuffers[0].mData = buf; + bufferList.mBuffers[0].mDataByteSize = frames * channels * (bitsPerSample/8); + + frameCount = frames; + err = ExtAudioFileRead(_in, &frameCount, &bufferList); + if (err != noErr) { + return 0; + } + + return frameCount; } - (BOOL)open:(id)source { self.metadata = [NSMutableDictionary dictionary]; _source = [source retain]; - OSStatus result = AudioFileOpenWithCallbacks(_source, audioFile_ReadProc, NULL, + OSStatus result = AudioFileOpenWithCallbacks(_source, audioFile_ReadProc, NULL, audioFile_GetSizeProc, NULL, 0, &_audioFile); - - if(noErr != result) { + + if (noErr != result) { + return NO; + } + + result = ExtAudioFileWrapAudioFileID(_audioFile, false, &_in); + if (noErr != result) { return NO; } - - result = ExtAudioFileWrapAudioFileID(_audioFile, false, &_in); - if(noErr != result) { - return NO; - } - - return [self readInfoFromExtAudioFileRef]; + + return [self readInfoFromExtAudioFileRef]; } - (long)seek:(long)frame { - OSStatus err; - - err = ExtAudioFileSeek(_in, frame); - if(noErr != err) { - return -1; - } - - return frame; + OSStatus err; + + err = ExtAudioFileSeek(_in, frame); + if (noErr != err) { + return -1; + } + + return frame; } - (void)close { @@ -137,120 +136,179 @@ - (void)close { } #pragma mark - private + - (BOOL)readInfoFromExtAudioFileRef { - OSStatus err; - UInt32 size; - AudioStreamBasicDescription asbd; - - size = sizeof(asbd); - err = ExtAudioFileGetProperty(_in, kExtAudioFileProperty_FileDataFormat, - &size, &asbd); - if(err != noErr) { + OSStatus err; + UInt32 size; + AudioStreamBasicDescription asbd; + + size = sizeof(asbd); + err = ExtAudioFileGetProperty(_in, + kExtAudioFileProperty_FileDataFormat, + &size, + &asbd); + if (err != noErr) { + ExtAudioFileDispose(_in); + return NO; + } + + SInt64 total; + size = sizeof(total); + err = ExtAudioFileGetProperty(_in, + kExtAudioFileProperty_FileLengthFrames, + &size, + &total); + if(err != noErr) { ExtAudioFileDispose(_in); - return NO; - } - - SInt64 total; - size = sizeof(total); - err = ExtAudioFileGetProperty(_in, kExtAudioFileProperty_FileLengthFrames, - &size, &total); - if(err != noErr) { - ExtAudioFileDispose(_in); - return NO; - } - totalFrames = (long)total; - + return NO; + } + totalFrames = (long)total; + AudioFileID audioFile; size = sizeof(AudioFileID); err = ExtAudioFileGetProperty(_in, - kExtAudioFileProperty_AudioFile, - &size, - &audioFile); + kExtAudioFileProperty_AudioFile, + &size, + &audioFile); + if (err == noErr) { UInt32 dictionarySize = 0; err = AudioFileGetPropertyInfo(audioFile, - kAudioFilePropertyInfoDictionary, - &dictionarySize, - 0); + kAudioFilePropertyInfoDictionary, + &dictionarySize, + 0); + if (err == noErr) { CFDictionaryRef dictionary; AudioFileGetProperty(audioFile, - kAudioFilePropertyInfoDictionary, - &dictionarySize, - &dictionary); + kAudioFilePropertyInfoDictionary, + &dictionarySize, + &dictionary); self.metadata = [NSMutableDictionary dictionaryWithDictionary:(NSDictionary *)dictionary]; CFRelease(dictionary); } - + err = AudioFileGetPropertyInfo(audioFile, - kAudioFilePropertyAlbumArtwork, - &dictionarySize, - 0); - + kAudioFilePropertyAlbumArtwork, + &dictionarySize, + 0); + if (err == noErr) { CFDataRef data; AudioFileGetProperty(audioFile, - kAudioFilePropertyAlbumArtwork, - &dictionarySize, - &data); + kAudioFilePropertyAlbumArtwork, + &dictionarySize, + &data); + if (data) { [self.metadata setObject:(NSData *)data forKey:@"picture"]; CFRelease(data); } + } else { + [self.metadata setObject:[self imageDataFromID3Tag:audioFile] forKey:@"picture"]; } } - - bitrate = 0; - bitsPerSample = asbd.mBitsPerChannel; - channels = asbd.mChannelsPerFrame; - frequency = asbd.mSampleRate; - - if(0 == bitsPerSample) { - bitsPerSample = 16; - } - - AudioStreamBasicDescription result; - bzero(&result, sizeof(AudioStreamBasicDescription)); - - result.mFormatID = kAudioFormatLinearPCM; - result.mFormatFlags = kAudioFormatFlagIsSignedInteger | - kLinearPCMFormatFlagIsBigEndian; - - result.mSampleRate = frequency; - result.mChannelsPerFrame = channels; - result.mBitsPerChannel = bitsPerSample; - - result.mBytesPerPacket = channels * (bitsPerSample / 8); - result.mFramesPerPacket = 1; - result.mBytesPerFrame = channels * (bitsPerSample / 8); - - err = ExtAudioFileSetProperty(_in, kExtAudioFileProperty_ClientDataFormat, - sizeof(result), &result); - if(noErr != err) { - ExtAudioFileDispose(_in); - return NO; - } - - return YES; + + bitrate = 0; + bitsPerSample = asbd.mBitsPerChannel; + channels = asbd.mChannelsPerFrame; + frequency = asbd.mSampleRate; + + if(0 == bitsPerSample) { + bitsPerSample = 16; + } + + AudioStreamBasicDescription result; + bzero(&result, sizeof(AudioStreamBasicDescription)); + + result.mFormatID = kAudioFormatLinearPCM; + result.mFormatFlags = kAudioFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsBigEndian; + + result.mSampleRate = frequency; + result.mChannelsPerFrame = channels; + result.mBitsPerChannel = bitsPerSample; + + result.mBytesPerPacket = channels * (bitsPerSample / 8); + result.mFramesPerPacket = 1; + result.mBytesPerFrame = channels * (bitsPerSample / 8); + + err = ExtAudioFileSetProperty(_in, kExtAudioFileProperty_ClientDataFormat, + sizeof(result), &result); + if(noErr != err) { + ExtAudioFileDispose(_in); + return NO; + } + + return YES; +} + +- (NSData *)imageDataFromID3Tag:(AudioFileID)audioFile { + + OSStatus err; + + UInt32 propertySize = 0; + AudioFileGetPropertyInfo(audioFile, + kAudioFilePropertyID3Tag, + &propertySize, + 0); + + char *rawID3Tag = (char *)malloc(propertySize); + err = AudioFileGetProperty(audioFile, + kAudioFilePropertyID3Tag, + &propertySize, + rawID3Tag); + + if (err != noErr) { + return nil; + } + + UInt32 id3TagSize = 0; + UInt32 id3TagSizeLength = sizeof(id3TagSize); + AudioFormatGetProperty(kAudioFormatProperty_ID3TagSize, + propertySize, + rawID3Tag, + &id3TagSizeLength, + &id3TagSize); + + CFDictionaryRef id3Dict; + AudioFormatGetProperty(kAudioFormatProperty_ID3TagToDictionary, + propertySize, + rawID3Tag, + &id3TagSize, + &id3Dict); + + NSDictionary *tagDict = [NSDictionary dictionaryWithDictionary:(NSDictionary *)id3Dict]; + free(rawID3Tag); + CFRelease(id3Dict); + + NSDictionary *apicDict = tagDict[@"APIC"]; + if (!apicDict) return nil; + + NSString *picKey = [[apicDict allKeys] lastObject]; + NSDictionary *picDict = apicDict[picKey]; + if (!picDict) return nil; + + return picDict[@"data"]; } #pragma mark - callback functions + static OSStatus audioFile_ReadProc(void *inClientData, SInt64 inPosition, UInt32 requestCount, - void *buffer, + void *buffer, UInt32 *actualCount) { id source = inClientData; [source seek:(long)inPosition whence:0]; - *actualCount = [source read:buffer amount:requestCount]; - - return noErr; + *actualCount = [source read:buffer amount:requestCount]; + + return noErr; } static SInt64 audioFile_GetSizeProc(void *inClientData) { - id source = inClientData; + id source = inClientData; SInt64 len = [source size]; - return len; + return len; } @end