diff --git a/Cog.xcodeproj/project.pbxproj b/Cog.xcodeproj/project.pbxproj index 1871aff80..dbce54fd3 100644 --- a/Cog.xcodeproj/project.pbxproj +++ b/Cog.xcodeproj/project.pbxproj @@ -13,6 +13,10 @@ 8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; }; 8E4C7F080A0509FC003BE25F /* DragScrollView.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8E4C7F060A0509FC003BE25F /* DragScrollView.h */; }; 8E4C7F090A0509FC003BE25F /* DragScrollView.m in Sources */ = {isa = PBXBuildFile; fileRef = 8E4C7F070A0509FC003BE25F /* DragScrollView.m */; }; + 8E6A8E2B0A0D8A68002ABE9C /* CoreAudioFile.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8E6A8E270A0D8A68002ABE9C /* CoreAudioFile.h */; }; + 8E6A8E2C0A0D8A68002ABE9C /* CoreAudioFile.m in Sources */ = {isa = PBXBuildFile; fileRef = 8E6A8E280A0D8A68002ABE9C /* CoreAudioFile.m */; }; + 8E6A8E370A0D8AD8002ABE9C /* CoreAudioUtils.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8E6A8E350A0D8AD8002ABE9C /* CoreAudioUtils.h */; }; + 8E6A8E380A0D8AD8002ABE9C /* CoreAudioUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 8E6A8E360A0D8AD8002ABE9C /* CoreAudioUtils.m */; }; 8E75756909F31D5A0080F1EE /* AppController.m in Sources */ = {isa = PBXBuildFile; fileRef = 8E75751909F31D5A0080F1EE /* AppController.m */; }; 8E75756A09F31D5A0080F1EE /* ClickField.m in Sources */ = {isa = PBXBuildFile; fileRef = 8E75751C09F31D5A0080F1EE /* ClickField.m */; }; 8E75756B09F31D5A0080F1EE /* InfoView.m in Sources */ = {isa = PBXBuildFile; fileRef = 8E75751E09F31D5A0080F1EE /* InfoView.m */; }; @@ -142,6 +146,8 @@ 8E757B5809F326710080F1EE /* FAAD2.framework in CopyFiles */, 8E757B5909F326710080F1EE /* DecMPA.framework in CopyFiles */, 8E4C7F080A0509FC003BE25F /* DragScrollView.h in CopyFiles */, + 8E6A8E2B0A0D8A68002ABE9C /* CoreAudioFile.h in CopyFiles */, + 8E6A8E370A0D8AD8002ABE9C /* CoreAudioUtils.h in CopyFiles */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -160,6 +166,10 @@ 8D1107320486CEB800E47090 /* Cog.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Cog.app; sourceTree = BUILT_PRODUCTS_DIR; }; 8E4C7F060A0509FC003BE25F /* DragScrollView.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = DragScrollView.h; sourceTree = ""; }; 8E4C7F070A0509FC003BE25F /* DragScrollView.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = DragScrollView.m; sourceTree = ""; }; + 8E6A8E270A0D8A68002ABE9C /* CoreAudioFile.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = CoreAudioFile.h; sourceTree = ""; }; + 8E6A8E280A0D8A68002ABE9C /* CoreAudioFile.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = CoreAudioFile.m; sourceTree = ""; }; + 8E6A8E350A0D8AD8002ABE9C /* CoreAudioUtils.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = CoreAudioUtils.h; sourceTree = ""; }; + 8E6A8E360A0D8AD8002ABE9C /* CoreAudioUtils.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = CoreAudioUtils.m; sourceTree = ""; }; 8E75751309F31D130080F1EE /* French */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = French; path = French.lproj/MainMenu.nib; sourceTree = ""; }; 8E75751809F31D5A0080F1EE /* AppController.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = AppController.h; sourceTree = ""; }; 8E75751909F31D5A0080F1EE /* AppController.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = AppController.m; sourceTree = ""; }; @@ -474,6 +484,8 @@ 8E75754409F31D5A0080F1EE /* SoundFile */ = { isa = PBXGroup; children = ( + 8E6A8E270A0D8A68002ABE9C /* CoreAudioFile.h */, + 8E6A8E280A0D8A68002ABE9C /* CoreAudioFile.m */, 8E75754509F31D5A0080F1EE /* AACFile.h */, 8E75754609F31D5A0080F1EE /* AACFile.m */, 8E75754709F31D5A0080F1EE /* FlacFile.h */, @@ -512,6 +524,8 @@ 8E75756209F31D5A0080F1EE /* Utils */ = { isa = PBXGroup; children = ( + 8E6A8E350A0D8AD8002ABE9C /* CoreAudioUtils.h */, + 8E6A8E360A0D8AD8002ABE9C /* CoreAudioUtils.m */, 8E75756309F31D5A0080F1EE /* DBLog.h */, 8E75756409F31D5A0080F1EE /* DBLog.m */, 8E75756509F31D5A0080F1EE /* Semaphore.h */, @@ -699,6 +713,8 @@ 8E75758C09F31D5A0080F1EE /* Semaphore.m in Sources */, 8E75758D09F31D5A0080F1EE /* VirtualRingBuffer.m in Sources */, 8E4C7F090A0509FC003BE25F /* DragScrollView.m in Sources */, + 8E6A8E2C0A0D8A68002ABE9C /* CoreAudioFile.m in Sources */, + 8E6A8E380A0D8AD8002ABE9C /* CoreAudioUtils.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/English.lproj/MainMenu.nib/info.nib b/English.lproj/MainMenu.nib/info.nib index 62541da41..cd1c35531 100644 --- a/English.lproj/MainMenu.nib/info.nib +++ b/English.lproj/MainMenu.nib/info.nib @@ -28,11 +28,11 @@ 3 IBOpenObjects - 513 - 823 463 - 29 + 823 21 + 29 + 513 IBSystem Version 8I127 diff --git a/English.lproj/MainMenu.nib/keyedobjects.nib b/English.lproj/MainMenu.nib/keyedobjects.nib index 74275ed5d..02929b509 100644 Binary files a/English.lproj/MainMenu.nib/keyedobjects.nib and b/English.lproj/MainMenu.nib/keyedobjects.nib differ diff --git a/Info.plist b/Info.plist index 01ba218a9..4915ba8f8 100644 --- a/Info.plist +++ b/Info.plist @@ -95,7 +95,7 @@ CFBundleSignature ???? CFBundleVersion - 0.05 alpha 1 + 0.06 NSAppleScriptEnabled YES NSMainNibFile diff --git a/Playlist/PlaylistController.m b/Playlist/PlaylistController.m index e932440a1..f3d62321d 100644 --- a/Playlist/PlaylistController.m +++ b/Playlist/PlaylistController.m @@ -10,6 +10,8 @@ #import "PlaylistEntry.h" #import "Shuffle.h" +extern NSArray * getCoreAudioExtensions(); + @implementation PlaylistController #define SHUFFLE_HISTORY_SIZE 100 @@ -20,7 +22,8 @@ if (self) { - acceptableFileTypes = [[NSArray alloc] initWithObjects:@"shn",@"wv",@"ogg",@"wav",@"mpc",@"flac",@"ape",@"mp3",@"aiff",@"aif",@"aac",nil]; + acceptableFileTypes = [NSArray arrayWithObjects:@"shn",@"wv",@"ogg",@"mpc",@"flac",@"ape",nil]; + acceptableFileTypes = [[acceptableFileTypes arrayByAddingObjectsFromArray:getCoreAudioExtensions()] retain]; acceptablePlaylistTypes = [[NSArray alloc] initWithObjects:@"playlist",nil]; shuffleList = [[NSMutableArray alloc] init]; // DBLog(@"DAH BUTTER CHORNAR: %@", history); @@ -40,7 +43,7 @@ { PlaylistEntry *pe = [[PlaylistEntry alloc] init]; - [pe setFilename:filename]; //Setfilename takes car of opening the soundfile..cheap hack, but works for now + [pe setFilename:filename]; [pe setIndex:index]; [pe readTags]; [pe readInfo]; diff --git a/Playlist/PlaylistEntry.m b/Playlist/PlaylistEntry.m index 9cf63438d..6c285823d 100644 --- a/Playlist/PlaylistEntry.m +++ b/Playlist/PlaylistEntry.m @@ -199,6 +199,7 @@ sampleRate = [sf frequency]; [self setLengthString:length]; + [sf release]; // DBLog(@"Length: %f bitRate: %i channels: %i bps: %i samplerate: %f", length, bitRate, channels, bitsPerSample, sampleRate); //[(SoundFile *)sf close]; diff --git a/Sound/BufferChain.m b/Sound/BufferChain.m index 78b1885a4..31c944417 100644 --- a/Sound/BufferChain.m +++ b/Sound/BufferChain.m @@ -67,6 +67,7 @@ [playlistEntry release]; [inputNode release]; + [converterNode release]; [super dealloc]; diff --git a/Sound/InputNode.m b/Sound/InputNode.m index 717420dea..ee074d959 100644 --- a/Sound/InputNode.m +++ b/Sound/InputNode.m @@ -40,7 +40,7 @@ char *buf; int amountRead; - DBLog(@"Playing file.\n"); + NSLog(@"Playing file: %i", self); buf = malloc(chunk_size); while ([self shouldContinue] == YES && [self endOfStream] == NO) @@ -65,6 +65,8 @@ free(buf); [soundFile close]; + + NSLog(@"CLOSED: %i", self); } - (void)seek:(double)time diff --git a/Sound/SoundController.m b/Sound/SoundController.m index 02ac11fbb..fa43d97f0 100644 --- a/Sound/SoundController.m +++ b/Sound/SoundController.m @@ -50,6 +50,7 @@ if (bufferChain) { [bufferChain setShouldContinue:NO]; + [bufferChain release]; } bufferChain = [[BufferChain alloc] initWithController:self]; diff --git a/Sound/SoundFile/CoreAudioFile.h b/Sound/SoundFile/CoreAudioFile.h new file mode 100644 index 000000000..61a613346 --- /dev/null +++ b/Sound/SoundFile/CoreAudioFile.h @@ -0,0 +1,32 @@ +/* + * $Id$ + * + * Copyright (C) 2006 Stephen F. Booth + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#import + +#include + +#import "SoundFile.h" + +@interface CoreAudioFile : SoundFile +{ + ExtAudioFileRef _in; +} + +@end diff --git a/Sound/SoundFile/CoreAudioFile.m b/Sound/SoundFile/CoreAudioFile.m new file mode 100644 index 000000000..e50b89efc --- /dev/null +++ b/Sound/SoundFile/CoreAudioFile.m @@ -0,0 +1,192 @@ +/* + * $Id$ + * + * Copyright (C) 2006 Stephen F. Booth + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#import "CoreAudioFile.h" + +@interface CoreAudioFile (Private) +- (BOOL) readInfoFromExtAudioFileRef:(ExtAudioFileRef)file; +@end + +@implementation CoreAudioFile + +- (BOOL) open:(const char *)filename +{ + OSStatus err; + FSRef ref; + + // Open the input file + err = FSPathMakeRef((const UInt8 *)filename, &ref, NULL); + if(noErr != err) { + NSLog(@"Error opening ExtAudioFile: %i", err); + return NO; + } + + err = ExtAudioFileOpen(&ref, &_in); + if(noErr != err) { + NSLog(@"Error opening ExtAudioFile: %i", err); + return NO; + } + + // Read properties + return [self readInfoFromExtAudioFileRef:_in]; +} + +- (void) close +{ + OSStatus err; + + err = ExtAudioFileDispose(_in); + if(noErr != err) { + NSLog(@"Error closing ExtAudioFile: %i", err); + } +} + +- (BOOL) readInfo:(const char *)filename +{ + OSStatus err; + FSRef ref; + BOOL result; + + result = YES; + + // Open the input file + err = FSPathMakeRef((const UInt8 *)filename, &ref, NULL); + if(noErr != err) { + NSLog(@"Error closing ExtAudioFile: %i", err); + return NO; + } + + err = ExtAudioFileOpen(&ref, &_in); + if(noErr != err) { + NSLog(@"Error closing ExtAudioFile: %i", err); + return NO; + } + + result = [self readInfoFromExtAudioFileRef:_in]; + + return result; +} + +- (BOOL) readInfoFromExtAudioFileRef:(ExtAudioFileRef)file +{ + OSStatus err; + UInt32 size; + SInt64 totalFrames; + AudioStreamBasicDescription asbd; + + // Get input file information + size = sizeof(asbd); + err = ExtAudioFileGetProperty(file, kExtAudioFileProperty_FileDataFormat, &size, &asbd); + if(err != noErr) { + err = ExtAudioFileDispose(file); + NSLog(@"Error closing ExtAudioFile: %i", err); + return NO; + } + + size = sizeof(totalFrames); + err = ExtAudioFileGetProperty(file, kExtAudioFileProperty_FileLengthFrames, &size, &totalFrames); + if(err != noErr) { + err = ExtAudioFileDispose(file); + NSLog(@"Error closing ExtAudioFile: %i", err); + return NO; + } + + // Set our properties + bitsPerSample = asbd.mBitsPerChannel; + channels = asbd.mChannelsPerFrame; + frequency = asbd.mSampleRate; + + // mBitsPerChannel will only be set for lpcm formats + if(0 == bitsPerSample) { + bitsPerSample = 16; + } + + totalSize = totalFrames * channels * (bitsPerSample / 8); + currentPosition = 0; + bitRate = 0; + + // Set output format + 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(file, kExtAudioFileProperty_ClientDataFormat, sizeof(result), &result); + if(noErr != err) { + err = ExtAudioFileDispose(file); + NSLog(@"Error closing ExtAudioFile: %i", err); + return NO; + } + + // Further properties + isBigEndian = YES; + isUnsigned = NO; + + NSLog(@"Successfully read file"); + + return YES; +} + +- (int) fillBuffer:(void *)buf ofSize:(UInt32)size +{ + OSStatus err; + AudioBufferList bufferList; + UInt32 frameCount; + + // Set up the AudioBufferList + bufferList.mNumberBuffers = 1; + bufferList.mBuffers[0].mNumberChannels = channels; + bufferList.mBuffers[0].mData = buf; + bufferList.mBuffers[0].mDataByteSize = size; + + // Read a chunk of PCM input (converted from whatever format) + frameCount = (size / (channels * (bitsPerSample / 8))); + err = ExtAudioFileRead(_in, &frameCount, &bufferList); + if(err != noErr) { + NSLog(@"Error reading ExtAudioFile: %i", err); + return 0; + } + + return frameCount * (channels * (bitsPerSample / 8)); +} + +- (double) seekToTime:(double)milliseconds +{ + OSStatus err; + + err = ExtAudioFileSeek(_in, ((milliseconds / 1000.f) * frequency)); + if(noErr != err) { + return -1.f; + } + + return milliseconds; +} + +@end diff --git a/Sound/SoundFile/SoundFile.mm b/Sound/SoundFile/SoundFile.mm index 33c8e1e4e..dedd9dca8 100644 --- a/Sound/SoundFile/SoundFile.mm +++ b/Sound/SoundFile/SoundFile.mm @@ -9,14 +9,15 @@ #import "SoundFile.h" #import "FlacFile.h" -#import "AACFile.h" +//#import "AACFile.h" #import "MonkeysFile.h" -#import "MPEGFile.h" +//#import "MPEGFile.h" #import "MusepackFile.h" #import "VorbisFile.h" -#import "WaveFile.h" +//#import "WaveFile.h" #import "WavPackFile.h" #import "ShnFile.h" +#import "CoreAudioFile.h" extern "C" { BOOL hostIsBigEndian() @@ -27,6 +28,9 @@ BOOL hostIsBigEndian() return NO; #endif } + +extern NSArray * getCoreAudioExtensions(); + }; @implementation SoundFile @@ -75,14 +79,17 @@ BOOL hostIsBigEndian() */ + (SoundFile *)soundFileFromFilename:(NSString *)filename { - SoundFile *soundFile; + SoundFile *soundFile; + NSString *extension; DBLog(@"Filename: %@", filename); - if (([[filename pathExtension] caseInsensitiveCompare:@"wav"] == NSOrderedSame) || ([[filename pathExtension] caseInsensitiveCompare:@"aiff"] == NSOrderedSame) || ([[filename pathExtension] caseInsensitiveCompare:@"aif"] == NSOrderedSame)) + extension = [filename pathExtension]; + + /*if (([[filename pathExtension] caseInsensitiveCompare:@"wav"] == NSOrderedSame) || ([[filename pathExtension] caseInsensitiveCompare:@"aiff"] == NSOrderedSame) || ([[filename pathExtension] caseInsensitiveCompare:@"aif"] == NSOrderedSame)) { soundFile = [[WaveFile alloc] init]; - } - else if ([[filename pathExtension] caseInsensitiveCompare:@"ogg"] == NSOrderedSame) + }*/ + if ([[filename pathExtension] caseInsensitiveCompare:@"ogg"] == NSOrderedSame) { soundFile = [[VorbisFile alloc] init]; } @@ -98,14 +105,14 @@ BOOL hostIsBigEndian() { soundFile = [[MonkeysFile alloc] init]; } - else if ([[filename pathExtension] caseInsensitiveCompare:@"mp3"] == NSOrderedSame) + /*else if ([[filename pathExtension] caseInsensitiveCompare:@"mp3"] == NSOrderedSame) { soundFile = [[MPEGFile alloc] init]; } else if ([[filename pathExtension] caseInsensitiveCompare:@"aac"] == NSOrderedSame) { soundFile = [[AACFile alloc] init]; - } + }*/ else if ([[filename pathExtension] caseInsensitiveCompare:@"wv"] == NSOrderedSame) { soundFile = [[WavPackFile alloc] init]; @@ -116,7 +123,17 @@ BOOL hostIsBigEndian() } else { + unsigned i; + NSArray *extensions = getCoreAudioExtensions(); + soundFile = nil; + + for(i = 0; i < [extensions count]; ++i) { + if([[extensions objectAtIndex:i] caseInsensitiveCompare:extension]) { + soundFile = [[CoreAudioFile alloc] init]; + break; + } + } } return soundFile; @@ -148,7 +165,7 @@ BOOL hostIsBigEndian() return nil; [soundFile close]; - + return soundFile; } diff --git a/Utils/CoreAudioUtils.h b/Utils/CoreAudioUtils.h new file mode 100644 index 000000000..2b0138690 --- /dev/null +++ b/Utils/CoreAudioUtils.h @@ -0,0 +1,24 @@ +/* + * $Id$ + * + * Copyright (C) 2006 Stephen F. Booth + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#import + +// Return an array of valid audio file extensions recognized by Core Audio +NSArray * getCoreAudioExtensions(); diff --git a/Utils/CoreAudioUtils.m b/Utils/CoreAudioUtils.m new file mode 100644 index 000000000..b59c55db2 --- /dev/null +++ b/Utils/CoreAudioUtils.m @@ -0,0 +1,49 @@ +/* + * $Id$ + * + * Copyright (C) 2006 Stephen F. Booth + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "CoreAudioUtils.h" + +#include + +// CoreAudio utility function +static NSArray *sAudioExtensions = nil; + +// Return an array of valid audio file extensions recognized by Core Audio +NSArray * +getCoreAudioExtensions() +{ + OSStatus err; + UInt32 size; + + @synchronized(sAudioExtensions) { + if(nil == sAudioExtensions) { + size = sizeof(sAudioExtensions); + err = AudioFileGetGlobalInfo(kAudioFileGlobalInfo_AllExtensions, 0, NULL, &size, &sAudioExtensions); + if(noErr != err) { + return nil; + } + + [sAudioExtensions retain]; + } + } + + return sAudioExtensions; +} +