From a4eb42eab0f1a5f4779f72022dce607157f0a5e3 Mon Sep 17 00:00:00 2001 From: vspader Date: Sat, 16 Feb 2008 02:46:19 +0000 Subject: [PATCH] Fixed crash, and in doing so introduced a huge memory leak! Added patch from Eric Hanneken that improves shuffle. --- Audio/Chain/ConverterNode.m | 1 + Audio/Chain/Node.h | 1 + Audio/Chain/Node.m | 16 ++++++++--- Audio/Chain/OutputNode.m | 2 +- Cog.xcodeproj/project.pbxproj | 18 ++++++++----- Playlist/Shuffle.h | 1 + Playlist/Shuffle.m | 51 +++++++++++++---------------------- 7 files changed, 48 insertions(+), 42 deletions(-) diff --git a/Audio/Chain/ConverterNode.m b/Audio/Chain/ConverterNode.m index 34981abf3..346422dad 100644 --- a/Audio/Chain/ConverterNode.m +++ b/Audio/Chain/ConverterNode.m @@ -165,6 +165,7 @@ static OSStatus ACInputProc(AudioConverterRef inAudioConverter, UInt32* ioNumber } if (callbackBuffer) { free(callbackBuffer); + callbackBuffer = NULL; } } diff --git a/Audio/Chain/Node.h b/Audio/Chain/Node.h index b9bdd35b1..baf56c04a 100644 --- a/Audio/Chain/Node.h +++ b/Audio/Chain/Node.h @@ -44,6 +44,7 @@ - (NSLock *)readLock; - (NSLock *)writeLock; +- (void)setPreviousNode:(id)p; - (id)previousNode; - (BOOL)shouldContinue; diff --git a/Audio/Chain/Node.m b/Audio/Chain/Node.m index e77e6d5ce..15c0a7320 100644 --- a/Audio/Chain/Node.m +++ b/Audio/Chain/Node.m @@ -22,10 +22,11 @@ initialBufferFilled = NO; - controller = c; - previousNode = p; + controller = [c retain]; endOfStream = NO; shouldContinue = YES; + + [self setPreviousNode:p]; } return self; @@ -88,7 +89,6 @@ [self process]; - [pool release]; [self release]; @@ -154,6 +154,13 @@ [NSThread detachNewThreadSelector:@selector(threadEntry:) toTarget:self withObject:nil]; } +- (void)setPreviousNode:(id)p +{ + [p retain]; + [previousNode release]; + previousNode = p; +} + - (id)previousNode { return previousNode; @@ -221,6 +228,9 @@ - (void)dealloc { + [controller release]; + [previousNode release]; + [buffer release]; [semaphore release]; [readLock release]; diff --git a/Audio/Chain/OutputNode.m b/Audio/Chain/OutputNode.m index 14b3addce..c3f72e001 100644 --- a/Audio/Chain/OutputNode.m +++ b/Audio/Chain/OutputNode.m @@ -49,7 +49,7 @@ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; int n; - previousNode = [[controller bufferChain] finalNode]; + [self setPreviousNode:[[controller bufferChain] finalNode]]; n = [super readData:ptr amount:amount]; if (endOfStream == YES) diff --git a/Cog.xcodeproj/project.pbxproj b/Cog.xcodeproj/project.pbxproj index 0a8805327..8297f4d0b 100644 --- a/Cog.xcodeproj/project.pbxproj +++ b/Cog.xcodeproj/project.pbxproj @@ -3,10 +3,11 @@ archiveVersion = 1; classes = { }; - objectVersion = 42; + objectVersion = 44; objects = { /* Begin PBXBuildFile section */ + 07E18DF30D62B38400BB0E11 /* NSArray+ShuffleUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 07E18DF20D62B38400BB0E11 /* NSArray+ShuffleUtils.m */; }; 170680630B950158006BA573 /* Growl.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 170680620B950158006BA573 /* Growl.framework */; }; 170680840B950164006BA573 /* Growl.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 170680620B950158006BA573 /* Growl.framework */; }; 171678C00AC8C39E00C28CF3 /* SmartFolderNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 171678BE0AC8C39E00C28CF3 /* SmartFolderNode.m */; }; @@ -462,6 +463,8 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 07E18DF10D62B38400BB0E11 /* NSArray+ShuffleUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSArray+ShuffleUtils.h"; sourceTree = ""; }; + 07E18DF20D62B38400BB0E11 /* NSArray+ShuffleUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSArray+ShuffleUtils.m"; sourceTree = ""; }; 089C165DFE840E0CC02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = ""; }; 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = ""; }; 1705F1420B8BCB0C00C8B40D /* English */ = {isa = PBXFileReference; lastKnownFileType = folder; name = English; path = English.lproj/Help; sourceTree = ""; }; @@ -812,6 +815,8 @@ 177EC01D0B8BC2CF0000BC8C /* TrackingSlider.m */, 8E9A30130BA792DC0091081B /* NSFileHandle+CreateFile.h */, 8E9A30140BA792DC0091081B /* NSFileHandle+CreateFile.m */, + 07E18DF10D62B38400BB0E11 /* NSArray+ShuffleUtils.h */, + 07E18DF20D62B38400BB0E11 /* NSArray+ShuffleUtils.m */, ); path = Utils; sourceTree = ""; @@ -1282,7 +1287,7 @@ 29B97313FDCFA39411CA2CEA /* Project object */ = { isa = PBXProject; buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "Cog" */; - compatibilityVersion = "Xcode 2.4"; + compatibilityVersion = "Xcode 3.0"; hasScannedForEncodings = 1; knownRegions = ( English, @@ -1643,6 +1648,7 @@ 56462DDA0D61D71E000AB68C /* SpotlightPlaylistView.m in Sources */, 56462EAF0D6341F6000AB68C /* SpotlightTransformers.m in Sources */, 56462EB20D634206000AB68C /* SpotlightPlaylistController.m in Sources */, + 07E18DF30D62B38400BB0E11 /* NSArray+ShuffleUtils.m in Sources */, 56C63D910D647DF300EAE25A /* NSComparisonPredicate+CogPredicate.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -1826,7 +1832,7 @@ CogAudio, ); PRODUCT_NAME = Cog; - SDKROOT = /Developer/SDKs/MacOSX10.5.sdk; + SDKROOT = "$(DEVELOPER_SDK_DIR)/MacOSX10.5.sdk"; WRAPPER_EXTENSION = app; ZERO_LINK = NO; }; @@ -1855,7 +1861,7 @@ CogAudio, ); PRODUCT_NAME = Cog; - SDKROOT = /Developer/SDKs/MacOSX10.5.sdk; + SDKROOT = "$(DEVELOPER_SDK_DIR)/MacOSX10.5.sdk"; WRAPPER_EXTENSION = app; }; name = Release; @@ -1866,7 +1872,7 @@ GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNUSED_VARIABLE = YES; PREBINDING = NO; - SDKROOT = /Developer/SDKs/MacOSX10.5.sdk; + SDKROOT = "$(DEVELOPER_SDK_DIR)/MacOSX10.5.sdk"; }; name = Debug; }; @@ -1876,7 +1882,7 @@ GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNUSED_VARIABLE = YES; PREBINDING = NO; - SDKROOT = /Developer/SDKs/MacOSX10.5.sdk; + SDKROOT = "$(DEVELOPER_SDK_DIR)/MacOSX10.5.sdk"; }; name = Release; }; diff --git a/Playlist/Shuffle.h b/Playlist/Shuffle.h index cdfdf0433..d0f0a8743 100644 --- a/Playlist/Shuffle.h +++ b/Playlist/Shuffle.h @@ -13,6 +13,7 @@ } ++ (void)initialize; + (NSMutableArray *)shuffleList:(NSArray *)l; @end diff --git a/Playlist/Shuffle.m b/Playlist/Shuffle.m index d9105d12a..b0ae76df3 100644 --- a/Playlist/Shuffle.m +++ b/Playlist/Shuffle.m @@ -3,52 +3,39 @@ // Cog // // Created by Vincent Spader on 1/14/06. -// Copyright 2006 Vincent Spader. All rights reserved. +// Revised by Eric Hanneken on 2/14/08. +// Copyright 2008 Vincent Spader. All rights reserved. // #import "Shuffle.h" - +#import "NSArray+ShuffleUtils.h" @implementation Shuffle -int sum(int n) ++ (void)initialize { - return (n*n+n)/2; -} - -int reverse_sum(int n) -{ - return (int)(ceil((-1.0 + sqrt(1.0 + 8.0*n))/2.0)); -} - -int randint(int low, int high) -{ - return (random()%high)+low; + static BOOL initialized = NO; + if (!initialized) { + // Call srandom() exactly once. + srandom((unsigned) time(NULL)); + initialized = YES; + } } + (NSMutableArray *)shuffleList:(NSArray *)l { - srandom(time(NULL)); - - NSMutableArray *a = [l mutableCopy]; - NSMutableArray *b = [[NSMutableArray alloc] init]; + NSArray* randomLongs = [NSArray arrayWithRandomLongs:[l count]]; + // randomLongs is an array of random integers, equal in length to l. - while([a count] > 0) - { - int t, r, p; - - t = sum([a count]); - r = randint(1, t); - p = reverse_sum(r) - 1; - //printf("%i, %i, %i, %i\n", [a count], t, r, p); - - [b insertObject:[a objectAtIndex:p] atIndex:0]; - [a removeObjectAtIndex:p]; - } + NSArray* pairs = [NSArray zipArray:randomLongs withArray:l]; + // randomLongs and l are paired. - [a release]; + NSArray* shuffledPairs = [pairs sortedArrayUsingSelector:@selector(compareFirsts:)]; + // The numbers from randomLongs are sorted in ascending order; the tracks from l + // are in random order. - return [b autorelease]; + // Peel the tracks off and return them. + return [[NSArray unzipArray:shuffledPairs] objectAtIndex:1]; } @end