Implemented new libvgm-based VGM, S98, DRO, and GYM player

CQTexperiment
Christopher Snowhill 2022-01-03 01:51:53 -08:00
parent 8ad7e086a8
commit 888ee2fb38
49 changed files with 134624 additions and 0 deletions

View File

@ -106,6 +106,7 @@
830596EE277F05EE00EBFAAE /* Vorbis.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 830596E7277F05E200EBFAAE /* Vorbis.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
83293070277886250010C07E /* OpenMPTOld.bundle in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8329306D277885790010C07E /* OpenMPTOld.bundle */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
832C1253180BD1E2005507C1 /* Cog.help in Resources */ = {isa = PBXBuildFile; fileRef = 832C1252180BD1E2005507C1 /* Cog.help */; };
83489C6B2782F78700BDCEA2 /* libvgmPlayer.bundle in CopyFiles */ = {isa = PBXBuildFile; fileRef = 83489C542782F2DF00BDCEA2 /* libvgmPlayer.bundle */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
834D793F20E4EFEA00C4A5CC /* OpusPlugin.bundle in CopyFiles */ = {isa = PBXBuildFile; fileRef = 830B62B320E4EF89004A74B2 /* OpusPlugin.bundle */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
834D794020E4EFEF00C4A5CC /* VorbisPlugin.bundle in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8301F94520E4EEF70017B2DC /* VorbisPlugin.bundle */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
834F7F4320E4E4ED00228DAB /* AdPlug.bundle in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8303A30920E4E3D000951EF8 /* AdPlug.bundle */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
@ -429,6 +430,20 @@
remoteGlobalIDString = 8D5B49B6048680CD000E48DA;
remoteInfo = "WavPackPlugin Plugin";
};
83489C532782F2DF00BDCEA2 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 83489C4E2782F2DF00BDCEA2 /* libvgmPlayer.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 8D5B49B6048680CD000E48DA;
remoteInfo = "libvgmPlayer Plugin";
};
83489C692782F76900BDCEA2 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 83489C4E2782F2DF00BDCEA2 /* libvgmPlayer.xcodeproj */;
proxyType = 1;
remoteGlobalIDString = 8D5B49AC048680CD000E48DA;
remoteInfo = "libvgmPlayer Plugin";
};
834D792F20E4EFCC00C4A5CC /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 17C808B70C3BD1D2005707C4 /* VorbisPlugin.xcodeproj */;
@ -679,6 +694,7 @@
dstPath = "";
dstSubfolderSpec = 13;
files = (
83489C6B2782F78700BDCEA2 /* libvgmPlayer.bundle in CopyFiles */,
83293070277886250010C07E /* OpenMPTOld.bundle in CopyFiles */,
834D794020E4EFEF00C4A5CC /* VorbisPlugin.bundle in CopyFiles */,
834D793F20E4EFEA00C4A5CC /* OpusPlugin.bundle in CopyFiles */,
@ -904,6 +920,7 @@
833F681E1CDBCAA700AFB9F0 /* es */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/InfoPlist.strings; sourceTree = "<group>"; };
833F681F1CDBCAA800AFB9F0 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Localizable.strings; sourceTree = "<group>"; };
833F68251CDBCAA800AFB9F0 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.html; name = es; path = es.lproj/Credits.html; sourceTree = "<group>"; };
83489C4E2782F2DF00BDCEA2 /* libvgmPlayer.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = libvgmPlayer.xcodeproj; path = Plugins/libvgmPlayer/libvgmPlayer.xcodeproj; sourceTree = "<group>"; };
8355D6B4180612F300D05687 /* NSData+MD5.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSData+MD5.h"; sourceTree = "<group>"; };
8355D6B5180612F300D05687 /* NSData+MD5.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSData+MD5.m"; sourceTree = "<group>"; };
8355D6B7180613FB00D05687 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; };
@ -1228,6 +1245,7 @@
8360EF0017F92B23005208A4 /* HighlyComplete.xcodeproj */,
836FB5421820538700B3AD2D /* Hively.xcodeproj */,
17C808830C3BD181005707C4 /* HTTPSource.xcodeproj */,
83489C4E2782F2DF00BDCEA2 /* libvgmPlayer.xcodeproj */,
8E8D40820CBB036600135C1B /* M3u.xcodeproj */,
83B0669C180D5668008E3612 /* MIDI.xcodeproj */,
17C8089E0C3BD1AB005707C4 /* Musepack.xcodeproj */,
@ -1613,6 +1631,14 @@
name = Products;
sourceTree = "<group>";
};
83489C4F2782F2DF00BDCEA2 /* Products */ = {
isa = PBXGroup;
children = (
83489C542782F2DF00BDCEA2 /* libvgmPlayer.bundle */,
);
name = Products;
sourceTree = "<group>";
};
8359FF2D17FEF35C0060F3ED /* Products */ = {
isa = PBXGroup;
children = (
@ -1806,6 +1832,7 @@
buildRules = (
);
dependencies = (
83489C6A2782F76900BDCEA2 /* PBXTargetDependency */,
8329306F2778860C0010C07E /* PBXTargetDependency */,
ED69CBC625BE32B40090B90D /* PBXTargetDependency */,
834D793E20E4EFD200C4A5CC /* PBXTargetDependency */,
@ -1932,6 +1959,10 @@
ProductGroup = 17C808840C3BD181005707C4 /* Products */;
ProjectRef = 17C808830C3BD181005707C4 /* HTTPSource.xcodeproj */;
},
{
ProductGroup = 83489C4F2782F2DF00BDCEA2 /* Products */;
ProjectRef = 83489C4E2782F2DF00BDCEA2 /* libvgmPlayer.xcodeproj */;
},
{
ProductGroup = 8E8D40830CBB036600135C1B /* Products */;
ProjectRef = 8E8D40820CBB036600135C1B /* M3u.xcodeproj */;
@ -2181,6 +2212,13 @@
remoteRef = 834068BC20E4E40200A01561 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
83489C542782F2DF00BDCEA2 /* libvgmPlayer.bundle */ = {
isa = PBXReferenceProxy;
fileType = wrapper.cfbundle;
path = libvgmPlayer.bundle;
remoteRef = 83489C532782F2DF00BDCEA2 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
8359FF3117FEF35D0060F3ED /* ArchiveSource.bundle */ = {
isa = PBXReferenceProxy;
fileType = wrapper.cfbundle;
@ -2501,6 +2539,11 @@
name = OpenMPTOld;
targetProxy = 8329306E2778860C0010C07E /* PBXContainerItemProxy */;
};
83489C6A2782F76900BDCEA2 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
name = "libvgmPlayer Plugin";
targetProxy = 83489C692782F76900BDCEA2 /* PBXContainerItemProxy */;
};
834D793020E4EFCC00C4A5CC /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
name = "VorbisPlugin Plugin";

Binary file not shown.

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIconFile</key>
<string></string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>

Binary file not shown.

View File

@ -0,0 +1,3 @@
/* Localized versions of Info.plist keys */
NSHumanReadableCopyright = "© __MyCompanyName__, 2007";

View File

@ -0,0 +1,17 @@
//
// libvgmContainer.h
// libvgmPlayer
//
// Created by Christopher Snowhill on 1/02/22.
// Copyright 2022 __LoSnoCo__. All rights reserved.
//
#import <Cocoa/Cocoa.h>
#import "Plugin.h"
@interface libvgmContainer : NSObject <CogContainer> {
}
@end

View File

@ -0,0 +1,45 @@
//
// libvgmContainer.mm
// libvgmPlayer
//
// Created by Christopher Snowhill on 1/02/22.
// Copyright 2022 __LoSnoCo__. All rights reserved.
//
#import "libvgmContainer.h"
#import "libvgmDecoder.h"
#import "Logging.h"
@implementation libvgmContainer
+ (NSArray *)fileTypes
{
return [NSArray arrayWithObjects:@"s98", @"dro", @"gym",
@"vgm",@"vgz", // These are included so they can override AdPlug
nil];
}
+ (NSArray *)mimeTypes
{
return nil;
}
+ (float)priority
{
return [libvgmDecoder priority];
}
//This really should be source...
+ (NSArray *)urlsForContainerURL:(NSURL *)url
{
if ([url fragment]) {
// input url already has fragment defined - no need to expand further
return [NSMutableArray arrayWithObject:url];
}
// None of the covered formats include subsongs, but dodge VGMStream and AdPlug
return [NSArray arrayWithObject:[NSURL URLWithString:[[url absoluteString] stringByAppendingString:@"#0"]]];
}
@end

View File

@ -0,0 +1,32 @@
//
// libvgmDecoder.h
// libvgmPlayer
//
// Created by Christopher Snowhill on 1/02/22.
// Copyright 2022 __LoSnoCo__. All rights reserved.
//
#import <Cocoa/Cocoa.h>
#import <libvgm/utils/DataLoader.h>
#import <libvgm/player/playerbase.hpp>
#import <libvgm/player/playera.hpp>
#import "Plugin.h"
@interface libvgmDecoder : NSObject <CogDecoder> {
UINT8* fileData;
DATA_LOADER* dLoad;
PlayerA* mainPlr;
id<CogSource> source;
long length;
BOOL trackEnded;
}
- (BOOL)trackEnded;
- (void)setTrackEnded:(BOOL)ended;
- (void)setSource:(id<CogSource>)s;
- (id<CogSource>)source;
@end

View File

@ -0,0 +1,314 @@
//
// libvgmDecoder.mm
// libvgmPlayer
//
// Created by Christopher Snowhill on 1/02/22.
// Copyright 2022 __LoSnoCo__. All rights reserved.
//
#import "libvgmDecoder.h"
#import "Logging.h"
#import "PlaylistController.h"
#import <libvgm/utils/MemoryLoader.h>
#import <libvgm/utils/FileLoader.h>
#import <libvgm/player/s98player.hpp>
#import <libvgm/player/droplayer.hpp>
#import <libvgm/player/vgmplayer.hpp>
#import <libvgm/player/gymplayer.hpp>
#import <libvgm/emu/Resampler.h>
#import <libvgm/emu/SoundDevs.h>
#import <libvgm/emu/EmuCores.h>
@implementation libvgmDecoder
#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)
{
libvgmDecoder * decoder = (__bridge libvgmDecoder *)(userParam);
switch(evtType)
{
case PLREVT_START:
//printf("Playback started.\n");
break;
case PLREVT_STOP:
//printf("Playback stopped.\n");
break;
case PLREVT_LOOP:
{
//UINT32* curLoop = (UINT32*)evtParam;
//if (player->GetState() & PLAYSTATE_SEEK)
// break;
}
break;
case PLREVT_END:
if ([decoder trackEnded])
break;
[decoder setTrackEnded:YES];
break;
}
return 0x00;
}
#include "yrw801.h"
static DATA_LOADER* RequestFileCallback(void* userParam, PlayerBase* player, const char* fileName)
{
DATA_LOADER* dLoad;
if (strcmp(fileName, "yrw801.rom") == 0)
{
dLoad = MemoryLoader_Init(yrw801_rom, sizeof(yrw801_rom));
}
else
{
dLoad = FileLoader_Init(fileName);
}
UINT8 retVal = DataLoader_Load(dLoad);
if (! retVal)
return dLoad;
DataLoader_Deinit(dLoad);
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;
}
const int sampleRate = 44100;
const int numChannels = 2;
const int numBitsPerSample = 24;
const int smplAlloc = 2048;
const int masterVol = 0x10000; // Fixed point 16.16
- (id)init
{
self = [super init];
if (self) {
fileData = NULL;
dLoad = NULL;
mainPlr = NULL;
}
return self;
}
- (BOOL)open:(id<CogSource>)s
{
[self setSource:s];
//We need file-size to use GME
if (![source seekable]) {
return NO;
}
BOOL repeatOne = IsRepeatOneSet();
uint32_t maxLoops = repeatOne ? 0 : 2;
mainPlr = new PlayerA;
mainPlr->RegisterPlayerEngine(new VGMPlayer);
mainPlr->RegisterPlayerEngine(new S98Player);
mainPlr->RegisterPlayerEngine(new DROPlayer);
mainPlr->RegisterPlayerEngine(new GYMPlayer);
mainPlr->SetEventCallback(FilePlayCallback, (__bridge void *)(self));
mainPlr->SetFileReqCallback(RequestFileCallback, NULL);
mainPlr->SetLogCallback(PlayerLogCallback, NULL);
{
PlayerA::Config pCfg = mainPlr->GetConfiguration();
pCfg.masterVol = masterVol;
pCfg.loopCount = maxLoops;
pCfg.fadeSmpls = sampleRate * 4; // fade over 4 seconds
pCfg.endSilenceSmpls = sampleRate / 2; // 0.5 seconds of silence at the end
pCfg.pbSpeed = 1.0;
mainPlr->SetConfiguration(pCfg);
}
mainPlr->SetOutputSettings(sampleRate, numChannels, numBitsPerSample, smplAlloc);
[source seek:0 whence:SEEK_END];
size_t size = [source tell];
[source seek:0 whence:SEEK_SET];
fileData = (UINT8*) malloc(size);
if (!fileData)
return NO;
size_t bytesRead = [source read:fileData amount:size];
if (bytesRead != size)
return NO;
dLoad = MemoryLoader_Init(fileData, (unsigned int)size);
if (!dLoad)
return NO;
DataLoader_SetPreloadBytes(dLoad,0x100);
if (DataLoader_Load(dLoad))
return NO;
if (mainPlr->LoadFile(dLoad))
return NO;
PlayerBase* player = mainPlr->GetPlayer();
mainPlr->SetLoopCount(maxLoops);
if (player->GetPlayerType() == FCC_VGM)
{
VGMPlayer* vgmplay = dynamic_cast<VGMPlayer*>(player);
mainPlr->SetLoopCount(vgmplay->GetModifiedLoopCount(maxLoops));
}
length = player->Tick2Second(player->GetTotalTicks()) * sampleRate;
[self setTrackEnded:NO];
mainPlr->Start();
[self willChangeValueForKey:@"properties"];
[self didChangeValueForKey:@"properties"];
return YES;
}
- (NSDictionary *)properties
{
return [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:0], @"bitrate",
[NSNumber numberWithFloat:sampleRate], @"sampleRate",
[NSNumber numberWithLong:length], @"totalFrames",
[NSNumber numberWithInt:numBitsPerSample], @"bitsPerSample", //Samples are short
[NSNumber numberWithInt:numChannels], @"channels", //output from gme_play is in stereo
[NSNumber numberWithBool:[source seekable]], @"seekable",
@"host", @"endian",
nil];
}
- (int)readAudio:(void *)buf frames:(UInt32)frames
{
if ([self trackEnded])
return 0;
BOOL repeatOne = IsRepeatOneSet();
uint32_t maxLoops = repeatOne ? 0 : 2;
PlayerBase* player = mainPlr->GetPlayer();
mainPlr->SetLoopCount(maxLoops);
if (player->GetPlayerType() == FCC_VGM)
{
VGMPlayer* vgmplay = dynamic_cast<VGMPlayer*>(player);
mainPlr->SetLoopCount(vgmplay->GetModifiedLoopCount(maxLoops));
}
UInt32 framesDone = 0;
while (framesDone < frames)
{
UInt32 framesToDo = frames - framesDone;
if (framesToDo > smplAlloc)
framesToDo = smplAlloc;
int numSamples = framesToDo * numChannels * (numBitsPerSample/8);
mainPlr->Render(numSamples, buf);
buf = (void *)(((uint8_t*)buf) + numSamples);
framesDone += framesToDo;
}
return framesDone;
}
- (long)seek:(long)frame
{
[self setTrackEnded:NO];
mainPlr->Seek(PLAYPOS_SAMPLE, (unsigned int)frame);
return frame;
}
- (void)close
{
if (mainPlr) {
mainPlr->Stop();
mainPlr->UnloadFile();
delete mainPlr;
mainPlr = NULL;
}
if (dLoad) {
DataLoader_Deinit(dLoad);
dLoad = NULL;
}
if (fileData) {
free(fileData);
fileData = NULL;
}
}
- (void)dealloc
{
[self close];
}
+ (NSArray *)fileTypes
{
return [NSArray arrayWithObjects:@"vgm", @"vgz", @"s98", @"dro", @"gym", nil];
}
+ (NSArray *)mimeTypes
{
return nil;
}
+ (float)priority
{
return 1.25;
}
- (void)setSource:(id<CogSource>)s
{
source = s;
}
- (id<CogSource>)source
{
return source;
}
- (BOOL)trackEnded
{
return trackEnded;
}
- (void)setTrackEnded:(BOOL)ended
{
trackEnded = ended;
}
@end

View File

@ -0,0 +1,17 @@
//
// libvgmMetadataReader.h
// libvgmPlayer
//
// Created by Christopher Snowhill on 1/03/22.
// Copyright 2022 __LoSnoCo__. All rights reserved.
//
#import <Cocoa/Cocoa.h>
#import "Plugin.h"
@interface libvgmMetadataReader : NSObject <CogMetadataReader> {
}
@end

View File

@ -0,0 +1,192 @@
//
// 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)
{
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<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);
system = [NSString stringWithFormat:@"%s v%X.%X", 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

View File

@ -0,0 +1,421 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
17C8F3420CBED3BE008D969D /* libvgmContainer.mm in Sources */ = {isa = PBXBuildFile; fileRef = 17C8F33C0CBED3BE008D969D /* libvgmContainer.mm */; };
17C8F3440CBED3BE008D969D /* libvgmDecoder.mm in Sources */ = {isa = PBXBuildFile; fileRef = 17C8F33E0CBED3BE008D969D /* libvgmDecoder.mm */; };
17DA34BB0CC052030003F6B2 /* libvgmMetadataReader.mm in Sources */ = {isa = PBXBuildFile; fileRef = 17DA34B90CC052030003F6B2 /* libvgmMetadataReader.mm */; };
8319C750237629D400BFFAE0 /* libvgmPropertiesReader.mm in Sources */ = {isa = PBXBuildFile; fileRef = 8319C74F237629D400BFFAE0 /* libvgmPropertiesReader.mm */; };
83489C612782F39D00BDCEA2 /* libvgm-utils.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 83489C5E2782F39D00BDCEA2 /* libvgm-utils.a */; };
83489C622782F39D00BDCEA2 /* libvgm-emu.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 83489C5F2782F39D00BDCEA2 /* libvgm-emu.a */; };
83489C632782F39D00BDCEA2 /* libvgm-player.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 83489C602782F39D00BDCEA2 /* libvgm-player.a */; };
83489C662782F74800BDCEA2 /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 83489C652782F74800BDCEA2 /* libz.tbd */; };
83489C682782F74E00BDCEA2 /* libiconv.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 83489C672782F74E00BDCEA2 /* libiconv.tbd */; };
8D5B49B0048680CD000E48DA /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C167DFE841241C02AAC07 /* InfoPlist.strings */; };
8D5B49B4048680CD000E48DA /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7ADFEA557BF11CA2CBB /* Cocoa.framework */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
089C1672FE841209C02AAC07 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = "<absolute>"; };
089C167FFE841241C02AAC07 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = "<absolute>"; };
1058C7ADFEA557BF11CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = "<absolute>"; };
17C8F33B0CBED3BE008D969D /* libvgmContainer.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = libvgmContainer.h; sourceTree = "<group>"; };
17C8F33C0CBED3BE008D969D /* libvgmContainer.mm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objcpp; path = libvgmContainer.mm; sourceTree = "<group>"; };
17C8F33D0CBED3BE008D969D /* libvgmDecoder.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = libvgmDecoder.h; sourceTree = "<group>"; };
17C8F33E0CBED3BE008D969D /* libvgmDecoder.mm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objcpp; path = libvgmDecoder.mm; sourceTree = "<group>"; };
17C8F3470CBED3C7008D969D /* Plugin.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = Plugin.h; path = ../../Audio/Plugin.h; sourceTree = SOURCE_ROOT; };
17DA34B80CC052030003F6B2 /* libvgmMetadataReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = libvgmMetadataReader.h; sourceTree = "<group>"; };
17DA34B90CC052030003F6B2 /* libvgmMetadataReader.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objcpp; path = libvgmMetadataReader.mm; sourceTree = "<group>"; };
32DBCF630370AF2F00C91783 /* libvgmPlayer_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = libvgmPlayer_Prefix.pch; sourceTree = "<group>"; };
8319C74E237629D300BFFAE0 /* libvgmPropertiesReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = libvgmPropertiesReader.h; sourceTree = "<group>"; };
8319C74F237629D400BFFAE0 /* libvgmPropertiesReader.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objcpp; path = libvgmPropertiesReader.mm; sourceTree = "<group>"; };
833F68351CDBCAB200AFB9F0 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/InfoPlist.strings; sourceTree = "<group>"; };
83489C5E2782F39D00BDCEA2 /* libvgm-utils.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "libvgm-utils.a"; path = "../../ThirdParty/libvgm/lib/libvgm-utils.a"; sourceTree = "<group>"; };
83489C5F2782F39D00BDCEA2 /* libvgm-emu.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "libvgm-emu.a"; path = "../../ThirdParty/libvgm/lib/libvgm-emu.a"; sourceTree = "<group>"; };
83489C602782F39D00BDCEA2 /* libvgm-player.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "libvgm-player.a"; path = "../../ThirdParty/libvgm/lib/libvgm-player.a"; sourceTree = "<group>"; };
83489C652782F74800BDCEA2 /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; };
83489C672782F74E00BDCEA2 /* libiconv.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libiconv.tbd; path = usr/lib/libiconv.tbd; sourceTree = SDKROOT; };
835C888F22CC1883001B4B3F /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
8384912E1808175400E7332D /* Logging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Logging.h; path = ../../Utils/Logging.h; sourceTree = "<group>"; };
83FAF8A518ADD4D100057CAF /* PlaylistController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PlaylistController.h; path = ../../Playlist/PlaylistController.h; sourceTree = "<group>"; };
8D5B49B6048680CD000E48DA /* libvgmPlayer.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = libvgmPlayer.bundle; sourceTree = BUILT_PRODUCTS_DIR; };
8D5B49B7048680CD000E48DA /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
D2F7E65807B2D6F200F64583 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = /System/Library/Frameworks/CoreData.framework; sourceTree = "<absolute>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
8D5B49B3048680CD000E48DA /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
83489C682782F74E00BDCEA2 /* libiconv.tbd in Frameworks */,
83489C662782F74800BDCEA2 /* libz.tbd in Frameworks */,
83489C612782F39D00BDCEA2 /* libvgm-utils.a in Frameworks */,
83489C632782F39D00BDCEA2 /* libvgm-player.a in Frameworks */,
83489C622782F39D00BDCEA2 /* libvgm-emu.a in Frameworks */,
8D5B49B4048680CD000E48DA /* Cocoa.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
089C166AFE841209C02AAC07 /* libvgmPlayer */ = {
isa = PBXGroup;
children = (
08FB77AFFE84173DC02AAC07 /* Classes */,
32C88E010371C26100C91783 /* Other Sources */,
089C167CFE841241C02AAC07 /* Resources */,
089C1671FE841209C02AAC07 /* Frameworks and Libraries */,
19C28FB8FE9D52D311CA2CBB /* Products */,
83489C642782F74800BDCEA2 /* Frameworks */,
);
name = libvgmPlayer;
sourceTree = "<group>";
};
089C1671FE841209C02AAC07 /* Frameworks and Libraries */ = {
isa = PBXGroup;
children = (
83489C5D2782F37100BDCEA2 /* Linked Libraries */,
1058C7ACFEA557BF11CA2CBB /* Linked Frameworks */,
1058C7AEFEA557BF11CA2CBB /* Other Frameworks */,
);
name = "Frameworks and Libraries";
sourceTree = "<group>";
};
089C167CFE841241C02AAC07 /* Resources */ = {
isa = PBXGroup;
children = (
8D5B49B7048680CD000E48DA /* Info.plist */,
089C167DFE841241C02AAC07 /* InfoPlist.strings */,
);
name = Resources;
sourceTree = "<group>";
};
08FB77AFFE84173DC02AAC07 /* Classes */ = {
isa = PBXGroup;
children = (
17C8F33B0CBED3BE008D969D /* libvgmContainer.h */,
17C8F33C0CBED3BE008D969D /* libvgmContainer.mm */,
17C8F33D0CBED3BE008D969D /* libvgmDecoder.h */,
17C8F33E0CBED3BE008D969D /* libvgmDecoder.mm */,
17DA34B80CC052030003F6B2 /* libvgmMetadataReader.h */,
17DA34B90CC052030003F6B2 /* libvgmMetadataReader.mm */,
8319C74E237629D300BFFAE0 /* libvgmPropertiesReader.h */,
8319C74F237629D400BFFAE0 /* libvgmPropertiesReader.mm */,
8384912E1808175400E7332D /* Logging.h */,
83FAF8A518ADD4D100057CAF /* PlaylistController.h */,
17C8F3470CBED3C7008D969D /* Plugin.h */,
);
name = Classes;
sourceTree = "<group>";
};
1058C7ACFEA557BF11CA2CBB /* Linked Frameworks */ = {
isa = PBXGroup;
children = (
1058C7ADFEA557BF11CA2CBB /* Cocoa.framework */,
);
name = "Linked Frameworks";
sourceTree = "<group>";
};
1058C7AEFEA557BF11CA2CBB /* Other Frameworks */ = {
isa = PBXGroup;
children = (
089C167FFE841241C02AAC07 /* AppKit.framework */,
D2F7E65807B2D6F200F64583 /* CoreData.framework */,
089C1672FE841209C02AAC07 /* Foundation.framework */,
);
name = "Other Frameworks";
sourceTree = "<group>";
};
19C28FB8FE9D52D311CA2CBB /* Products */ = {
isa = PBXGroup;
children = (
8D5B49B6048680CD000E48DA /* libvgmPlayer.bundle */,
);
name = Products;
sourceTree = "<group>";
};
32C88E010371C26100C91783 /* Other Sources */ = {
isa = PBXGroup;
children = (
32DBCF630370AF2F00C91783 /* libvgmPlayer_Prefix.pch */,
);
name = "Other Sources";
sourceTree = "<group>";
};
83489C5D2782F37100BDCEA2 /* Linked Libraries */ = {
isa = PBXGroup;
children = (
83489C5F2782F39D00BDCEA2 /* libvgm-emu.a */,
83489C602782F39D00BDCEA2 /* libvgm-player.a */,
83489C5E2782F39D00BDCEA2 /* libvgm-utils.a */,
);
name = "Linked Libraries";
sourceTree = "<group>";
};
83489C642782F74800BDCEA2 /* Frameworks */ = {
isa = PBXGroup;
children = (
83489C672782F74E00BDCEA2 /* libiconv.tbd */,
83489C652782F74800BDCEA2 /* libz.tbd */,
);
name = Frameworks;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
8D5B49AC048680CD000E48DA /* libvgmPlayer Plugin */ = {
isa = PBXNativeTarget;
buildConfigurationList = 1DEB913A08733D840010E9CD /* Build configuration list for PBXNativeTarget "libvgmPlayer Plugin" */;
buildPhases = (
8D5B49AF048680CD000E48DA /* Resources */,
8D5B49B1048680CD000E48DA /* Sources */,
8D5B49B3048680CD000E48DA /* Frameworks */,
);
buildRules = (
);
dependencies = (
);
name = "libvgmPlayer Plugin";
productInstallPath = "$(HOME)/Library/Bundles";
productName = libvgmPlayer;
productReference = 8D5B49B6048680CD000E48DA /* libvgmPlayer.bundle */;
productType = "com.apple.product-type.bundle";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
089C1669FE841209C02AAC07 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 1250;
TargetAttributes = {
8D5B49AC048680CD000E48DA = {
DevelopmentTeam = "";
ProvisioningStyle = Automatic;
};
};
};
buildConfigurationList = 1DEB913E08733D840010E9CD /* Build configuration list for PBXProject "libvgmPlayer" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = en;
hasScannedForEncodings = 1;
knownRegions = (
en,
es,
Base,
);
mainGroup = 089C166AFE841209C02AAC07 /* libvgmPlayer */;
projectDirPath = "";
projectRoot = "";
targets = (
8D5B49AC048680CD000E48DA /* libvgmPlayer Plugin */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
8D5B49AF048680CD000E48DA /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
8D5B49B0048680CD000E48DA /* InfoPlist.strings in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
8D5B49B1048680CD000E48DA /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
17C8F3420CBED3BE008D969D /* libvgmContainer.mm in Sources */,
17C8F3440CBED3BE008D969D /* libvgmDecoder.mm in Sources */,
17DA34BB0CC052030003F6B2 /* libvgmMetadataReader.mm in Sources */,
8319C750237629D400BFFAE0 /* libvgmPropertiesReader.mm in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXVariantGroup section */
089C167DFE841241C02AAC07 /* InfoPlist.strings */ = {
isa = PBXVariantGroup;
children = (
833F68351CDBCAB200AFB9F0 /* es */,
835C888F22CC1883001B4B3F /* en */,
);
name = InfoPlist.strings;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
1DEB913B08733D840010E9CD /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_IDENTITY = "";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = NO;
DEVELOPMENT_TEAM = "";
GCC_DYNAMIC_NO_PIC = NO;
GCC_MODEL_TUNING = G5;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = libvgmPlayer_Prefix.pch;
HEADER_SEARCH_PATHS = ../../ThirdParty/libvgm/include;
INFOPLIST_FILE = Info.plist;
INSTALL_PATH = "$(HOME)/Library/Bundles";
LIBRARY_SEARCH_PATHS = ../../ThirdParty/libvgm/lib;
PRODUCT_BUNDLE_IDENTIFIER = org.cogx.libvgmPlayer;
PRODUCT_NAME = libvgmPlayer;
PROVISIONING_PROFILE_SPECIFIER = "";
SDKROOT = macosx;
SKIP_INSTALL = YES;
SYMROOT = ../../build;
WRAPPER_EXTENSION = bundle;
ZERO_LINK = YES;
};
name = Debug;
};
1DEB913C08733D840010E9CD /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_IDENTITY = "";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
DEVELOPMENT_TEAM = "";
GCC_MODEL_TUNING = G5;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = libvgmPlayer_Prefix.pch;
HEADER_SEARCH_PATHS = ../../ThirdParty/libvgm/include;
INFOPLIST_FILE = Info.plist;
INSTALL_PATH = "$(HOME)/Library/Bundles";
LIBRARY_SEARCH_PATHS = ../../ThirdParty/libvgm/lib;
PRODUCT_BUNDLE_IDENTIFIER = org.cogx.libvgmPlayer;
PRODUCT_NAME = libvgmPlayer;
PROVISIONING_PROFILE_SPECIFIER = "";
SDKROOT = macosx;
SKIP_INSTALL = YES;
SYMROOT = ../../build;
WRAPPER_EXTENSION = bundle;
};
name = Release;
};
1DEB913F08733D840010E9CD /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_NO_COMMON_BLOCKS = YES;
GCC_PREPROCESSOR_DEFINITIONS = "DEBUG=1";
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.12;
OBJROOT = ../../build;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx;
SYMROOT = ../../build;
};
name = Debug;
};
1DEB914008733D840010E9CD /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.12;
OBJROOT = ../../build;
SDKROOT = macosx;
SYMROOT = ../../build;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
1DEB913A08733D840010E9CD /* Build configuration list for PBXNativeTarget "libvgmPlayer Plugin" */ = {
isa = XCConfigurationList;
buildConfigurations = (
1DEB913B08733D840010E9CD /* Debug */,
1DEB913C08733D840010E9CD /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
1DEB913E08733D840010E9CD /* Build configuration list for PBXProject "libvgmPlayer" */ = {
isa = XCConfigurationList;
buildConfigurations = (
1DEB913F08733D840010E9CD /* Debug */,
1DEB914008733D840010E9CD /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 089C1669FE841209C02AAC07 /* Project object */;
}

View File

@ -0,0 +1,76 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1250"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "8D5B49AC048680CD000E48DA"
BuildableName = "GME.bundle"
BlueprintName = "GME Plugin"
ReferencedContainer = "container:GME.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "8D5B49AC048680CD000E48DA"
BuildableName = "GME.bundle"
BlueprintName = "GME Plugin"
ReferencedContainer = "container:GME.xcodeproj">
</BuildableReference>
</MacroExpansion>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "8D5B49AC048680CD000E48DA"
BuildableName = "GME.bundle"
BlueprintName = "GME Plugin"
ReferencedContainer = "container:GME.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -0,0 +1,7 @@
//
// Prefix header for all source files of the 'GME' target in the 'GME' project.
//
#ifdef __OBJC__
#import <Cocoa/Cocoa.h>
#endif

View File

@ -0,0 +1,17 @@
//
// libvgmPropertiesReader.h
// libvgmPlayer
//
// Created by Christopher Snowhill on 01/02/22.
// Copyright 2022 __LoSnoCo__. All rights reserved.
//
#import <Cocoa/Cocoa.h>
#import "Plugin.h"
@interface libvgmPropertiesReader : NSObject <CogPropertiesReader> {
}
@end

View File

@ -0,0 +1,45 @@
//
// libvgmPropertiesReader.m
// libvgmPlayer
//
// Created by Christopher Snowhill on 01/02/22.
// Copyright 2022 __LoSnoCo__. All rights reserved.
//
#import "libvgmPropertiesReader.h"
#import "libvgmDecoder.h"
@implementation libvgmPropertiesReader
+ (NSArray *)fileTypes
{
return [libvgmDecoder fileTypes];
}
+ (NSArray *)mimeTypes
{
return [libvgmDecoder mimeTypes];
}
+ (float)priority
{
return [libvgmDecoder priority];
}
+ (NSDictionary *)propertiesForSource:(id<CogSource>)source
{
libvgmDecoder * decoder = [[libvgmDecoder alloc] init];
NSDictionary * properties = [NSDictionary dictionary];
if ([decoder open:source])
{
properties = [decoder properties];
[decoder close];
}
return properties;
}
@end

131075
Plugins/libvgmPlayer/yrw801.h Normal file

File diff suppressed because it is too large Load Diff

10
ThirdParty/libvgm/README.md vendored Normal file
View File

@ -0,0 +1,10 @@
This is verbatim from the following repository:
https://github.com/ValleyBell/libvgm.git
Built on an M1 Mac mini, using CMake from Homebrew, with the following
options:
```
cmake .. -DCMAKE_OSX_ARCHITECTURES="x86_64;arm64" -DCMAKE_OSX_DEPLOYMENT_TARGET="10.12"
```

View File

@ -0,0 +1,17 @@
#ifndef __COMMON_DEF_H__
#define __COMMON_DEF_H__
#include "stdtype.h"
#include "stdbool.h"
#ifndef INLINE
#if defined(_MSC_VER)
#define INLINE static __inline // __forceinline
#elif defined(__GNUC__)
#define INLINE static __inline__
#else
#define INLINE static inline
#endif
#endif // INLINE
#endif // __COMMON_DEF_H__

View File

@ -0,0 +1,19 @@
#ifndef __EMUCORES_H__
#define __EMUCORES_H__
#define FCC_MAME 0x4D414D45 // MAME
#define FCC_MAXM 0x4D41584D // SN76489 by Maxim
#define FCC_EMU_ 0x454D5500 // EMU2413/EMU2149
#define FCC_GPGX 0x47504758 // Genesis Plus GX
#define FCC_GENS 0x47454E53 // Gens
#define FCC_ADLE 0x41444C45 // AdLibEmu
#define FCC_OMSX 0x4F4D5358 // openMSX
#define FCC_NSFP 0x4E534650 // NSFPlay
#define FCC_OOTK 0x4F4F544B // Ootake
#define FCC_MEDN 0x4D45444E // Mednafen
#define FCC_NUKE 0x4E554B45 // Nuked OPx
#define FCC_NRS_ 0x4E525300 // NewRisingSun
#define FCC_VBEL 0x5642454C // Valley Bell
#define FCC_CTR_ 0x43545200 // superctr
#endif // __EMUCORES_H__

View File

@ -0,0 +1,87 @@
#ifndef __EMUHELPER_H__
#define __EMUHELPER_H__
#include <stddef.h> // for NULL
#include "../stdtype.h"
#include "../common_def.h" // for INLINE
#include "EmuStructs.h"
#ifdef _DEBUG
#include <stdio.h>
#endif
#ifdef _USE_MATH_DEFINES
// MS VC6 doesn't have M_PI yet
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
#endif
#if defined(_MSC_VER) && _MSC_VER < 1400
// Math function defines from VC2010's math.h for VC6
#ifndef powf
#define powf(x,y) ((float)pow((double)(x), (double)(y)))
#endif
#endif
#ifdef _DEBUG
#define logerror printf
#elif defined(_MSC_VER) && _MSC_VER < 1400
// MS VC6 doesn't support the variadic macro syntax
#define logerror
#else
#define logerror(...) {}
#endif
INLINE void INIT_DEVINF(DEV_INFO* devInf, DEV_DATA* devData, UINT32 sampleRate, const DEV_DEF* devDef)
{
devInf->dataPtr = devData;
devInf->sampleRate = sampleRate;
devInf->devDef = devDef;
devInf->linkDevCount = 0;
devInf->linkDevs = NULL;
return;
}
// get parent struct from chip data pointer
#define CHP_GET_INF_PTR(info) (((DEV_DATA*)info)->chipInf)
#define SRATE_CUSTOM_HIGHEST(srmode, rate, customrate) \
if (srmode == DEVRI_SRMODE_CUSTOM || \
(srmode == DEVRI_SRMODE_HIGHEST && rate < customrate)) \
rate = customrate;
// round up to the nearest power of 2
// from http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
INLINE UINT32 ceil_pow2(UINT32 v)
{
v --;
v |= (v >> 1);
v |= (v >> 2);
v |= (v >> 4);
v |= (v >> 8);
v |= (v >> 16);
v ++;
return v;
}
// create a mask that covers the range 0...v-1
INLINE UINT32 pow2_mask(UINT32 v)
{
if (v == 0)
return 0;
v --;
v |= (v >> 1);
v |= (v >> 2);
v |= (v >> 4);
v |= (v >> 8);
v |= (v >> 16);
return v;
}
#endif // __EMUHELPER_H__

View File

@ -0,0 +1,145 @@
#ifndef __EMUSTRUCTS_H__
#define __EMUSTRUCTS_H__
#ifdef __cplusplus
extern "C"
{
#endif
#include "../stdtype.h"
#include "snddef.h"
typedef struct _device_definition DEV_DEF;
typedef struct _device_info DEV_INFO;
typedef struct _device_generic_config DEV_GEN_CFG;
typedef struct _device_link_info DEVLINK_INFO;
typedef void (*DEVCB_SRATE_CHG)(void* userParam, UINT32 newSRate);
typedef void (*DEVCB_LOG)(void* userParam, void* source, UINT8 level, const char* message);
typedef UINT8 (*DEVFUNC_START)(const DEV_GEN_CFG* cfg, DEV_INFO* retDevInf);
typedef void (*DEVFUNC_CTRL)(void* info);
typedef void (*DEVFUNC_UPDATE)(void* info, UINT32 samples, DEV_SMPL** outputs);
typedef void (*DEVFUNC_OPTMASK)(void* info, UINT32 optionBits);
typedef void (*DEVFUNC_PANALL)(void* info, const INT16* channelPanVal);
typedef void (*DEVFUNC_SRCCB)(void* info, DEVCB_SRATE_CHG SmpRateChgCallback, void* paramPtr);
typedef UINT8 (*DEVFUNC_LINKDEV)(void* info, UINT8 devID, const DEV_INFO* devInfLink);
typedef void (*DEVFUNC_SETLOGCB)(void* info, DEVCB_LOG logFunc, void* userParam);
typedef UINT8 (*DEVFUNC_READ_A8D8)(void* info, UINT8 addr);
typedef UINT16 (*DEVFUNC_READ_A8D16)(void* info, UINT8 addr);
typedef UINT8 (*DEVFUNC_READ_A16D8)(void* info, UINT16 addr);
typedef UINT16 (*DEVFUNC_READ_A16D16)(void* info, UINT16 addr);
typedef UINT32 (*DEVFUNC_READ_CLOCK)(void* info);
typedef UINT32 (*DEVFUNC_READ_SRATE)(void* info);
typedef UINT32 (*DEVFUNC_READ_VOLUME)(void* info);
typedef void (*DEVFUNC_WRITE_A8D8)(void* info, UINT8 addr, UINT8 data);
typedef void (*DEVFUNC_WRITE_A8D16)(void* info, UINT8 addr, UINT16 data);
typedef void (*DEVFUNC_WRITE_A16D8)(void* info, UINT16 addr, UINT8 data);
typedef void (*DEVFUNC_WRITE_A16D16)(void* info, UINT16 addr, UINT16 data);
typedef void (*DEVFUNC_WRITE_MEMSIZE)(void* info, UINT32 memsize);
typedef void (*DEVFUNC_WRITE_BLOCK)(void* info, UINT32 offset, UINT32 length, const UINT8* data);
typedef void (*DEVFUNC_WRITE_CLOCK)(void* info, UINT32 clock);
typedef void (*DEVFUNC_WRITE_VOLUME)(void* info, INT32 volume); // 16.16 fixed point
typedef void (*DEVFUNC_WRITE_VOL_LR)(void* info, INT32 volL, INT32 volR);
#define RWF_WRITE 0x00
#define RWF_READ 0x01
#define RWF_QUICKWRITE (0x02 | RWF_WRITE)
#define RWF_QUICKREAD (0x02 | RWF_READ)
#define RWF_REGISTER 0x00 // register r/w
#define RWF_MEMORY 0x10 // memory (RAM) r/w
// Note: These chip setting constants can be ORed with RWF_WRITE/RWF_READ.
#define RWF_CLOCK 0x80 // chip clock
#define RWF_SRATE 0x82 // sample rate
#define RWF_VOLUME 0x84 // volume (all speakers)
#define RWF_VOLUME_LR 0x86 // volume (left/right separately)
#define RWF_CHN_MUTE 0x90 // set channel muting (DEVRW_VALUE = single channel, DEVRW_ALL = mask)
#define RWF_CHN_PAN 0x92 // set channel panning (DEVRW_VALUE = single channel, DEVRW_ALL = array)
// register/memory DEVRW constants
#define DEVRW_A8D8 0x11 // 8-bit address, 8-bit data
#define DEVRW_A8D16 0x12 // 8-bit address, 16-bit data
#define DEVRW_A16D8 0x21 // 16-bit address, 8-bit data
#define DEVRW_A16D16 0x22 // 16-bit address, 16-bit data
#define DEVRW_BLOCK 0x80 // write sample ROM/RAM
#define DEVRW_MEMSIZE 0x81 // set ROM/RAM size
// chip setting DEVRW constants
#define DEVRW_VALUE 0x00
#define DEVRW_ALL 0x01
#define DEVLOG_OFF 0x00
#define DEVLOG_ERROR 0x01
#define DEVLOG_WARN 0x02
#define DEVLOG_INFO 0x03
#define DEVLOG_DEBUG 0x04
#define DEVLOG_TRACE 0x05
typedef struct _devdef_readwrite_function
{
UINT8 funcType; // function type, see RWF_ constants
UINT8 rwType; // read/write function type, see DEVRW_ constants
UINT16 user; // user-defined value
void* funcPtr;
} DEVDEF_RWFUNC;
struct _device_definition
{
const char* name; // name of the device
const char* author; // author/origin of emulation
UINT32 coreID; // 4-character identifier ID to distinguish between
// multiple emulators of a device
DEVFUNC_START Start;
DEVFUNC_CTRL Stop;
DEVFUNC_CTRL Reset;
DEVFUNC_UPDATE Update;
DEVFUNC_OPTMASK SetOptionBits;
DEVFUNC_OPTMASK SetMuteMask;
DEVFUNC_PANALL SetPanning; // **NOTE: deprecated, moved to rwFuncs**
DEVFUNC_SRCCB SetSRateChgCB; // used to set callback function for realtime sample rate changes
DEVFUNC_SETLOGCB SetLogCB; // set callback for logging
DEVFUNC_LINKDEV LinkDevice; // used to link multiple devices together
const DEVDEF_RWFUNC* rwFuncs; // terminated by (funcPtr == NULL)
}; // DEV_DEF
struct _device_info
{
DEV_DATA* dataPtr; // points to chip data structure
UINT32 sampleRate;
const DEV_DEF* devDef;
UINT32 linkDevCount; // number of link-able devices
DEVLINK_INFO* linkDevs; // [freed by caller]
}; // DEV_INFO
struct _device_link_info
{
UINT8 devID; // device ID (DEVID_ constant)
UINT8 linkID; // device link ID
DEV_GEN_CFG* cfg; // pointer to DEV_GEN_CFG structures and derivates [freed by caller]
}; // DEVLINK_INFO
// device resampling info constants
#define DEVRI_SRMODE_NATIVE 0x00
#define DEVRI_SRMODE_CUSTOM 0x01
#define DEVRI_SRMODE_HIGHEST 0x02
struct _device_generic_config
{
UINT32 emuCore; // emulation core (4-character code, 0 = default)
UINT8 srMode; // sample rate mode
UINT8 flags; // chip flags
UINT32 clock; // chip clock
UINT32 smplRate; // sample rate for SRMODE_CUSTOM/DEVRI_SRMODE_HIGHEST
// Note: Some cores ignore the srMode setting and always use smplRate.
}; // DEV_GEN_CFG
#ifdef __cplusplus
}
#endif
#endif // __EMUSTRUCTS_H__

View File

@ -0,0 +1,89 @@
#ifndef __RATIOCNTR_H__
#define __RATIOCNTR_H__
#include "../common_def.h"
#if ! LOW_PRECISION_RATIOCNTR
// by default we use a high-precision 32.32 fixed point counter
#define RC_SHIFT 32
typedef UINT64 RC_TYPE;
typedef INT64 RC_STYPE;
#else
// alternatively we can use lower-precision 12.20 fixed point
#define RC_SHIFT 20
typedef UINT32 RC_TYPE;
typedef INT32 RC_STYPE;
#endif
typedef struct
{
RC_TYPE inc; // counter increment
RC_TYPE val; // current value
} RATIO_CNTR;
INLINE void RC_SET_RATIO(RATIO_CNTR* rc, UINT32 mul, UINT32 div)
{
rc->inc = (RC_TYPE)((((UINT64)mul << RC_SHIFT) + div / 2) / div);
}
INLINE void RC_SET_INC(RATIO_CNTR* rc, double val)
{
rc->inc = (RC_TYPE)(((RC_TYPE)1 << RC_SHIFT) * val + 0.5);
}
INLINE void RC_STEP(RATIO_CNTR* rc)
{
rc->val += rc->inc;
}
INLINE void RC_STEPS(RATIO_CNTR* rc, UINT32 step)
{
rc->val += rc->inc * step;
}
INLINE UINT32 RC_GET_VAL(const RATIO_CNTR* rc)
{
return (UINT32)(rc->val >> RC_SHIFT);
}
INLINE void RC_SET_VAL(RATIO_CNTR* rc, UINT32 val)
{
rc->val = (RC_TYPE)val << RC_SHIFT;
}
INLINE void RC_RESET(RATIO_CNTR* rc)
{
rc->val = 0;
}
INLINE void RC_RESET_PRESTEP(RATIO_CNTR* rc)
{
rc->val = ((RC_TYPE)1 << RC_SHIFT) - rc->inc;
}
INLINE void RC_MASK(RATIO_CNTR* rc)
{
rc->val &= (((RC_TYPE)1 << RC_SHIFT) - 1);
}
INLINE void RC_VAL_INC(RATIO_CNTR* rc)
{
rc->val += (RC_TYPE)1 << RC_SHIFT;
}
INLINE void RC_VAL_DEC(RATIO_CNTR* rc)
{
rc->val -= (RC_TYPE)1 << RC_SHIFT;
}
INLINE void RC_VAL_ADD(RATIO_CNTR* rc, INT32 val)
{
rc->val += (RC_STYPE)val << RC_SHIFT;
}
INLINE void RC_VAL_SUB(RATIO_CNTR* rc, INT32 val)
{
rc->val -= (RC_STYPE)val << RC_SHIFT;
}
#endif // __RATIOCNTR_H__

View File

@ -0,0 +1,92 @@
#ifndef __RESAMPLER_H__
#define __RESAMPLER_H__
#ifdef __cplusplus
extern "C"
{
#endif
#include "../stdtype.h"
#include "snddef.h" // for DEV_SMPL
#include "EmuStructs.h"
typedef struct _waveform_32bit_stereo
{
DEV_SMPL L;
DEV_SMPL R;
} WAVE_32BS;
typedef struct _resampling_state
{
UINT32 smpRateSrc;
UINT32 smpRateDst;
INT16 volumeL;
INT16 volumeR;
// Resampler Type:
// 00 - Old
// 01 - Upsampling
// 02 - Copy
// 03 - Downsampling
UINT8 resampleMode; // can be FF [auto] or Resampler Type
UINT8 resampler;
DEVFUNC_UPDATE StreamUpdate;
void* su_DataPtr;
UINT32 smpP; // Current Sample (Playback Rate)
UINT32 smpLast; // Sample Number Last
UINT32 smpNext; // Sample Number Next
WAVE_32BS lSmpl; // Last Sample
WAVE_32BS nSmpl; // Next Sample
UINT32 smplBufSize;
DEV_SMPL* smplBufs[2];
} RESMPL_STATE;
// ---- resampler helper functions (for quick/comfortable initialization) ----
/**
* @brief Sets up a the resampler to use a certain sound device.
*
* @param CAA resampler to be connected to a device
* @param devInf device to be used by the resampler
*/
void Resmpl_DevConnect(RESMPL_STATE* CAA, const DEV_INFO* devInf);
/**
* @brief Helper function to quickly set resampler configuration values.
*
* @param CAA resampler to be configured
* @param resampleMode resampling mode, 0xFF = auto
* @param volume volume gain applied during resampling process, 8.8 fixed point, 0x100 equals 100%
* @param destSampleRate sample rate of the output stream
*/
void Resmpl_SetVals(RESMPL_STATE* CAA, UINT8 resampleMode, UINT16 volume, UINT32 destSampleRate);
// ---- resampler main functions ----
/**
* @brief Initializes a resampler. The resampler must be configured and connected to a device.
*
* @param CAA resampler to be initialized
*/
void Resmpl_Init(RESMPL_STATE* CAA);
/**
* @brief Deinitializes a resampler and frees used memory.
*
* @param CAA resampler to be deinitialized
*/
void Resmpl_Deinit(RESMPL_STATE* CAA);
/**
* @brief Sets the sample rate of the sound device. Used for sample rate changes without deinit/init.
*
* @param CAA resampler whose input sample rate is changed
*/
void Resmpl_ChangeRate(void* DataPtr, UINT32 newSmplRate);
/**
* @brief Request and resample input data in order to render samples into the output buffer.
*
* @param CAA resampler to be executed
* @param samples number of output samples to be rendered
* @param smplBuffer buffer for output data
*/
void Resmpl_Execute(RESMPL_STATE* CAA, UINT32 samples, WAVE_32BS* smplBuffer);
#ifdef __cplusplus
}
#endif
#endif // __RESAMPLER_H__

View File

@ -0,0 +1,46 @@
#ifndef __SOUNDDEVS_H__
#define __SOUNDDEVS_H__
#define DEVID_SN76496 0x00 // variants: SN76489(A), SEGA PSG, T6W28
#define DEVID_YM2413 0x01 // variants: VRC7
#define DEVID_YM2612 0x02 // variants: YM3438
#define DEVID_YM2151 0x03
#define DEVID_SEGAPCM 0x04
#define DEVID_RF5C68 0x05 // variants: RF5C164, RF5C105
#define DEVID_YM2203 0x06
#define DEVID_YM2608 0x07 // variants: YMF288
#define DEVID_YM2610 0x08 // variants: YM2610B
#define DEVID_YM3812 0x09 // also known as OPL2
#define DEVID_YM3526 0x0A
#define DEVID_Y8950 0x0B
#define DEVID_YMF262 0x0C // also known as OPL3
#define DEVID_YMF278B 0x0D // also known as OPL4
#define DEVID_YMF271 0x0E
#define DEVID_YMZ280B 0x0F
#define DEVID_32X_PWM 0x11
#define DEVID_AY8910 0x12 // variants: AY-3-8912/8913/8930, YM2149, YM3439, YMZ284/294
#define DEVID_GB_DMG 0x13
#define DEVID_NES_APU 0x14 // also known as RP2A03/RP2A07
#define DEVID_YMW258 0x15 // also known as MultiPCM
#define DEVID_uPD7759 0x16
#define DEVID_OKIM6258 0x17 // also known as MSM6258
#define DEVID_OKIM6295 0x18 // also known as MSM6295
#define DEVID_K051649 0x19 // also known as SCC1, variants: K052539, also known as SCC+
#define DEVID_K054539 0x1A
#define DEVID_C6280 0x1B
#define DEVID_C140 0x1C
#define DEVID_C219 0x80 // TODO: renumber devices
#define DEVID_K053260 0x1D
#define DEVID_POKEY 0x1E
#define DEVID_QSOUND 0x1F
#define DEVID_SCSP 0x20 // also known as YMF292
#define DEVID_WSWAN 0x21
#define DEVID_VBOY_VSU 0x22
#define DEVID_SAA1099 0x23
#define DEVID_ES5503 0x24
#define DEVID_ES5506 0x25 // variants: ES5505
#define DEVID_X1_010 0x26
#define DEVID_C352 0x27
#define DEVID_GA20 0x28
#endif // __SOUNDDEVS_H__

View File

@ -0,0 +1,78 @@
#ifndef __SOUNDEMU_H__
#define __SOUNDEMU_H__
#ifdef __cplusplus
extern "C"
{
#endif
#include "../stdtype.h"
#include "EmuStructs.h"
/**
* @brief Retrieve a list of all available sound cores for a device.
*
* @param deviceID ID of the sound device (see DEVID_ constants in SoundDevs.h)
* @return an array of DEV_DEF* that is terminated by a NULL pointer
*/
const DEV_DEF** SndEmu_GetDevDefList(UINT8 deviceID);
/**
* @brief Initializes emulation for a sound device.
*
* @param deviceID ID of the sound device to be emulated (see DEVID constants in SoundDevs.h)
* @param cfg chip-dependent configuration structure, contains various settings
* @param retDevInf pointer to DEV_INFO structure that gets filled with device information,
* caller has to free information about linkable devices
* @return error code. 0 = success, see EERR constants
*/
UINT8 SndEmu_Start(UINT8 deviceID, const DEV_GEN_CFG* cfg, DEV_INFO* retDevInf);
/**
* @brief Deinitializes the sound core.
*
* @param devInf DEV_INFO structure of the device to be stopped
* @return always returns 0 (success)
*/
UINT8 SndEmu_Stop(DEV_INFO* devInf);
/**
* @brief Frees memory that holds information about linkable devices.
* Should be called sometime after a successful SndEmu_Start() in order to prevent memory leaks.
*
* @param devInf DEV_INFO structure of the main device
*/
void SndEmu_FreeDevLinkData(DEV_INFO* devInf);
/**
* @brief Retrieve a function of a sound core that fullfills certain conditions.
*
* @param devInf DEV_INFO structure of the device
* @param funcType function type (write/read, register/memory, ...), see RWF_ constants in EmuStructs.h
* @param rwType read/write data type, see DEVRW_ constants in EmuStructs.h
* @param user user-defined value for distinguishing functions with the same funcType/rwType, 0 = default
* @param retFuncPtr parameter the function pointer is stored in
* @return error code. 0 = success, 1 - success, but more possible candidates found, see EERR constants
*/
UINT8 SndEmu_GetDeviceFunc(const DEV_DEF* devInf, UINT8 funcType, UINT8 rwType, UINT16 user, void** retFuncPtr);
/**
* @brief Retrieve the name of a sound device.
* Device configuration parameters may be use to identify exact sound chip models.
*
* @param deviceID ID of the sound device to get the name of (see DEVID constants in SoundDevs.h)
* @param opts bitfield of options
* Bit 0 (0x01): enable long names
* @param cfg chip-dependent configuration structure, allows for correct names of device variations,
* ONLY used when long names are enabled
* @return pointer to name of the device
*/
const char* SndEmu_GetDevName(UINT8 deviceID, UINT8 opts, const DEV_GEN_CFG* devCfg);
#define EERR_OK 0x00
#define EERR_MORE_FOUND 0x01 // success, but more items were found
#define EERR_UNK_DEVICE 0xF0 // unknown/invalid device ID
#define EERR_NOT_FOUND 0xF8 // sound core or function not found
#define EERR_INIT_ERR 0xFF // sound core initialization error (usually malloc error)
#ifdef __cplusplus
}
#endif
#endif // __SOUNDEMU_H__

View File

@ -0,0 +1,34 @@
#ifndef __DAC_CONTROL_H__
#define __DAC_CONTROL_H__
#ifdef __cplusplus
extern "C"
{
#endif
#include "../stdtype.h"
#include "EmuStructs.h"
void daccontrol_update(void* info, UINT32 samples, DEV_SMPL** dummy);
UINT8 device_start_daccontrol(const DEV_GEN_CFG* cfg, DEV_INFO* retDevInf);
void device_stop_daccontrol(void* info);
void device_reset_daccontrol(void* info);
void daccontrol_setup_chip(void* info, DEV_INFO* devInf, UINT8 ChType, UINT16 Command);
void daccontrol_set_data(void* info, UINT8* Data, UINT32 DataLen, UINT8 StepSize, UINT8 StepBase);
void daccontrol_refresh_data(void* info, UINT8* Data, UINT32 DataLen);
void daccontrol_set_frequency(void* info, UINT32 Frequency);
void daccontrol_start(void* info, UINT32 DataPos, UINT8 LenMode, UINT32 Length);
void daccontrol_stop(void* info);
#define DCTRL_LMODE_IGNORE 0x00
#define DCTRL_LMODE_CMDS 0x01
#define DCTRL_LMODE_MSEC 0x02
#define DCTRL_LMODE_TOEND 0x03
#define DCTRL_LMODE_BYTES 0x0F
#ifdef __cplusplus
}
#endif
#endif // __DAC_CONTROL_H__

View File

@ -0,0 +1,35 @@
#ifndef __EMU_LOGGING_H__
#define __EMU_LOGGING_H__
#ifdef __cplusplus
extern "C"
{
#endif
#include "../stdtype.h"
#include "../common_def.h"
#include "EmuStructs.h"
typedef struct _device_logger
{
DEVCB_LOG func;
void* source;
void* param;
} DEV_LOGGER;
INLINE void dev_logger_set(DEV_LOGGER* logger, void* source, DEVCB_LOG func, void* param)
{
logger->func = func;
logger->source = source;
logger->param = param;
return;
}
void emu_logf(DEV_LOGGER* logger, UINT8 level, const char* format, ...);
#ifdef __cplusplus
}
#endif
#endif // __EMU_LOGGING_H__

View File

@ -0,0 +1,26 @@
#ifndef __EMU_PANNING_H__
#define __EMU_PANNING_H__
#ifdef __cplusplus
extern "C"
{
#endif
#include "../stdtype.h"
#define PANNING_BITS 16 // 16.16 fixed point
#define PANNING_NORMAL (1 << PANNING_BITS)
// apply panning value to x, x should be within +-16384
#define APPLY_PANNING_S(x, panval) ((x * panval) >> PANNING_BITS)
// apply panning value to x, version for larger values
#define APPLY_PANNING_L(x, panval) (INT32)(((INT64)x * panval) >> PANNING_BITS)
void Panning_Calculate(INT32 channels[2], INT16 position);
void Panning_Centre(INT32 channels[2]);
#ifdef __cplusplus
}
#endif
#endif // __EMU_PANNING_H__

View File

@ -0,0 +1,17 @@
#ifndef __SNDDEF_H__
#define __SNDDEF_H__
#include "../stdtype.h"
// DEV_SMPL is used to represent a single sample in a sound stream
typedef INT32 DEV_SMPL;
// generic device data structure
// MUST be the first variable included in all device-specifc structures
// (i.e. all sound cores inherit this structure)
typedef struct _device_data
{
void* chipInf; // pointer to CHIP_INF (depends on specific chip)
} DEV_DATA;
#endif // __SNDDEF_H__

View File

@ -0,0 +1,79 @@
#ifndef __DBLK_COMPR_H__
#define __DBLK_COMPR_H__
#ifdef __cplusplus
extern "C"
{
#endif
#include "../stdtype.h"
#include "../common_def.h"
typedef struct _pcm_compression_table
{
UINT8 comprType;
UINT8 cmpSubType;
UINT8 bitsDec;
UINT8 bitsCmp;
UINT16 valueCount;
union
{
UINT8* d8;
UINT16* d16; // note: stored in Native Endian
} values;
} PCM_COMPR_TBL;
typedef struct _compression_parameters
{
// Compression Types:
// 00 - bit packing
// 01 - Delta-PCM
UINT8 comprType;
UINT8 subType; // compression sub-type
UINT8 bitsDec; // bits per value (decompressed)
UINT8 bitsCmp; // bits per value (compressed)
UINT16 baseVal;
const PCM_COMPR_TBL* comprTbl;
} PCM_CMP_INF;
typedef struct _pcm_compr_datablk_info
{
// general data
UINT32 hdrSize; // number of bytes taken by the compression header in the VGM *1
UINT32 decmpLen; // size of decompressed data *2
// *1 written by Read/WriteComprDataBlkHdr
// *2 set by ReadComprDataBlkHdr, read by WriteComprDataBlkHdr
// actual parameters required for (De-)CompressDataBlk
PCM_CMP_INF cmprInfo;
} PCM_CDB_INF;
// small functions to help calculating data sizes
// Bit Packing/DPCM:
INLINE UINT32 BPACK_SIZE_CMP(UINT32 sizeDec, UINT32 bitsCmp, UINT32 bitsDec)
{
UINT32 byteBits = (bitsDec + 7) & ~7;
return (UINT32)(((UINT64)sizeDec * bitsCmp + 7) / byteBits);
}
INLINE UINT32 BPACK_SIZE_DEC(UINT32 sizeCmp, UINT32 bitsCmp, UINT32 bitsDec)
{
UINT32 byteBits = (bitsDec + 7) & ~7;
return (UINT32)((UINT64)sizeCmp * byteBits / bitsCmp);
}
UINT8 ReadComprDataBlkHdr(UINT32 inLen, const UINT8* inData, PCM_CDB_INF* retCdbInf);
UINT8 WriteComprDataBlkHdr(UINT32 outLen, UINT8* outData, PCM_CDB_INF* cdbInf);
UINT8 DecompressDataBlk(UINT32 outLen, UINT8* outData, UINT32 inLen, const UINT8* inData, const PCM_CMP_INF* cmprInfo);
UINT8 DecompressDataBlk_VGM(UINT32* outLen, UINT8** retOutData, UINT32 inLen, const UINT8* inData, const PCM_COMPR_TBL* comprTbl);
UINT8 CompressDataBlk(UINT32 outLen, UINT8* outData, UINT32 inLen, const UINT8* inData, const PCM_CMP_INF* cmprInfo);
void ReadPCMComprTable(UINT32 dataSize, const UINT8* data, PCM_COMPR_TBL* comprTbl);
UINT32 WriteCompressionTable(UINT32 dataSize, UINT8* data, PCM_COMPR_TBL* comprTbl);
void GenerateReverseLUT_8(UINT16 dstLen, UINT8* dstLUT, UINT16 srcLen, const UINT8* srcLUT);
void GenerateReverseLUT_16(UINT32 dstLen, UINT16* dstLUT, UINT32 srcLen, const UINT16* srcLUT);
#ifdef __cplusplus
}
#endif
#endif // __DBLK_COMPR_H__

View File

@ -0,0 +1,197 @@
#ifndef __DROPLAYER_HPP__
#define __DROPLAYER_HPP__
#include "../stdtype.h"
#include "../emu/EmuStructs.h"
#include "../emu/Resampler.h"
#include "helper.h"
#include "playerbase.hpp"
#include "../utils/DataLoader.h"
#include "../emu/logging.h"
#include <vector>
#include <string>
#define FCC_DRO 0x44524F00
// DRO v0 header (DOSBox 0.62, SVN r1864)
// Ofs Len Description
// 00 08 "DBRAWOPL"
// 04 04 data length in milliseconds
// 08 04 data length in bytes
// 0C 01 hardware type (0 = OPL2, 1 = OPL3, 2 = DualOPL2)
// DRO v1 header (DOSBox 0.63, SVN r2065)
// Ofs Len Description
// 00 08 "DBRAWOPL"
// 04 04 version minor
// 08 04 version major
// 0C 04 data length in milliseconds
// 10 04 data length in bytes
// 14 04 hardware type (0 = OPL2, 1 = OPL3, 2 = DualOPL2)
// DRO v2 header (DOSBox 0.73, SVN r3178)
// Ofs Len Description
// 00 08 "DBRAWOPL"
// 04 04 version major
// 08 04 version minor
// 0C 04 data length in "pairs" (1 pair = 2 bytes, a pair consists of command + data)
// 10 04 data length in milliseconds
// 14 01 hardware type (0 = OPL2, 1 = DualOPL2, 2 = OPL3)
// 15 01 data format (0 = interleaved command/data)
// 16 01 compression (0 = no compression)
// 17 01 command code for short delay
// 18 01 command code for long delay
// 19 01 size of register codemap cl
// 1A cl register codemap
struct DRO_HEADER
{
UINT16 verMajor;
UINT16 verMinor;
UINT32 dataSize; // in bytes
UINT32 lengthMS;
UINT8 hwType;
UINT8 format;
UINT8 compression;
UINT8 cmdDlyShort;
UINT8 cmdDlyLong;
UINT8 regCmdCnt;
UINT8 regCmdMap[0x80];
UINT32 dataOfs;
};
// DRO v2 often incorrectly specify DualOPL2 instead of OPL3
// These constants allow a configuration of how to handle DualOPL2 in DRO v2 files.
#define DRO_V2OPL3_DETECT 0x00 // scan the initialization block and use OPL3 if "OPL3 enable" if found [default]
#define DRO_V2OPL3_HEADER 0x01 // strictly follow the DRO header
#define DRO_V2OPL3_ENFORCE 0x02 // always enforce OPL3 mode when the DRO says DualOPL2
struct DRO_PLAY_OPTIONS
{
UINT8 v2opl3Mode; // DRO v2 DualOPL2 -> OPL3 fixes
};
class DROPlayer : public PlayerBase
{
private:
struct DEVLOG_CB_DATA
{
DROPlayer* player;
size_t chipDevID;
};
struct DRO_CHIPDEV
{
VGM_BASEDEV base;
size_t optID;
DEVFUNC_WRITE_A8D8 write;
DEVLOG_CB_DATA logCbData;
};
public:
DROPlayer();
~DROPlayer();
UINT32 GetPlayerType(void) const;
const char* GetPlayerName(void) const;
static UINT8 PlayerCanLoadFile(DATA_LOADER *dataLoader);
UINT8 CanLoadFile(DATA_LOADER *dataLoader) const;
UINT8 LoadFile(DATA_LOADER *dataLoader);
UINT8 UnloadFile(void);
const DRO_HEADER* GetFileHeader(void) const;
const char* const* GetTags(void);
UINT8 GetSongInfo(PLR_SONG_INFO& songInf);
UINT8 GetSongDeviceInfo(std::vector<PLR_DEV_INFO>& devInfList) const;
UINT8 SetDeviceOptions(UINT32 id, const PLR_DEV_OPTS& devOpts);
UINT8 GetDeviceOptions(UINT32 id, PLR_DEV_OPTS& devOpts) const;
UINT8 SetDeviceMuting(UINT32 id, const PLR_MUTE_OPTS& muteOpts);
UINT8 GetDeviceMuting(UINT32 id, PLR_MUTE_OPTS& muteOpts) const;
UINT8 SetPlayerOptions(const DRO_PLAY_OPTIONS& playOpts);
UINT8 GetPlayerOptions(DRO_PLAY_OPTIONS& playOpts) const;
//UINT32 GetSampleRate(void) const;
UINT8 SetSampleRate(UINT32 sampleRate);
//UINT8 SetPlaybackSpeed(double speed);
//void SetEventCallback(PLAYER_EVENT_CB cbFunc, void* cbParam);
UINT32 Tick2Sample(UINT32 ticks) const;
UINT32 Sample2Tick(UINT32 samples) const;
double Tick2Second(UINT32 ticks) const;
//double Sample2Second(UINT32 samples) const;
UINT8 GetState(void) const;
UINT32 GetCurPos(UINT8 unit) const;
UINT32 GetCurLoop(void) const;
UINT32 GetTotalTicks(void) const; // get time for playing once in ticks
UINT32 GetLoopTicks(void) const; // get time for one loop in ticks
//UINT32 GetTotalPlayTicks(UINT32 numLoops) const; // get time for playing + looping (without fading)
UINT8 Start(void);
UINT8 Stop(void);
UINT8 Reset(void);
UINT8 Seek(UINT8 unit, UINT32 pos);
UINT32 Render(UINT32 smplCnt, WAVE_32BS* data);
private:
size_t DeviceID2OptionID(UINT32 id) const;
void RefreshMuting(DRO_CHIPDEV& chipDev, const PLR_MUTE_OPTS& muteOpts);
void RefreshPanning(DRO_CHIPDEV& chipDev, const PLR_PAN_OPTS& panOpts);
void ScanInitBlock(void);
static void PlayerLogCB(void* userParam, void* source, UINT8 level, const char* message);
static void SndEmuLogCB(void* userParam, void* source, UINT8 level, const char* message);
void GenerateDeviceConfig(void);
UINT8 SeekToTick(UINT32 tick);
UINT8 SeekToFilePos(UINT32 pos);
void ParseFile(UINT32 ticks);
void DoCommand_v1(void);
void DoCommand_v2(void);
void DoFileEnd(void);
void WriteReg(UINT8 port, UINT8 reg, UINT8 data);
DEV_LOGGER _logger;
DATA_LOADER* _dLoad;
const UINT8* _fileData; // data pointer for quick access, equals _dLoad->GetFileData().data()
DRO_HEADER _fileHdr;
std::vector<UINT8> _devTypes;
std::vector<UINT8> _devPanning;
std::vector<DEV_GEN_CFG> _devCfgs;
UINT8 _realHwType;
UINT8 _portShift; // 0 for OPL2 (1 port per chip), 1 for OPL3 (2 ports per chip)
UINT8 _portMask; // (1 << _portShift) - 1
UINT32 _tickFreq;
UINT32 _totalTicks;
// information about the initialization block (ends with first delay)
UINT32 _initBlkEndOfs; // offset of end of init. block (for special fixes)
std::vector<bool> _initRegSet; // registers set during init. block
UINT8 _initOPL3Enable; // value of OPL3 enable register set during init. block
//UINT32 _outSmplRate;
// tick/sample conversion rates
UINT64 _tsMult;
UINT64 _tsDiv;
DRO_PLAY_OPTIONS _playOpts;
PLR_DEV_OPTS _devOpts[3]; // 0 = 1st OPL2, 1 = 2nd OPL2, 2 = 1st OPL3
std::vector<DRO_CHIPDEV> _devices;
std::vector<std::string> _devNames;
size_t _optDevMap[3]; // maps _devOpts vector index to _devices vector
UINT32 _filePos;
UINT32 _fileTick;
UINT32 _playTick;
UINT32 _playSmpl;
UINT8 _playState;
UINT8 _psTrigger; // used to temporarily trigger special commands
UINT8 _selPort; // currently selected OPL chip (for DRO v1)
//PLAYER_EVENT_CB _eventCbFunc;
//void* _eventCbParam;
};
#endif // __DROPLAYER_HPP__

View File

@ -0,0 +1,171 @@
#ifndef __GYMPLAYER_HPP__
#define __GYMPLAYER_HPP__
#include "../stdtype.h"
#include "../emu/EmuStructs.h"
#include "../emu/Resampler.h"
#include "../utils/StrUtils.h"
#include "helper.h"
#include "playerbase.hpp"
#include "../utils/DataLoader.h"
#include "../emu/logging.h"
#include <vector>
#include <map>
#include <string>
#define FCC_GYM 0x47594D00
// GYMX header (optional, added by YMAMP WinAMP plugin)
// Ofs Len Description
// 000 04 "GYMX"
// 004 20 song title
// 024 20 game name
// 044 20 publisher
// 064 20 emulator ("Dumped with")
// 084 20 file creator ("Dumped by")
// 0A4 100 comments
// 1A4 04 loop start frame (0 = no loop)
// 1A8 04 uncompressed data size (0 = data is uncompressed, 1 = data is zlib compressed)
struct GYM_HEADER
{
UINT8 hasHeader;
UINT32 uncomprSize;
UINT32 loopFrame;
UINT32 dataOfs;
UINT32 realFileSize; // internal file size after possible decompression
};
class GYMPlayer : public PlayerBase
{
private:
struct DevCfg
{
UINT8 type;
UINT16 volume;
std::vector<UINT8> data;
};
struct DEVLOG_CB_DATA
{
GYMPlayer* player;
size_t chipDevID;
};
struct GYM_CHIPDEV
{
VGM_BASEDEV base;
size_t optID;
DEVFUNC_WRITE_A8D8 write;
DEVLOG_CB_DATA logCbData;
};
public:
GYMPlayer();
~GYMPlayer();
UINT32 GetPlayerType(void) const;
const char* GetPlayerName(void) const;
static UINT8 PlayerCanLoadFile(DATA_LOADER *dataLoader);
UINT8 CanLoadFile(DATA_LOADER *dataLoader) const;
UINT8 LoadFile(DATA_LOADER *dataLoader);
UINT8 UnloadFile(void);
const GYM_HEADER* GetFileHeader(void) const;
const char* const* GetTags(void);
UINT8 GetSongInfo(PLR_SONG_INFO& songInf);
UINT8 GetSongDeviceInfo(std::vector<PLR_DEV_INFO>& devInfList) const;
UINT8 SetDeviceOptions(UINT32 id, const PLR_DEV_OPTS& devOpts);
UINT8 GetDeviceOptions(UINT32 id, PLR_DEV_OPTS& devOpts) const;
UINT8 SetDeviceMuting(UINT32 id, const PLR_MUTE_OPTS& muteOpts);
UINT8 GetDeviceMuting(UINT32 id, PLR_MUTE_OPTS& muteOpts) const;
//UINT32 GetSampleRate(void) const;
UINT8 SetSampleRate(UINT32 sampleRate);
//UINT8 SetPlaybackSpeed(double speed);
//void SetEventCallback(PLAYER_EVENT_CB cbFunc, void* cbParam);
UINT32 Tick2Sample(UINT32 ticks) const;
UINT32 Sample2Tick(UINT32 samples) const;
double Tick2Second(UINT32 ticks) const;
//double Sample2Second(UINT32 samples) const;
UINT8 GetState(void) const;
UINT32 GetCurPos(UINT8 unit) const;
UINT32 GetCurLoop(void) const;
UINT32 GetTotalTicks(void) const; // get time for playing once in ticks
UINT32 GetLoopTicks(void) const; // get time for one loop in ticks
//UINT32 GetTotalPlayTicks(UINT32 numLoops) const; // get time for playing + looping (without fading)
UINT8 Start(void);
UINT8 Stop(void);
UINT8 Reset(void);
UINT8 Seek(UINT8 unit, UINT32 pos);
UINT32 Render(UINT32 smplCnt, WAVE_32BS* data);
private:
size_t DeviceID2OptionID(UINT32 id) const;
void RefreshMuting(GYM_CHIPDEV& chipDev, const PLR_MUTE_OPTS& muteOpts);
void RefreshPanning(GYM_CHIPDEV& chipDev, const PLR_PAN_OPTS& panOpts);
UINT8 DecompressZlibData(void);
void CalcSongLength(void);
UINT8 LoadTags(void);
void LoadTag(const char* tagName, const void* data, size_t maxlen);
std::string GetUTF8String(const char* startPtr, const char* endPtr);
static void PlayerLogCB(void* userParam, void* source, UINT8 level, const char* message);
static void SndEmuLogCB(void* userParam, void* source, UINT8 level, const char* message);
void GenerateDeviceConfig(void);
UINT8 SeekToTick(UINT32 tick);
UINT8 SeekToFilePos(UINT32 pos);
void ParseFile(UINT32 ticks);
void DoCommand(void);
void DoFileEnd(void);
CPCONV* _cpc1252; // CP1252 -> UTF-8 codepage conversion
DEV_LOGGER _logger;
DATA_LOADER* _dLoad;
UINT32 _fileLen;
const UINT8* _fileData; // data pointer for quick access, equals _dLoad->GetFileData().data()
std::vector<UINT8> _decFData;
GYM_HEADER _fileHdr;
std::vector<DevCfg> _devCfgs;
UINT32 _tickFreq;
UINT32 _totalTicks;
UINT32 _loopOfs;
std::map<std::string, std::string> _tagData;
std::vector<const char*> _tagList;
std::vector<UINT8> _pcmBuffer;
UINT32 _pcmBaseTick;
UINT32 _pcmInPos; // input position (GYM -> buffer)
UINT32 _pcmOutPos; // output position (buffer -> YM2612)
UINT8 _ymFreqRegs[0x20]; // cache of 0x0A0..0x0AF and 0x1A0..0x1AF frequency registers
UINT8 _ymLatch[2]; // current latch value ([0] = normal channels, [1] = CH3 multi-freq mode registers]
//UINT32 _outSmplRate;
// tick/sample conversion rates
UINT64 _tsMult;
UINT64 _tsDiv;
PLR_DEV_OPTS _devOpts[2]; // 0 = YM2612, 1 = SEGA PSG
std::vector<GYM_CHIPDEV> _devices;
std::vector<std::string> _devNames;
size_t _optDevMap[2]; // maps _devOpts vector index to _devices vector
UINT32 _filePos;
UINT32 _fileTick;
UINT32 _playTick;
UINT32 _playSmpl;
UINT32 _curLoop;
UINT32 _lastLoopTick;
UINT8 _playState;
UINT8 _psTrigger; // used to temporarily trigger special commands
//PLAYER_EVENT_CB _eventCbFunc;
//void* _eventCbParam;
};
#endif // __GYMPLAYER_HPP__

View File

@ -0,0 +1,32 @@
#ifndef __PLAYER_HELPER_H__
#define __PLAYER_HELPER_H__
#ifdef __cplusplus
extern "C"
{
#endif
#include "../stdtype.h"
#include "../emu/EmuStructs.h"
#include "../emu/Resampler.h"
typedef struct _vgm_base_device VGM_BASEDEV;
struct _vgm_base_device
{
DEV_INFO defInf;
RESMPL_STATE resmpl;
VGM_BASEDEV* linkDev;
};
// callback function typedef for SetupLinkedDevices
typedef void (*SETUPLINKDEV_CB)(void* userParam, VGM_BASEDEV* cDev, DEVLINK_INFO* dLink);
void SetupLinkedDevices(VGM_BASEDEV* cBaseDev, SETUPLINKDEV_CB devCfgCB, void* cbUserParam);
void FreeDeviceTree(VGM_BASEDEV* cBaseDev, UINT8 freeBase);
#ifdef __cplusplus
}
#endif
#endif // __PLAYER_HELPER_H__

View File

@ -0,0 +1,100 @@
#ifndef __PLAYERA_HPP__
#define __PLAYERA_HPP__
#include <vector>
#include "../stdtype.h"
#include "../utils/DataLoader.h"
#include "../emu/Resampler.h" // for WAVE_32BS
#include "playerbase.hpp"
#define PLAYSTATE_FADE 0x10 // is fading
#define PLAYSTATE_FIN 0x20 // finished playing (file end + fading + trailing silence)
// TODO: find a proper name for this class
class PlayerA
{
public:
struct Config
{
INT32 masterVol; // master volume (16.16 fixed point, negative value = phase inversion)
bool ignoreVolGain; // ignore track-specific volume gain
UINT8 chnInvert; // channel phase inversion (bit 0 - left, bit 1 - right)
UINT32 loopCount;
UINT32 fadeSmpls;
UINT32 endSilenceSmpls;
double pbSpeed;
};
typedef void (*PLR_SMPL_PACK)(void* buffer, INT32 value);
PlayerA();
~PlayerA();
void RegisterPlayerEngine(PlayerBase* player);
void UnregisterAllPlayers(void);
const std::vector<PlayerBase*>& GetRegisteredPlayers(void) const;
UINT8 SetOutputSettings(UINT32 smplRate, UINT8 channels, UINT8 smplBits, UINT32 smplBufferLen);
UINT32 GetSampleRate(void) const;
void SetSampleRate(UINT32 sampleRate);
double GetPlaybackSpeed(void) const;
void SetPlaybackSpeed(double speed);
UINT32 GetLoopCount(void) const;
void SetLoopCount(UINT32 loops);
INT32 GetMasterVolume(void) const;
void SetMasterVolume(INT32 volume);
INT32 GetSongVolume(void) const;
UINT32 GetFadeSamples(void) const;
void SetFadeSamples(UINT32 smplCnt);
UINT32 GetEndSilenceSamples(void) const;
void SetEndSilenceSamples(UINT32 smplCnt);
const Config& GetConfiguration(void) const;
void SetConfiguration(const Config& config);
void SetEventCallback(PLAYER_EVENT_CB cbFunc, void* cbParam);
void SetFileReqCallback(PLAYER_FILEREQ_CB cbFunc, void* cbParam);
void SetLogCallback(PLAYER_LOG_CB cbFunc, void* cbParam);
UINT8 GetState(void) const;
UINT32 GetCurPos(UINT8 unit) const;
double GetCurTime(UINT8 includeLoops) const;
double GetTotalTime(UINT8 includeLoops) const;
UINT32 GetCurLoop(void) const;
double GetLoopTime(void) const;
PlayerBase* GetPlayer(void);
const PlayerBase* GetPlayer(void) const;
UINT8 LoadFile(DATA_LOADER* dLoad);
UINT8 UnloadFile(void);
UINT32 GetFileSize(void);
UINT8 Start(void);
UINT8 Stop(void);
UINT8 Reset(void);
UINT8 FadeOut(void);
UINT8 Seek(UINT8 unit, UINT32 pos);
UINT32 Render(UINT32 bufSize, void* data);
private:
void FindPlayerEngine(void);
INT32 CalcSongVolume(void);
INT32 CalcCurrentVolume(UINT32 playbackSmpl);
static UINT8 PlayCallbackS(PlayerBase* player, void* userParam, UINT8 evtType, void* evtParam);
UINT8 PlayCallback(PlayerBase* player, UINT8 evtType, void* evtParam);
std::vector<PlayerBase*> _avbPlrs; // available players
UINT32 _smplRate;
Config _config;
PLAYER_EVENT_CB _plrCbFunc;
void* _plrCbParam;
UINT8 _myPlayState;
UINT8 _outSmplChns;
UINT8 _outSmplBits;
UINT32 _outSmplSize1; // for 1 channel
UINT32 _outSmplSizeA; // for all channels
PLR_SMPL_PACK _outSmplPack;
std::vector<WAVE_32BS> _smplBuf;
PlayerBase* _player;
DATA_LOADER* _dLoad;
INT32 _songVolume;
UINT32 _fadeSmplStart;
UINT32 _endSilenceStart;
};
#endif // __PLAYERA_HPP__

View File

@ -0,0 +1,160 @@
#ifndef __PLAYERBASE_HPP__
#define __PLAYERBASE_HPP__
#include "../stdtype.h"
#include "../emu/EmuStructs.h" // for DEV_GEN_CFG
#include "../emu/Resampler.h" // for WAVE_32BS
#include "../utils/DataLoader.h"
#include <vector>
// GetState() bit masks
#define PLAYSTATE_PLAY 0x01 // is playing
#define PLAYSTATE_END 0x02 // has reached the end of the file
#define PLAYSTATE_PAUSE 0x04 // is paused (render wave, but don't advance in the song)
#define PLAYSTATE_SEEK 0x08 // is seeking
// GetCurPos()/Seek() units
#define PLAYPOS_FILEOFS 0x00 // file offset (in bytes)
#define PLAYPOS_TICK 0x01 // tick position (scale: internal tick rate)
#define PLAYPOS_SAMPLE 0x02 // sample number (scale: rendering sample rate)
#define PLAYPOS_COMMAND 0x03 // internal command ID
// callback functions and event constants
class PlayerBase;
typedef UINT8 (*PLAYER_EVENT_CB)(PlayerBase* player, void* userParam, UINT8 evtType, void* evtParam);
#define PLREVT_NONE 0x00
#define PLREVT_START 0x01 // playback started
#define PLREVT_STOP 0x02 // playback stopped
#define PLREVT_LOOP 0x03 // starting next loop [evtParam: UINT32* loopNumber, ret == 0x01 -> stop processing]
#define PLREVT_END 0x04 // reached the end of the song
typedef DATA_LOADER* (*PLAYER_FILEREQ_CB)(void* userParam, PlayerBase* player, const char* fileName);
typedef void (*PLAYER_LOG_CB)(void* userParam, PlayerBase* player, UINT8 level, UINT8 srcType, const char* srcTag, const char* message);
// log levels
#define PLRLOG_OFF DEVLOG_OFF
#define PLRLOG_ERROR DEVLOG_ERROR
#define PLRLOG_WARN DEVLOG_WARN
#define PLRLOG_INFO DEVLOG_INFO
#define PLRLOG_DEBUG DEVLOG_DEBUG
#define PLRLOG_TRACE DEVLOG_TRACE
// log source types
#define PLRLOGSRC_PLR 0x00 // player
#define PLRLOGSRC_EMU 0x01 // sound emulation
struct PLR_SONG_INFO
{
UINT32 format; // four-character-code for file format
UINT16 fileVerMaj; // file version (major, encoded as BCD)
UINT16 fileVerMin; // file version (minor, encoded as BCD)
UINT32 tickRateMul; // internal ticks per second: numerator
UINT32 tickRateDiv; // internal ticks per second: denumerator
// 1 second = 1 tick * tickMult / tickDiv
UINT32 songLen; // song length in ticks
UINT32 loopTick; // tick position where the loop begins (-1 = no loop)
INT32 volGain; // song-specific volume gain, 16.16 fixed point factor (0x10000 = 100%)
UINT32 deviceCnt; // number of used sound devices
};
struct PLR_DEV_INFO
{
UINT32 id; // device ID
UINT8 type; // device type
UINT8 instance; // instance ID of this device type (0xFF -> N/A for this format)
UINT16 volume; // output volume (0x100 = 100%)
UINT32 core; // FCC of device emulation core
UINT32 smplRate; // current sample rate (0 if not running)
const DEV_GEN_CFG* devCfg; // device configuration parameters
};
struct PLR_MUTE_OPTS
{
UINT8 disable; // suspend emulation (0x01 = main device, 0x02 = linked, 0xFF = all)
UINT32 chnMute[2]; // channel muting mask ([1] is used for linked devices)
};
struct PLR_PAN_OPTS
{
INT16 chnPan[2][32]; // channel panning [TODO: rethink how this should be really configured]
};
#define PLR_DEV_ID(chip, instance) (0x80000000 | (instance << 16) | (chip << 0))
struct PLR_DEV_OPTS
{
UINT32 emuCore[2]; // enforce a certain sound core (0 = use default, [1] is used for linked devices)
UINT8 srMode; // sample rate mode (see DEVRI_SRMODE)
UINT8 resmplMode; // resampling mode (0 - high quality, 1 - low quality, 2 - LQ down, HQ up)
UINT32 smplRate; // emulaiton sample rate
UINT32 coreOpts;
PLR_MUTE_OPTS muteOpts;
PLR_PAN_OPTS panOpts;
};
// --- concept ---
// - Player class does file rendering at fixed volume (but changeable speed)
// - host program handles master volume + fading + stopping after X loops (notified via callback)
// TODO: rename to "PlayerEngine"
class PlayerBase
{
public:
PlayerBase();
virtual ~PlayerBase();
virtual UINT32 GetPlayerType(void) const;
virtual const char* GetPlayerName(void) const;
static UINT8 PlayerCanLoadFile(DATA_LOADER *dataLoader);
virtual UINT8 CanLoadFile(DATA_LOADER *dataLoader) const;
virtual UINT8 LoadFile(DATA_LOADER *dataLoader) = 0;
virtual UINT8 UnloadFile(void) = 0;
virtual const char* const* GetTags(void) = 0;
virtual UINT8 GetSongInfo(PLR_SONG_INFO& songInf) = 0;
virtual UINT8 GetSongDeviceInfo(std::vector<PLR_DEV_INFO>& devInfList) const = 0;
static UINT8 InitDeviceOptions(PLR_DEV_OPTS& devOpts);
virtual UINT8 SetDeviceOptions(UINT32 id, const PLR_DEV_OPTS& devOpts) = 0;
virtual UINT8 GetDeviceOptions(UINT32 id, PLR_DEV_OPTS& devOpts) const = 0;
virtual UINT8 SetDeviceMuting(UINT32 id, const PLR_MUTE_OPTS& muteOpts) = 0;
virtual UINT8 GetDeviceMuting(UINT32 id, PLR_MUTE_OPTS& muteOpts) const = 0;
// player-specific options
//virtual UINT8 SetPlayerOptions(const ###_PLAY_OPTIONS& playOpts) = 0;
//virtual UINT8 GetPlayerOptions(###_PLAY_OPTIONS& playOpts) const = 0;
virtual UINT32 GetSampleRate(void) const;
virtual UINT8 SetSampleRate(UINT32 sampleRate);
virtual UINT8 SetPlaybackSpeed(double speed);
virtual void SetEventCallback(PLAYER_EVENT_CB cbFunc, void* cbParam);
virtual void SetFileReqCallback(PLAYER_FILEREQ_CB cbFunc, void* cbParam);
virtual void SetLogCallback(PLAYER_LOG_CB cbFunc, void* cbParam);
virtual UINT32 Tick2Sample(UINT32 ticks) const = 0;
virtual UINT32 Sample2Tick(UINT32 samples) const = 0;
virtual double Tick2Second(UINT32 ticks) const = 0;
virtual double Sample2Second(UINT32 samples) const;
virtual UINT8 GetState(void) const = 0; // get playback state (playing / paused / ...)
virtual UINT32 GetCurPos(UINT8 unit) const = 0; // get current playback position
virtual UINT32 GetCurLoop(void) const = 0; // get current loop index (0 = 1st loop, 1 = 2nd loop, ...)
virtual UINT32 GetTotalTicks(void) const = 0; // get time for playing once in ticks
virtual UINT32 GetLoopTicks(void) const = 0; // get time for one loop in ticks
virtual UINT32 GetTotalPlayTicks(UINT32 numLoops) const; // get time for playing + looping (without fading)
virtual UINT8 Start(void) = 0;
virtual UINT8 Stop(void) = 0;
virtual UINT8 Reset(void) = 0;
virtual UINT8 Seek(UINT8 unit, UINT32 pos) = 0; // seek to playback position
virtual UINT32 Render(UINT32 smplCnt, WAVE_32BS* data) = 0;
protected:
UINT32 _outSmplRate;
PLAYER_EVENT_CB _eventCbFunc;
void* _eventCbParam;
PLAYER_FILEREQ_CB _fileReqCbFunc;
void* _fileReqCbParam;
PLAYER_LOG_CB _logCbFunc;
void* _logCbParam;
};
#endif // __PLAYERBASE_HPP__

View File

@ -0,0 +1,176 @@
#ifndef __S98PLAYER_HPP__
#define __S98PLAYER_HPP__
#include "../stdtype.h"
#include "../emu/EmuStructs.h"
#include "../emu/Resampler.h"
#include "../utils/StrUtils.h"
#include "helper.h"
#include "playerbase.hpp"
#include "../utils/DataLoader.h"
#include "../emu/logging.h"
#include <vector>
#include <map>
#include <string>
#define FCC_S98 0x53393800
struct S98_HEADER
{
UINT8 fileVer;
UINT32 tickMult; // [v1] tick timing numerator
UINT32 tickDiv; // [v2] tick timing denumerator
UINT32 compression; // [v1: 0 - no compression, >0 - size of uncompressed data] [v2: ??] [v3: must be 0]
UINT32 tagOfs; // [v1/2: song title file offset] [v3: tag data file offset]
UINT32 dataOfs; // play data file offset
UINT32 loopOfs; // loop file offset
};
struct S98_DEVICE
{
UINT32 devType;
UINT32 clock;
UINT32 pan; // [v2: reserved] [v3: pan setting]
UINT32 app_spec; // [v2: application-specific] [v3: reserved]
};
class S98Player : public PlayerBase
{
private:
struct DevCfgBuffer
{
std::vector<UINT8> data;
};
struct DEVLOG_CB_DATA
{
S98Player* player;
size_t chipDevID;
};
struct S98_CHIPDEV
{
VGM_BASEDEV base;
size_t optID;
std::vector<UINT8> cfg;
DEVFUNC_WRITE_A8D8 write;
DEVLOG_CB_DATA logCbData;
};
struct DEVLINK_CB_DATA
{
S98Player* player;
S98_CHIPDEV* chipDev;
};
public:
S98Player();
~S98Player();
UINT32 GetPlayerType(void) const;
const char* GetPlayerName(void) const;
static UINT8 PlayerCanLoadFile(DATA_LOADER *dataLoader);
UINT8 CanLoadFile(DATA_LOADER *dataLoader) const;
UINT8 LoadFile(DATA_LOADER *dataLoader);
UINT8 UnloadFile(void);
const S98_HEADER* GetFileHeader(void) const;
const char* const* GetTags(void);
UINT8 GetSongInfo(PLR_SONG_INFO& songInf);
UINT8 GetSongDeviceInfo(std::vector<PLR_DEV_INFO>& devInfList) const;
UINT8 SetDeviceOptions(UINT32 id, const PLR_DEV_OPTS& devOpts);
UINT8 GetDeviceOptions(UINT32 id, PLR_DEV_OPTS& devOpts) const;
UINT8 SetDeviceMuting(UINT32 id, const PLR_MUTE_OPTS& muteOpts);
UINT8 GetDeviceMuting(UINT32 id, PLR_MUTE_OPTS& muteOpts) const;
//UINT32 GetSampleRate(void) const;
UINT8 SetSampleRate(UINT32 sampleRate);
//UINT8 SetPlaybackSpeed(double speed);
//void SetEventCallback(PLAYER_EVENT_CB cbFunc, void* cbParam);
UINT32 Tick2Sample(UINT32 ticks) const;
UINT32 Sample2Tick(UINT32 samples) const;
double Tick2Second(UINT32 ticks) const;
//double Sample2Second(UINT32 samples) const;
UINT8 GetState(void) const;
UINT32 GetCurPos(UINT8 unit) const;
UINT32 GetCurLoop(void) const;
UINT32 GetTotalTicks(void) const; // get time for playing once in ticks
UINT32 GetLoopTicks(void) const; // get time for one loop in ticks
//UINT32 GetTotalPlayTicks(UINT32 numLoops) const; // get time for playing + looping (without fading)
UINT8 Start(void);
UINT8 Stop(void);
UINT8 Reset(void);
UINT8 Seek(UINT8 unit, UINT32 pos);
UINT32 Render(UINT32 smplCnt, WAVE_32BS* data);
private:
UINT8 GetDeviceInstance(size_t id) const;
size_t DeviceID2OptionID(UINT32 id) const;
void RefreshMuting(S98_CHIPDEV& chipDev, const PLR_MUTE_OPTS& muteOpts);
void RefreshPanning(S98_CHIPDEV& chipDev, const PLR_PAN_OPTS& panOpts);
void CalcSongLength(void);
UINT8 LoadTags(void);
std::string GetUTF8String(const char* startPtr, const char* endPtr);
UINT8 ParsePSFTags(const std::string& tagData);
UINT32 ReadVarInt(UINT32& filePos);
void RefreshTSRates(void);
static void PlayerLogCB(void* userParam, void* source, UINT8 level, const char* message);
static void SndEmuLogCB(void* userParam, void* source, UINT8 level, const char* message);
void GenerateDeviceConfig(void);
static void DeviceLinkCallback(void* userParam, VGM_BASEDEV* cDev, DEVLINK_INFO* dLink);
UINT8 SeekToTick(UINT32 tick);
UINT8 SeekToFilePos(UINT32 pos);
void ParseFile(UINT32 ticks);
void HandleEOF(void);
void DoCommand(void);
void DoRegWrite(UINT8 deviceID, UINT8 port, UINT8 reg, UINT8 data);
enum
{
_OPT_DEV_COUNT = 0x0A
};
CPCONV* _cpcSJIS; // ShiftJIS -> UTF-8 codepage conversion
DEV_LOGGER _logger;
DATA_LOADER *_dLoad;
const UINT8* _fileData; // data pointer for quick access, equals _dLoad->GetFileData().data()
S98_HEADER _fileHdr;
std::vector<S98_DEVICE> _devHdrs;
std::vector<DevCfgBuffer> _devCfgs;
UINT32 _totalTicks;
UINT32 _loopTick;
std::map<std::string, std::string> _tagData;
std::vector<const char*> _tagList;
//UINT32 _outSmplRate;
// tick/sample conversion rates
UINT64 _tsMult;
UINT64 _tsDiv;
static const UINT8 _OPT_DEV_LIST[_OPT_DEV_COUNT]; // list of configurable libvgm devices
PLR_DEV_OPTS _devOpts[_OPT_DEV_COUNT * 2]; // space for 2 instances per chip
size_t _devOptMap[0x100][2]; // maps libvgm device ID to _devOpts vector
std::vector<S98_CHIPDEV> _devices;
std::vector<std::string> _devNames;
size_t _optDevMap[_OPT_DEV_COUNT * 2]; // maps _devOpts vector index to _devices vector
UINT32 _filePos;
UINT32 _fileTick;
UINT32 _playTick;
UINT32 _playSmpl;
UINT32 _curLoop;
UINT32 _lastLoopTick;
UINT8 _playState;
UINT8 _psTrigger; // used to temporarily trigger special commands
//PLAYER_EVENT_CB _eventCbFunc;
//void* _eventCbParam;
};
#endif // __S98PLAYER_HPP__

View File

@ -0,0 +1,368 @@
#ifndef __VGMPLAYER_HPP__
#define __VGMPLAYER_HPP__
#include "../stdtype.h"
#include "../emu/EmuStructs.h"
#include "../emu/Resampler.h"
#include "../utils/StrUtils.h"
#include "helper.h"
#include "playerbase.hpp"
#include "../utils/DataLoader.h"
#include "../emu/logging.h"
#include "dblk_compr.h"
#include <vector>
#include <string>
#define FCC_VGM 0x56474D00
// This structure contains only some basic information about the VGM file,
// not the full header.
struct VGM_HEADER
{
UINT32 fileVer;
UINT32 eofOfs;
UINT32 extraHdrOfs;
UINT32 dataOfs; // command data start offset
UINT32 loopOfs; // loop offset
UINT32 dataEnd; // command data end offset
UINT32 gd3Ofs; // GD3 tag offset
UINT32 xhChpClkOfs; // extra header offset: chip clocks
UINT32 xhChpVolOfs; // extra header offset: chip volume
UINT32 numTicks; // total number of samples
UINT32 loopTicks; // number of samples for the looping part
UINT32 recordHz; // rate of the recording in Hz (60 for NTSC, 50 for PAL, 0 disables rate scaling)
INT8 loopBase; // to be subtracted from total number of loops
UINT8 loopModifier; // 4.4 fixed point, loop multiplicator applies to default number of loops
INT16 volumeGain; // 8.8 fixed point, log scale, +0x100 = +6 db
};
struct VGM_PLAY_OPTIONS
{
UINT32 playbackHz; // set to 60 (NTSC) or 50 (PAL) for region-specific song speed adjustment
// Note: requires VGM_HEADER.recordHz to be non-zero to work.
UINT8 hardStopOld; // enforce silence at end of old VGMs (<1.50), fixes Key Off events being trimmed off
};
class VGMPlayer : public PlayerBase
{
public:
struct DEVLOG_CB_DATA
{
VGMPlayer* player;
size_t chipDevID;
};
struct CHIP_DEVICE // Note: has to be a POD, because I use memset() on it.
{
VGM_BASEDEV base;
UINT8 vgmChipType;
UINT8 chipType;
UINT8 chipID;
UINT32 flags;
size_t optID;
DEVFUNC_WRITE_A8D8 write8; // write 8-bit data to 8-bit register/offset
DEVFUNC_WRITE_A16D8 writeM8; // write 8-bit data to 16-bit memory offset
DEVFUNC_WRITE_A8D16 writeD16; // write 16-bit data to 8-bit register/offset
DEVFUNC_WRITE_A16D16 writeM16; // write 16-bit data to 16-bit register/offset
DEVFUNC_WRITE_MEMSIZE romSize;
DEVFUNC_WRITE_BLOCK romWrite;
DEVFUNC_WRITE_MEMSIZE romSizeB;
DEVFUNC_WRITE_BLOCK romWriteB;
DEVLOG_CB_DATA logCbData;
};
struct DACSTRM_DEV
{
DEV_INFO defInf;
UINT8 streamID;
UINT8 bankID;
UINT8 pbMode;
UINT32 freq;
UINT32 lastItem;
UINT32 maxItems;
};
protected:
struct HDR_CHIP_DEF
{
UINT8 devType;
UINT16 volume;
UINT32 clock;
};
struct XHDR_DATA32
{
UINT8 type;
UINT32 data;
};
struct XHDR_DATA16
{
UINT8 type;
UINT8 flags;
UINT16 data;
};
struct SONG_DEV_CFG
{
size_t deviceID; // index for _devices array
UINT8 vgmChipType;
UINT8 type;
UINT8 instance;
std::vector<UINT8> cfgData;
};
struct PCM_BANK
{
std::vector<UINT8> data;
std::vector<UINT32> bankOfs;
std::vector<UINT32> bankSize;
};
typedef void (VGMPlayer::*COMMAND_FUNC)(void); // VGM command member function callback
struct DEVLINK_CB_DATA
{
VGMPlayer* player;
SONG_DEV_CFG* sdCfg;
CHIP_DEVICE* chipDev;
};
struct COMMAND_INFO
{
UINT8 chipType;
UINT32 cmdLen;
COMMAND_FUNC func;
};
struct QSOUND_WORK
{
void (*write)(CHIP_DEVICE*, UINT8, UINT16); // pointer to WriteQSound_A/B
UINT16 startAddrCache[16]; // QSound register 0x01
UINT16 pitchCache[16]; // QSound register 0x02
};
public:
VGMPlayer();
~VGMPlayer();
UINT32 GetPlayerType(void) const;
const char* GetPlayerName(void) const;
static UINT8 PlayerCanLoadFile(DATA_LOADER *dataLoader);
UINT8 CanLoadFile(DATA_LOADER *dataLoader) const;
UINT8 LoadFile(DATA_LOADER *dataLoader);
UINT8 UnloadFile(void);
const VGM_HEADER* GetFileHeader(void) const;
const char* const* GetTags(void);
UINT8 GetSongInfo(PLR_SONG_INFO& songInf);
UINT8 GetSongDeviceInfo(std::vector<PLR_DEV_INFO>& devInfList) const;
UINT8 SetDeviceOptions(UINT32 id, const PLR_DEV_OPTS& devOpts);
UINT8 GetDeviceOptions(UINT32 id, PLR_DEV_OPTS& devOpts) const;
UINT8 SetDeviceMuting(UINT32 id, const PLR_MUTE_OPTS& muteOpts);
UINT8 GetDeviceMuting(UINT32 id, PLR_MUTE_OPTS& muteOpts) const;
// player-specific options
UINT8 SetPlayerOptions(const VGM_PLAY_OPTIONS& playOpts);
UINT8 GetPlayerOptions(VGM_PLAY_OPTIONS& playOpts) const;
//UINT32 GetSampleRate(void) const;
UINT8 SetSampleRate(UINT32 sampleRate);
//UINT8 SetPlaybackSpeed(double speed);
//void SetEventCallback(PLAYER_EVENT_CB cbFunc, void* cbParam);
//void SetFileReqCallback(PLAYER_FILEREQ_CB cbFunc, void* cbParam);
UINT32 Tick2Sample(UINT32 ticks) const;
UINT32 Sample2Tick(UINT32 samples) const;
double Tick2Second(UINT32 ticks) const;
//double Sample2Second(UINT32 samples) const;
UINT8 GetState(void) const;
UINT32 GetCurPos(UINT8 unit) const;
UINT32 GetCurLoop(void) const;
UINT32 GetTotalTicks(void) const; // get time for playing once in ticks
UINT32 GetLoopTicks(void) const; // get time for one loop in ticks
//UINT32 GetTotalPlayTicks(UINT32 numLoops) const; // get time for playing + looping (without fading)
UINT32 GetModifiedLoopCount(UINT32 defaultLoops) const; // get loop count, modified according to LoopModified/LoopBase header
const std::vector<DACSTRM_DEV>& GetStreamDevInfo(void) const;
UINT8 Start(void);
UINT8 Stop(void);
UINT8 Reset(void);
UINT8 Seek(UINT8 unit, UINT32 pos);
UINT32 Render(UINT32 smplCnt, WAVE_32BS* data);
protected:
UINT8 ParseHeader(void);
void ParseXHdr_Data32(UINT32 fileOfs, std::vector<XHDR_DATA32>& xData);
void ParseXHdr_Data16(UINT32 fileOfs, std::vector<XHDR_DATA16>& xData);
UINT8 LoadTags(void);
std::string GetUTF8String(const UINT8* startPtr, const UINT8* endPtr);
size_t DeviceID2OptionID(UINT32 id) const;
void RefreshDevOptions(CHIP_DEVICE& chipDev, const PLR_DEV_OPTS& devOpts);
void RefreshMuting(CHIP_DEVICE& chipDev, const PLR_MUTE_OPTS& muteOpts);
void RefreshPanning(CHIP_DEVICE& chipDev, const PLR_PAN_OPTS& panOpts);
void RefreshTSRates(void);
static void PlayerLogCB(void* userParam, void* source, UINT8 level, const char* message);
static void SndEmuLogCB(void* userParam, void* source, UINT8 level, const char* message);
UINT32 GetHeaderChipClock(UINT8 chipType) const; // returns raw chip clock value from VGM header
inline UINT32 GetChipCount(UINT8 chipType) const;
UINT32 GetChipClock(UINT8 chipType, UINT8 chipID) const;
UINT16 GetChipVolume(UINT8 chipType, UINT8 chipID, UINT8 isLinked) const;
UINT16 EstimateOverallVolume(void) const;
void NormalizeOverallVolume(UINT16 overallVol);
void GenerateDeviceConfig(void);
void InitDevices(void);
static void DeviceLinkCallback(void* userParam, VGM_BASEDEV* cDev, DEVLINK_INFO* dLink);
CHIP_DEVICE* GetDevicePtr(UINT8 chipType, UINT8 chipID);
void LoadOPL4ROM(CHIP_DEVICE* chipDev);
UINT8 SeekToTick(UINT32 tick);
UINT8 SeekToFilePos(UINT32 pos);
void ParseFile(UINT32 ticks);
// --- VGM command functions ---
void Cmd_invalid(void);
void Cmd_unknown(void);
void Cmd_EndOfData(void); // command 66
void Cmd_DelaySamples2B(void); // command 61 - wait for N samples (2-byte parameter)
void Cmd_Delay60Hz(void); // command 62 - wait 735 samples (1/60 second)
void Cmd_Delay50Hz(void); // command 63 - wait 882 samples (1/50 second)
void Cmd_DelaySamplesN1(void); // command 70..7F - wait (N+1) samples
void DoRAMOfsPatches(UINT8 chipType, UINT8 chipID, UINT32& dataOfs, UINT32& dataLen);
void Cmd_DataBlock(void); // command 67
void Cmd_PcmRamWrite(void); // command 68
void Cmd_YM2612PCM_Delay(void); // command 80..8F - write YM2612 PCM from data block + delay by N samples
void Cmd_YM2612PCM_Seek(void); // command E0 - set YM2612 PCM data offset
void Cmd_DACCtrl_Setup(void); // command 90
void Cmd_DACCtrl_SetData(void); // command 91
void Cmd_DACCtrl_SetFrequency(void); // command 92
void Cmd_DACCtrl_PlayData_Loc(void); // command 93
void Cmd_DACCtrl_Stop(void); // command 94
void Cmd_DACCtrl_PlayData_Blk(void); // command 95
void Cmd_GGStereo(void); // command 4F - set GameGear Stereo mask
void Cmd_SN76489(void); // command 50 - SN76489 register write
void Cmd_Reg8_Data8(void); // command 51/54/55/5A..5D - Register, Data (8-bit)
void Cmd_CPort_Reg8_Data8(void); // command 52/53/56..59/5E/5F - Port (in command byte), Register, Data (8-bit)
void Cmd_Port_Reg8_Data8(void); // command D0..D2 - Port, Register, Data (8-bit)
void Cmd_Ofs8_Data8(void); // command B3/B5..BB/BE/BF - Offset (8-bit), Data (8-bit)
void Cmd_Ofs16_Data8(void); // command C5..C8/D3/D4/D6/E5 - Offset (16-bit), Data (8-bit)
void Cmd_Ofs8_Data16(void); // unused - Offset (8-bit), Data (16-bit)
void Cmd_Ofs16_Data16(void); // command E1 - Offset (16-bit), Data (16-bit)
void Cmd_Port_Ofs8_Data8(void); // command D5 - Port, Offset (8-bit), Data (8-bit)
void Cmd_DReg8_Data8(void); // command A0 - Register (with dual-chip bit), Data (8-bit)
void Cmd_SegaPCM_Mem(void); // command C0 - SegaPCM memory write
void Cmd_RF5C_Mem(void); // command C1/C2 - RF5C68/164 memory write
void Cmd_RF5C_Reg(void); // command B0/B1 - RF5C68/164 register write
void Cmd_PWM_Reg(void); // command B2 - PWM register write (4-bit offset, 12-bit data)
void Cmd_QSound_Reg(void); // command C4 - QSound register write (16-bit data, 8-bit offset)
static void WriteQSound_A(CHIP_DEVICE* cDev, UINT8 ofs, UINT16 data); // write by calling write8
static void WriteQSound_B(CHIP_DEVICE* cDev, UINT8 ofs, UINT16 data); // write by calling writeD16
void Cmd_WSwan_Reg(void); // command BC - WonderSwan register write (Reg8_Data8 with remapping)
void Cmd_NES_Reg(void); // command B4 - NES APU register write (Reg8_Data8 with remapping)
void Cmd_YMW_Bank(void); // command C3 - YMW258 bank write (Ofs8_Data16 with remapping)
void Cmd_SAA_Reg(void); // command BD - SAA1099 register write (Reg8_Data8 with remapping)
void Cmd_OKIM6295_Reg(void); // command B8 - OKIM6295 register write (Ofs8_Data8 with minor fixes)
void Cmd_AY_Stereo(void); // command 30 - set AY8910 stereo mask
CPCONV* _cpcUTF16; // UTF-16 LE -> UTF-8 codepage conversion
DEV_LOGGER _logger;
DATA_LOADER *_dLoad;
const UINT8* _fileData; // data pointer for quick access, equals _dLoad->GetFileData().data()
std::vector<UINT8> _yrwRom; // cache for OPL4 sample ROM (yrw801.rom)
enum
{
_HDR_BUF_SIZE = 0x100,
_OPT_DEV_COUNT = 0x29,
_CHIP_COUNT = 0x29,
_PCM_BANK_COUNT = 0x40
};
VGM_HEADER _fileHdr;
std::vector<XHDR_DATA32> _xHdrChipClk;
std::vector<XHDR_DATA16> _xHdrChipVol;
UINT8 _hdrBuffer[_HDR_BUF_SIZE]; // buffer containing the file header
UINT32 _hdrLenFile;
UINT32 _tagVer;
enum
{
_TAG_TRACK_NAME_EN,
_TAG_TRACK_NAME_JP,
_TAG_GAME_NAME_EN,
_TAG_GAME_NAME_JP,
_TAG_SYSTEM_NAME_EN,
_TAG_SYSTEM_NAME_JP,
_TAG_ARTIST_EN,
_TAG_ARTIST_JP,
_TAG_GAME_RELEASE_DATE,
_TAG_VGM_CREATOR,
_TAG_NOTES,
_TAG_COUNT,
};
static const char* const _TAG_TYPE_LIST[_TAG_COUNT];
std::string _tagData[_TAG_COUNT];
const char* _tagList[2 * _TAG_COUNT + 1];
//UINT32 _outSmplRate;
// tick/sample conversion rates
UINT64 _tsMult;
UINT64 _tsDiv;
UINT64 _ttMult;
UINT64 _ttDiv;
UINT32 _filePos;
UINT32 _fileTick;
UINT32 _playTick;
UINT32 _playSmpl;
UINT32 _curLoop;
UINT32 _lastLoopTick;
UINT8 _playState;
UINT8 _psTrigger; // used to temporarily trigger special commands
//PLAYER_EVENT_CB _eventCbFunc;
//void* _eventCbParam;
//PLAYER_FILEREQ_CB _fileReqCbFunc;
//void* _fileReqCbParam;
static const UINT8 _OPT_DEV_LIST[_OPT_DEV_COUNT]; // list of configurable libvgm devices (different from VGM chip list]
static const UINT8 _DEV_LIST[_CHIP_COUNT]; // VGM chip ID -> libvgm device ID
static const UINT32 _CHIPCLK_OFS[_CHIP_COUNT]; // file offsets for chip clocks in VGM header
static const UINT16 _CHIP_VOLUME[_CHIP_COUNT]; // default volume for chips
static const UINT16 _PB_VOL_AMNT[_CHIP_COUNT]; // amount of the chip's playback volume in overall gain
static const COMMAND_INFO _CMD_INFO[0x100]; // VGM commands
static const UINT8 _VGM_BANK_CHIPS[_PCM_BANK_COUNT]; // PCM database ID -> VGM chip
static const UINT8 _VGM_ROM_CHIPS[0x40][2]; // ROM write datablock ID -> VGM chip / memory type
static const UINT8 _VGM_RAM_CHIPS[0x40]; // RAM write datablock ID -> VGM chip
VGM_PLAY_OPTIONS _playOpts;
PLR_DEV_OPTS _devOpts[_OPT_DEV_COUNT * 2]; // space for 2 instances per chip
size_t _devOptMap[0x100][2]; // maps libvgm device ID to _devOpts vector
std::vector<SONG_DEV_CFG> _devCfgs;
size_t _vdDevMap[_CHIP_COUNT][2]; // maps VGM device ID to _devices vector
size_t _optDevMap[_OPT_DEV_COUNT * 2]; // maps _devOpts vector index to _devices vector
std::vector<CHIP_DEVICE> _devices;
std::vector<std::string> _devNames;
size_t _dacStrmMap[0x100]; // maps VGM DAC stream ID -> _dacStreams vector
std::vector<DACSTRM_DEV> _dacStreams;
PCM_BANK _pcmBank[_PCM_BANK_COUNT];
PCM_COMPR_TBL _pcmComprTbl;
UINT8 _p2612Fix; // enable hack/fix for Project2612 VGMs
UINT32 _ym2612pcm_bnkPos;
UINT8 _rf5cBank[2][2]; // [0 RF5C68 / 1 RF5C164][chipID]
QSOUND_WORK _qsWork[2];
};
#endif // __VGMPLAYER_HPP__

View File

@ -0,0 +1,45 @@
#ifndef __CST_STDTYPE_H__
#define __CST_STDTYPE_H__
#ifdef HAVE_STDINT_H
#include <stdint.h>
typedef uint8_t UINT8;
typedef int8_t INT8;
typedef uint16_t UINT16;
typedef int16_t INT16;
typedef uint32_t UINT32;
typedef int32_t INT32;
typedef uint64_t UINT64;
typedef int64_t INT64;
#else // ! HAVE_STDINT_H
// typedefs to use MAME's (U)INTxx types (copied from MAME\src\ods\odscomm.h)
// 8-bit values
typedef unsigned char UINT8;
typedef signed char INT8;
// 16-bit values
typedef unsigned short UINT16;
typedef signed short INT16;
// 32-bit values
#ifndef _WINDOWS_H
typedef unsigned int UINT32;
typedef signed int INT32;
// 64-bit values
#ifdef _MSC_VER
typedef unsigned __int64 UINT64;
typedef signed __int64 INT64;
#else
__extension__ typedef unsigned long long UINT64;
__extension__ typedef signed long long INT64;
#endif
#endif // _WINDOWS_H
#endif // HAVE_STDINT
#endif // __CST_STDTYPE_H__

View File

@ -0,0 +1,98 @@
#ifndef __DATALOADER_H__
#define __DATALOADER_H__
#ifdef __cplusplus
extern "C" {
#endif
#include "../stdtype.h"
typedef UINT8 (*DLOADCB_GENERIC)(void *context);
typedef void (*DLOADCB_GEN_CALL)(void *context);
typedef UINT32 (*DLOADCB_READ)(void *context, UINT8 *buffer, UINT32 numBytes);
typedef UINT8 (*DLOADCB_SEEK)(void *context, UINT32 offset, UINT8 whence);
typedef INT32 (*DLOADCB_TELL)(void *context);
typedef UINT32 (*DLOADCB_LENGTH)(void *context);
typedef struct _data_loader_callbacks
{
UINT32 type; /* 4-character-code for the file loader */
const char *name; /* human-readable name of the file loader */
DLOADCB_GENERIC dopen; /* open a file, URL, piece of memory, return 0 on success */
DLOADCB_READ dread; /* read bytes into buffer */
DLOADCB_SEEK dseek; /* seek to byte offset */
DLOADCB_GENERIC dclose; /* closes out file, return 0 on success */
DLOADCB_TELL dtell; /* returns the current position of the data */
DLOADCB_LENGTH dlength; /* returns the length of the data, in bytes */
DLOADCB_GENERIC deof; /* determines if we've seen eof or not (return 1 for eof) */
DLOADCB_GEN_CALL ddeinit; /* deinitialize loader and free context, may be NULL */
} DATA_LOADER_CALLBACKS;
enum
{
DLSTAT_EMPTY = 0,
DLSTAT_LOADING = 1,
DLSTAT_LOADED = 2
};
typedef struct _data_loader
{
UINT8 _status;
UINT32 _bytesTotal;
UINT32 _bytesLoaded;
UINT32 _readStopOfs;
UINT8 *_data;
const DATA_LOADER_CALLBACKS *_callbacks;
void *_context;
} DATA_LOADER;
/* calls the dopen and dlength functions
* by default, loads whole file into memory, use
* DataLoader_SetPreloadBytes to change this */
UINT8 DataLoader_Load(DATA_LOADER *loader);
/* Resets the DataLoader (calls DataReader_CancelLoading, unloads data, etc */
UINT8 DataLoader_Reset(DATA_LOADER *loader);
/* Returns a pointer to the DataLoader's memory buffer
* call after any invocation of "Read", "ReadUntil", etc,
* since the memory buffer pointer can change */
UINT8 *DataLoader_GetData(DATA_LOADER *loader);
/* returns _bytesTotal */
UINT32 DataLoader_GetTotalSize(const DATA_LOADER *loader);
/* returns _bytesLoaded */
UINT32 DataLoader_GetSize(const DATA_LOADER *loader);
/* returns _status */
UINT8 DataLoader_GetStatus(const DATA_LOADER *loader);
/* calls dread, then deof
* if deof > 0, also calls CancelLoading (dclose) */
UINT32 DataLoader_Read(DATA_LOADER *loader, UINT32 numBytes);
/* calls dclose */
UINT8 DataLoader_CancelLoading(DATA_LOADER *loader);
/* sets number of bytes to preload */
void DataLoader_SetPreloadBytes(DATA_LOADER *loader, UINT32 byteCount);
/* reads until offset */
void DataLoader_ReadUntil(DATA_LOADER *loader, UINT32 fileOffset);
/* read all data */
void DataLoader_ReadAll(DATA_LOADER *loader);
/* convenience function for MemoryLoader,FileLoader, etc */
void DataLoader_Setup(DATA_LOADER *loader, const DATA_LOADER_CALLBACKS *callbacks, void *context);
/* tear-down function */
void DataLoader_Deinit(DATA_LOADER *loader);
#ifdef __cplusplus
}
#endif
#endif /* __DATALOADER_H__ */

View File

@ -0,0 +1,39 @@
#ifndef __FILELOADER_H__
#define __FILELOADER_H__
#ifdef __cplusplus
extern "C" {
#endif
#ifdef _WIN32
#define HAVE_FILELOADER_W 1
#endif
#include "DataLoader.h"
DATA_LOADER *FileLoader_Init(const char *fileName);
#ifdef HAVE_FILELOADER_W
#include <wchar.h>
DATA_LOADER *FileLoader_InitW(const wchar_t *fileName);
#endif
#define FileLoader_Load DataLoader_Load
#define FileLoader_Reset DataLoader_Reset
#define FileLoader_GetData DataLoader_GetData
#define FileLoader_GetTotalSize DataLoader_GetTotalSize
#define FileLoader_GetSize DataLoader_GetSize
#define FileLoader_GetStatus DataLoader_GetStatus
#define FileLoader_Read DataLoader_Read
#define FileLoader_CancelLoading DataLoader_CancelLoading
#define FileLoader_SetPreloadBytes DataLoader_SetPreloadBytes
#define FileLoader_ReadUntil DataLoader_ReadUntil
#define FileLoader_ReadAll DataLoader_ReadAll
#define FileLoader_Deinit DataLoader_Deinit
extern const DATA_LOADER_CALLBACKS fileLoader;
#ifdef __cplusplus
}
#endif
#endif // __FILELOADER_H__

View File

@ -0,0 +1,31 @@
#ifndef __MEMORYLOADER_H__
#define __MEMORYLOADER_H__
#ifdef __cplusplus
extern "C" {
#endif
#include "../stdtype.h"
#include "DataLoader.h"
DATA_LOADER *MemoryLoader_Init(const UINT8 *buffer, UINT32 length);
#define MemoryLoader_Load DataLoader_Load
#define MemoryLoader_Reset DataLoader_Reset
#define MemoryLoader_GetData DataLoader_GetData
#define MemoryLoader_GetTotalSize DataLoader_GetTotalSize
#define MemoryLoader_GetSize DataLoader_GetSize
#define MemoryLoader_GetStatus DataLoader_GetStatus
#define MemoryLoader_Read DataLoader_Read
#define MemoryLoader_CancelLoading DataLoader_CancelLoading
#define MemoryLoader_SetPreloadBytes DataLoader_SetPreloadBytes
#define MemoryLoader_ReadUntil DataLoader_ReadUntil
#define MemoryLoader_ReadAll DataLoader_ReadAll
#define MemoryLoader_Deinit DataLoader_Deinit
extern const DATA_LOADER_CALLBACKS memoryLoader;
#ifdef __cplusplus
}
#endif
#endif // __MEMORYLOADER_H__

View File

@ -0,0 +1,23 @@
#ifndef __OSMUTEX_H__
#define __OSMUTEX_H__
#ifdef __cplusplus
extern "C"
{
#endif
#include "../stdtype.h"
typedef struct _os_mutex OS_MUTEX;
UINT8 OSMutex_Init(OS_MUTEX** retMutex, UINT8 initLocked);
void OSMutex_Deinit(OS_MUTEX* mtx);
UINT8 OSMutex_Lock(OS_MUTEX* mtx);
UINT8 OSMutex_TryLock(OS_MUTEX* mtx);
UINT8 OSMutex_Unlock(OS_MUTEX* mtx);
#ifdef __cplusplus
}
#endif
#endif // __OSMUTEX_H__

View File

@ -0,0 +1,23 @@
#ifndef __OSSIGNAL_H__
#define __OSSIGNAL_H__
#ifdef __cplusplus
extern "C"
{
#endif
#include "../stdtype.h"
typedef struct _os_signal OS_SIGNAL;
UINT8 OSSignal_Init(OS_SIGNAL** retSignal, UINT8 initState);
void OSSignal_Deinit(OS_SIGNAL* sig);
UINT8 OSSignal_Signal(OS_SIGNAL* sig);
UINT8 OSSignal_Reset(OS_SIGNAL* sig);
UINT8 OSSignal_Wait(OS_SIGNAL* sig);
#ifdef __cplusplus
}
#endif
#endif // __OSSIGNAL_H__

View File

@ -0,0 +1,25 @@
#ifndef __OSTHREAD_H__
#define __OSTHREAD_H__
#ifdef __cplusplus
extern "C"
{
#endif
#include "../stdtype.h"
typedef struct _os_thread OS_THREAD;
typedef void (*OS_THR_FUNC)(void* args);
UINT8 OSThread_Init(OS_THREAD** retThread, OS_THR_FUNC threadFunc, void* args);
void OSThread_Deinit(OS_THREAD* thr);
void OSThread_Join(OS_THREAD* thr);
void OSThread_Cancel(OS_THREAD* thr);
UINT64 OSThread_GetID(const OS_THREAD* thr);
void* OSThread_GetHandle(OS_THREAD* thr); // return a reference to the actual handle
#ifdef __cplusplus
}
#endif
#endif // __OSTHREAD_H__

View File

@ -0,0 +1,32 @@
#ifndef __STRUTILS_H__
#define __STRUTILS_H__
#ifdef __cplusplus
extern "C"
{
#endif
#include "../stdtype.h"
#include <stddef.h> // for size_t
typedef struct _codepage_conversion CPCONV;
UINT8 CPConv_Init(CPCONV** retCPC, const char* cpFrom, const char* cpTo);
void CPConv_Deinit(CPCONV* cpc);
// parameters:
// cpc: codepage conversion object
// outSize: [input] size of output buffer, [output] size of converted string
// outStr: [input/output] pointer to output buffer
// *outStr == NULL: The routine will allocate a buffer large enough to hold all the data.
// *outStr != NULL: place results into the existing buffer (no reallocation when buffer is too small)
// inSize: [input] length of input string
// inSize == 0: automatically determine the string's length, includes the terminating \0 character.
// inStr: [input] input string
// Note: For nonzero return codes, the \0-terminator will be missing!
UINT8 CPConv_StrConvert(CPCONV* cpc, size_t* outSize, char** outStr, size_t inSize, const char* inStr);
#ifdef __cplusplus
}
#endif
#endif // __STRUTILS_H__

BIN
ThirdParty/libvgm/lib/libvgm-emu.a vendored Normal file

Binary file not shown.

BIN
ThirdParty/libvgm/lib/libvgm-player.a vendored Normal file

Binary file not shown.

BIN
ThirdParty/libvgm/lib/libvgm-utils.a vendored Normal file

Binary file not shown.