// // libvgmMetadataReader.mm // libvgmPlayer // // Created by Christopher Snowhill on 1/03/22. // Copyright 2022 __LoSnoCo__. All rights reserved. // #import "libvgmMetadataReader.h" #import "libvgmDecoder.h" #import "Logging.h" #import #import #import #import #import @implementation libvgmMetadataReader #ifdef _DEBUG const int logLevel = DEVLOG_DEBUG; #else const int logLevel = DEVLOG_INFO; #endif static UINT8 FilePlayCallback(PlayerBase* player, void* userParam, UINT8 evtType, void* evtParam) { return 0x00; } static DATA_LOADER* RequestFileCallback(void* userParam, PlayerBase* player, const char* fileName) { return NULL; } static const char* LogLevel2Str(UINT8 level) { static const char* LVL_NAMES[6] = {" ??? ", "Error", "Warn ", "Info ", "Debug", "Trace"}; if (level >= (sizeof(LVL_NAMES) / sizeof(LVL_NAMES[0]))) level = 0; return LVL_NAMES[level]; } static void PlayerLogCallback(void* userParam, PlayerBase* player, UINT8 level, UINT8 srcType, const char* srcTag, const char* message) { if (level > logLevel) return; // don't print messages with higher verbosity than current log level if (srcType == PLRLOGSRC_PLR) { ALog(@"[%s] %s: %s", LogLevel2Str(level), player->GetPlayerName(), message); } else { ALog(@"[%s] %s %s: %s", LogLevel2Str(level), player->GetPlayerName(), srcTag, message); } return; } static std::string FCC2Str(UINT32 fcc) { std::string result(4, '\0'); result[0] = (char)((fcc >> 24) & 0xFF); result[1] = (char)((fcc >> 16) & 0xFF); result[2] = (char)((fcc >> 8) & 0xFF); result[3] = (char)((fcc >> 0) & 0xFF); return result; } + (NSArray *)fileTypes { return [libvgmDecoder fileTypes]; } + (NSArray *)mimeTypes { return [libvgmDecoder mimeTypes]; } + (float)priority { return [libvgmDecoder priority]; } + (NSDictionary *)metadataForURL:(NSURL *)url { id audioSourceClass = NSClassFromString(@"AudioSource"); id source = [audioSourceClass audioSourceForURL:url]; if (![source open:url]) return 0; if (![source seekable]) return 0; PlayerA mainPlr; mainPlr.RegisterPlayerEngine(new VGMPlayer); mainPlr.RegisterPlayerEngine(new S98Player); mainPlr.RegisterPlayerEngine(new DROPlayer); mainPlr.RegisterPlayerEngine(new GYMPlayer); mainPlr.SetEventCallback(FilePlayCallback, NULL); mainPlr.SetFileReqCallback(RequestFileCallback, NULL); mainPlr.SetLogCallback(PlayerLogCallback, NULL); mainPlr.SetOutputSettings(44100, 2, 24, 2048); [source seek:0 whence:SEEK_END]; size_t size = [source tell]; [source seek:0 whence:SEEK_SET]; UINT8* fileData = (UINT8*) malloc(size); if (!fileData) return 0; size_t bytesRead = [source read:fileData amount:size]; if (bytesRead != size) { free(fileData); return 0; } DATA_LOADER *dLoad = MemoryLoader_Init(fileData, (unsigned int)size); if (!dLoad) { free(fileData); return 0; } DataLoader_SetPreloadBytes(dLoad,0x100); if (DataLoader_Load(dLoad)) { DataLoader_Deinit(dLoad); free(fileData); return 0; } if (mainPlr.LoadFile(dLoad)) { DataLoader_Deinit(dLoad); free(fileData); return 0; } NSString *system = @""; NSString *title = @""; NSString *artist = @""; NSString *album = @""; NSNumber *year = [NSNumber numberWithInt:0]; PlayerBase* player = mainPlr.GetPlayer(); const char* const* tagList = player->GetTags(); for (const char* const* t = tagList; *t; t += 2) { if (!strcmp(t[0], "TITLE")) title = [NSString stringWithUTF8String:t[1]]; else if (!strcmp(t[0], "ARTIST")) artist = [NSString stringWithUTF8String:t[1]]; else if (!strcmp(t[0], "GAME")) album = [NSString stringWithUTF8String:t[1]]; else if (!strcmp(t[0], "DATE")) { char * end; unsigned long theYear = strtoul(t[1], &end, 10); year = [NSNumber numberWithLong:theYear]; } } PLR_SONG_INFO sInf; player->GetSongInfo(sInf); system = [NSString stringWithFormat:@"%s v%X.%02X", FCC2Str(sInf.format).c_str(), sInf.fileVerMaj, sInf.fileVerMin]; mainPlr.UnloadFile(); DataLoader_Deinit(dLoad); free(fileData); NSDictionary * dict = [NSDictionary dictionaryWithObjectsAndKeys: system, @"codec", album, @"album", title, @"title", artist, @"artist", year, @"year", nil]; return dict; } @end