From e695e3353738424086b27924e40af72dc67d1995 Mon Sep 17 00:00:00 2001 From: Christopher Snowhill Date: Fri, 11 Feb 2022 04:43:20 -0800 Subject: [PATCH] SID Input: Bring back file hints, better this time Now file hint stashes the whole file in memory, so that any other threads reading the file at the same time will just grab the same memory block and read it, rather than opening the file repeatedly. Signed-off-by: Christopher Snowhill --- Plugins/sidplay/SidDecoder.h | 3 + Plugins/sidplay/SidDecoder.mm | 151 +++++++++++++++++++++++++++++++--- 2 files changed, 144 insertions(+), 10 deletions(-) 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"]; }