Audiostuff (#236)
* Add option to enable/disable audio channels Audio options are backports from FCEUX. Options are set as on/off toggle for each apu channel. Compile with DEBUG=1 to see options. * Add missing audio state vars, fix for hq audio when using runahead * Additional checks for save ram (battery) * Cleanup * Update libretro header
This commit is contained in:
committed by
hizzlekizzle
parent
e3362d3772
commit
829a7552f1
@@ -27,6 +27,8 @@ static int32 IRQCount;
|
||||
static uint8 *WRAM = NULL;
|
||||
static uint32 WRAMSIZE;
|
||||
|
||||
static void(*sfun[3]) (void);
|
||||
|
||||
static SFORMAT StateRegs[] =
|
||||
{
|
||||
{ &cmdreg, 1, "CMDR" },
|
||||
@@ -41,7 +43,7 @@ static SFORMAT StateRegs[] =
|
||||
static void Sync(void) {
|
||||
uint8 i;
|
||||
if ((preg[3] & 0xC0) == 0xC0)
|
||||
setprg8r(0x10, 0x6000, 0);
|
||||
setprg8r(0x10, 0x6000, preg[3] & 0x3F);
|
||||
else
|
||||
setprg8(0x6000, preg[3] & 0x3F);
|
||||
setprg8(0x8000, preg[0]);
|
||||
@@ -89,16 +91,13 @@ static DECLFW(M69Write1) {
|
||||
case 0xA: preg[1] = V; Sync(); break;
|
||||
case 0xB: preg[2] = V; Sync(); break;
|
||||
case 0xC: mirr = V & 3; Sync();break;
|
||||
/* 17/10/17- reg $0D should awknowledge IRQ and no other
|
||||
* http://forums.nesdev.com/viewtopic.php?f=2&t=12436&start=15
|
||||
*/
|
||||
case 0xD: IRQa = V; X6502_IRQEnd(FCEU_IQEXT); break;
|
||||
case 0xE: IRQCount &= 0xFF00; IRQCount |= V; break;
|
||||
case 0xF: IRQCount &= 0x00FF; IRQCount |= V << 8; break;
|
||||
}
|
||||
}
|
||||
|
||||
/* SUNSOFT-5/FME-7 Sound */
|
||||
// SUNSOFT-5/FME-7 Sound
|
||||
|
||||
static void AYSound(int Count);
|
||||
static void AYSoundHQ(void);
|
||||
@@ -114,6 +113,15 @@ static SFORMAT SStateRegs[] =
|
||||
{
|
||||
{ &sndcmd, 1, "SCMD" },
|
||||
{ sreg, 14, "SREG" },
|
||||
{ &dcount[0], 4 | FCEUSTATE_RLSB, "DCT0" },
|
||||
{ &dcount[1], 4 | FCEUSTATE_RLSB, "DCT1" },
|
||||
{ &dcount[2], 4 | FCEUSTATE_RLSB, "DCT2" },
|
||||
{ &vcount[0], 4 | FCEUSTATE_RLSB, "VCT0" },
|
||||
{ &vcount[1], 4 | FCEUSTATE_RLSB, "VCT1" },
|
||||
{ &vcount[2], 4 | FCEUSTATE_RLSB, "VCT2" },
|
||||
{ &CAYBC[0], 4 | FCEUSTATE_RLSB, "BC00" },
|
||||
{ &CAYBC[1], 4 | FCEUSTATE_RLSB, "BC01" },
|
||||
{ &CAYBC[2], 4 | FCEUSTATE_RLSB, "BC02" },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
@@ -125,22 +133,21 @@ static DECLFW(M69SWrite1) {
|
||||
int x;
|
||||
GameExpSound.Fill = AYSound;
|
||||
GameExpSound.HiFill = AYSoundHQ;
|
||||
if (FSettings.SndRate)
|
||||
switch (sndcmd) {
|
||||
case 0:
|
||||
case 1:
|
||||
case 8: if (FSettings.soundq >= 1) DoAYSQHQ(0); else DoAYSQ(0); break;
|
||||
case 2:
|
||||
case 3:
|
||||
case 9: if (FSettings.soundq >= 1) DoAYSQHQ(1); else DoAYSQ(1); break;
|
||||
case 4:
|
||||
case 5:
|
||||
case 10: if (FSettings.soundq >= 1) DoAYSQHQ(2); else DoAYSQ(2); break;
|
||||
case 7:
|
||||
for (x = 0; x < 2; x++)
|
||||
if (FSettings.soundq >= 1) DoAYSQHQ(x); else DoAYSQ(x);
|
||||
break;
|
||||
}
|
||||
switch (sndcmd) {
|
||||
case 0:
|
||||
case 1:
|
||||
case 8: if (sfun[0]) sfun[0](); break;
|
||||
case 2:
|
||||
case 3:
|
||||
case 9: if (sfun[1]) sfun[1](); break;
|
||||
case 4:
|
||||
case 5:
|
||||
case 10: if (sfun[2]) sfun[2](); break;
|
||||
case 7:
|
||||
if (sfun[0]) sfun[0]();
|
||||
if (sfun[1]) sfun[1]();
|
||||
break;
|
||||
}
|
||||
sreg[sndcmd] = V;
|
||||
}
|
||||
|
||||
@@ -190,19 +197,43 @@ static void DoAYSQHQ(int x) {
|
||||
CAYBC[x] = SOUNDTS;
|
||||
}
|
||||
|
||||
static void DoAYSQ1(void) {
|
||||
DoAYSQ(0);
|
||||
}
|
||||
|
||||
static void DoAYSQ2(void) {
|
||||
DoAYSQ(1);
|
||||
}
|
||||
|
||||
static void DoAYSQ3(void) {
|
||||
DoAYSQ(2);
|
||||
}
|
||||
|
||||
static void DoAYSQ1HQ(void) {
|
||||
DoAYSQHQ(0);
|
||||
}
|
||||
|
||||
static void DoAYSQ2HQ(void) {
|
||||
DoAYSQHQ(1);
|
||||
}
|
||||
|
||||
static void DoAYSQ3HQ(void) {
|
||||
DoAYSQHQ(2);
|
||||
}
|
||||
|
||||
static void AYSound(int Count) {
|
||||
int x;
|
||||
DoAYSQ(0);
|
||||
DoAYSQ(1);
|
||||
DoAYSQ(2);
|
||||
DoAYSQ1();
|
||||
DoAYSQ2();
|
||||
DoAYSQ3();
|
||||
for (x = 0; x < 3; x++)
|
||||
CAYBC[x] = Count;
|
||||
}
|
||||
|
||||
static void AYSoundHQ(void) {
|
||||
DoAYSQHQ(0);
|
||||
DoAYSQHQ(1);
|
||||
DoAYSQHQ(2);
|
||||
DoAYSQ1HQ();
|
||||
DoAYSQ2HQ();
|
||||
DoAYSQ3HQ();
|
||||
}
|
||||
|
||||
static void AYHiSync(int32 ts) {
|
||||
@@ -218,6 +249,18 @@ void Mapper69_ESI(void) {
|
||||
memset(dcount, 0, sizeof(dcount));
|
||||
memset(vcount, 0, sizeof(vcount));
|
||||
memset(CAYBC, 0, sizeof(CAYBC));
|
||||
if (FSettings.SndRate) {
|
||||
if (FSettings.soundq >= 1) {
|
||||
sfun[0] = DoAYSQ1HQ;
|
||||
sfun[1] = DoAYSQ2HQ;
|
||||
sfun[2] = DoAYSQ3HQ;
|
||||
} else {
|
||||
sfun[0] = DoAYSQ1;
|
||||
sfun[1] = DoAYSQ2;
|
||||
sfun[2] = DoAYSQ3;
|
||||
}
|
||||
} else
|
||||
memset(sfun, 0, sizeof(sfun));
|
||||
}
|
||||
|
||||
/* SUNSOFT-5/FME-7 Sound */
|
||||
@@ -270,8 +313,8 @@ void Mapper69_Init(CartInfo *info) {
|
||||
}
|
||||
GameStateRestore = StateRestore;
|
||||
Mapper69_ESI();
|
||||
AddExState(&SStateRegs, ~0, 0, 0);
|
||||
AddExState(&StateRegs, ~0, 0, 0);
|
||||
AddExState(&SStateRegs, ~0, 0, 0);
|
||||
}
|
||||
|
||||
void NSFAY_Init(void) {
|
||||
|
||||
@@ -224,6 +224,28 @@ static int32 CVBC;
|
||||
|
||||
#define TOINDEX (16 + 1)
|
||||
|
||||
static SFORMAT N106_SStateRegs[] =
|
||||
{
|
||||
{ &PlayIndex[0], 4 | FCEUSTATE_RLSB, "IDX0" },
|
||||
{ &PlayIndex[1], 4 | FCEUSTATE_RLSB, "IDX1" },
|
||||
{ &PlayIndex[2], 4 | FCEUSTATE_RLSB, "IDX2" },
|
||||
{ &PlayIndex[3], 4 | FCEUSTATE_RLSB, "IDX3" },
|
||||
{ &PlayIndex[4], 4 | FCEUSTATE_RLSB, "IDX4" },
|
||||
{ &PlayIndex[5], 4 | FCEUSTATE_RLSB, "IDX5" },
|
||||
{ &PlayIndex[6], 4 | FCEUSTATE_RLSB, "IDX6" },
|
||||
{ &PlayIndex[7], 4 | FCEUSTATE_RLSB, "IDX7" },
|
||||
{ &vcount[0], 4 | FCEUSTATE_RLSB, "VCT0" },
|
||||
{ &vcount[1], 4 | FCEUSTATE_RLSB, "VCT1" },
|
||||
{ &vcount[2], 4 | FCEUSTATE_RLSB, "VCT2" },
|
||||
{ &vcount[3], 4 | FCEUSTATE_RLSB, "VCT3" },
|
||||
{ &vcount[4], 4 | FCEUSTATE_RLSB, "VCT4" },
|
||||
{ &vcount[5], 4 | FCEUSTATE_RLSB, "VCT5" },
|
||||
{ &vcount[6], 4 | FCEUSTATE_RLSB, "VCT6" },
|
||||
{ &vcount[7], 4 | FCEUSTATE_RLSB, "VCT7" },
|
||||
{ &CVBC, 4 | FCEUSTATE_RLSB, "BC00" },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
/* 16:15 */
|
||||
static void SyncHQ(int32 ts) {
|
||||
CVBC = ts;
|
||||
@@ -404,6 +426,7 @@ void Mapper19_Init(CartInfo *info) {
|
||||
AddExState(WRAM, 8192, 0, "WRAM");
|
||||
AddExState(IRAM, 128, 0, "IRAM");
|
||||
AddExState(N106_StateRegs, ~0, 0, 0);
|
||||
AddExState(N106_SStateRegs, ~0, 0, 0);
|
||||
|
||||
if (info->battery) {
|
||||
info->SaveGame[0] = WRAM;
|
||||
|
||||
@@ -44,16 +44,32 @@ static SFORMAT StateRegs[] =
|
||||
};
|
||||
|
||||
static void(*sfun[3]) (void);
|
||||
|
||||
static uint8 vpsg1[8];
|
||||
static uint8 vpsg2[4];
|
||||
static int32 cvbc[3];
|
||||
static int32 vcount[3];
|
||||
static int32 dcount[2];
|
||||
static int32 saw1phaseacc;
|
||||
static int32 phaseacc;
|
||||
static uint8 b3; /* clock counter, resets phaseacc on the 7th clock */
|
||||
|
||||
static SFORMAT SStateRegs[] =
|
||||
{
|
||||
{ vpsg1, 8, "PSG1" },
|
||||
{ vpsg2, 4, "PSG2" },
|
||||
/* rw - 2018-11-28 Added */
|
||||
{ &cvbc[0], 4 | FCEUSTATE_RLSB, "BC01" },
|
||||
{ &cvbc[1], 4 | FCEUSTATE_RLSB, "BC02" },
|
||||
{ &cvbc[2], 4 | FCEUSTATE_RLSB, "BC03" },
|
||||
{ &dcount[0], 4 | FCEUSTATE_RLSB, "DCT0" },
|
||||
{ &dcount[1], 4 | FCEUSTATE_RLSB, "DCT1" },
|
||||
{ &vcount[0], 4 | FCEUSTATE_RLSB, "VCT0" },
|
||||
{ &vcount[1], 4 | FCEUSTATE_RLSB, "VCT1" },
|
||||
{ &vcount[2], 4 | FCEUSTATE_RLSB, "VCT1" },
|
||||
{ &saw1phaseacc, 4| FCEUSTATE_RLSB, "SAW1" },
|
||||
{ &phaseacc, 4 | FCEUSTATE_RLSB, "PACC" },
|
||||
{ &b3, 1, "CLKC" },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
@@ -177,15 +193,20 @@ static INLINE void DoSQV(int x) {
|
||||
} else {
|
||||
int32 thresh = (vpsg1[x << 2] >> 4) & 7;
|
||||
int32 freq = ((vpsg1[(x << 2) | 0x1] | ((vpsg1[(x << 2) | 0x2] & 15) << 8)) + 1) << 17;
|
||||
int32 dc = dcount[x];
|
||||
int32 vc = vcount[x];
|
||||
|
||||
for (V = start; V < end; V++) {
|
||||
if (dcount[x] > thresh)
|
||||
if (dc > thresh)
|
||||
Wave[V >> 4] += amp;
|
||||
vcount[x] -= nesincsize;
|
||||
while (vcount[x] <= 0) {
|
||||
vcount[x] += freq;
|
||||
dcount[x] = (dcount[x] + 1) & 15;
|
||||
vc -= nesincsize;
|
||||
while (vc <= 0) {
|
||||
vc += freq;
|
||||
dc = (dc + 1) & 15;
|
||||
}
|
||||
}
|
||||
vcount[x] = vc;
|
||||
dcount[x] = dc;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -208,10 +229,7 @@ static void DoSawV(void) {
|
||||
cvbc[2] = end;
|
||||
|
||||
if (vpsg2[2] & 0x80) {
|
||||
static int32 saw1phaseacc = 0;
|
||||
uint32 freq3;
|
||||
static uint8 b3 = 0;
|
||||
static int32 phaseacc = 0;
|
||||
static uint32 duff = 0;
|
||||
|
||||
freq3 = (vpsg2[1] + ((vpsg2[2] & 15) << 8) + 1);
|
||||
@@ -249,15 +267,20 @@ static INLINE void DoSQVHQ(int x) {
|
||||
WaveHi[V] += amp;
|
||||
} else {
|
||||
int32 thresh = (vpsg1[x << 2] >> 4) & 7;
|
||||
int32 dc = dcount[x];
|
||||
int32 vc = vcount[x];
|
||||
|
||||
for (V = cvbc[x]; V < (int)SOUNDTS; V++) {
|
||||
if (dcount[x] > thresh)
|
||||
if (dc > thresh)
|
||||
WaveHi[V] += amp;
|
||||
vcount[x]--;
|
||||
if (vcount[x] <= 0) {
|
||||
vcount[x] = (vpsg1[(x << 2) | 0x1] | ((vpsg1[(x << 2) | 0x2] & 15) << 8)) + 1;
|
||||
dcount[x] = (dcount[x] + 1) & 15;
|
||||
vc--;
|
||||
if (vc <= 0) {
|
||||
vc = (vpsg1[(x << 2) | 0x1] | ((vpsg1[(x << 2) | 0x2] & 15) << 8)) + 1;
|
||||
dc = (dc + 1) & 15;
|
||||
}
|
||||
}
|
||||
dcount[x] = dc;
|
||||
vcount[x] = vc;
|
||||
}
|
||||
}
|
||||
cvbc[x] = SOUNDTS;
|
||||
@@ -272,8 +295,6 @@ static void DoSQV2HQ(void) {
|
||||
}
|
||||
|
||||
static void DoSawVHQ(void) {
|
||||
static uint8 b3 = 0;
|
||||
static int32 phaseacc = 0;
|
||||
int32 V;
|
||||
|
||||
if (vpsg2[2] & 0x80) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2010-2017 The RetroArch team
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this libretro API header (libretro.h).
|
||||
@@ -128,7 +128,8 @@ extern "C" {
|
||||
|
||||
/* LIGHTGUN device is similar to Guncon-2 for PlayStation 2.
|
||||
* It reports X/Y coordinates in screen space (similar to the pointer)
|
||||
* in the range [-0x8000, 0x7fff] in both axes, with zero being center.
|
||||
* in the range [-0x8000, 0x7fff] in both axes, with zero being center and
|
||||
* -0x8000 being out of bounds.
|
||||
* As well as reporting on/off screen state. It features a trigger,
|
||||
* start/select buttons, auxiliary action buttons and a
|
||||
* directional pad. A forced off-screen shot can be requested for
|
||||
@@ -139,7 +140,8 @@ extern "C" {
|
||||
/* The ANALOG device is an extension to JOYPAD (RetroPad).
|
||||
* Similar to DualShock2 it adds two analog sticks and all buttons can
|
||||
* be analog. This is treated as a separate device type as it returns
|
||||
* axis values in the full analog range of [-0x8000, 0x7fff].
|
||||
* axis values in the full analog range of [-0x7fff, 0x7fff],
|
||||
* although some devices may return -0x8000.
|
||||
* Positive X axis is right. Positive Y axis is down.
|
||||
* Buttons are returned in the range [0, 0x7fff].
|
||||
* Only use ANALOG type when polling for analog values.
|
||||
@@ -271,6 +273,7 @@ enum retro_language
|
||||
RETRO_LANGUAGE_POLISH = 14,
|
||||
RETRO_LANGUAGE_VIETNAMESE = 15,
|
||||
RETRO_LANGUAGE_ARABIC = 16,
|
||||
RETRO_LANGUAGE_GREEK = 17,
|
||||
RETRO_LANGUAGE_LAST,
|
||||
|
||||
/* Ensure sizeof(enum) == sizeof(int) */
|
||||
@@ -450,6 +453,7 @@ enum retro_key
|
||||
RETROK_POWER = 320,
|
||||
RETROK_EURO = 321,
|
||||
RETROK_UNDO = 322,
|
||||
RETROK_OEM_102 = 323,
|
||||
|
||||
RETROK_LAST,
|
||||
|
||||
@@ -599,9 +603,12 @@ enum retro_mod
|
||||
* GET_VARIABLE.
|
||||
* This allows the frontend to present these variables to
|
||||
* a user dynamically.
|
||||
* This should be called as early as possible (ideally in
|
||||
* retro_set_environment).
|
||||
*
|
||||
* This should be called the first time as early as
|
||||
* possible (ideally in retro_set_environment).
|
||||
* Afterward it may be called again for the core to communicate
|
||||
* updated options to the frontend, but the number of core
|
||||
* options must not change from the number in the initial call.
|
||||
*
|
||||
* 'data' points to an array of retro_variable structs
|
||||
* terminated by a { NULL, NULL } element.
|
||||
* retro_variable::key should be namespaced to not collide
|
||||
@@ -654,6 +661,15 @@ enum retro_mod
|
||||
/* Environment 20 was an obsolete version of SET_AUDIO_CALLBACK.
|
||||
* It was not used by any known core at the time,
|
||||
* and was removed from the API. */
|
||||
#define RETRO_ENVIRONMENT_SET_FRAME_TIME_CALLBACK 21
|
||||
/* const struct retro_frame_time_callback * --
|
||||
* Lets the core know how much time has passed since last
|
||||
* invocation of retro_run().
|
||||
* The frontend can tamper with the timing to fake fast-forward,
|
||||
* slow-motion, frame stepping, etc.
|
||||
* In this case the delta time will use the reference value
|
||||
* in frame_time_callback..
|
||||
*/
|
||||
#define RETRO_ENVIRONMENT_SET_AUDIO_CALLBACK 22
|
||||
/* const struct retro_audio_callback * --
|
||||
* Sets an interface which is used to notify a libretro core about audio
|
||||
@@ -680,15 +696,6 @@ enum retro_mod
|
||||
* A libretro core using SET_AUDIO_CALLBACK should also make use of
|
||||
* SET_FRAME_TIME_CALLBACK.
|
||||
*/
|
||||
#define RETRO_ENVIRONMENT_SET_FRAME_TIME_CALLBACK 21
|
||||
/* const struct retro_frame_time_callback * --
|
||||
* Lets the core know how much time has passed since last
|
||||
* invocation of retro_run().
|
||||
* The frontend can tamper with the timing to fake fast-forward,
|
||||
* slow-motion, frame stepping, etc.
|
||||
* In this case the delta time will use the reference value
|
||||
* in frame_time_callback..
|
||||
*/
|
||||
#define RETRO_ENVIRONMENT_GET_RUMBLE_INTERFACE 23
|
||||
/* struct retro_rumble_interface * --
|
||||
* Gets an interface which is used by a libretro core to set
|
||||
@@ -775,17 +782,18 @@ enum retro_mod
|
||||
*/
|
||||
#define RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY 31
|
||||
/* const char ** --
|
||||
* Returns the "save" directory of the frontend.
|
||||
* This directory can be used to store SRAM, memory cards,
|
||||
* high scores, etc, if the libretro core
|
||||
* Returns the "save" directory of the frontend, unless there is no
|
||||
* save directory available. The save directory should be used to
|
||||
* store SRAM, memory cards, high scores, etc, if the libretro core
|
||||
* cannot use the regular memory interface (retro_get_memory_data()).
|
||||
*
|
||||
* NOTE: libretro cores used to check GET_SYSTEM_DIRECTORY for
|
||||
* similar things before.
|
||||
* They should still check GET_SYSTEM_DIRECTORY if they want to
|
||||
* be backwards compatible.
|
||||
* The path here can be NULL. It should only be non-NULL if the
|
||||
* frontend user has set a specific save path.
|
||||
* If the frontend cannot designate a save directory, it will return
|
||||
* NULL to indicate that the core should attempt to operate without a
|
||||
* save directory set.
|
||||
*
|
||||
* NOTE: early libretro cores used the system directory for save
|
||||
* files. Cores that need to be backwards-compatible can still check
|
||||
* GET_SYSTEM_DIRECTORY.
|
||||
*/
|
||||
#define RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO 32
|
||||
/* const struct retro_system_av_info * --
|
||||
@@ -853,26 +861,39 @@ enum retro_mod
|
||||
#define RETRO_ENVIRONMENT_SET_CONTROLLER_INFO 35
|
||||
/* const struct retro_controller_info * --
|
||||
* This environment call lets a libretro core tell the frontend
|
||||
* which controller types are recognized in calls to
|
||||
* which controller subclasses are recognized in calls to
|
||||
* retro_set_controller_port_device().
|
||||
*
|
||||
* Some emulators such as Super Nintendo
|
||||
* support multiple lightgun types which must be specifically
|
||||
* selected from.
|
||||
* It is therefore sometimes necessary for a frontend to be able
|
||||
* to tell the core about a special kind of input device which is
|
||||
* not covered by the libretro input API.
|
||||
* Some emulators such as Super Nintendo support multiple lightgun
|
||||
* types which must be specifically selected from. It is therefore
|
||||
* sometimes necessary for a frontend to be able to tell the core
|
||||
* about a special kind of input device which is not specifcally
|
||||
* provided by the Libretro API.
|
||||
*
|
||||
* In order for a frontend to understand the workings of an input device,
|
||||
* it must be a specialized type
|
||||
* of the generic device types already defined in the libretro API.
|
||||
* In order for a frontend to understand the workings of those devices,
|
||||
* they must be defined as a specialized subclass of the generic device
|
||||
* types already defined in the libretro API.
|
||||
*
|
||||
* Which devices are supported can vary per input port.
|
||||
* The core must pass an array of const struct retro_controller_info which
|
||||
* is terminated with a blanked out struct. Each element of the struct
|
||||
* corresponds to an ascending port index to
|
||||
* retro_set_controller_port_device().
|
||||
* Even if special device types are set in the libretro core,
|
||||
* is terminated with a blanked out struct. Each element of the
|
||||
* retro_controller_info struct corresponds to the ascending port index
|
||||
* that is passed to retro_set_controller_port_device() when that function
|
||||
* is called to indicate to the core that the frontend has changed the
|
||||
* active device subclass. SEE ALSO: retro_set_controller_port_device()
|
||||
*
|
||||
* The ascending input port indexes provided by the core in the struct
|
||||
* are generally presented by frontends as ascending User # or Player #,
|
||||
* such as Player 1, Player 2, Player 3, etc. Which device subclasses are
|
||||
* supported can vary per input port.
|
||||
*
|
||||
* The first inner element of each entry in the retro_controller_info array
|
||||
* is a retro_controller_description struct that specifies the names and
|
||||
* codes of all device subclasses that are available for the corresponding
|
||||
* User or Player, beginning with the generic Libretro device that the
|
||||
* subclasses are derived from. The second inner element of each entry is the
|
||||
* total number of subclasses that are listed in the retro_controller_description.
|
||||
*
|
||||
* NOTE: Even if special device types are set in the libretro core,
|
||||
* libretro should only poll input based on the base input device types.
|
||||
*/
|
||||
#define RETRO_ENVIRONMENT_SET_MEMORY_MAPS (36 | RETRO_ENVIRONMENT_EXPERIMENTAL)
|
||||
@@ -951,7 +972,37 @@ enum retro_mod
|
||||
* A frontend must make sure that the pointer obtained from this function is
|
||||
* writeable (and readable).
|
||||
*/
|
||||
|
||||
#define RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE (41 | RETRO_ENVIRONMENT_EXPERIMENTAL)
|
||||
/* const struct retro_hw_render_interface ** --
|
||||
* Returns an API specific rendering interface for accessing API specific data.
|
||||
* Not all HW rendering APIs support or need this.
|
||||
* The contents of the returned pointer is specific to the rendering API
|
||||
* being used. See the various headers like libretro_vulkan.h, etc.
|
||||
*
|
||||
* GET_HW_RENDER_INTERFACE cannot be called before context_reset has been called.
|
||||
* Similarly, after context_destroyed callback returns,
|
||||
* the contents of the HW_RENDER_INTERFACE are invalidated.
|
||||
*/
|
||||
#define RETRO_ENVIRONMENT_SET_SUPPORT_ACHIEVEMENTS (42 | RETRO_ENVIRONMENT_EXPERIMENTAL)
|
||||
/* const bool * --
|
||||
* If true, the libretro implementation supports achievements
|
||||
* either via memory descriptors set with RETRO_ENVIRONMENT_SET_MEMORY_MAPS
|
||||
* or via retro_get_memory_data/retro_get_memory_size.
|
||||
*
|
||||
* This must be called before the first call to retro_run.
|
||||
*/
|
||||
#define RETRO_ENVIRONMENT_SET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE (43 | RETRO_ENVIRONMENT_EXPERIMENTAL)
|
||||
/* const struct retro_hw_render_context_negotiation_interface * --
|
||||
* Sets an interface which lets the libretro core negotiate with frontend how a context is created.
|
||||
* The semantics of this interface depends on which API is used in SET_HW_RENDER earlier.
|
||||
* This interface will be used when the frontend is trying to create a HW rendering context,
|
||||
* so it will be used after SET_HW_RENDER, but before the context_reset callback.
|
||||
*/
|
||||
#define RETRO_ENVIRONMENT_SET_SERIALIZATION_QUIRKS 44
|
||||
/* uint64_t * --
|
||||
* Sets quirk flags associated with serialization. The frontend will zero any flags it doesn't
|
||||
* recognize or support. Should be set in either retro_init or retro_load_game, but not both.
|
||||
*/
|
||||
#define RETRO_ENVIRONMENT_SET_HW_SHARED_CONTEXT (44 | RETRO_ENVIRONMENT_EXPERIMENTAL)
|
||||
/* N/A (null) * --
|
||||
* The frontend will try to use a 'shared' hardware context (mostly applicable
|
||||
@@ -963,14 +1014,70 @@ enum retro_mod
|
||||
* This will do nothing on its own until SET_HW_RENDER env callbacks are
|
||||
* being used.
|
||||
*/
|
||||
|
||||
#define RETRO_ENVIRONMENT_GET_VFS_INTERFACE (45 | RETRO_ENVIRONMENT_EXPERIMENTAL)
|
||||
/* struct retro_vfs_interface_info * --
|
||||
* Gets access to the VFS interface.
|
||||
* VFS presence needs to be queried prior to load_game or any
|
||||
* get_system/save/other_directory being called to let front end know
|
||||
* core supports VFS before it starts handing out paths.
|
||||
* It is recomended to do so in retro_set_environment */
|
||||
* It is recomended to do so in retro_set_environment
|
||||
*/
|
||||
#define RETRO_ENVIRONMENT_GET_LED_INTERFACE (46 | RETRO_ENVIRONMENT_EXPERIMENTAL)
|
||||
/* struct retro_led_interface * --
|
||||
* Gets an interface which is used by a libretro core to set
|
||||
* state of LEDs.
|
||||
*/
|
||||
#define RETRO_ENVIRONMENT_GET_AUDIO_VIDEO_ENABLE (47 | RETRO_ENVIRONMENT_EXPERIMENTAL)
|
||||
/* int * --
|
||||
* Tells the core if the frontend wants audio or video.
|
||||
* If disabled, the frontend will discard the audio or video,
|
||||
* so the core may decide to skip generating a frame or generating audio.
|
||||
* This is mainly used for increasing performance.
|
||||
* Bit 0 (value 1): Enable Video
|
||||
* Bit 1 (value 2): Enable Audio
|
||||
* Bit 2 (value 4): Use Fast Savestates.
|
||||
* Bit 3 (value 8): Hard Disable Audio
|
||||
* Other bits are reserved for future use and will default to zero.
|
||||
* If video is disabled:
|
||||
* * The frontend wants the core to not generate any video,
|
||||
* including presenting frames via hardware acceleration.
|
||||
* * The frontend's video frame callback will do nothing.
|
||||
* * After running the frame, the video output of the next frame should be
|
||||
* no different than if video was enabled, and saving and loading state
|
||||
* should have no issues.
|
||||
* If audio is disabled:
|
||||
* * The frontend wants the core to not generate any audio.
|
||||
* * The frontend's audio callbacks will do nothing.
|
||||
* * After running the frame, the audio output of the next frame should be
|
||||
* no different than if audio was enabled, and saving and loading state
|
||||
* should have no issues.
|
||||
* Fast Savestates:
|
||||
* * Guaranteed to be created by the same binary that will load them.
|
||||
* * Will not be written to or read from the disk.
|
||||
* * Suggest that the core assumes loading state will succeed.
|
||||
* * Suggest that the core updates its memory buffers in-place if possible.
|
||||
* * Suggest that the core skips clearing memory.
|
||||
* * Suggest that the core skips resetting the system.
|
||||
* * Suggest that the core may skip validation steps.
|
||||
* Hard Disable Audio:
|
||||
* * Used for a secondary core when running ahead.
|
||||
* * Indicates that the frontend will never need audio from the core.
|
||||
* * Suggests that the core may stop synthesizing audio, but this should not
|
||||
* compromise emulation accuracy.
|
||||
* * Audio output for the next frame does not matter, and the frontend will
|
||||
* never need an accurate audio state in the future.
|
||||
* * State will never be saved when using Hard Disable Audio.
|
||||
*/
|
||||
#define RETRO_ENVIRONMENT_GET_MIDI_INTERFACE (48 | RETRO_ENVIRONMENT_EXPERIMENTAL)
|
||||
/* struct retro_midi_interface ** --
|
||||
* Returns a MIDI interface that can be used for raw data I/O.
|
||||
*/
|
||||
|
||||
#define RETRO_ENVIRONMENT_GET_FASTFORWARDING (49 | RETRO_ENVIRONMENT_EXPERIMENTAL)
|
||||
/* bool * --
|
||||
* Boolean value that indicates whether or not the frontend is in
|
||||
* fastforwarding mode.
|
||||
*/
|
||||
|
||||
/* VFS functionality */
|
||||
|
||||
@@ -1030,6 +1137,10 @@ typedef int (RETRO_CALLCONV *retro_vfs_close_t)(struct retro_vfs_file_handle *st
|
||||
* Introduced in VFS API v1 */
|
||||
typedef int64_t (RETRO_CALLCONV *retro_vfs_size_t)(struct retro_vfs_file_handle *stream);
|
||||
|
||||
/* Truncate file to specified size. Returns 0 on success or -1 on error
|
||||
* Introduced in VFS API v2 */
|
||||
typedef int64_t (RETRO_CALLCONV *retro_vfs_truncate_t)(struct retro_vfs_file_handle *stream, int64_t length);
|
||||
|
||||
/* Get the current read / write position for the file. Returns - 1 for error.
|
||||
* Introduced in VFS API v1 */
|
||||
typedef int64_t (RETRO_CALLCONV *retro_vfs_tell_t)(struct retro_vfs_file_handle *stream);
|
||||
@@ -1060,6 +1171,7 @@ typedef int (RETRO_CALLCONV *retro_vfs_rename_t)(const char *old_path, const cha
|
||||
|
||||
struct retro_vfs_interface
|
||||
{
|
||||
/* VFS API v1 */
|
||||
retro_vfs_get_path_t get_path;
|
||||
retro_vfs_open_t open;
|
||||
retro_vfs_close_t close;
|
||||
@@ -1071,6 +1183,8 @@ struct retro_vfs_interface
|
||||
retro_vfs_flush_t flush;
|
||||
retro_vfs_remove_t remove;
|
||||
retro_vfs_rename_t rename;
|
||||
/* VFS API v2 */
|
||||
retro_vfs_truncate_t truncate;
|
||||
};
|
||||
|
||||
struct retro_vfs_interface_info
|
||||
@@ -1104,81 +1218,41 @@ struct retro_hw_render_interface
|
||||
unsigned interface_version;
|
||||
};
|
||||
|
||||
|
||||
#define RETRO_ENVIRONMENT_GET_LED_INTERFACE (46 | RETRO_ENVIRONMENT_EXPERIMENTAL)
|
||||
/* struct retro_led_interface * --
|
||||
* Gets an interface which is used by a libretro core to set
|
||||
* state of LEDs.
|
||||
*/
|
||||
|
||||
typedef void (RETRO_CALLCONV *retro_set_led_state_t)(int led, int state);
|
||||
struct retro_led_interface
|
||||
{
|
||||
retro_set_led_state_t set_led_state;
|
||||
};
|
||||
|
||||
#define RETRO_ENVIRONMENT_GET_AUDIO_VIDEO_ENABLE (47 | RETRO_ENVIRONMENT_EXPERIMENTAL)
|
||||
/* int * --
|
||||
* Tells the core if the frontend wants audio or video.
|
||||
* If disabled, the frontend will discard the audio or video,
|
||||
* so the core may decide to skip generating a frame or generating audio.
|
||||
* This is mainly used for increasing performance.
|
||||
* Bit 0 (value 1): Enable Video
|
||||
* Bit 1 (value 2): Enable Audio
|
||||
* Bit 2 (value 4): Use Fast Savestates.
|
||||
* Bit 3 (value 8): Hard Disable Audio
|
||||
* Other bits are reserved for future use and will default to zero.
|
||||
* If video is disabled:
|
||||
* * The frontend wants the core to not generate any video,
|
||||
* including presenting frames via hardware acceleration.
|
||||
* * The frontend's video frame callback will do nothing.
|
||||
* * After running the frame, the video output of the next frame should be
|
||||
* no different than if video was enabled, and saving and loading state
|
||||
* should have no issues.
|
||||
* If audio is disabled:
|
||||
* * The frontend wants the core to not generate any audio.
|
||||
* * The frontend's audio callbacks will do nothing.
|
||||
* * After running the frame, the audio output of the next frame should be
|
||||
* no different than if audio was enabled, and saving and loading state
|
||||
* should have no issues.
|
||||
* Fast Savestates:
|
||||
* * Guaranteed to be created by the same binary that will load them.
|
||||
* * Will not be written to or read from the disk.
|
||||
* * Suggest that the core assumes loading state will succeed.
|
||||
* * Suggest that the core updates its memory buffers in-place if possible.
|
||||
* * Suggest that the core skips clearing memory.
|
||||
* * Suggest that the core skips resetting the system.
|
||||
* * Suggest that the core may skip validation steps.
|
||||
* Hard Disable Audio:
|
||||
* * Used for a secondary core when running ahead.
|
||||
* * Indicates that the frontend will never need audio from the core.
|
||||
* * Suggests that the core may stop synthesizing audio, but this should not
|
||||
* compromise emulation accuracy.
|
||||
* * Audio output for the next frame does not matter, and the frontend will
|
||||
* never need an accurate audio state in the future.
|
||||
* * State will never be saved when using Hard Disable Audio.
|
||||
*/
|
||||
/* Retrieves the current state of the MIDI input.
|
||||
* Returns true if it's enabled, false otherwise. */
|
||||
typedef bool (RETRO_CALLCONV *retro_midi_input_enabled_t)(void);
|
||||
|
||||
#define RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE (41 | RETRO_ENVIRONMENT_EXPERIMENTAL)
|
||||
/* const struct retro_hw_render_interface ** --
|
||||
* Returns an API specific rendering interface for accessing API specific data.
|
||||
* Not all HW rendering APIs support or need this.
|
||||
* The contents of the returned pointer is specific to the rendering API
|
||||
* being used. See the various headers like libretro_vulkan.h, etc.
|
||||
*
|
||||
* GET_HW_RENDER_INTERFACE cannot be called before context_reset has been called.
|
||||
* Similarly, after context_destroyed callback returns,
|
||||
* the contents of the HW_RENDER_INTERFACE are invalidated.
|
||||
*/
|
||||
/* Retrieves the current state of the MIDI output.
|
||||
* Returns true if it's enabled, false otherwise */
|
||||
typedef bool (RETRO_CALLCONV *retro_midi_output_enabled_t)(void);
|
||||
|
||||
#define RETRO_ENVIRONMENT_SET_SUPPORT_ACHIEVEMENTS (42 | RETRO_ENVIRONMENT_EXPERIMENTAL)
|
||||
/* const bool * --
|
||||
* If true, the libretro implementation supports achievements
|
||||
* either via memory descriptors set with RETRO_ENVIRONMENT_SET_MEMORY_MAPS
|
||||
* or via retro_get_memory_data/retro_get_memory_size.
|
||||
*
|
||||
* This must be called before the first call to retro_run.
|
||||
*/
|
||||
/* Reads next byte from the input stream.
|
||||
* Returns true if byte is read, false otherwise. */
|
||||
typedef bool (RETRO_CALLCONV *retro_midi_read_t)(uint8_t *byte);
|
||||
|
||||
/* Writes byte to the output stream.
|
||||
* 'delta_time' is in microseconds and represent time elapsed since previous write.
|
||||
* Returns true if byte is written, false otherwise. */
|
||||
typedef bool (RETRO_CALLCONV *retro_midi_write_t)(uint8_t byte, uint32_t delta_time);
|
||||
|
||||
/* Flushes previously written data.
|
||||
* Returns true if successful, false otherwise. */
|
||||
typedef bool (RETRO_CALLCONV *retro_midi_flush_t)(void);
|
||||
|
||||
struct retro_midi_interface
|
||||
{
|
||||
retro_midi_input_enabled_t input_enabled;
|
||||
retro_midi_output_enabled_t output_enabled;
|
||||
retro_midi_read_t read;
|
||||
retro_midi_write_t write;
|
||||
retro_midi_flush_t flush;
|
||||
};
|
||||
|
||||
enum retro_hw_render_context_negotiation_interface_type
|
||||
{
|
||||
@@ -1193,13 +1267,6 @@ struct retro_hw_render_context_negotiation_interface
|
||||
enum retro_hw_render_context_negotiation_interface_type interface_type;
|
||||
unsigned interface_version;
|
||||
};
|
||||
#define RETRO_ENVIRONMENT_SET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE (43 | RETRO_ENVIRONMENT_EXPERIMENTAL)
|
||||
/* const struct retro_hw_render_context_negotiation_interface * --
|
||||
* Sets an interface which lets the libretro core negotiate with frontend how a context is created.
|
||||
* The semantics of this interface depends on which API is used in SET_HW_RENDER earlier.
|
||||
* This interface will be used when the frontend is trying to create a HW rendering context,
|
||||
* so it will be used after SET_HW_RENDER, but before the context_reset callback.
|
||||
*/
|
||||
|
||||
/* Serialized state is incomplete in some way. Set if serialization is
|
||||
* usable in typical end-user cases but should not be relied upon to
|
||||
@@ -1225,20 +1292,17 @@ struct retro_hw_render_context_negotiation_interface
|
||||
* dependence */
|
||||
#define RETRO_SERIALIZATION_QUIRK_PLATFORM_DEPENDENT (1 << 6)
|
||||
|
||||
#define RETRO_ENVIRONMENT_SET_SERIALIZATION_QUIRKS 44
|
||||
/* uint64_t * --
|
||||
* Sets quirk flags associated with serialization. The frontend will zero any flags it doesn't
|
||||
* recognize or support. Should be set in either retro_init or retro_load_game, but not both.
|
||||
*/
|
||||
|
||||
#define RETRO_MEMDESC_CONST (1 << 0) /* The frontend will never change this memory area once retro_load_game has returned. */
|
||||
#define RETRO_MEMDESC_BIGENDIAN (1 << 1) /* The memory area contains big endian data. Default is little endian. */
|
||||
#define RETRO_MEMDESC_ALIGN_2 (1 << 16) /* All memory access in this area is aligned to their own size, or 2, whichever is smaller. */
|
||||
#define RETRO_MEMDESC_ALIGN_4 (2 << 16)
|
||||
#define RETRO_MEMDESC_ALIGN_8 (3 << 16)
|
||||
#define RETRO_MEMDESC_MINSIZE_2 (1 << 24) /* All memory in this region is accessed at least 2 bytes at the time. */
|
||||
#define RETRO_MEMDESC_MINSIZE_4 (2 << 24)
|
||||
#define RETRO_MEMDESC_MINSIZE_8 (3 << 24)
|
||||
#define RETRO_MEMDESC_CONST (1 << 0) /* The frontend will never change this memory area once retro_load_game has returned. */
|
||||
#define RETRO_MEMDESC_BIGENDIAN (1 << 1) /* The memory area contains big endian data. Default is little endian. */
|
||||
#define RETRO_MEMDESC_SYSTEM_RAM (1 << 2) /* The memory area is system RAM. This is main RAM of the gaming system. */
|
||||
#define RETRO_MEMDESC_SAVE_RAM (1 << 3) /* The memory area is save RAM. This RAM is usually found on a game cartridge, backed up by a battery. */
|
||||
#define RETRO_MEMDESC_VIDEO_RAM (1 << 4) /* The memory area is video RAM (VRAM) */
|
||||
#define RETRO_MEMDESC_ALIGN_2 (1 << 16) /* All memory access in this area is aligned to their own size, or 2, whichever is smaller. */
|
||||
#define RETRO_MEMDESC_ALIGN_4 (2 << 16)
|
||||
#define RETRO_MEMDESC_ALIGN_8 (3 << 16)
|
||||
#define RETRO_MEMDESC_MINSIZE_2 (1 << 24) /* All memory in this region is accessed at least 2 bytes at the time. */
|
||||
#define RETRO_MEMDESC_MINSIZE_4 (2 << 24)
|
||||
#define RETRO_MEMDESC_MINSIZE_8 (3 << 24)
|
||||
struct retro_memory_descriptor
|
||||
{
|
||||
uint64_t flags;
|
||||
@@ -2138,17 +2202,26 @@ struct retro_system_info
|
||||
* Typically used for a GUI to filter
|
||||
* out extensions. */
|
||||
|
||||
/* If true, retro_load_game() is guaranteed to provide a valid pathname
|
||||
* in retro_game_info::path.
|
||||
* ::data and ::size are both invalid.
|
||||
/* Libretro cores that need to have direct access to their content
|
||||
* files, including cores which use the path of the content files to
|
||||
* determine the paths of other files, should set need_fullpath to true.
|
||||
*
|
||||
* If false, ::data and ::size are guaranteed to be valid, but ::path
|
||||
* might not be valid.
|
||||
* Cores should strive for setting need_fullpath to false,
|
||||
* as it allows the frontend to perform patching, etc.
|
||||
*
|
||||
* This is typically set to true for libretro implementations that must
|
||||
* load from file.
|
||||
* Implementations should strive for setting this to false, as it allows
|
||||
* the frontend to perform patching, etc. */
|
||||
* If need_fullpath is true and retro_load_game() is called:
|
||||
* - retro_game_info::path is guaranteed to have a valid path
|
||||
* - retro_game_info::data and retro_game_info::size are invalid
|
||||
*
|
||||
* If need_fullpath is false and retro_load_game() is called:
|
||||
* - retro_game_info::path may be NULL
|
||||
* - retro_game_info::data and retro_game_info::size are guaranteed
|
||||
* to be valid
|
||||
*
|
||||
* See also:
|
||||
* - RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY
|
||||
* - RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY
|
||||
*/
|
||||
bool need_fullpath;
|
||||
|
||||
/* If true, the frontend is not allowed to extract any archives before
|
||||
@@ -2333,7 +2406,13 @@ RETRO_API void retro_get_system_av_info(struct retro_system_av_info *info);
|
||||
* will only poll input based on that particular device type. It is only a
|
||||
* hint to the libretro core when a core cannot automatically detect the
|
||||
* appropriate input device type on its own. It is also relevant when a
|
||||
* core can change its behavior depending on device type. */
|
||||
* core can change its behavior depending on device type.
|
||||
*
|
||||
* As part of the core's implementation of retro_set_controller_port_device,
|
||||
* the core should call RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS to notify the
|
||||
* frontend if the descriptions for any controls have changed as a
|
||||
* result of changing the device type.
|
||||
*/
|
||||
RETRO_API void retro_set_controller_port_device(unsigned port, unsigned device);
|
||||
|
||||
/* Resets the current game. */
|
||||
@@ -2365,7 +2444,9 @@ RETRO_API bool retro_unserialize(const void *data, size_t size);
|
||||
RETRO_API void retro_cheat_reset(void);
|
||||
RETRO_API void retro_cheat_set(unsigned index, bool enabled, const char *code);
|
||||
|
||||
/* Loads a game. */
|
||||
/* Loads a game.
|
||||
* Return true to indicate successful loading and false to indicate load failure.
|
||||
*/
|
||||
RETRO_API bool retro_load_game(const struct retro_game_info *game);
|
||||
|
||||
/* Loads a "special" kind of game. Should not be used,
|
||||
@@ -2375,7 +2456,7 @@ RETRO_API bool retro_load_game_special(
|
||||
const struct retro_game_info *info, size_t num_info
|
||||
);
|
||||
|
||||
/* Unloads a currently loaded game. */
|
||||
/* Unloads the currently loaded game. Called before retro_deinit(void). */
|
||||
RETRO_API void retro_unload_game(void);
|
||||
|
||||
/* Gets region of game. */
|
||||
|
||||
@@ -719,6 +719,13 @@ void retro_set_environment(retro_environment_t cb)
|
||||
{ "fceumm_show_crosshair", "Show Crosshair; enabled|disabled" },
|
||||
{ "fceumm_overclocking", "Overclocking; disabled|2x-Postrender|2x-VBlank" },
|
||||
{ "fceumm_ramstate", "RAM power up state (Restart); fill $ff|fill $00|random" },
|
||||
#ifdef DEBUG
|
||||
{ "fceumm_apu_1", "Enable Sound Channel 1 (Square 1); enabled|disabled" },
|
||||
{ "fceumm_apu_2", "Enable Sound Channel 2 (Square 2); enabled|disabled" },
|
||||
{ "fceumm_apu_3", "Enable Sound Channel 3 (Triangle); enabled|disabled" },
|
||||
{ "fceumm_apu_4", "Enable Sound Channel 4 (Noise) ; enabled|disabled" },
|
||||
{ "fceumm_apu_5", "Enable Sound Channel 5 (PCM); enabled|disabled" },
|
||||
#endif
|
||||
{ NULL, NULL },
|
||||
};
|
||||
|
||||
@@ -957,11 +964,22 @@ static const keymap bindmap[] = {
|
||||
{ RETRO_DEVICE_ID_JOYPAD_Y, JOY_B },
|
||||
};
|
||||
|
||||
static void set_apu_channels(int chan)
|
||||
{
|
||||
FSettings.SquareVolume[1] = 255 * ((chan >> 0) & 1);
|
||||
FSettings.SquareVolume[0] = 255 * ((chan >> 1) & 1);
|
||||
FSettings.TriangleVolume = 255 * ((chan >> 2) & 1);
|
||||
FSettings.NoiseVolume = 255 * ((chan >> 3) & 1);
|
||||
FSettings.PCMVolume = 255 * ((chan >> 4) & 1);
|
||||
}
|
||||
|
||||
static void check_variables(bool startup)
|
||||
{
|
||||
struct retro_variable var = {0};
|
||||
struct retro_system_av_info av_info;
|
||||
bool geometry_update = false;
|
||||
char key[256];
|
||||
int i, enable_apu;
|
||||
|
||||
var.key = "fceumm_palette";
|
||||
|
||||
@@ -1169,7 +1187,6 @@ static void check_variables(bool startup)
|
||||
FCEUD_RegionOverride(setregion);
|
||||
}
|
||||
|
||||
|
||||
var.key = "fceumm_aspect";
|
||||
|
||||
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
|
||||
@@ -1221,6 +1238,27 @@ static void check_variables(bool startup)
|
||||
swapDuty = newval;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
var.key = key;
|
||||
|
||||
enable_apu = 0;
|
||||
|
||||
strcpy(key, "fceumm_apu_x");
|
||||
for (i = 0; i < 5; i++)
|
||||
{
|
||||
key[strlen("fceumm_apu_")] = '1' + i;
|
||||
var.value = NULL;
|
||||
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && !strcmp(var.value, "disabled"))
|
||||
{
|
||||
enable_apu |= (1 << i);
|
||||
}
|
||||
}
|
||||
set_apu_channels(enable_apu ^ 0xff);
|
||||
#else
|
||||
set_apu_channels(0xff);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
static int mzx = 0, mzy = 0;
|
||||
@@ -2043,7 +2081,6 @@ unsigned retro_get_region(void)
|
||||
return FSettings.PAL ? RETRO_REGION_PAL : RETRO_REGION_NTSC;
|
||||
}
|
||||
|
||||
|
||||
void *retro_get_memory_data(unsigned type)
|
||||
{
|
||||
uint8_t* data;
|
||||
@@ -2051,9 +2088,9 @@ void *retro_get_memory_data(unsigned type)
|
||||
switch(type)
|
||||
{
|
||||
case RETRO_MEMORY_SAVE_RAM:
|
||||
if (iNESCart.battery)
|
||||
if (iNESCart.battery && iNESCart.SaveGame[0] && iNESCart.SaveGameLen[0])
|
||||
return iNESCart.SaveGame[0];
|
||||
else if (UNIFCart.battery)
|
||||
else if (UNIFCart.battery && UNIFCart.SaveGame[0] && UNIFCart.SaveGameLen[0])
|
||||
return UNIFCart.SaveGame[0];
|
||||
else
|
||||
data = NULL;
|
||||
@@ -2076,9 +2113,9 @@ size_t retro_get_memory_size(unsigned type)
|
||||
switch(type)
|
||||
{
|
||||
case RETRO_MEMORY_SAVE_RAM:
|
||||
if (iNESCart.battery)
|
||||
if (iNESCart.battery && iNESCart.SaveGame[0] && iNESCart.SaveGameLen[0])
|
||||
size = iNESCart.SaveGameLen[0];
|
||||
else if (UNIFCart.battery)
|
||||
else if (UNIFCart.battery && UNIFCart.SaveGame[0] && UNIFCart.SaveGameLen[0])
|
||||
size = UNIFCart.SaveGameLen[0];
|
||||
else
|
||||
size = 0;
|
||||
|
||||
@@ -83,6 +83,10 @@ typedef struct {
|
||||
int PAL;
|
||||
int NetworkPlay;
|
||||
int SoundVolume;
|
||||
int TriangleVolume;
|
||||
int SquareVolume[2];
|
||||
int NoiseVolume;
|
||||
int PCMVolume;
|
||||
int GameGenie;
|
||||
|
||||
/* Current first and last rendered scanlines. */
|
||||
|
||||
@@ -58,8 +58,6 @@ static MEMWRAP *MakeMemWrap(void *tz, int type)
|
||||
fread(tmp->data, 1, tmp->size, (FILE*)tz);
|
||||
|
||||
doret:
|
||||
if (type == 0)
|
||||
fclose((FILE*)tz);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
@@ -97,6 +95,7 @@ FCEUFILE * FCEU_fopen(const char *path, const char *ipsfn,
|
||||
|
||||
fseek((FILE*)t, 0, SEEK_SET);
|
||||
fceufp->fp = MakeMemWrap(t, 0);
|
||||
fclose((FILE*)t);
|
||||
}
|
||||
return fceufp;
|
||||
}
|
||||
|
||||
@@ -100,7 +100,7 @@ int32 NeoFilterSound(int32 *in, int32 *out, uint32 inlen, int32 *leftover) {
|
||||
#endif
|
||||
max = (inlen - 1) << 16;
|
||||
|
||||
if (FSettings.soundq == 2)
|
||||
if (FSettings.soundq == 2) {
|
||||
for (x = mrindex; x < max; x += mrratio) {
|
||||
int32 acc = 0, acc2 = 0;
|
||||
uint32 c;
|
||||
@@ -116,7 +116,7 @@ int32 NeoFilterSound(int32 *in, int32 *out, uint32 inlen, int32 *leftover) {
|
||||
out++;
|
||||
count++;
|
||||
}
|
||||
else
|
||||
} else {
|
||||
for (x = mrindex; x < max; x += mrratio) {
|
||||
int32 acc = 0, acc2 = 0;
|
||||
uint32 c;
|
||||
@@ -132,6 +132,7 @@ int32 NeoFilterSound(int32 *in, int32 *out, uint32 inlen, int32 *leftover) {
|
||||
out++;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
mrindex = x - max;
|
||||
|
||||
|
||||
95
src/sound.c
95
src/sound.c
@@ -520,7 +520,8 @@ void RDoPCM(void) {
|
||||
uint32 V;
|
||||
|
||||
for (V = ChannelBC[4]; V < SOUNDTS; V++)
|
||||
WaveHi[V] += RawDALatch << 16;
|
||||
/* TODO: get rid of floating calculations to binary. set log volume scaling. */
|
||||
WaveHi[V] += (((RawDALatch << 16) / 256) * FSettings.PCMVolume ) & (~0xFFFF);
|
||||
|
||||
ChannelBC[4] = SOUNDTS;
|
||||
}
|
||||
@@ -546,7 +547,16 @@ static INLINE void RDoSQ(int x) {
|
||||
amp = EnvUnits[x].Speed;
|
||||
else
|
||||
amp = EnvUnits[x].decvolume;
|
||||
/* printf("%d\n",amp); */
|
||||
/* printf("%d\n",amp); */
|
||||
|
||||
/* Modify Square wave volume based on channel volume modifiers
|
||||
* Note: the formulat x = x * y /100 does not yield exact results,
|
||||
* but is "close enough" and avoids the need for using double values
|
||||
* or implicit cohersion which are slower (we need speed here) */
|
||||
/* TODO: Optimize this. */
|
||||
if (FSettings.SquareVolume[x] != 256)
|
||||
amp = (amp * FSettings.SquareVolume[x]) / 256;
|
||||
|
||||
amp <<= 24;
|
||||
|
||||
rthresh = RectDuties[(PSG[(x << 2)] & 0xC0) >> 6];
|
||||
@@ -618,6 +628,15 @@ static void RDoSQLQ(void) {
|
||||
else
|
||||
amp[x] = EnvUnits[x].decvolume;
|
||||
|
||||
/* Modify Square wave volume based on channel volume modifiers
|
||||
* Note: the formulat x = x * y /100 does not yield exact results,
|
||||
* but is "close enough" and avoids the need for using double vales
|
||||
* or implicit cohersion which are slower (we need speed here)
|
||||
* fixed - setting up maximum volume for square2 caused complete mute square2 channel.
|
||||
* TODO: Optimize this. */
|
||||
if (FSettings.SquareVolume[x] != 256)
|
||||
amp[x] = (amp[x] * FSettings.SquareVolume[x]) / 256;
|
||||
|
||||
if (!inie[x]) amp[x] = 0; /* Correct? Buzzing in MM2, others otherwise... */
|
||||
|
||||
rthresh[x] = RectDuties[(PSG[x * 4] & 0xC0) >> 6];
|
||||
@@ -637,7 +656,7 @@ static void RDoSQLQ(void) {
|
||||
if (!inie[0] && !inie[1]) {
|
||||
for (V = start; V < end; V++)
|
||||
Wave[V >> 4] += totalout;
|
||||
} else
|
||||
} else {
|
||||
for (V = start; V < end; V++) {
|
||||
/* int tmpamp=0;
|
||||
if(RectDutyCount[0]<rthresh[0])
|
||||
@@ -669,11 +688,12 @@ static void RDoSQLQ(void) {
|
||||
totalout = wlookup1[ ttable[0][RectDutyCount[0]] + ttable[1][RectDutyCount[1]] ];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void RDoTriangle(void) {
|
||||
int32 V;
|
||||
int32 tcout;
|
||||
int32 tcout, cout;
|
||||
|
||||
tcout = (tristep & 0xF);
|
||||
if (!(tristep & 0x10)) tcout ^= 0xF;
|
||||
@@ -683,16 +703,17 @@ static void RDoTriangle(void) {
|
||||
int32 *start = &WaveHi[ChannelBC[2]];
|
||||
int32 count = SOUNDTS - ChannelBC[2];
|
||||
while (count--) {
|
||||
*start += tcout;
|
||||
*start += (tcout / 256 * FSettings.TriangleVolume) & (~0xFFFF); /* TODO OPTIMIZE ME */
|
||||
start++;
|
||||
}
|
||||
#if 0
|
||||
|
||||
/* cout = (tcout / 256 * FSettings.TriangleVolume) & (~0xFFFF);
|
||||
for(V = ChannelBC[2]; V < SOUNDTS; V++)
|
||||
WaveHi[V] += tcout;
|
||||
#endif
|
||||
} else
|
||||
WaveHi[V] += cout; */
|
||||
|
||||
} else {
|
||||
for (V = ChannelBC[2]; V < SOUNDTS; V++) {
|
||||
WaveHi[V] += tcout;
|
||||
WaveHi[V] += (tcout / 256 * FSettings.TriangleVolume) & (~0xFFFF); /* TODO OPTIMIZE ME! */
|
||||
wlcount[2]--;
|
||||
if (!wlcount[2]) {
|
||||
wlcount[2] = (PSG[0xa] | ((PSG[0xb] & 7) << 8)) + 1;
|
||||
@@ -702,6 +723,7 @@ static void RDoTriangle(void) {
|
||||
tcout = (tcout * 3) << 16;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ChannelBC[2] = SOUNDTS;
|
||||
}
|
||||
@@ -738,6 +760,15 @@ static void RDoTriangleNoisePCMLQ(void) {
|
||||
amptab[0] = EnvUnits[2].Speed;
|
||||
else
|
||||
amptab[0] = EnvUnits[2].decvolume;
|
||||
|
||||
/* Modify Square wave volume based on channel volume modifiers
|
||||
* Note: the formulat x = x * y /100 does not yield exact results,
|
||||
* but is "close enough" and avoids the need for using double vales
|
||||
* or implicit cohersion which are slower (we need speed here)
|
||||
* TODO: Optimize this. */
|
||||
if (FSettings.TriangleVolume != 256)
|
||||
amptab[0] = (amptab[0] * FSettings.TriangleVolume) / 256;
|
||||
|
||||
amptab[1] = 0;
|
||||
amptab[0] <<= 1;
|
||||
|
||||
@@ -751,7 +782,6 @@ static void RDoTriangleNoisePCMLQ(void) {
|
||||
else
|
||||
nshift = 13;
|
||||
|
||||
|
||||
totalout = wlookup2[lq_tcout + noiseout + RawDALatch];
|
||||
|
||||
if (inie[0] && inie[1]) {
|
||||
@@ -842,6 +872,14 @@ static void RDoNoise(void) {
|
||||
else
|
||||
amptab[0] = EnvUnits[2].decvolume;
|
||||
|
||||
/* Modify Square wave volume based on channel volume modifiers
|
||||
* Note: the formulat x = x * y /100 does not yield exact results,
|
||||
* but is "close enough" and avoids the need for using double vales
|
||||
* or implicit cohersion which are slower (we need speed here)
|
||||
* TODO: Optimize this. */
|
||||
if (FSettings.NoiseVolume != 256)
|
||||
amptab[0] = (amptab[0] * FSettings.NoiseVolume) / 256;
|
||||
|
||||
amptab[0] <<= 16;
|
||||
amptab[1] = 0;
|
||||
|
||||
@@ -853,7 +891,7 @@ static void RDoNoise(void) {
|
||||
outo = amptab[0] = 0;
|
||||
}
|
||||
|
||||
if (PSG[0xE] & 0x80)/* "short" noise */
|
||||
if (PSG[0xE] & 0x80) {/* "short" noise */
|
||||
for (V = ChannelBC[3]; V < SOUNDTS; V++) {
|
||||
WaveHi[V] += outo;
|
||||
wlcount[3]--;
|
||||
@@ -869,7 +907,7 @@ static void RDoNoise(void) {
|
||||
outo = amptab[(nreg >> 0xe) & 1];
|
||||
}
|
||||
}
|
||||
else
|
||||
} else {
|
||||
for (V = ChannelBC[3]; V < SOUNDTS; V++) {
|
||||
WaveHi[V] += outo;
|
||||
wlcount[3]--;
|
||||
@@ -885,6 +923,7 @@ static void RDoNoise(void) {
|
||||
outo = amptab[(nreg >> 0xe) & 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
ChannelBC[3] = SOUNDTS;
|
||||
}
|
||||
|
||||
@@ -938,6 +977,7 @@ int FlushEmulateSound(void) {
|
||||
*tmpo = (b & 65535) + wlookup2[(b >> 16) & 255] + wlookup1[b >> 24];
|
||||
tmpo++;
|
||||
}
|
||||
|
||||
end = NeoFilterSound(WaveHi, WaveFinal, SOUNDTS, &left);
|
||||
|
||||
memmove(WaveHi, WaveHi + SOUNDTS - left, left * sizeof(uint32));
|
||||
@@ -953,10 +993,9 @@ int FlushEmulateSound(void) {
|
||||
|
||||
SexyFilter(Wave, WaveFinal, end >> 4);
|
||||
|
||||
#if 0
|
||||
if (FSettings.lowpass)
|
||||
SexyFilter2(WaveFinal, end >> 4);
|
||||
#endif
|
||||
/* if (FSettings.lowpass)
|
||||
SexyFilter2(WaveFinal, end >> 4); */
|
||||
|
||||
if (end & 0xF)
|
||||
Wave[0] = Wave[(end >> 4)];
|
||||
Wave[end >> 4] = 0;
|
||||
@@ -1023,6 +1062,8 @@ void FCEUSND_Reset(void) {
|
||||
DMCAddress = 0;
|
||||
DMCSize = 0;
|
||||
DMCShift = 0;
|
||||
DMCacc=1;
|
||||
DMCBitCount=0;
|
||||
}
|
||||
|
||||
void FCEUSND_Power(void) {
|
||||
@@ -1162,7 +1203,7 @@ SFORMAT FCEUSND_STATEINFO[] = {
|
||||
{ &DMCAddressLatch, 1, "5ADL" },
|
||||
{ &DMCFormat, 1, "5FMT" },
|
||||
{ &RawDALatch, 1, "RWDA" },
|
||||
|
||||
|
||||
//these are important for smooth sound after loading state
|
||||
{ &sqacc[0], sizeof(sqacc[0]) | FCEUSTATE_RLSB, "SAC1" },
|
||||
{ &sqacc[1], sizeof(sqacc[1]) | FCEUSTATE_RLSB, "SAC2" },
|
||||
@@ -1171,7 +1212,7 @@ SFORMAT FCEUSND_STATEINFO[] = {
|
||||
{ &tristep, sizeof(tristep) | FCEUSTATE_RLSB, "TRIS"},
|
||||
{ &lq_triacc, sizeof(lq_triacc) | FCEUSTATE_RLSB, "TACC" },
|
||||
{ &lq_noiseacc, sizeof(lq_noiseacc) | FCEUSTATE_RLSB, "NACC" },
|
||||
|
||||
|
||||
//less important but still necessary
|
||||
{ &ChannelBC[0], sizeof(ChannelBC[0]) | FCEUSTATE_RLSB, "CBC1" },
|
||||
{ &ChannelBC[1], sizeof(ChannelBC[1]) | FCEUSTATE_RLSB, "CBC2" },
|
||||
@@ -1187,10 +1228,10 @@ SFORMAT FCEUSND_STATEINFO[] = {
|
||||
{ &sexyfilter_acc1, sizeof(sexyfilter_acc1) | FCEUSTATE_RLSB, "FAC1" },
|
||||
{ &sexyfilter_acc2, sizeof(sexyfilter_acc2) | FCEUSTATE_RLSB, "FAC2" },
|
||||
{ &lq_tcout, sizeof(lq_tcout) | FCEUSTATE_RLSB, "TCOU"},
|
||||
|
||||
|
||||
//wave buffer is used for filtering, only need first 17 values from it
|
||||
{ &Wave, 32 * sizeof(int32), "WAVE"},
|
||||
{ 0 }
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
void FCEUSND_SaveState(void) {
|
||||
@@ -1205,7 +1246,17 @@ void FCEUSND_LoadState(int version) {
|
||||
//minimal validation
|
||||
for (i = 0; i < 5; i++)
|
||||
{
|
||||
if (ChannelBC[i] < 0 || ChannelBC[i] > 15)
|
||||
int BC_max = 15;
|
||||
|
||||
if (FSettings.soundq == 2)
|
||||
{
|
||||
BC_max = 1025;
|
||||
}
|
||||
else if (FSettings.soundq == 1)
|
||||
{
|
||||
BC_max = 485;
|
||||
}
|
||||
if (ChannelBC[i] < 0 || ChannelBC[i] > BC_max)
|
||||
{
|
||||
ChannelBC[i] = 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user