Implemented new libvgm-based VGM, S98, DRO, and GYM player
parent
8ad7e086a8
commit
888ee2fb38
|
@ -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.
|
@ -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.
|
@ -0,0 +1,3 @@
|
|||
/* Localized versions of Info.plist keys */
|
||||
|
||||
NSHumanReadableCopyright = "© __MyCompanyName__, 2007";
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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 */;
|
||||
}
|
|
@ -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>
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
File diff suppressed because it is too large
Load Diff
|
@ -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"
|
||||
```
|
|
@ -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__
|
|
@ -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__
|
|
@ -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__
|
|
@ -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__
|
|
@ -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__
|
|
@ -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__
|
|
@ -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__
|
|
@ -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__
|
|
@ -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__
|
|
@ -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__
|
|
@ -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__
|
|
@ -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__
|
|
@ -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__
|
|
@ -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__
|
|
@ -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__
|
|
@ -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__
|
|
@ -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__
|
|
@ -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__
|
|
@ -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__
|
|
@ -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__
|
|
@ -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__
|
|
@ -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__ */
|
|
@ -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__
|
|
@ -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__
|
|
@ -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__
|
|
@ -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__
|
|
@ -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__
|
|
@ -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__
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue