diff --git a/Plugins/vgmstream/vgmstream.xcodeproj/project.pbxproj b/Plugins/vgmstream/vgmstream.xcodeproj/project.pbxproj index ce12e89fd..86fd5d550 100644 --- a/Plugins/vgmstream/vgmstream.xcodeproj/project.pbxproj +++ b/Plugins/vgmstream/vgmstream.xcodeproj/project.pbxproj @@ -8,6 +8,7 @@ /* Begin PBXBuildFile section */ 8340888E1F6F604C00DCD404 /* VGMMetadataReader.m in Sources */ = {isa = PBXBuildFile; fileRef = 8340888B1F6F604A00DCD404 /* VGMMetadataReader.m */; }; + 835D2420235AB319009A1251 /* VGMPropertiesReader.m in Sources */ = {isa = PBXBuildFile; fileRef = 835D241E235AB318009A1251 /* VGMPropertiesReader.m */; }; 836F6B1418BDB80D0095E648 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 836F6B1318BDB80D0095E648 /* Cocoa.framework */; }; 836F6B1E18BDB80D0095E648 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 836F6B1C18BDB80D0095E648 /* InfoPlist.strings */; }; 836F705C18BDC40E0095E648 /* VGMDecoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 836F705B18BDC40E0095E648 /* VGMDecoder.m */; }; @@ -51,6 +52,8 @@ 833F68491CDBCAC000AFB9F0 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/InfoPlist.strings; sourceTree = ""; }; 8340888B1F6F604A00DCD404 /* VGMMetadataReader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VGMMetadataReader.m; sourceTree = ""; }; 8340888D1F6F604B00DCD404 /* VGMMetadataReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VGMMetadataReader.h; sourceTree = ""; }; + 835D241E235AB318009A1251 /* VGMPropertiesReader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VGMPropertiesReader.m; sourceTree = ""; }; + 835D241F235AB319009A1251 /* VGMPropertiesReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VGMPropertiesReader.h; sourceTree = ""; }; 836F6B1018BDB80D0095E648 /* vgmstream.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = vgmstream.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; 836F6B1318BDB80D0095E648 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; 836F6B1618BDB80D0095E648 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; @@ -124,6 +127,8 @@ 836F6B1918BDB80D0095E648 /* vgmstream */ = { isa = PBXGroup; children = ( + 835D241F235AB319009A1251 /* VGMPropertiesReader.h */, + 835D241E235AB318009A1251 /* VGMPropertiesReader.m */, 8340888D1F6F604B00DCD404 /* VGMMetadataReader.h */, 8340888B1F6F604A00DCD404 /* VGMMetadataReader.m */, 83AA5D2C1F6E30080020821C /* VGMContainer.h */, @@ -248,6 +253,7 @@ 8340888E1F6F604C00DCD404 /* VGMMetadataReader.m in Sources */, 83AA5D2D1F6E30080020821C /* VGMInterface.m in Sources */, 83AA5D2E1F6E30080020821C /* VGMContainer.m in Sources */, + 835D2420235AB319009A1251 /* VGMPropertiesReader.m in Sources */, 836F705C18BDC40E0095E648 /* VGMDecoder.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/Plugins/vgmstream/vgmstream/VGMDecoder.h b/Plugins/vgmstream/vgmstream/VGMDecoder.h index c7c206e1e..1b2d086ca 100644 --- a/Plugins/vgmstream/vgmstream/VGMDecoder.h +++ b/Plugins/vgmstream/vgmstream/VGMDecoder.h @@ -13,6 +13,18 @@ #import "Plugin.h" +@interface VGMInfoCache : NSObject { + NSMutableDictionary *storage; +} + ++(id)sharedCache; + +-(void)stuffURL:(NSURL *)url stream:(VGMSTREAM *)stream; +-(NSDictionary*)getPropertiesForURL:(NSURL *)url; +-(NSDictionary*)getMetadataForURL:(NSURL *)url; + +@end + @interface VGMDecoder : NSObject { VGMSTREAM *stream; diff --git a/Plugins/vgmstream/vgmstream/VGMDecoder.m b/Plugins/vgmstream/vgmstream/VGMDecoder.m index 8faad1562..27a0ea1ce 100644 --- a/Plugins/vgmstream/vgmstream/VGMDecoder.m +++ b/Plugins/vgmstream/vgmstream/VGMDecoder.m @@ -11,6 +11,101 @@ #import "PlaylistController.h" +@implementation VGMInfoCache + ++(id)sharedCache { + static VGMInfoCache *sharedMyCache = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedMyCache = [[self alloc] init]; + }); + return sharedMyCache; +} + +-(id)init { + if (self = [super init]) { + storage = [[NSMutableDictionary alloc] init]; + } + return self; +} + +-(void)stuffURL:(NSURL *)url stream:(VGMSTREAM *)stream { + int track_num = [[url fragment] intValue]; + + int sampleRate = stream->sample_rate; + int channels = stream->channels; + long totalFrames = get_vgmstream_play_samples( 2.0, 10.0, 10.0, stream ); + long framesFade = stream->loop_flag ? sampleRate * 10 : 0; + long framesLength = totalFrames - framesFade; + + int bitrate = get_vgmstream_average_bitrate(stream); + + NSDictionary * properties = + [NSDictionary dictionaryWithObjectsAndKeys: + [NSNumber numberWithInt:bitrate / 1000], @"bitrate", + [NSNumber numberWithInt:sampleRate], @"sampleRate", + [NSNumber numberWithDouble:totalFrames], @"totalFrames", + [NSNumber numberWithInt:16], @"bitsPerSample", + [NSNumber numberWithBool:NO], @"floatingPoint", + [NSNumber numberWithInt:channels], @"channels", + [NSNumber numberWithBool:YES], @"seekable", + @"host", @"endian", + nil]; + + NSString * title; + + if ( stream->num_streams > 1 ) { + title = [NSString stringWithFormat:@"%@ - %s", [[url URLByDeletingPathExtension] lastPathComponent], stream->stream_name]; + } else { + title = [[url URLByDeletingPathExtension] lastPathComponent]; + } + + NSDictionary * metadata = + [NSDictionary dictionaryWithObjectsAndKeys: + title, @"title", + [NSNumber numberWithInt:track_num], @"track", + nil]; + + NSDictionary * package = + [NSDictionary dictionaryWithObjectsAndKeys: + properties, @"properties", + metadata, @"metadata", + nil]; + + @synchronized (self) { + [storage setValue:package forKey:[url absoluteString]]; + } +} + +-(NSDictionary*)getPropertiesForURL:(NSURL *)url { + NSDictionary *properties = nil; + + @synchronized (self) { + NSDictionary * package = [storage objectForKey:[url absoluteString]]; + if (package) { + properties = [package objectForKey:@"properties"]; + } + } + + return properties; +} + +-(NSDictionary*)getMetadataForURL:(NSURL *)url { + NSDictionary *metadata = nil; + + @synchronized (self) { + NSDictionary * package = [storage objectForKey:[url absoluteString]]; + if (package) { + metadata = [package objectForKey:@"metadata"]; + } + } + + return metadata; +} + +@end + + @implementation VGMDecoder - (BOOL)open:(id)s @@ -22,6 +117,8 @@ if (fragmentRange.location != NSNotFound) { path = [path substringToIndex:fragmentRange.location]; } + + NSLog(@"Opening %@ subsong %d", path, track_num); stream = init_vgmstream_from_cogfile([[path stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding] UTF8String], track_num); if ( !stream ) @@ -45,16 +142,16 @@ - (NSDictionary *)properties { - return [NSDictionary dictionaryWithObjectsAndKeys: - [NSNumber numberWithInt:bitrate / 1000], @"bitrate", - [NSNumber numberWithInt:sampleRate], @"sampleRate", - [NSNumber numberWithDouble:totalFrames], @"totalFrames", - [NSNumber numberWithInt:16], @"bitsPerSample", - [NSNumber numberWithBool:NO], @"floatingPoint", - [NSNumber numberWithInt:channels], @"channels", - [NSNumber numberWithBool:YES], @"seekable", - @"host", @"endian", - nil]; + return [NSDictionary dictionaryWithObjectsAndKeys: + [NSNumber numberWithInt:bitrate / 1000], @"bitrate", + [NSNumber numberWithInt:sampleRate], @"sampleRate", + [NSNumber numberWithDouble:totalFrames], @"totalFrames", + [NSNumber numberWithInt:16], @"bitsPerSample", + [NSNumber numberWithBool:NO], @"floatingPoint", + [NSNumber numberWithInt:channels], @"channels", + [NSNumber numberWithBool:YES], @"seekable", + @"host", @"endian", + nil]; } - (int)readAudio:(void *)buf frames:(UInt32)frames diff --git a/Plugins/vgmstream/vgmstream/VGMMetadataReader.m b/Plugins/vgmstream/vgmstream/VGMMetadataReader.m index e3c2bcc96..d607b0176 100644 --- a/Plugins/vgmstream/vgmstream/VGMMetadataReader.m +++ b/Plugins/vgmstream/vgmstream/VGMMetadataReader.m @@ -29,30 +29,31 @@ + (NSDictionary *)metadataForURL:(NSURL *)url { - int track_num = [[url fragment] intValue]; + VGMInfoCache * sharedMyCache = [VGMInfoCache sharedCache]; - NSString * path = [url absoluteString]; - NSRange fragmentRange = [path rangeOfString:@"#" options:NSBackwardsSearch]; - if (fragmentRange.location != NSNotFound) { - path = [path substringToIndex:fragmentRange.location]; + NSDictionary * metadata = [sharedMyCache getMetadataForURL:url]; + + if (!metadata) { + int track_num = [[url fragment] intValue]; + + NSString * path = [url absoluteString]; + NSRange fragmentRange = [path rangeOfString:@"#" options:NSBackwardsSearch]; + if (fragmentRange.location != NSNotFound) { + path = [path substringToIndex:fragmentRange.location]; + } + + VGMSTREAM * stream = init_vgmstream_from_cogfile([[path stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding] UTF8String], track_num); + if ( !stream ) + return nil; + + [sharedMyCache stuffURL:url stream:stream]; + + close_vgmstream(stream); + + metadata = [sharedMyCache getMetadataForURL:url]; } - VGMSTREAM * stream = init_vgmstream_from_cogfile([[path stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding] UTF8String], track_num); - if ( !stream ) - return nil; - - NSString * title; - - if ( stream->num_streams > 1 ) { - title = [NSString stringWithFormat:@"%@ - %s", [[url URLByDeletingPathExtension] lastPathComponent], stream->stream_name]; - } else { - title = [[url URLByDeletingPathExtension] lastPathComponent]; - } - - return [NSDictionary dictionaryWithObjectsAndKeys: - title, @"title", - [NSNumber numberWithInt:track_num], @"track", - nil]; + return metadata; } @end diff --git a/Plugins/vgmstream/vgmstream/VGMPropertiesReader.h b/Plugins/vgmstream/vgmstream/VGMPropertiesReader.h new file mode 100644 index 000000000..36c02e316 --- /dev/null +++ b/Plugins/vgmstream/vgmstream/VGMPropertiesReader.h @@ -0,0 +1,17 @@ +// +// VGMPropertiesReader.h +// VGMStream +// +// Created by Christopher Snowhill on 10/18/19. +// Copyright 2019 __LoSnoCo__. All rights reserved. +// + +#import + +#import "Plugin.h" + +@interface VGMPropertiesReader : NSObject { + +} + +@end diff --git a/Plugins/vgmstream/vgmstream/VGMPropertiesReader.m b/Plugins/vgmstream/vgmstream/VGMPropertiesReader.m new file mode 100644 index 000000000..bf5fcb9f0 --- /dev/null +++ b/Plugins/vgmstream/vgmstream/VGMPropertiesReader.m @@ -0,0 +1,61 @@ +// +// VGMPropertiesReader.m +// VGMStream +// +// Created by Christopher Snowhill on 10/18/19. +// Copyright 2019 __LoSnoCo__. All rights reserved. +// + +#import "VGMPropertiesReader.h" +#import "VGMDecoder.h" +#import "VGMInterface.h" + +@implementation VGMPropertiesReader + ++ (NSArray *)fileTypes +{ + return [VGMDecoder fileTypes]; +} + ++ (NSArray *)mimeTypes +{ + return [VGMDecoder mimeTypes]; +} + ++ (float)priority +{ + return [VGMDecoder priority]; +} + ++ (NSDictionary *)propertiesForSource:(id)source +{ + VGMInfoCache * sharedMyCache = [VGMInfoCache sharedCache]; + + NSURL * url = [source url]; + + NSDictionary * properties = [sharedMyCache getPropertiesForURL:url]; + + if (!properties) { + int track_num = [[url fragment] intValue]; + + NSString * path = [url absoluteString]; + NSRange fragmentRange = [path rangeOfString:@"#" options:NSBackwardsSearch]; + if (fragmentRange.location != NSNotFound) { + path = [path substringToIndex:fragmentRange.location]; + } + + VGMSTREAM * stream = init_vgmstream_from_cogfile([[path stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding] UTF8String], track_num); + if ( !stream ) + return nil; + + [sharedMyCache stuffURL:url stream:stream]; + + close_vgmstream(stream); + + properties = [sharedMyCache getPropertiesForURL:url]; + } + + return properties; +} + +@end