2022-01-03 09:51:53 +00:00
|
|
|
//
|
|
|
|
// 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 <libvgm/utils/MemoryLoader.h>
|
|
|
|
#import <libvgm/player/s98player.hpp>
|
|
|
|
#import <libvgm/player/droplayer.hpp>
|
|
|
|
#import <libvgm/player/vgmplayer.hpp>
|
|
|
|
#import <libvgm/player/gymplayer.hpp>
|
|
|
|
|
|
|
|
@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)
|
|
|
|
{
|
2022-01-08 03:07:46 +00:00
|
|
|
ALog(@"[%s] %s: %s", LogLevel2Str(level), player->GetPlayerName(), message);
|
2022-01-03 09:51:53 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-01-08 03:07:46 +00:00
|
|
|
ALog(@"[%s] %s %s: %s", LogLevel2Str(level), player->GetPlayerName(), srcTag, message);
|
2022-01-03 09:51:53 +00:00
|
|
|
}
|
|
|
|
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<CogSource> 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);
|
|
|
|
|
2022-01-05 10:37:39 +00:00
|
|
|
system = [NSString stringWithFormat:@"%s v%X.%02X", FCC2Str(sInf.format).c_str(), sInf.fileVerMaj, sInf.fileVerMin];
|
2022-01-03 09:51:53 +00:00
|
|
|
|
|
|
|
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
|