diff --git a/Plugins/sidplay/SidDecoder.h b/Plugins/sidplay/SidDecoder.h index de7f75bce..e3b69a691 100644 --- a/Plugins/sidplay/SidDecoder.h +++ b/Plugins/sidplay/SidDecoder.h @@ -23,6 +23,7 @@ sidplayfp *engine; sidbuilder *builder; + id source; long length; NSString *currentUrl; @@ -35,5 +36,7 @@ long fadeRemain; } +- (void)setSource:(id)s; +- (id)source; - (void)cleanUp; @end diff --git a/Plugins/sidplay/SidDecoder.mm b/Plugins/sidplay/SidDecoder.mm index 555545708..b6f79c469 100644 --- a/Plugins/sidplay/SidDecoder.mm +++ b/Plugins/sidplay/SidDecoder.mm @@ -21,28 +21,141 @@ static const char *extListEmpty[] = { NULL }; static const char *extListStr[] = { ".str", NULL }; -static void sidTuneLoader(const char *fileName, std::vector &bufferRef) { - NSString *urlString = [NSString stringWithUTF8String:fileName]; - NSURL *url = [NSURL URLWithDataRepresentation:[urlString dataUsingEncoding:NSUTF8StringEncoding] relativeToURL:nil]; +@interface sid_file_object : NSObject { + size_t refCount; + NSString *path; + NSData *data; +} +@property size_t refCount; +@property NSString *path; +@property NSData *data; +@end - id audioSourceClass = NSClassFromString(@"AudioSource"); - id source = [audioSourceClass audioSourceForURL:url]; +@implementation sid_file_object +@synthesize refCount; +@synthesize path; +@synthesize data; +@end - if(![source open:url]) +@interface sid_file_container : NSObject { + NSLock *lock; + NSMutableDictionary *list; +} ++ (sid_file_container *)instance; +- (void)add_hint:(NSString *)path source:(id)source; +- (void)remove_hint:(NSString *)path; +- (BOOL)try_hint:(NSString *)path data:(NSData **)data; +@end + +@implementation sid_file_container ++ (sid_file_container *)instance { + static sid_file_container *instance; + + @synchronized(self) { + if(!instance) { + instance = [[self alloc] init]; + } + } + + return instance; +} +- (sid_file_container *)init { + if((self = [super init])) { + lock = [[NSLock alloc] init]; + list = [[NSMutableDictionary alloc] initWithCapacity:0]; + } + return self; +} +- (void)add_hint:(NSString *)path source:(id)source { + [lock lock]; + sid_file_object *obj = [list objectForKey:path]; + if(obj) { + obj.refCount += 1; + [lock unlock]; return; + } + [lock unlock]; + + obj = [[sid_file_object alloc] init]; + + obj.refCount = 1; if(![source seekable]) return; [source seek:0 whence:SEEK_END]; - long size = [source tell]; + size_t fileSize = [source tell]; + + void *dataBytes = malloc(fileSize); + if(!dataBytes) + return; + [source seek:0 whence:SEEK_SET]; + [source read:dataBytes amount:fileSize]; - bufferRef.resize(size); + NSData *data = [NSData dataWithBytes:dataBytes length:fileSize]; + free(dataBytes); - [source read:&bufferRef[0] amount:size]; + obj.path = path; + obj.data = data; - [source close]; + [lock lock]; + [list setObject:obj forKey:path]; + [lock unlock]; +} +- (void)remove_hint:(NSString *)path { + [lock lock]; + sid_file_object *obj = [list objectForKey:path]; + if(obj.refCount <= 1) { + [list removeObjectForKey:path]; + } else { + obj.refCount--; + } + [lock unlock]; +} +- (BOOL)try_hint:(NSString *)path data:(NSData **)data { + sid_file_object *obj; + [lock lock]; + obj = [list objectForKey:path]; + [lock unlock]; + if(obj) { + *data = obj.data; + return YES; + } else { + return NO; + } +} +@end + +static void sidTuneLoader(const char *fileName, std::vector &bufferRef) { + NSData *hintData = nil; + + if(![[sid_file_container instance] try_hint:[NSString stringWithUTF8String:fileName] data:&hintData]) { + NSString *urlString = [NSString stringWithUTF8String:fileName]; + NSURL *url = [NSURL URLWithDataRepresentation:[urlString dataUsingEncoding:NSUTF8StringEncoding] relativeToURL:nil]; + + id audioSourceClass = NSClassFromString(@"AudioSource"); + id source = [audioSourceClass audioSourceForURL:url]; + + if(![source open:url]) + return; + + if(![source seekable]) + return; + + [source seek:0 whence:SEEK_END]; + long fileSize = [source tell]; + [source seek:0 whence:SEEK_SET]; + + bufferRef.resize(fileSize); + + [source read:&bufferRef[0] amount:fileSize]; + + [source close]; + } else { + bufferRef.resize([hintData length]); + memcpy(&bufferRef[0], [hintData bytes], [hintData length]); + } } @implementation SidDecoder @@ -51,6 +164,8 @@ static void sidTuneLoader(const char *fileName, std::vector &bufferRef) if(![s seekable]) return NO; + [self setSource:s]; + NSString *path = [[s url] absoluteString]; NSRange fragmentRange = [path rangeOfString:@"#" options:NSBackwardsSearch]; if(fragmentRange.location != NSNotFound) { @@ -59,6 +174,9 @@ static void sidTuneLoader(const char *fileName, std::vector &bufferRef) currentUrl = [path stringByRemovingPercentEncoding]; + [[sid_file_container instance] add_hint:currentUrl source:s]; + hintAdded = YES; + NSString *extension = [[s url] pathExtension]; const char **extList = [extension isEqualToString:@"mus"] ? extListStr : extListEmpty; @@ -253,6 +371,11 @@ static void sidTuneLoader(const char *fileName, std::vector &bufferRef) tune = NULL; } + source = nil; + if(hintAdded) { + [[sid_file_container instance] remove_hint:currentUrl]; + hintAdded = NO; + } currentUrl = nil; } @@ -264,6 +387,14 @@ static void sidTuneLoader(const char *fileName, std::vector &bufferRef) [self close]; } +- (void)setSource:(id)s { + source = s; +} + +- (id)source { + return source; +} + + (NSArray *)fileTypes { return @[@"sid", @"mus"]; }