mirror of
https://github.com/ekeeke/Genesis-Plus-GX.git
synced 2024-12-27 11:41:48 +01:00
commit
258329cad4
@ -199,6 +199,7 @@ LIBRETRO_SRC := $(GENPLUS_SRC_DIR)/genesis.c \
|
|||||||
$(GENPLUS_SRC_DIR)/input_hw/teamplayer.c \
|
$(GENPLUS_SRC_DIR)/input_hw/teamplayer.c \
|
||||||
$(GENPLUS_SRC_DIR)/input_hw/xe_1ap.c \
|
$(GENPLUS_SRC_DIR)/input_hw/xe_1ap.c \
|
||||||
$(GENPLUS_SRC_DIR)/input_hw/terebi_oekaki.c \
|
$(GENPLUS_SRC_DIR)/input_hw/terebi_oekaki.c \
|
||||||
|
$(GENPLUS_SRC_DIR)/input_hw/graphic_board.c \
|
||||||
$(GENPLUS_SRC_DIR)/cd_hw/cd_cart.c \
|
$(GENPLUS_SRC_DIR)/cd_hw/cd_cart.c \
|
||||||
$(GENPLUS_SRC_DIR)/cd_hw/cdc.c \
|
$(GENPLUS_SRC_DIR)/cd_hw/cdc.c \
|
||||||
$(GENPLUS_SRC_DIR)/cd_hw/cdd.c \
|
$(GENPLUS_SRC_DIR)/cd_hw/cdd.c \
|
||||||
|
Binary file not shown.
Binary file not shown.
Before Width: | Height: | Size: 3.7 MiB After Width: | Height: | Size: 3.7 MiB |
Binary file not shown.
Before Width: | Height: | Size: 3.8 MiB After Width: | Height: | Size: 3.8 MiB |
@ -60,6 +60,7 @@ typedef struct
|
|||||||
|
|
||||||
/* Function prototypes */
|
/* Function prototypes */
|
||||||
static void mapper_sega_w(uint32 data);
|
static void mapper_sega_w(uint32 data);
|
||||||
|
static void mapper_512k_w(uint32 address, uint32 data);
|
||||||
static void mapper_ssf2_w(uint32 address, uint32 data);
|
static void mapper_ssf2_w(uint32 address, uint32 data);
|
||||||
static void mapper_sf001_w(uint32 address, uint32 data);
|
static void mapper_sf001_w(uint32 address, uint32 data);
|
||||||
static void mapper_sf002_w(uint32 address, uint32 data);
|
static void mapper_sf002_w(uint32 address, uint32 data);
|
||||||
@ -568,7 +569,15 @@ void md_cart_init(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* detect specific mappers */
|
/* detect specific mappers */
|
||||||
if (strstr(rominfo.domestic,"SUPER STREET FIGHTER2"))
|
if (strstr(rominfo.consoletype,"SEGA SSF"))
|
||||||
|
{
|
||||||
|
/* Everdrive extended SSF mapper */
|
||||||
|
cart.hw.bankshift = 1;
|
||||||
|
|
||||||
|
/* specific !TIME handler */
|
||||||
|
cart.hw.time_w = mapper_512k_w;
|
||||||
|
}
|
||||||
|
else if (strstr(rominfo.domestic,"SUPER STREET FIGHTER2"))
|
||||||
{
|
{
|
||||||
/* SSF2 mapper */
|
/* SSF2 mapper */
|
||||||
cart.hw.bankshift = 1;
|
cart.hw.bankshift = 1;
|
||||||
@ -912,25 +921,38 @@ static void mapper_sega_w(uint32 data)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Everdrive extended SSF ROM bankswitch
|
||||||
|
documented by Krikzz (http://krikzz.com/pub/support/mega-ed/dev/extended_ssf.txt)
|
||||||
|
*/
|
||||||
|
static void mapper_512k_w(uint32 address, uint32 data)
|
||||||
|
{
|
||||||
|
uint32 i;
|
||||||
|
|
||||||
|
/* 512K ROM paging */
|
||||||
|
uint8 *src = cart.rom + (data << 19);
|
||||||
|
|
||||||
|
|
||||||
|
/* cartridge area ($000000-$3FFFFF) is divided into 8 x 512K banks */
|
||||||
|
address = (address << 2) & 0x38;
|
||||||
|
|
||||||
|
/* remap selected ROM page to selected bank */
|
||||||
|
for (i=0; i<8; i++)
|
||||||
|
{
|
||||||
|
m68k.memory_map[address++].base = src + (i<<16);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Super Street Fighter 2 ROM bankswitch
|
Super Street Fighter 2 ROM bankswitch
|
||||||
documented by Bart Trzynadlowski (http://www.trzy.org/files/ssf2.txt)
|
documented by Bart Trzynadlowski (http://emu-docs.org/Genesis/ssf2.txt)
|
||||||
*/
|
*/
|
||||||
static void mapper_ssf2_w(uint32 address, uint32 data)
|
static void mapper_ssf2_w(uint32 address, uint32 data)
|
||||||
{
|
{
|
||||||
/* 8 x 512k banks */
|
/* only banks 1-7 are remappable, bank 0 remains unchanged */
|
||||||
address = (address << 2) & 0x38;
|
|
||||||
|
|
||||||
/* bank 0 remains unchanged */
|
|
||||||
if (address)
|
if (address)
|
||||||
{
|
{
|
||||||
uint32 i;
|
mapper_512k_w(address, data);
|
||||||
uint8 *src = cart.rom + (data << 19);
|
|
||||||
|
|
||||||
for (i=0; i<8; i++)
|
|
||||||
{
|
|
||||||
m68k.memory_map[address++].base = src + (i<<16);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -258,6 +258,9 @@ static const rominfo_t game_list[] =
|
|||||||
{0xFAB6F52F, 0, 0, SYSTEM_MASTERTAP, MAPPER_NONE, SYSTEM_SMS2, REGION_USA}, /* BOom (v1.0) */
|
{0xFAB6F52F, 0, 0, SYSTEM_MASTERTAP, MAPPER_NONE, SYSTEM_SMS2, REGION_USA}, /* BOom (v1.0) */
|
||||||
{0x143AB50B, 0, 0, SYSTEM_MASTERTAP, MAPPER_NONE, SYSTEM_SMS2, REGION_USA}, /* BOom (v1.1) */
|
{0x143AB50B, 0, 0, SYSTEM_MASTERTAP, MAPPER_NONE, SYSTEM_SMS2, REGION_USA}, /* BOom (v1.1) */
|
||||||
|
|
||||||
|
/* games requiring Sega Graphic Board */
|
||||||
|
{0x276AA542, 0, 0, SYSTEM_GRAPHIC_BOARD, MAPPER_NONE, SYSTEM_SMS, REGION_USA}, /* Sega Graphic Board v2.0 Software (Prototype) */
|
||||||
|
|
||||||
/* games supporting YM2413 FM */
|
/* games supporting YM2413 FM */
|
||||||
{0x1C951F8E, 0, 1, SYSTEM_GAMEPAD, MAPPER_SEGA, SYSTEM_SMS2, REGION_USA}, /* After Burner */
|
{0x1C951F8E, 0, 1, SYSTEM_GAMEPAD, MAPPER_SEGA, SYSTEM_SMS2, REGION_USA}, /* After Burner */
|
||||||
{0xC13896D5, 0, 1, SYSTEM_GAMEPAD, MAPPER_SEGA, SYSTEM_SMS2, REGION_USA}, /* Alex Kidd: The Lost Stars */
|
{0xC13896D5, 0, 1, SYSTEM_GAMEPAD, MAPPER_SEGA, SYSTEM_SMS2, REGION_USA}, /* Alex Kidd: The Lost Stars */
|
||||||
@ -420,7 +423,7 @@ void sms_cart_init(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* auto-detect required peripherals */
|
/* auto-detect required peripherals */
|
||||||
input.system[0] = input.system[1] = game_list[i].peripheral;
|
input.system[0] = game_list[i].peripheral;
|
||||||
|
|
||||||
/* auto-detect 3D glasses support */
|
/* auto-detect 3D glasses support */
|
||||||
cart.special = game_list[i].g_3d;
|
cart.special = game_list[i].g_3d;
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
* Genesis Plus
|
* Genesis Plus
|
||||||
* CD drive processor & CD-DA fader
|
* CD drive processor & CD-DA fader
|
||||||
*
|
*
|
||||||
* Copyright (C) 2012-2013 Eke-Eke (Genesis Plus GX)
|
* Copyright (C) 2012-2014 Eke-Eke (Genesis Plus GX)
|
||||||
*
|
*
|
||||||
* Redistribution and use of this code or any derivative works are permitted
|
* Redistribution and use of this code or any derivative works are permitted
|
||||||
* provided that the following conditions are met:
|
* provided that the following conditions are met:
|
||||||
@ -150,9 +150,6 @@ static const char extensions[SUPPORTED_EXT][16] =
|
|||||||
" - %d.wav"
|
" - %d.wav"
|
||||||
};
|
};
|
||||||
|
|
||||||
static blip_t* blip[2];
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef USE_LIBTREMOR
|
#ifdef USE_LIBTREMOR
|
||||||
#ifdef DISABLE_MANY_OGG_OPEN_FILES
|
#ifdef DISABLE_MANY_OGG_OPEN_FILES
|
||||||
static void ogg_free(int i)
|
static void ogg_free(int i)
|
||||||
@ -172,14 +169,12 @@ static void ogg_free(int i)
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void cdd_init(blip_t* left, blip_t* right)
|
void cdd_init(int samplerate)
|
||||||
{
|
{
|
||||||
/* CD-DA is running by default at 44100 Hz */
|
/* CD-DA is running by default at 44100 Hz */
|
||||||
/* Audio stream is resampled to desired rate using Blip Buffer */
|
/* Audio stream is resampled to desired rate using Blip Buffer */
|
||||||
blip[0] = left;
|
blip_set_rates(snd.blips[2][0], 44100, samplerate);
|
||||||
blip[1] = right;
|
blip_set_rates(snd.blips[2][1], 44100, samplerate);
|
||||||
blip_set_rates(left, 44100, snd.sample_rate);
|
|
||||||
blip_set_rates(right, 44100, snd.sample_rate);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void cdd_reset(void)
|
void cdd_reset(void)
|
||||||
@ -953,7 +948,7 @@ void cdd_read_audio(unsigned int samples)
|
|||||||
int16 r = cdd.audio[1];
|
int16 r = cdd.audio[1];
|
||||||
|
|
||||||
/* get number of internal clocks (samples) needed */
|
/* get number of internal clocks (samples) needed */
|
||||||
samples = blip_clocks_needed(blip[0], samples);
|
samples = blip_clocks_needed(snd.blips[2][0], samples);
|
||||||
|
|
||||||
/* audio track playing ? */
|
/* audio track playing ? */
|
||||||
if (!scd.regs[0x36>>1].byte.h && cdd.toc.tracks[cdd.index].fd)
|
if (!scd.regs[0x36>>1].byte.h && cdd.toc.tracks[cdd.index].fd)
|
||||||
@ -996,13 +991,13 @@ void cdd_read_audio(unsigned int samples)
|
|||||||
delta = ((ptr[0] * mul) / 1024) - l;
|
delta = ((ptr[0] * mul) / 1024) - l;
|
||||||
ptr++;
|
ptr++;
|
||||||
l += delta;
|
l += delta;
|
||||||
blip_add_delta_fast(blip[0], i, delta);
|
blip_add_delta_fast(snd.blips[2][0], i, delta);
|
||||||
|
|
||||||
/* right channel */
|
/* right channel */
|
||||||
delta = ((ptr[0] * mul) / 1024) - r;
|
delta = ((ptr[0] * mul) / 1024) - r;
|
||||||
ptr++;
|
ptr++;
|
||||||
r += delta;
|
r += delta;
|
||||||
blip_add_delta_fast(blip[1], i, delta);
|
blip_add_delta_fast(snd.blips[2][1], i, delta);
|
||||||
|
|
||||||
/* update CD-DA fader volume (one step/sample) */
|
/* update CD-DA fader volume (one step/sample) */
|
||||||
if (curVol < endVol)
|
if (curVol < endVol)
|
||||||
@ -1048,7 +1043,7 @@ void cdd_read_audio(unsigned int samples)
|
|||||||
ptr += 2;
|
ptr += 2;
|
||||||
#endif
|
#endif
|
||||||
l += delta;
|
l += delta;
|
||||||
blip_add_delta_fast(blip[0], i, delta);
|
blip_add_delta_fast(snd.blips[2][0], i, delta);
|
||||||
|
|
||||||
/* right channel */
|
/* right channel */
|
||||||
#ifdef LSB_FIRST
|
#ifdef LSB_FIRST
|
||||||
@ -1059,7 +1054,7 @@ void cdd_read_audio(unsigned int samples)
|
|||||||
ptr += 2;
|
ptr += 2;
|
||||||
#endif
|
#endif
|
||||||
r += delta;
|
r += delta;
|
||||||
blip_add_delta_fast(blip[1], i, delta);
|
blip_add_delta_fast(snd.blips[2][1], i, delta);
|
||||||
|
|
||||||
/* update CD-DA fader volume (one step/sample) */
|
/* update CD-DA fader volume (one step/sample) */
|
||||||
if (curVol < endVol)
|
if (curVol < endVol)
|
||||||
@ -1090,8 +1085,8 @@ void cdd_read_audio(unsigned int samples)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* no audio output */
|
/* no audio output */
|
||||||
if (l) blip_add_delta_fast(blip[0], 0, -l);
|
if (l) blip_add_delta_fast(snd.blips[2][0], 0, -l);
|
||||||
if (r) blip_add_delta_fast(blip[1], 0, -r);
|
if (r) blip_add_delta_fast(snd.blips[2][1], 0, -r);
|
||||||
|
|
||||||
/* save audio output for next frame */
|
/* save audio output for next frame */
|
||||||
cdd.audio[0] = 0;
|
cdd.audio[0] = 0;
|
||||||
@ -1099,8 +1094,8 @@ void cdd_read_audio(unsigned int samples)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* end of Blip Buffer timeframe */
|
/* end of Blip Buffer timeframe */
|
||||||
blip_end_frame(blip[0], samples);
|
blip_end_frame(snd.blips[2][0], samples);
|
||||||
blip_end_frame(blip[1], samples);
|
blip_end_frame(snd.blips[2][1], samples);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
* Genesis Plus
|
* Genesis Plus
|
||||||
* CD drive processor & CD-DA fader
|
* CD drive processor & CD-DA fader
|
||||||
*
|
*
|
||||||
* Copyright (C) 2012-2013 Eke-Eke (Genesis Plus GX)
|
* Copyright (C) 2012-2014 Eke-Eke (Genesis Plus GX)
|
||||||
*
|
*
|
||||||
* Redistribution and use of this code or any derivative works are permitted
|
* Redistribution and use of this code or any derivative works are permitted
|
||||||
* provided that the following conditions are met:
|
* provided that the following conditions are met:
|
||||||
@ -98,7 +98,7 @@ typedef struct
|
|||||||
} cdd_t;
|
} cdd_t;
|
||||||
|
|
||||||
/* Function prototypes */
|
/* Function prototypes */
|
||||||
extern void cdd_init(blip_t* left, blip_t* right);
|
extern void cdd_init(int samplerate);
|
||||||
extern void cdd_reset(void);
|
extern void cdd_reset(void);
|
||||||
extern int cdd_context_save(uint8 *state);
|
extern int cdd_context_save(uint8 *state);
|
||||||
extern int cdd_context_load(uint8 *state);
|
extern int cdd_context_load(uint8 *state);
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
* Genesis Plus
|
* Genesis Plus
|
||||||
* PCM sound chip (315-5476A) (RF5C164 compatible)
|
* PCM sound chip (315-5476A) (RF5C164 compatible)
|
||||||
*
|
*
|
||||||
* Copyright (C) 2012 Eke-Eke (Genesis Plus GX)
|
* Copyright (C) 2012-2014 Eke-Eke (Genesis Plus GX)
|
||||||
*
|
*
|
||||||
* Redistribution and use of this code or any derivative works are permitted
|
* Redistribution and use of this code or any derivative works are permitted
|
||||||
* provided that the following conditions are met:
|
* provided that the following conditions are met:
|
||||||
@ -41,19 +41,12 @@
|
|||||||
|
|
||||||
#define pcm scd.pcm_hw
|
#define pcm scd.pcm_hw
|
||||||
|
|
||||||
static blip_t* blip[2];
|
void pcm_init(double clock, int samplerate)
|
||||||
|
|
||||||
void pcm_init(blip_t* left, blip_t* right)
|
|
||||||
{
|
{
|
||||||
/* number of SCD master clocks run per second */
|
/* PCM chip is running at original rate and is synchronized with SUB-CPU */
|
||||||
double mclk = snd.frame_rate ? (SCYCLES_PER_LINE * (vdp_pal ? 313 : 262) * snd.frame_rate) : SCD_CLOCK;
|
|
||||||
|
|
||||||
/* PCM chips is running at original rate and is synchronized with SUB-CPU */
|
|
||||||
/* Chip output is resampled to desired rate using Blip Buffer. */
|
/* Chip output is resampled to desired rate using Blip Buffer. */
|
||||||
blip[0] = left;
|
blip_set_rates(snd.blips[1][0], clock / PCM_SCYCLES_RATIO, samplerate);
|
||||||
blip[1] = right;
|
blip_set_rates(snd.blips[1][1], clock / PCM_SCYCLES_RATIO, samplerate);
|
||||||
blip_set_rates(left, mclk / PCM_SCYCLES_RATIO, snd.sample_rate);
|
|
||||||
blip_set_rates(right, mclk / PCM_SCYCLES_RATIO, snd.sample_rate);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void pcm_reset(void)
|
void pcm_reset(void)
|
||||||
@ -78,8 +71,8 @@ void pcm_reset(void)
|
|||||||
pcm.cycles = 0;
|
pcm.cycles = 0;
|
||||||
|
|
||||||
/* clear blip buffers */
|
/* clear blip buffers */
|
||||||
blip_clear(blip[0]);
|
blip_clear(snd.blips[1][0]);
|
||||||
blip_clear(blip[1]);
|
blip_clear(snd.blips[1][1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
int pcm_context_save(uint8 *state)
|
int pcm_context_save(uint8 *state)
|
||||||
@ -190,14 +183,14 @@ void pcm_run(unsigned int length)
|
|||||||
/* check if PCM left output changed */
|
/* check if PCM left output changed */
|
||||||
if (pcm.out[0] != l)
|
if (pcm.out[0] != l)
|
||||||
{
|
{
|
||||||
blip_add_delta_fast(blip[0], i, l-pcm.out[0]);
|
blip_add_delta_fast(snd.blips[1][0], i, l-pcm.out[0]);
|
||||||
pcm.out[0] = l;
|
pcm.out[0] = l;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check if PCM right output changed */
|
/* check if PCM right output changed */
|
||||||
if (pcm.out[1] != r)
|
if (pcm.out[1] != r)
|
||||||
{
|
{
|
||||||
blip_add_delta_fast(blip[1], i, r-pcm.out[1]);
|
blip_add_delta_fast(snd.blips[1][1], i, r-pcm.out[1]);
|
||||||
pcm.out[1] = r;
|
pcm.out[1] = r;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -207,21 +200,21 @@ void pcm_run(unsigned int length)
|
|||||||
/* check if PCM left output changed */
|
/* check if PCM left output changed */
|
||||||
if (pcm.out[0])
|
if (pcm.out[0])
|
||||||
{
|
{
|
||||||
blip_add_delta_fast(blip[0], 0, -pcm.out[0]);
|
blip_add_delta_fast(snd.blips[1][0], 0, -pcm.out[0]);
|
||||||
pcm.out[0] = 0;
|
pcm.out[0] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check if PCM right output changed */
|
/* check if PCM right output changed */
|
||||||
if (pcm.out[1])
|
if (pcm.out[1])
|
||||||
{
|
{
|
||||||
blip_add_delta_fast(blip[1], 0, -pcm.out[1]);
|
blip_add_delta_fast(snd.blips[1][1], 0, -pcm.out[1]);
|
||||||
pcm.out[1] = 0;
|
pcm.out[1] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* end of blip buffer frame */
|
/* end of blip buffer frame */
|
||||||
blip_end_frame(blip[0], length);
|
blip_end_frame(snd.blips[1][0], length);
|
||||||
blip_end_frame(blip[1], length);
|
blip_end_frame(snd.blips[1][1], length);
|
||||||
|
|
||||||
/* update PCM master clock counter */
|
/* update PCM master clock counter */
|
||||||
pcm.cycles += length * PCM_SCYCLES_RATIO;
|
pcm.cycles += length * PCM_SCYCLES_RATIO;
|
||||||
@ -230,7 +223,7 @@ void pcm_run(unsigned int length)
|
|||||||
void pcm_update(unsigned int samples)
|
void pcm_update(unsigned int samples)
|
||||||
{
|
{
|
||||||
/* get number of internal clocks (samples) needed */
|
/* get number of internal clocks (samples) needed */
|
||||||
unsigned int clocks = blip_clocks_needed(blip[0], samples);
|
unsigned int clocks = blip_clocks_needed(snd.blips[1][0], samples);
|
||||||
|
|
||||||
/* run PCM chip */
|
/* run PCM chip */
|
||||||
if (clocks > 0)
|
if (clocks > 0)
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
* Genesis Plus
|
* Genesis Plus
|
||||||
* PCM sound chip (315-5476A) (RF5C164 compatible)
|
* PCM sound chip (315-5476A) (RF5C164 compatible)
|
||||||
*
|
*
|
||||||
* Copyright (C) 2012 Eke-Eke (Genesis Plus GX)
|
* Copyright (C) 2012-2014 Eke-Eke (Genesis Plus GX)
|
||||||
*
|
*
|
||||||
* Redistribution and use of this code or any derivative works are permitted
|
* Redistribution and use of this code or any derivative works are permitted
|
||||||
* provided that the following conditions are met:
|
* provided that the following conditions are met:
|
||||||
@ -65,7 +65,7 @@ typedef struct
|
|||||||
} pcm_t;
|
} pcm_t;
|
||||||
|
|
||||||
/* Function prototypes */
|
/* Function prototypes */
|
||||||
extern void pcm_init(blip_t* left, blip_t* right);
|
extern void pcm_init(double clock, int rate);
|
||||||
extern void pcm_reset(void);
|
extern void pcm_reset(void);
|
||||||
extern int pcm_context_save(uint8 *state);
|
extern int pcm_context_save(uint8 *state);
|
||||||
extern int pcm_context_load(uint8 *state);
|
extern int pcm_context_load(uint8 *state);
|
||||||
|
111
core/input_hw/graphic_board.c
Normal file
111
core/input_hw/graphic_board.c
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
/***************************************************************************************
|
||||||
|
* Genesis Plus
|
||||||
|
* Sega Graphic Board support
|
||||||
|
*
|
||||||
|
* Copyright (C) 2014 Eke-Eke (Genesis Plus GX)
|
||||||
|
*
|
||||||
|
* Redistribution and use of this code or any derivative works are permitted
|
||||||
|
* provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* - Redistributions may not be sold, nor may they be used in a commercial
|
||||||
|
* product or activity.
|
||||||
|
*
|
||||||
|
* - Redistributions that are modified from the original source must include the
|
||||||
|
* complete source code, including the source code for all components used by a
|
||||||
|
* binary built from the modified sources. However, as a special exception, the
|
||||||
|
* source code distributed need not include anything that is normally distributed
|
||||||
|
* (in either source or binary form) with the major components (compiler, kernel,
|
||||||
|
* and so on) of the operating system on which the executable runs, unless that
|
||||||
|
* component itself accompanies the executable.
|
||||||
|
*
|
||||||
|
* - Redistributions must reproduce the above copyright notice, this list of
|
||||||
|
* conditions and the following disclaimer in the documentation and/or other
|
||||||
|
* materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
****************************************************************************************/
|
||||||
|
|
||||||
|
#include "shared.h"
|
||||||
|
|
||||||
|
static struct
|
||||||
|
{
|
||||||
|
uint8 State;
|
||||||
|
uint8 Counter;
|
||||||
|
uint8 Port;
|
||||||
|
} board;
|
||||||
|
|
||||||
|
void graphic_board_reset(int port)
|
||||||
|
{
|
||||||
|
input.analog[0][0] = 128;
|
||||||
|
input.analog[0][1] = 128;
|
||||||
|
board.State = 0x7f;
|
||||||
|
board.Counter = 0;
|
||||||
|
board.Port = port;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char graphic_board_read(void)
|
||||||
|
{
|
||||||
|
uint8 data;
|
||||||
|
|
||||||
|
if (board.State & 0x20)
|
||||||
|
{
|
||||||
|
return 0x60;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (board.Counter & 7)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
data = ~input.pad[board.Port];
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
data = 0x0f;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
data = 0x0f;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
data = input.analog[board.Port][0] >> 4;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
data = input.analog[board.Port][0];
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
data = input.analog[board.Port][1] >> 4;
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
data = input.analog[board.Port][1];
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
data = 0x0f;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (board.State & ~0x1f) | (data & 0x0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void graphic_board_write(unsigned char data, unsigned char mask)
|
||||||
|
{
|
||||||
|
data = (board.State & ~mask) | (data & mask);
|
||||||
|
|
||||||
|
if ((data ^ board.State) & 0x20)
|
||||||
|
{
|
||||||
|
board.Counter = 0;
|
||||||
|
}
|
||||||
|
else if ((data ^ board.State) & 0x40)
|
||||||
|
{
|
||||||
|
board.Counter++;
|
||||||
|
}
|
||||||
|
|
||||||
|
board.State = data;
|
||||||
|
}
|
47
core/input_hw/graphic_board.h
Normal file
47
core/input_hw/graphic_board.h
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
/***************************************************************************************
|
||||||
|
* Genesis Plus
|
||||||
|
* Sega Graphic board support
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017 Eke-Eke (Genesis Plus GX)
|
||||||
|
*
|
||||||
|
* Redistribution and use of this code or any derivative works are permitted
|
||||||
|
* provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* - Redistributions may not be sold, nor may they be used in a commercial
|
||||||
|
* product or activity.
|
||||||
|
*
|
||||||
|
* - Redistributions that are modified from the original source must include the
|
||||||
|
* complete source code, including the source code for all components used by a
|
||||||
|
* binary built from the modified sources. However, as a special exception, the
|
||||||
|
* source code distributed need not include anything that is normally distributed
|
||||||
|
* (in either source or binary form) with the major components (compiler, kernel,
|
||||||
|
* and so on) of the operating system on which the executable runs, unless that
|
||||||
|
* component itself accompanies the executable.
|
||||||
|
*
|
||||||
|
* - Redistributions must reproduce the above copyright notice, this list of
|
||||||
|
* conditions and the following disclaimer in the documentation and/or other
|
||||||
|
* materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
****************************************************************************************/
|
||||||
|
|
||||||
|
#ifndef _GRAPHIC_H_
|
||||||
|
#define _GRAPHIC_H_
|
||||||
|
|
||||||
|
/* Function prototypes */
|
||||||
|
extern void graphic_board_reset(int port);
|
||||||
|
extern unsigned char graphic_board_read(void);
|
||||||
|
extern void graphic_board_write(unsigned char data, unsigned char mask);
|
||||||
|
|
||||||
|
#endif
|
@ -47,6 +47,7 @@
|
|||||||
#include "paddle.h"
|
#include "paddle.h"
|
||||||
#include "sportspad.h"
|
#include "sportspad.h"
|
||||||
#include "terebi_oekaki.h"
|
#include "terebi_oekaki.h"
|
||||||
|
#include "graphic_board.h"
|
||||||
|
|
||||||
t_input input;
|
t_input input;
|
||||||
int old_system[2] = {-1,-1};
|
int old_system[2] = {-1,-1};
|
||||||
@ -203,6 +204,13 @@ void input_init(void)
|
|||||||
player++;
|
player++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case SYSTEM_GRAPHIC_BOARD:
|
||||||
|
{
|
||||||
|
input.dev[0] = DEVICE_GRAPHIC_BOARD;
|
||||||
|
player++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (player == MAX_INPUTS)
|
if (player == MAX_INPUTS)
|
||||||
@ -322,6 +330,13 @@ void input_init(void)
|
|||||||
player++;
|
player++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case SYSTEM_GRAPHIC_BOARD:
|
||||||
|
{
|
||||||
|
input.dev[4] = DEVICE_GRAPHIC_BOARD;
|
||||||
|
player++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* J-CART */
|
/* J-CART */
|
||||||
@ -405,6 +420,12 @@ void input_reset(void)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case DEVICE_GRAPHIC_BOARD:
|
||||||
|
{
|
||||||
|
graphic_board_reset(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
|
@ -44,33 +44,35 @@
|
|||||||
#define MAX_DEVICES (8)
|
#define MAX_DEVICES (8)
|
||||||
|
|
||||||
/* Ports configuration */
|
/* Ports configuration */
|
||||||
#define NO_SYSTEM (0) /* unconnected port*/
|
#define NO_SYSTEM (0) /* unconnected port*/
|
||||||
#define SYSTEM_GAMEPAD (1) /* 2-buttons, 3-buttons or 6-buttons Control Pad */
|
#define SYSTEM_GAMEPAD (1) /* 2-buttons, 3-buttons or 6-buttons Control Pad */
|
||||||
#define SYSTEM_MOUSE (2) /* Sega Mouse (only supported in either port A or port B) */
|
#define SYSTEM_MOUSE (2) /* Sega Mouse (only supported in either port A or port B) */
|
||||||
#define SYSTEM_MENACER (3) /* Sega Menacer (only supported in port B) */
|
#define SYSTEM_MENACER (3) /* Sega Menacer (only supported in port B) */
|
||||||
#define SYSTEM_JUSTIFIER (4) /* Konami Justifiers (only supported in port B) */
|
#define SYSTEM_JUSTIFIER (4) /* Konami Justifiers (only supported in port B) */
|
||||||
#define SYSTEM_XE_1AP (5) /* XE-1AP analog controller */
|
#define SYSTEM_XE_1AP (5) /* XE-1AP analog controller */
|
||||||
#define SYSTEM_ACTIVATOR (6) /* Sega Activator */
|
#define SYSTEM_ACTIVATOR (6) /* Sega Activator */
|
||||||
#define SYSTEM_LIGHTPHASER (7) /* Sega Light Phaser */
|
#define SYSTEM_LIGHTPHASER (7) /* Sega Light Phaser */
|
||||||
#define SYSTEM_PADDLE (8) /* Sega Paddle Control */
|
#define SYSTEM_PADDLE (8) /* Sega Paddle Control */
|
||||||
#define SYSTEM_SPORTSPAD (9) /* Sega Sports Pad */
|
#define SYSTEM_SPORTSPAD (9) /* Sega Sports Pad */
|
||||||
#define SYSTEM_MASTERTAP (10) /* Multi Tap -- Furrtek's Master Tap (unofficial) */
|
#define SYSTEM_GRAPHIC_BOARD (10) /* Sega Graphic Board */
|
||||||
#define SYSTEM_TEAMPLAYER (11) /* Multi Tap -- Sega TeamPlayer */
|
#define SYSTEM_MASTERTAP (11) /* Multi Tap -- Furrtek's Master Tap (unofficial) */
|
||||||
#define SYSTEM_WAYPLAY (12) /* Multi Tap -- EA 4-Way Play (use both ports) */
|
#define SYSTEM_TEAMPLAYER (12) /* Multi Tap -- Sega TeamPlayer */
|
||||||
|
#define SYSTEM_WAYPLAY (13) /* Multi Tap -- EA 4-Way Play (use both ports) */
|
||||||
|
|
||||||
/* Device type */
|
/* Device type */
|
||||||
#define NO_DEVICE (0xff) /* unconnected device (fixed ID for Team Player) */
|
#define NO_DEVICE (0xff) /* unconnected device (fixed ID for Team Player) */
|
||||||
#define DEVICE_PAD3B (0x00) /* 3-buttons Control Pad (fixed ID for Team Player)*/
|
#define DEVICE_PAD3B (0x00) /* 3-buttons Control Pad (fixed ID for Team Player)*/
|
||||||
#define DEVICE_PAD6B (0x01) /* 6-buttons Control Pad (fixed ID for Team Player) */
|
#define DEVICE_PAD6B (0x01) /* 6-buttons Control Pad (fixed ID for Team Player) */
|
||||||
#define DEVICE_PAD2B (0x02) /* 2-buttons Control Pad */
|
#define DEVICE_PAD2B (0x02) /* 2-buttons Control Pad */
|
||||||
#define DEVICE_MOUSE (0x03) /* Sega Mouse */
|
#define DEVICE_MOUSE (0x03) /* Sega Mouse */
|
||||||
#define DEVICE_LIGHTGUN (0x04) /* Sega Light Phaser, Menacer or Konami Justifiers */
|
#define DEVICE_LIGHTGUN (0x04) /* Sega Light Phaser, Menacer or Konami Justifiers */
|
||||||
#define DEVICE_PADDLE (0x05) /* Sega Paddle Control */
|
#define DEVICE_PADDLE (0x05) /* Sega Paddle Control */
|
||||||
#define DEVICE_SPORTSPAD (0x06) /* Sega Sports Pad */
|
#define DEVICE_SPORTSPAD (0x06) /* Sega Sports Pad */
|
||||||
#define DEVICE_PICO (0x07) /* PICO tablet */
|
#define DEVICE_GRAPHIC_BOARD (0x07) /* Sega Graphic Board */
|
||||||
#define DEVICE_TEREBI (0x08) /* Terebi Oekaki tablet */
|
#define DEVICE_PICO (0x08) /* PICO tablet */
|
||||||
#define DEVICE_XE_1AP (0x09) /* XE-1AP analog controller */
|
#define DEVICE_TEREBI (0x09) /* Terebi Oekaki tablet */
|
||||||
#define DEVICE_ACTIVATOR (0x0a) /* Activator */
|
#define DEVICE_XE_1AP (0x0a) /* XE-1AP analog controller */
|
||||||
|
#define DEVICE_ACTIVATOR (0x0b) /* Activator */
|
||||||
|
|
||||||
/* Default Input bitmasks */
|
/* Default Input bitmasks */
|
||||||
#define INPUT_MODE (0x0800)
|
#define INPUT_MODE (0x0800)
|
||||||
@ -127,6 +129,11 @@
|
|||||||
#define INPUT_ACTIVATOR_1U (0x0002)
|
#define INPUT_ACTIVATOR_1U (0x0002)
|
||||||
#define INPUT_ACTIVATOR_1L (0x0001)
|
#define INPUT_ACTIVATOR_1L (0x0001)
|
||||||
|
|
||||||
|
/* Graphic Board specific bitmasks */
|
||||||
|
#define INPUT_GRAPHIC_PEN (0x0004)
|
||||||
|
#define INPUT_GRAPHIC_DO (0x0002)
|
||||||
|
#define INPUT_GRAPHIC_MENU (0x0001)
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
uint8 system[2]; /* can be one of the SYSTEM_* values */
|
uint8 system[2]; /* can be one of the SYSTEM_* values */
|
||||||
|
@ -48,6 +48,7 @@
|
|||||||
#include "teamplayer.h"
|
#include "teamplayer.h"
|
||||||
#include "paddle.h"
|
#include "paddle.h"
|
||||||
#include "sportspad.h"
|
#include "sportspad.h"
|
||||||
|
#include "graphic_board.h"
|
||||||
|
|
||||||
uint8 io_reg[0x10];
|
uint8 io_reg[0x10];
|
||||||
|
|
||||||
@ -150,6 +151,13 @@ void io_init(void)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case SYSTEM_GRAPHIC_BOARD:
|
||||||
|
{
|
||||||
|
port[0].data_w = graphic_board_write;
|
||||||
|
port[0].data_r = graphic_board_read;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
port[0].data_w = dummy_write;
|
port[0].data_w = dummy_write;
|
||||||
@ -244,6 +252,13 @@ void io_init(void)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case SYSTEM_GRAPHIC_BOARD:
|
||||||
|
{
|
||||||
|
port[1].data_w = graphic_board_write;
|
||||||
|
port[1].data_r = graphic_board_read;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
port[1].data_w = dummy_write;
|
port[1].data_w = dummy_write;
|
||||||
|
@ -94,14 +94,9 @@ static const uint16 PSGVolumeValues[16] =
|
|||||||
|
|
||||||
static SN76489_Context SN76489;
|
static SN76489_Context SN76489;
|
||||||
|
|
||||||
static blip_t* blip[2];
|
void SN76489_Init(int type)
|
||||||
|
|
||||||
void SN76489_Init(blip_t* left, blip_t* right, int type)
|
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
blip[0] = left;
|
|
||||||
blip[1] = right;
|
|
||||||
|
|
||||||
for (i=0; i<4; i++)
|
for (i=0; i<4; i++)
|
||||||
{
|
{
|
||||||
@ -177,7 +172,7 @@ INLINE void UpdateToneAmplitude(int i, int time)
|
|||||||
if (delta != 0)
|
if (delta != 0)
|
||||||
{
|
{
|
||||||
SN76489.ChanOut[i][0] += delta;
|
SN76489.ChanOut[i][0] += delta;
|
||||||
blip_add_delta_fast(blip[0], time, delta);
|
blip_add_delta_fast(snd.blips[0][0], time, delta);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* right output */
|
/* right output */
|
||||||
@ -185,7 +180,7 @@ INLINE void UpdateToneAmplitude(int i, int time)
|
|||||||
if (delta != 0)
|
if (delta != 0)
|
||||||
{
|
{
|
||||||
SN76489.ChanOut[i][1] += delta;
|
SN76489.ChanOut[i][1] += delta;
|
||||||
blip_add_delta_fast(blip[1], time, delta);
|
blip_add_delta_fast(snd.blips[0][1], time, delta);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -199,7 +194,7 @@ INLINE void UpdateNoiseAmplitude(int time)
|
|||||||
if (delta != 0)
|
if (delta != 0)
|
||||||
{
|
{
|
||||||
SN76489.ChanOut[3][0] += delta;
|
SN76489.ChanOut[3][0] += delta;
|
||||||
blip_add_delta_fast(blip[0], time, delta);
|
blip_add_delta_fast(snd.blips[0][0], time, delta);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* right output */
|
/* right output */
|
||||||
@ -207,7 +202,7 @@ INLINE void UpdateNoiseAmplitude(int time)
|
|||||||
if (delta != 0)
|
if (delta != 0)
|
||||||
{
|
{
|
||||||
SN76489.ChanOut[3][1] += delta;
|
SN76489.ChanOut[3][1] += delta;
|
||||||
blip_add_delta_fast(blip[1], time, delta);
|
blip_add_delta_fast(snd.blips[0][1], time, delta);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
#define SN_INTEGRATED 1
|
#define SN_INTEGRATED 1
|
||||||
|
|
||||||
/* Function prototypes */
|
/* Function prototypes */
|
||||||
extern void SN76489_Init(blip_t* left, blip_t* right, int type);
|
extern void SN76489_Init(int type);
|
||||||
extern void SN76489_Reset(void);
|
extern void SN76489_Reset(void);
|
||||||
extern void SN76489_Config(unsigned int clocks, int preAmp, int boostNoise, int stereo);
|
extern void SN76489_Config(unsigned int clocks, int preAmp, int boostNoise, int stereo);
|
||||||
extern void SN76489_Write(unsigned int clocks, unsigned int data);
|
extern void SN76489_Write(unsigned int clocks, unsigned int data);
|
||||||
|
@ -102,6 +102,7 @@ void sound_init( void )
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Initialize PSG chip */
|
/* Initialize PSG chip */
|
||||||
|
SN76489_Init((system_hw == SYSTEM_SG) ? SN_DISCRETE : SN_INTEGRATED);
|
||||||
SN76489_Config(0, config.psg_preamp, config.psgBoostNoise, 0xff);
|
SN76489_Config(0, config.psg_preamp, config.psgBoostNoise, 0xff);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,12 +116,10 @@ int state_load(unsigned char *state)
|
|||||||
bufferptr += sound_context_load(&state[bufferptr]);
|
bufferptr += sound_context_load(&state[bufferptr]);
|
||||||
if ((system_hw & SYSTEM_PBC) == SYSTEM_MD)
|
if ((system_hw & SYSTEM_PBC) == SYSTEM_MD)
|
||||||
{
|
{
|
||||||
SN76489_Init(snd.blips[0][0], snd.blips[0][1], SN_INTEGRATED);
|
|
||||||
SN76489_Config(0, config.psg_preamp, config.psgBoostNoise, 0xff);
|
SN76489_Config(0, config.psg_preamp, config.psgBoostNoise, 0xff);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
SN76489_Init(snd.blips[0][0], snd.blips[0][1], (system_hw == SYSTEM_SG) ? SN_DISCRETE : SN_INTEGRATED);
|
|
||||||
SN76489_Config(0, config.psg_preamp, config.psgBoostNoise, io_reg[6]);
|
SN76489_Config(0, config.psg_preamp, config.psgBoostNoise, io_reg[6]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,6 +60,50 @@ static int16 llp,rrp;
|
|||||||
/******************************************************************************************/
|
/******************************************************************************************/
|
||||||
|
|
||||||
int audio_init(int samplerate, double framerate)
|
int audio_init(int samplerate, double framerate)
|
||||||
|
{
|
||||||
|
/* Shutdown first */
|
||||||
|
audio_shutdown();
|
||||||
|
|
||||||
|
/* Clear the sound data context */
|
||||||
|
memset(&snd, 0, sizeof (snd));
|
||||||
|
|
||||||
|
/* Initialize Blip Buffers */
|
||||||
|
snd.blips[0][0] = blip_new(samplerate / 10);
|
||||||
|
snd.blips[0][1] = blip_new(samplerate / 10);
|
||||||
|
if (!snd.blips[0][0] || !snd.blips[0][1])
|
||||||
|
{
|
||||||
|
audio_shutdown();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mega CD sound hardware */
|
||||||
|
if (system_hw == SYSTEM_MCD)
|
||||||
|
{
|
||||||
|
/* allocate blip buffers */
|
||||||
|
snd.blips[1][0] = blip_new(samplerate / 10);
|
||||||
|
snd.blips[1][1] = blip_new(samplerate / 10);
|
||||||
|
snd.blips[2][0] = blip_new(samplerate / 10);
|
||||||
|
snd.blips[2][1] = blip_new(samplerate / 10);
|
||||||
|
if (!snd.blips[1][0] || !snd.blips[1][1] || !snd.blips[2][0] || !snd.blips[2][1])
|
||||||
|
{
|
||||||
|
audio_shutdown();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize resampler internal rates */
|
||||||
|
audio_set_rate(samplerate, framerate);
|
||||||
|
|
||||||
|
/* Set audio enable flag */
|
||||||
|
snd.enabled = 1;
|
||||||
|
|
||||||
|
/* Reset audio */
|
||||||
|
audio_reset();
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void audio_set_rate(int samplerate, double framerate)
|
||||||
{
|
{
|
||||||
/* Number of M-cycles executed per second. */
|
/* Number of M-cycles executed per second. */
|
||||||
/* All emulated chips are kept in sync by using a common oscillator (MCLOCK) */
|
/* All emulated chips are kept in sync by using a common oscillator (MCLOCK) */
|
||||||
@ -84,25 +128,6 @@ int audio_init(int samplerate, double framerate)
|
|||||||
/* */
|
/* */
|
||||||
double mclk = framerate ? (MCYCLES_PER_LINE * (vdp_pal ? 313 : 262) * framerate) : system_clock;
|
double mclk = framerate ? (MCYCLES_PER_LINE * (vdp_pal ? 313 : 262) * framerate) : system_clock;
|
||||||
|
|
||||||
/* Shutdown first */
|
|
||||||
audio_shutdown();
|
|
||||||
|
|
||||||
/* Clear the sound data context */
|
|
||||||
memset(&snd, 0, sizeof (snd));
|
|
||||||
|
|
||||||
/* Initialize audio rates */
|
|
||||||
snd.sample_rate = samplerate;
|
|
||||||
snd.frame_rate = framerate;
|
|
||||||
|
|
||||||
/* Initialize Blip Buffers */
|
|
||||||
snd.blips[0][0] = blip_new(samplerate / 10);
|
|
||||||
snd.blips[0][1] = blip_new(samplerate / 10);
|
|
||||||
if (!snd.blips[0][0] || !snd.blips[0][1])
|
|
||||||
{
|
|
||||||
audio_shutdown();
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* For maximal accuracy, sound chips are running at their original rate using common */
|
/* For maximal accuracy, sound chips are running at their original rate using common */
|
||||||
/* master clock timebase so they remain perfectly synchronized together, while still */
|
/* master clock timebase so they remain perfectly synchronized together, while still */
|
||||||
/* being synchronized with 68K and Z80 CPUs as well. Mixed sound chip output is then */
|
/* being synchronized with 68K and Z80 CPUs as well. Mixed sound chip output is then */
|
||||||
@ -110,37 +135,22 @@ int audio_init(int samplerate, double framerate)
|
|||||||
blip_set_rates(snd.blips[0][0], mclk, samplerate);
|
blip_set_rates(snd.blips[0][0], mclk, samplerate);
|
||||||
blip_set_rates(snd.blips[0][1], mclk, samplerate);
|
blip_set_rates(snd.blips[0][1], mclk, samplerate);
|
||||||
|
|
||||||
/* Initialize PSG core */
|
|
||||||
SN76489_Init(snd.blips[0][0], snd.blips[0][1], (system_hw == SYSTEM_SG) ? SN_DISCRETE : SN_INTEGRATED);
|
|
||||||
|
|
||||||
/* Mega CD sound hardware */
|
/* Mega CD sound hardware */
|
||||||
if (system_hw == SYSTEM_MCD)
|
if (system_hw == SYSTEM_MCD)
|
||||||
{
|
{
|
||||||
/* allocate blip buffers */
|
/* number of SCD master clocks run per second */
|
||||||
snd.blips[1][0] = blip_new(samplerate / 10);
|
mclk = framerate ? (SCYCLES_PER_LINE * (vdp_pal ? 313 : 262) * framerate) : SCD_CLOCK;
|
||||||
snd.blips[1][1] = blip_new(samplerate / 10);
|
|
||||||
snd.blips[2][0] = blip_new(samplerate / 10);
|
|
||||||
snd.blips[2][1] = blip_new(samplerate / 10);
|
|
||||||
if (!snd.blips[1][0] || !snd.blips[1][1] || !snd.blips[2][0] || !snd.blips[2][1])
|
|
||||||
{
|
|
||||||
audio_shutdown();
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Initialize PCM core */
|
/* PCM core */
|
||||||
pcm_init(snd.blips[1][0], snd.blips[1][1]);
|
pcm_init(mclk, samplerate);
|
||||||
|
|
||||||
/* Initialize CDD core */
|
/* CDD core */
|
||||||
cdd_init(snd.blips[2][0], snd.blips[2][1]);
|
cdd_init(samplerate);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set audio enable flag */
|
/* Reinitialize internal rates */
|
||||||
snd.enabled = 1;
|
snd.sample_rate = samplerate;
|
||||||
|
snd.frame_rate = framerate;
|
||||||
/* Reset audio */
|
|
||||||
audio_reset();
|
|
||||||
|
|
||||||
return (0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void audio_reset(void)
|
void audio_reset(void)
|
||||||
|
@ -106,6 +106,7 @@ extern uint32 system_clock;
|
|||||||
|
|
||||||
/* Function prototypes */
|
/* Function prototypes */
|
||||||
extern int audio_init(int samplerate, double framerate);
|
extern int audio_init(int samplerate, double framerate);
|
||||||
|
extern void audio_set_rate(int samplerate, double framerate);
|
||||||
extern void audio_reset(void);
|
extern void audio_reset(void);
|
||||||
extern void audio_shutdown(void);
|
extern void audio_shutdown(void);
|
||||||
extern int audio_update(int16 *buffer);
|
extern int audio_update(int16 *buffer);
|
||||||
|
@ -214,7 +214,7 @@ static void selector_cb(void)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (FONT_write(text,18,dir_icon.x,yoffset+22,bar_over.w-20,(GXColor)WHITE))
|
if (FONT_write(text,18,26,yoffset+22,bar_over.w-20,(GXColor)WHITE))
|
||||||
{
|
{
|
||||||
/* text scrolling */
|
/* text scrolling */
|
||||||
string_offset ++;
|
string_offset ++;
|
||||||
@ -231,7 +231,7 @@ static void selector_cb(void)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
FONT_write(filelist[i].filename,18,dir_icon.x,yoffset+22,bar_over.w-20,(GXColor)WHITE);
|
FONT_write(filelist[i].filename,18,26,yoffset+22,bar_over.w-20,(GXColor)WHITE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,6 +109,7 @@ extern const u8 Ctrl_sportspad_png[];
|
|||||||
extern const u8 Ctrl_none_png[];
|
extern const u8 Ctrl_none_png[];
|
||||||
extern const u8 Ctrl_teamplayer_png[];
|
extern const u8 Ctrl_teamplayer_png[];
|
||||||
extern const u8 Ctrl_mastertap_png[];
|
extern const u8 Ctrl_mastertap_png[];
|
||||||
|
extern const u8 Ctrl_graphic_board_png[];
|
||||||
extern const u8 Ctrl_pad_auto_png[];
|
extern const u8 Ctrl_pad_auto_png[];
|
||||||
extern const u8 Ctrl_pad2b_png[];
|
extern const u8 Ctrl_pad2b_png[];
|
||||||
extern const u8 Ctrl_pad3b_png[];
|
extern const u8 Ctrl_pad3b_png[];
|
||||||
@ -2205,37 +2206,39 @@ static void ctrlmenu(void)
|
|||||||
u32 exp, index = 0;
|
u32 exp, index = 0;
|
||||||
|
|
||||||
/* System devices */
|
/* System devices */
|
||||||
gui_item items_sys[2][13] =
|
gui_item items_sys[2][14] =
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
{NULL,Ctrl_none_png ,"","Select Port 1 device",110,130,48,72},
|
{NULL,Ctrl_none_png ,"","Select Port 1 device",110,130,48,72},
|
||||||
{NULL,Ctrl_gamepad_png ,"","Select Port 1 device",100,109,68,92},
|
{NULL,Ctrl_gamepad_png ,"","Select Port 1 device",100,109,68,92},
|
||||||
{NULL,Ctrl_mouse_png ,"","Select Port 1 device", 97,113,64,88},
|
{NULL,Ctrl_mouse_png ,"","Select Port 1 device", 97,113,64,88},
|
||||||
{NULL,Ctrl_menacer_png ,"","Select Port 1 device", 94,113,80,88},
|
{NULL,Ctrl_menacer_png ,"","Select Port 1 device", 94,113,80,88},
|
||||||
{NULL,Ctrl_justifiers_png ,"","Select Port 1 device", 88,117,80,84},
|
{NULL,Ctrl_justifiers_png ,"","Select Port 1 device", 88,117,80,84},
|
||||||
{NULL,Ctrl_xe_1ap_png ,"","Select Port 1 device", 98,118,72,84},
|
{NULL,Ctrl_xe_1ap_png ,"","Select Port 1 device", 98,118,72,84},
|
||||||
{NULL,Ctrl_activator_png ,"","Select Port 1 device", 94,121,72,80},
|
{NULL,Ctrl_activator_png ,"","Select Port 1 device", 94,121,72,80},
|
||||||
{NULL,Ctrl_lightphaser_png,"","Select Port 1 device", 89,109,88,92},
|
{NULL,Ctrl_lightphaser_png ,"","Select Port 1 device", 89,109,88,92},
|
||||||
{NULL,Ctrl_paddle_png ,"","Select Port 1 device", 86,117,96,84},
|
{NULL,Ctrl_paddle_png ,"","Select Port 1 device", 86,117,96,84},
|
||||||
{NULL,Ctrl_sportspad_png ,"","Select Port 1 device", 95,117,76,84},
|
{NULL,Ctrl_sportspad_png ,"","Select Port 1 device", 95,117,76,84},
|
||||||
{NULL,Ctrl_mastertap_png ,"","Select Port 1 device", 96,104,76,96},
|
{NULL,Ctrl_graphic_board_png ,"","Select Port 1 device", 90,105,88,96},
|
||||||
{NULL,Ctrl_teamplayer_png ,"","Select Port 1 device", 94,109,80,92},
|
{NULL,Ctrl_mastertap_png ,"","Select Port 1 device", 96,104,76,96},
|
||||||
{NULL,Ctrl_4wayplay_png ,"","Select Port 1 device", 98,110,72,92}
|
{NULL,Ctrl_teamplayer_png ,"","Select Port 1 device", 94,109,80,92},
|
||||||
|
{NULL,Ctrl_4wayplay_png ,"","Select Port 1 device", 98,110,72,92}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
{NULL,Ctrl_none_png ,"","Select Port 2 device",110,300,48,72},
|
{NULL,Ctrl_none_png ,"","Select Port 2 device",110,300,48,72},
|
||||||
{NULL,Ctrl_gamepad_png ,"","Select Port 2 device",100,279,68,92},
|
{NULL,Ctrl_gamepad_png ,"","Select Port 2 device",100,279,68,92},
|
||||||
{NULL,Ctrl_mouse_png ,"","Select Port 2 device", 97,283,64,88},
|
{NULL,Ctrl_mouse_png ,"","Select Port 2 device", 97,283,64,88},
|
||||||
{NULL,Ctrl_menacer_png ,"","Select Port 2 device", 94,283,80,88},
|
{NULL,Ctrl_menacer_png ,"","Select Port 2 device", 94,283,80,88},
|
||||||
{NULL,Ctrl_justifiers_png ,"","Select Port 2 device", 88,287,80,84},
|
{NULL,Ctrl_justifiers_png ,"","Select Port 2 device", 88,287,80,84},
|
||||||
{NULL,Ctrl_xe_1ap_png ,"","Select Port 2 device", 98,288,72,84},
|
{NULL,Ctrl_xe_1ap_png ,"","Select Port 2 device", 98,288,72,84},
|
||||||
{NULL,Ctrl_activator_png ,"","Select Port 2 device", 94,291,72,80},
|
{NULL,Ctrl_activator_png ,"","Select Port 2 device", 94,291,72,80},
|
||||||
{NULL,Ctrl_lightphaser_png,"","Select Port 2 device", 89,279,88,92},
|
{NULL,Ctrl_lightphaser_png ,"","Select Port 2 device", 89,279,88,92},
|
||||||
{NULL,Ctrl_paddle_png ,"","Select Port 2 device", 86,287,96,84},
|
{NULL,Ctrl_paddle_png ,"","Select Port 2 device", 86,287,96,84},
|
||||||
{NULL,Ctrl_sportspad_png ,"","Select Port 2 device", 95,287,76,84},
|
{NULL,Ctrl_sportspad_png ,"","Select Port 2 device", 95,287,76,84},
|
||||||
{NULL,Ctrl_mastertap_png ,"","Select Port 1 device", 96,274,76,96},
|
{NULL,Ctrl_graphic_board_png ,"","Select Port 2 device", 90,275,88,96},
|
||||||
{NULL,Ctrl_teamplayer_png ,"","Select Port 2 device", 94,279,80,92},
|
{NULL,Ctrl_mastertap_png ,"","Select Port 1 device", 96,274,76,96},
|
||||||
{NULL,Ctrl_4wayplay_png ,"","Select Port 2 device", 98,280,72,92}
|
{NULL,Ctrl_teamplayer_png ,"","Select Port 2 device", 94,279,80,92},
|
||||||
|
{NULL,Ctrl_4wayplay_png ,"","Select Port 2 device", 98,280,72,92}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -2300,7 +2303,7 @@ static void ctrlmenu(void)
|
|||||||
button_player_none_data.texture[0] = gxTextureOpenPNG(button_player_none_data.image[0],0);
|
button_player_none_data.texture[0] = gxTextureOpenPNG(button_player_none_data.image[0],0);
|
||||||
|
|
||||||
/* initialize custom images */
|
/* initialize custom images */
|
||||||
for (i=0; i<13; i++)
|
for (i=0; i<14; i++)
|
||||||
{
|
{
|
||||||
items_sys[1][i].texture = items_sys[0][i].texture = gxTextureOpenPNG(items_sys[0][i].data,0);
|
items_sys[1][i].texture = items_sys[0][i].texture = gxTextureOpenPNG(items_sys[0][i].data,0);
|
||||||
}
|
}
|
||||||
@ -2378,6 +2381,12 @@ static void ctrlmenu(void)
|
|||||||
input.system[0]++;
|
input.system[0]++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* allow only one connected graphic board */
|
||||||
|
if ((input.system[0] == SYSTEM_GRAPHIC_BOARD) && (input.system[1] == SYSTEM_GRAPHIC_BOARD))
|
||||||
|
{
|
||||||
|
input.system[0]++;
|
||||||
|
}
|
||||||
|
|
||||||
/* 4-wayplay uses both ports */
|
/* 4-wayplay uses both ports */
|
||||||
if (input.system[0] == SYSTEM_WAYPLAY)
|
if (input.system[0] == SYSTEM_WAYPLAY)
|
||||||
{
|
{
|
||||||
@ -2471,6 +2480,12 @@ static void ctrlmenu(void)
|
|||||||
input.system[1]++;
|
input.system[1]++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* allow only one connected graphic board */
|
||||||
|
if ((input.system[0] == SYSTEM_GRAPHIC_BOARD) && (input.system[1] == SYSTEM_GRAPHIC_BOARD))
|
||||||
|
{
|
||||||
|
input.system[1]++;
|
||||||
|
}
|
||||||
|
|
||||||
/* 4-wayplay uses both ports */
|
/* 4-wayplay uses both ports */
|
||||||
if (input.system[1] == SYSTEM_WAYPLAY)
|
if (input.system[1] == SYSTEM_WAYPLAY)
|
||||||
{
|
{
|
||||||
@ -2852,7 +2867,7 @@ static void ctrlmenu(void)
|
|||||||
if (config.input[player].device >= 0)
|
if (config.input[player].device >= 0)
|
||||||
{
|
{
|
||||||
GUI_MsgBoxOpen("Keys Configuration", "",0);
|
GUI_MsgBoxOpen("Keys Configuration", "",0);
|
||||||
if ((*special == 3) && !system_hw)
|
if (!system_hw && special && (*special == 3))
|
||||||
{
|
{
|
||||||
/* no auto-detected pad type, use 6-buttons key mapping as default */
|
/* no auto-detected pad type, use 6-buttons key mapping as default */
|
||||||
gx_input_Config(config.input[player].port, config.input[player].device, DEVICE_PAD6B);
|
gx_input_Config(config.input[player].port, config.input[player].device, DEVICE_PAD6B);
|
||||||
@ -2985,7 +3000,7 @@ static void ctrlmenu(void)
|
|||||||
gxTextureClose(&button_player_none_data.texture[0]);
|
gxTextureClose(&button_player_none_data.texture[0]);
|
||||||
|
|
||||||
/* delete custom images */
|
/* delete custom images */
|
||||||
for (i=0; i<13; i++)
|
for (i=0; i<14; i++)
|
||||||
{
|
{
|
||||||
gxTextureClose(&items_sys[0][i].texture);
|
gxTextureClose(&items_sys[0][i].texture);
|
||||||
}
|
}
|
||||||
|
@ -45,14 +45,12 @@
|
|||||||
/* Number of sound buffers */
|
/* Number of sound buffers */
|
||||||
#define SOUND_BUFFER_NUM 3
|
#define SOUND_BUFFER_NUM 3
|
||||||
|
|
||||||
/* audio DMA status */
|
|
||||||
u32 audioStarted;
|
|
||||||
|
|
||||||
/* DMA soundbuffers (required to be 32-bytes aligned) */
|
/* DMA soundbuffers (required to be 32-bytes aligned) */
|
||||||
static u8 soundbuffer[SOUND_BUFFER_NUM][SOUND_BUFFER_LEN] ATTRIBUTE_ALIGN(32);
|
static u8 soundbuffer[SOUND_BUFFER_NUM][SOUND_BUFFER_LEN] ATTRIBUTE_ALIGN(32);
|
||||||
|
|
||||||
/* Current work soundbuffer */
|
/* Current work soundbuffer */
|
||||||
static u8 mixbuffer;
|
static int bufferIndex;
|
||||||
|
static int bufferSize;
|
||||||
|
|
||||||
/* Background music */
|
/* Background music */
|
||||||
static u8 *Bg_music_ogg = NULL;
|
static u8 *Bg_music_ogg = NULL;
|
||||||
@ -96,9 +94,6 @@ void gx_audio_Init(void)
|
|||||||
}
|
}
|
||||||
fclose(f);
|
fclose(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* emulation is synchronized with audio hardware by default */
|
|
||||||
audioSync = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* AUDIO engine shutdown */
|
/* AUDIO engine shutdown */
|
||||||
@ -119,50 +114,64 @@ void gx_audio_Shutdown(void)
|
|||||||
|
|
||||||
This function retrieves samples for the frame then set the next DMA parameters
|
This function retrieves samples for the frame then set the next DMA parameters
|
||||||
Parameters will be taken in account only when current DMA operation is over
|
Parameters will be taken in account only when current DMA operation is over
|
||||||
|
|
||||||
|
To keep audio & video synchronized, DMA from external memory to audio interface is
|
||||||
|
started once by video update function when first frame is ready to be displayed,
|
||||||
|
then anytime video mode is changed and emulation resynchronized to video hardware.
|
||||||
|
|
||||||
|
Once started, audio DMA restarts automatically when all samples have been played.
|
||||||
|
At that time:
|
||||||
|
- if DMA settings have not been updated, previous sound buffer will be played again
|
||||||
|
- if DMA settings are updated too fast, one sound buffer frame might be skipped
|
||||||
|
|
||||||
|
Therefore, in order to maintain perfect audio playback without any sound skipping
|
||||||
|
or lagging, we need to make sure frame emulation is completed and this function is
|
||||||
|
called before previous DMA transfer is finished and after it has been started.
|
||||||
|
|
||||||
|
This is done by synchronizing frame emulation with audio DMA interrupt (which happens
|
||||||
|
anytime audio DMA restarts). When video sync is enabled, to keep emulation in sync
|
||||||
|
with both video AND audio, an appropriate number of samples is rendered per frame by
|
||||||
|
adjusting emulator output samplerate.
|
||||||
***/
|
***/
|
||||||
int gx_audio_Update(void)
|
int gx_audio_Update(int status)
|
||||||
{
|
{
|
||||||
if (audioWait && audioStarted)
|
|
||||||
{
|
|
||||||
return SYNC_WAIT;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Current available soundbuffer */
|
/* Current available soundbuffer */
|
||||||
s16 *sb = (s16 *)(soundbuffer[mixbuffer]);
|
s16 *sb = (s16 *)(soundbuffer[bufferIndex]);
|
||||||
|
|
||||||
/* Retrieve audio samples (size must be multiple of 32 bytes) */
|
/* Make sure current audio frame has not already been updated */
|
||||||
int size = audio_update(sb) * 4;
|
if (status & AUDIO_UPDATE)
|
||||||
|
|
||||||
/* Update DMA settings */
|
|
||||||
DCFlushRange((void *)sb, size);
|
|
||||||
AUDIO_InitDMA((u32) sb, size);
|
|
||||||
|
|
||||||
mixbuffer = (mixbuffer + 1) % SOUND_BUFFER_NUM;
|
|
||||||
|
|
||||||
audioWait = audioSync;
|
|
||||||
|
|
||||||
/* Start Audio DMA */
|
|
||||||
/* this is called once to kick-off DMA from external memory to audio interface */
|
|
||||||
/* DMA operation is automatically restarted when all samples have been sent. */
|
|
||||||
/* If DMA settings are not updated at that time, previous sound buffer will be used. */
|
|
||||||
/* Therefore we need to make sure frame emulation is completed before current DMA is */
|
|
||||||
/* completed, by synchronizing frame emulation with DMA start and also by syncing it */
|
|
||||||
/* with Video Interrupt and outputing a suitable number of samples per frame. */
|
|
||||||
if (!audioStarted)
|
|
||||||
{
|
{
|
||||||
/* restart audio DMA */
|
/* Retrieve audio samples (size must be multiple of 32 bytes) */
|
||||||
AUDIO_StopDMA();
|
bufferSize = audio_update(sb) * 4;
|
||||||
AUDIO_StartDMA();
|
DCFlushRange((void *)sb, bufferSize);
|
||||||
audioStarted = 1;
|
|
||||||
|
/* Mark current audio frame as being updated */
|
||||||
|
status &= ~AUDIO_UPDATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return SYNC_AUDIO;
|
/* Wait until previous audio frame is started before pushing current audio frame into DMA */
|
||||||
|
if ((status & AUDIO_WAIT) && !audioWait)
|
||||||
|
{
|
||||||
|
/* Update audio DMA settings for current frame */
|
||||||
|
AUDIO_InitDMA((u32)sb, bufferSize);
|
||||||
|
|
||||||
|
/* Next soundbuffer */
|
||||||
|
bufferIndex = (bufferIndex + 1) % SOUND_BUFFER_NUM;
|
||||||
|
|
||||||
|
/* Set audio wait flag */
|
||||||
|
audioWait = audioSync;
|
||||||
|
|
||||||
|
/* Current audio frame is ready for upcoming DMA */
|
||||||
|
status &= ~AUDIO_WAIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
/***
|
/***
|
||||||
gx_audio_Start
|
gx_audio_Start
|
||||||
|
|
||||||
This function restart the audio engine
|
This function restarts the audio engine
|
||||||
This is called when coming back from Main Menu
|
This is called when coming back from Main Menu
|
||||||
***/
|
***/
|
||||||
void gx_audio_Start(void)
|
void gx_audio_Start(void)
|
||||||
@ -181,11 +190,14 @@ void gx_audio_Start(void)
|
|||||||
/* DMA Interrupt callback */
|
/* DMA Interrupt callback */
|
||||||
AUDIO_RegisterDMACallback(ai_callback);
|
AUDIO_RegisterDMACallback(ai_callback);
|
||||||
|
|
||||||
|
/* emulation is synchronized with audio hardware by default */
|
||||||
|
audioSync = AUDIO_WAIT;
|
||||||
|
|
||||||
/* reset emulation audio processing */
|
/* reset emulation audio processing */
|
||||||
memset(soundbuffer, 0, sizeof(soundbuffer));
|
memset(soundbuffer, 0, sizeof(soundbuffer));
|
||||||
audioStarted = 0;
|
audioWait = 0;
|
||||||
mixbuffer = 0;
|
bufferSize = 0;
|
||||||
audioWait = 0;
|
bufferIndex = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/***
|
/***
|
||||||
@ -193,7 +205,6 @@ void gx_audio_Start(void)
|
|||||||
|
|
||||||
This function stops current Audio DMA process
|
This function stops current Audio DMA process
|
||||||
This is called when going back to Main Menu
|
This is called when going back to Main Menu
|
||||||
DMA need to be restarted when going back to the game (see above)
|
|
||||||
***/
|
***/
|
||||||
void gx_audio_Stop(void)
|
void gx_audio_Stop(void)
|
||||||
{
|
{
|
||||||
|
@ -40,13 +40,12 @@
|
|||||||
#ifndef _GC_AUDIO_H_
|
#ifndef _GC_AUDIO_H_
|
||||||
#define _GC_AUDIO_H_
|
#define _GC_AUDIO_H_
|
||||||
|
|
||||||
extern u32 audioStarted;
|
|
||||||
extern u32 audioSync;
|
extern u32 audioSync;
|
||||||
|
|
||||||
extern void gx_audio_Init(void);
|
extern void gx_audio_Init(void);
|
||||||
extern void gx_audio_Shutdown(void);
|
extern void gx_audio_Shutdown(void);
|
||||||
extern void gx_audio_Start(void);
|
extern void gx_audio_Start(void);
|
||||||
extern void gx_audio_Stop(void);
|
extern void gx_audio_Stop(void);
|
||||||
extern int gx_audio_Update(void);
|
extern int gx_audio_Update(int status);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
201
gx/gx_input.c
201
gx/gx_input.c
@ -221,8 +221,8 @@ static void pad_update(s8 chan, u8 i)
|
|||||||
/* Default fast-forward key combo */
|
/* Default fast-forward key combo */
|
||||||
if ((p & PAD_TRIGGER_R) && (PAD_ButtonsDown(0) & PAD_BUTTON_START))
|
if ((p & PAD_TRIGGER_R) && (PAD_ButtonsDown(0) & PAD_BUTTON_START))
|
||||||
{
|
{
|
||||||
audioSync ^= 1;
|
audioSync ^= AUDIO_WAIT;
|
||||||
videoSync = audioSync & config.vsync & !(gc_pal ^ vdp_pal);
|
videoSync = (audioSync && config.vsync && (gc_pal != vdp_pal)) ? VIDEO_WAIT : 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -386,10 +386,8 @@ static void pad_update(s8 chan, u8 i)
|
|||||||
if (input.analog[0][1] < 0x1fc) input.analog[0][1] = 0x1fc;
|
if (input.analog[0][1] < 0x1fc) input.analog[0][1] = 0x1fc;
|
||||||
else if (input.analog[0][1] > 0x2f7) input.analog[0][1] = 0x2f7;
|
else if (input.analog[0][1] > 0x2f7) input.analog[0][1] = 0x2f7;
|
||||||
|
|
||||||
/* PEN button */
|
/* PEN & RED button */
|
||||||
if (p & pad_keymap[KEY_BUTTONA]) input.pad[0] |= INPUT_PICO_RED;
|
if (p & pad_keymap[KEY_BUTTONA]) input.pad[0] |= INPUT_PICO_RED;
|
||||||
|
|
||||||
/* RED button */
|
|
||||||
if (p & pad_keymap[KEY_BUTTONB]) input.pad[0] |= INPUT_PICO_PEN;
|
if (p & pad_keymap[KEY_BUTTONB]) input.pad[0] |= INPUT_PICO_PEN;
|
||||||
|
|
||||||
/* PAGE index increment */
|
/* PAGE index increment */
|
||||||
@ -416,6 +414,26 @@ static void pad_update(s8 chan, u8 i)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case DEVICE_GRAPHIC_BOARD:
|
||||||
|
{
|
||||||
|
/* PEN screen position (x,y) */
|
||||||
|
input.analog[0][0] += x / ANALOG_SENSITIVITY;
|
||||||
|
input.analog[0][1] -= y / ANALOG_SENSITIVITY;
|
||||||
|
|
||||||
|
/* Limits */
|
||||||
|
if (input.analog[0][0] < 0) input.analog[0][0] = 0;
|
||||||
|
else if (input.analog[0][0] > 255) input.analog[0][0] = 255;
|
||||||
|
if (input.analog[0][1] < 0) input.analog[0][1] = 0;
|
||||||
|
else if (input.analog[0][1] > 255) input.analog[0][1] = 255;
|
||||||
|
|
||||||
|
/* MODE buttons */
|
||||||
|
if (p & pad_keymap[KEY_BUTTONA]) input.pad[0] |= INPUT_GRAPHIC_PEN;
|
||||||
|
if (p & pad_keymap[KEY_BUTTONB]) input.pad[0] |= INPUT_GRAPHIC_DO;
|
||||||
|
if (p & pad_keymap[KEY_BUTTONC]) input.pad[0] |= INPUT_GRAPHIC_MENU;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case DEVICE_ACTIVATOR:
|
case DEVICE_ACTIVATOR:
|
||||||
{
|
{
|
||||||
/* Left & right analog stick angle [0-360] */
|
/* Left & right analog stick angle [0-360] */
|
||||||
@ -893,12 +911,25 @@ static void wpad_update(s8 chan, u8 i, u32 exp)
|
|||||||
case DEVICE_MOUSE:
|
case DEVICE_MOUSE:
|
||||||
{
|
{
|
||||||
/* Mouse relative movement (-255,255) */
|
/* Mouse relative movement (-255,255) */
|
||||||
input.analog[i][0] = (x / ANALOG_SENSITIVITY) * 2;
|
if (MOUSE_IsConnected())
|
||||||
input.analog[i][1] = (y / ANALOG_SENSITIVITY) * 2;
|
|
||||||
|
|
||||||
/* Wiimote IR (buggy) */
|
|
||||||
if (exp != WPAD_EXP_CLASSIC)
|
|
||||||
{
|
{
|
||||||
|
/* USB mouse support */
|
||||||
|
mouse_event event;
|
||||||
|
MOUSE_GetEvent(&event);
|
||||||
|
MOUSE_FlushEvents();
|
||||||
|
|
||||||
|
/* USB mouse position (-127;+127) -> (-255;+255) */
|
||||||
|
input.analog[i][0] = event.rx * 2;
|
||||||
|
input.analog[i][1] = event.ry * 2;
|
||||||
|
|
||||||
|
/* USB mouse buttons */
|
||||||
|
if (event.button & 1) input.pad[i] |= INPUT_MOUSE_RIGHT;
|
||||||
|
if (event.button & 2) input.pad[i] |= INPUT_MOUSE_CENTER;
|
||||||
|
if (event.button & 4) input.pad[i] |= INPUT_MOUSE_LEFT;
|
||||||
|
}
|
||||||
|
else if (exp != WPAD_EXP_CLASSIC)
|
||||||
|
{
|
||||||
|
/* Wiimote IR (buggy) */
|
||||||
struct ir_t ir;
|
struct ir_t ir;
|
||||||
WPAD_IR(chan, &ir);
|
WPAD_IR(chan, &ir);
|
||||||
|
|
||||||
@ -909,23 +940,11 @@ static void wpad_update(s8 chan, u8 i, u32 exp)
|
|||||||
input.analog[i][1] = (int)((ir.sy - 384) * 2 / 3 / ANALOG_SENSITIVITY);
|
input.analog[i][1] = (int)((ir.sy - 384) * 2 / 3 / ANALOG_SENSITIVITY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
/* USB mouse support */
|
|
||||||
if (MOUSE_IsConnected())
|
|
||||||
{
|
{
|
||||||
/* read mouse data */
|
/* Classic Controller analog stick position (-127;+127) -> (-255;+255) */
|
||||||
mouse_event event;
|
input.analog[i][0] = (x / ANALOG_SENSITIVITY) * 2;
|
||||||
MOUSE_GetEvent(&event);
|
input.analog[i][1] = (y / ANALOG_SENSITIVITY) * 2;
|
||||||
MOUSE_FlushEvents();
|
|
||||||
|
|
||||||
/* mouse position (-127;+127) -> (-255;+255) */
|
|
||||||
input.analog[i][0] = event.rx * 2;
|
|
||||||
input.analog[i][1] = event.ry * 2;
|
|
||||||
|
|
||||||
/* mouse buttons */
|
|
||||||
if (event.button & 1) input.pad[i] |= INPUT_MOUSE_RIGHT;
|
|
||||||
if (event.button & 2) input.pad[i] |= INPUT_MOUSE_CENTER;
|
|
||||||
if (event.button & 4) input.pad[i] |= INPUT_MOUSE_LEFT;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Y-Axis inversion */
|
/* Y-Axis inversion */
|
||||||
@ -952,18 +971,9 @@ static void wpad_update(s8 chan, u8 i, u32 exp)
|
|||||||
else if (p & PAD_BUTTON_RIGHT) input.pad[i] |= INPUT_RIGHT;
|
else if (p & PAD_BUTTON_RIGHT) input.pad[i] |= INPUT_RIGHT;
|
||||||
|
|
||||||
/* PEN screen position (x,y) */
|
/* PEN screen position (x,y) */
|
||||||
input.analog[0][0] += x / ANALOG_SENSITIVITY;
|
|
||||||
input.analog[0][1] -= y / ANALOG_SENSITIVITY;
|
|
||||||
|
|
||||||
/* Limits */
|
|
||||||
if (input.analog[0][0] > 0x17c) input.analog[0][0] = 0x17c;
|
|
||||||
else if (input.analog[0][0] < 0x3c) input.analog[0][0] = 0x3c;
|
|
||||||
if (input.analog[0][1] < 0x1fc) input.analog[0][1] = 0x1fc;
|
|
||||||
else if (input.analog[0][1] > 0x2f7) input.analog[0][1] = 0x2f7;
|
|
||||||
|
|
||||||
/* Wiimote IR */
|
|
||||||
if (exp != WPAD_EXP_CLASSIC)
|
if (exp != WPAD_EXP_CLASSIC)
|
||||||
{
|
{
|
||||||
|
/* Wiimote IR */
|
||||||
struct ir_t ir;
|
struct ir_t ir;
|
||||||
WPAD_IR(chan, &ir);
|
WPAD_IR(chan, &ir);
|
||||||
if (ir.valid)
|
if (ir.valid)
|
||||||
@ -972,11 +982,21 @@ static void wpad_update(s8 chan, u8 i, u32 exp)
|
|||||||
input.analog[0][1] = 0x1fc + ((ir.y + config.caly) * (0x2f7 - 0x1fc + 1)) / 480;
|
input.analog[0][1] = 0x1fc + ((ir.y + config.caly) * (0x2f7 - 0x1fc + 1)) / 480;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Classic Controller analog stick */
|
||||||
|
input.analog[0][0] += x / ANALOG_SENSITIVITY;
|
||||||
|
input.analog[0][1] -= y / ANALOG_SENSITIVITY;
|
||||||
|
|
||||||
/* PEN button */
|
/* Limits */
|
||||||
|
if (input.analog[0][0] > 0x17c) input.analog[0][0] = 0x17c;
|
||||||
|
else if (input.analog[0][0] < 0x3c) input.analog[0][0] = 0x3c;
|
||||||
|
if (input.analog[0][1] < 0x1fc) input.analog[0][1] = 0x1fc;
|
||||||
|
else if (input.analog[0][1] > 0x2f7) input.analog[0][1] = 0x2f7;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* PEN & RED buttons */
|
||||||
if (p & wpad_keymap[KEY_BUTTONA]) input.pad[0] |= INPUT_PICO_PEN;
|
if (p & wpad_keymap[KEY_BUTTONA]) input.pad[0] |= INPUT_PICO_PEN;
|
||||||
|
|
||||||
/* RED button */
|
|
||||||
if (p & wpad_keymap[KEY_BUTTONB]) input.pad[0] |= INPUT_PICO_RED;
|
if (p & wpad_keymap[KEY_BUTTONB]) input.pad[0] |= INPUT_PICO_RED;
|
||||||
|
|
||||||
/* PAGE index increment */
|
/* PAGE index increment */
|
||||||
@ -988,18 +1008,9 @@ static void wpad_update(s8 chan, u8 i, u32 exp)
|
|||||||
case DEVICE_TEREBI:
|
case DEVICE_TEREBI:
|
||||||
{
|
{
|
||||||
/* PEN screen position (x,y) */
|
/* PEN screen position (x,y) */
|
||||||
input.analog[0][0] += x / ANALOG_SENSITIVITY;
|
|
||||||
input.analog[0][1] -= y / ANALOG_SENSITIVITY;
|
|
||||||
|
|
||||||
/* Limits */
|
|
||||||
if (input.analog[0][0] < 0) input.analog[0][0] = 0;
|
|
||||||
else if (input.analog[0][0] > 250) input.analog[0][0] = 250;
|
|
||||||
if (input.analog[0][1] < 0) input.analog[0][1] = 0;
|
|
||||||
else if (input.analog[0][1] > 250) input.analog[0][1] = 250;
|
|
||||||
|
|
||||||
/* Wiimote IR */
|
|
||||||
if (exp != WPAD_EXP_CLASSIC)
|
if (exp != WPAD_EXP_CLASSIC)
|
||||||
{
|
{
|
||||||
|
/* Wiimote IR */
|
||||||
struct ir_t ir;
|
struct ir_t ir;
|
||||||
WPAD_IR(chan, &ir);
|
WPAD_IR(chan, &ir);
|
||||||
if (ir.valid)
|
if (ir.valid)
|
||||||
@ -1008,6 +1019,18 @@ static void wpad_update(s8 chan, u8 i, u32 exp)
|
|||||||
input.analog[0][1] = ((ir.y + config.caly) * 250) / 480;
|
input.analog[0][1] = ((ir.y + config.caly) * 250) / 480;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Classic Controller analog stick */
|
||||||
|
input.analog[0][0] += x / ANALOG_SENSITIVITY;
|
||||||
|
input.analog[0][1] -= y / ANALOG_SENSITIVITY;
|
||||||
|
|
||||||
|
/* Limits */
|
||||||
|
if (input.analog[0][0] < 0)input.analog[0][0] = 0;
|
||||||
|
else if (input.analog[0][0] > 250) input.analog[0][0] = 250;
|
||||||
|
if (input.analog[0][1] < 0) input.analog[0][1] = 0;
|
||||||
|
else if (input.analog[0][1] > 250) input.analog[0][1] = 250;
|
||||||
|
}
|
||||||
|
|
||||||
/* PEN button */
|
/* PEN button */
|
||||||
if (p & wpad_keymap[KEY_BUTTONA]) input.pad[0] |= INPUT_BUTTON1;
|
if (p & wpad_keymap[KEY_BUTTONA]) input.pad[0] |= INPUT_BUTTON1;
|
||||||
@ -1015,6 +1038,41 @@ static void wpad_update(s8 chan, u8 i, u32 exp)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case DEVICE_GRAPHIC_BOARD:
|
||||||
|
{
|
||||||
|
/* PEN screen position (x,y) */
|
||||||
|
if (exp != WPAD_EXP_CLASSIC)
|
||||||
|
{
|
||||||
|
/* Wiimote IR */
|
||||||
|
struct ir_t ir;
|
||||||
|
WPAD_IR(chan, &ir);
|
||||||
|
if (ir.valid)
|
||||||
|
{
|
||||||
|
input.analog[0][0] = ((ir.x + config.calx) * 255) / 640;
|
||||||
|
input.analog[0][1] = ((ir.y + config.caly) * 255) / 480;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Classic Controller analog stick */
|
||||||
|
input.analog[0][0] += x / ANALOG_SENSITIVITY;
|
||||||
|
input.analog[0][1] -= y / ANALOG_SENSITIVITY;
|
||||||
|
|
||||||
|
/* Limits */
|
||||||
|
if (input.analog[0][0] < 0)input.analog[0][0] = 0;
|
||||||
|
else if (input.analog[0][0] > 255) input.analog[0][0] = 255;
|
||||||
|
if (input.analog[0][1] < 0) input.analog[0][1] = 0;
|
||||||
|
else if (input.analog[0][1] > 255) input.analog[0][1] = 255;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* MODE Buttons */
|
||||||
|
if (p & wpad_keymap[KEY_BUTTONA]) input.pad[0] |= INPUT_GRAPHIC_PEN;
|
||||||
|
if (p & wpad_keymap[KEY_BUTTONB]) input.pad[0] |= INPUT_GRAPHIC_DO;
|
||||||
|
if (p & wpad_keymap[KEY_BUTTONC]) input.pad[0] |= INPUT_GRAPHIC_MENU;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case DEVICE_ACTIVATOR:
|
case DEVICE_ACTIVATOR:
|
||||||
{
|
{
|
||||||
/* Classic Controller only */
|
/* Classic Controller only */
|
||||||
@ -1421,6 +1479,17 @@ void gx_input_Config(u8 chan, u8 device, u8 type)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case DEVICE_GRAPHIC_BOARD:
|
||||||
|
{
|
||||||
|
first_key = KEY_BUTTONA;
|
||||||
|
last_key = KEY_START;
|
||||||
|
sprintf(keyname[KEY_BUTTONA],"PEN Button");
|
||||||
|
sprintf(keyname[KEY_BUTTONB],"DO Button");
|
||||||
|
sprintf(keyname[KEY_BUTTONC],"MENU Button");
|
||||||
|
sprintf(keyname[KEY_START],"PAUSE Button");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
first_key = KEY_BUTTONA;
|
first_key = KEY_BUTTONA;
|
||||||
@ -1465,8 +1534,8 @@ void gx_input_UpdateEmu(void)
|
|||||||
/* Default fast-forward key combo */
|
/* Default fast-forward key combo */
|
||||||
if (WPAD_ButtonsHeld(0) & (WPAD_BUTTON_MINUS | WPAD_CLASSIC_BUTTON_MINUS))
|
if (WPAD_ButtonsHeld(0) & (WPAD_BUTTON_MINUS | WPAD_CLASSIC_BUTTON_MINUS))
|
||||||
{
|
{
|
||||||
audioSync ^= 1;
|
audioSync ^= AUDIO_WAIT;
|
||||||
videoSync = audioSync & config.vsync & !(gc_pal ^ vdp_pal);
|
videoSync = (audioSync && config.vsync && (gc_pal != vdp_pal)) ? VIDEO_WAIT : 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1539,6 +1608,36 @@ void gx_input_UpdateMenu(void)
|
|||||||
/* WPAD held keys (direction/selection) */
|
/* WPAD held keys (direction/selection) */
|
||||||
u32 hw = data->btns_h & WPAD_BUTTONS_HELD;
|
u32 hw = data->btns_h & WPAD_BUTTONS_HELD;
|
||||||
|
|
||||||
|
/* Some 3rd party classic controllers return invalid factory calibration data */
|
||||||
|
if (data->exp.type == EXP_CLASSIC)
|
||||||
|
{
|
||||||
|
/* Left analog stick */
|
||||||
|
struct joystick_t* js = &data->exp.classic.ljs;
|
||||||
|
|
||||||
|
/* Check acquired calibration data */
|
||||||
|
if ((js->max.x <= js->center.x) || (js->min.x >= js->center.x) ||
|
||||||
|
(js->max.y <= js->center.y) || (js->min.y >= js->center.y))
|
||||||
|
{
|
||||||
|
/* Reset to default values */
|
||||||
|
js->min.x = js->min.y = 0;
|
||||||
|
js->max.x = js->max.y = 64;
|
||||||
|
js->center.x = js->center.y = 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Right analog stick */
|
||||||
|
js = &data->exp.classic.rjs;
|
||||||
|
|
||||||
|
/* Check acquired calibration data */
|
||||||
|
if ((js->max.x <= js->center.x) || (js->min.x >= js->center.x) ||
|
||||||
|
(js->max.y <= js->center.y) || (js->min.y >= js->center.y))
|
||||||
|
{
|
||||||
|
/* Reset to default values */
|
||||||
|
js->min.x = js->min.y = 0;
|
||||||
|
js->max.x = js->max.y = 32;
|
||||||
|
js->center.x = js->center.y = 16;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* WPAD analog sticks (handled as PAD held direction keys) */
|
/* WPAD analog sticks (handled as PAD held direction keys) */
|
||||||
x = wpad_StickX(data, 0);
|
x = wpad_StickX(data, 0);
|
||||||
y = wpad_StickY(data, 0);
|
y = wpad_StickY(data, 0);
|
||||||
|
390
gx/gx_video.c
390
gx/gx_video.c
@ -357,9 +357,42 @@ static u8 d_list[32] ATTRIBUTE_ALIGN(32) =
|
|||||||
/* VSYNC callback */
|
/* VSYNC callback */
|
||||||
static void vi_callback(u32 cnt)
|
static void vi_callback(u32 cnt)
|
||||||
{
|
{
|
||||||
|
/* get audio DMA remaining length */
|
||||||
|
vu16* const _dspReg = (u16*)0xCC005000;
|
||||||
|
u16 remain = _dspReg[29];
|
||||||
|
|
||||||
|
/* adjust desired output samplerate if audio playback is not perfectly in sync with video */
|
||||||
|
if (remain > 0)
|
||||||
|
{
|
||||||
|
int samplerate;
|
||||||
|
|
||||||
|
/* check current audio DMA position (from testing, delta keeps limited to +/- one 32-bit block i.e 8 samples) */
|
||||||
|
if (remain < 5)
|
||||||
|
{
|
||||||
|
/* previous frame DMA is not yet finished (real output rate is slightly slower than expected value) */
|
||||||
|
samplerate = 47950;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* current frame DMA is already started (real output rate is slightly faster than expected value) */
|
||||||
|
samplerate = 48050;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* update resampler ratios if output samplerate has changed */
|
||||||
|
if (samplerate != snd.sample_rate)
|
||||||
|
{
|
||||||
|
/* this will adjust the number of samples returned on next frame(s) */
|
||||||
|
audio_set_rate(samplerate, snd.frame_rate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* clear VSYNC flag */
|
/* clear VSYNC flag */
|
||||||
videoWait = 0;
|
videoWait = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* XFB update */
|
||||||
|
static void xfb_update(u32 cnt)
|
||||||
|
{
|
||||||
/* check if EFB rendering is finished */
|
/* check if EFB rendering is finished */
|
||||||
if (drawDone)
|
if (drawDone)
|
||||||
{
|
{
|
||||||
@ -493,8 +526,8 @@ static void gxSetAspectRatio(int *xscale, int *yscale)
|
|||||||
|
|
||||||
/* Horizontal Scaling */
|
/* Horizontal Scaling */
|
||||||
/* Wii/Gamecube pixel clock = 13.5 Mhz */
|
/* Wii/Gamecube pixel clock = 13.5 Mhz */
|
||||||
/* "H32" pixel clock = Master Clock / 10 = 5.3693175 Mhz (NTSC) or 5.3203424 (PAL) */
|
/* "H32" pixel clock = Master Clock / 10 = 5.3693175 Mhz (NTSC) or 5.3203424 Mhz (PAL) */
|
||||||
/* "H40" pixel clock = Master Clock / 8 = 6,711646875 Mhz (NTSC) or 6,650428 Mhz (PAL) */
|
/* "H40" pixel clock = Master Clock / 8 = 6.711646875 Mhz (NTSC) or 6.650428 Mhz (PAL) */
|
||||||
if (config.overscan & 2)
|
if (config.overscan & 2)
|
||||||
{
|
{
|
||||||
/* Horizontal borders are emulated */
|
/* Horizontal borders are emulated */
|
||||||
@ -505,7 +538,7 @@ static void gxSetAspectRatio(int *xscale, int *yscale)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* 284 "H32" pixels = 284 * Wii/GC pixel clock / "H40" pixel clock = approx. 714 (NTSC) or 721 (PAL) Wii/GC pixels */
|
/* 284 "H32" pixels = 284 * Wii/GC pixel clock / "H32" pixel clock = approx. 714 (NTSC) or 721 (PAL) Wii/GC pixels */
|
||||||
*xscale = (system_clock == MCLOCK_NTSC) ? 357 : 361;
|
*xscale = (system_clock == MCLOCK_NTSC) ? 357 : 361;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1424,15 +1457,15 @@ void gxTextureClose(gx_texture **p_texture)
|
|||||||
/* Emulation mode -> Menu mode */
|
/* Emulation mode -> Menu mode */
|
||||||
void gx_video_Stop(void)
|
void gx_video_Stop(void)
|
||||||
{
|
{
|
||||||
/* disable VSYNC callback */
|
/* disable VSYNC callbacks */
|
||||||
VIDEO_SetPostRetraceCallback(NULL);
|
VIDEO_SetPostRetraceCallback(NULL);
|
||||||
|
VIDEO_SetPreRetraceCallback(NULL);
|
||||||
|
|
||||||
/* wait for next even field */
|
/* wait for next even field */
|
||||||
/* this prevents screen artefacts when switching between interlaced & non-interlaced modes */
|
/* this prevents screen artefacts when switching between interlaced & non-interlaced modes */
|
||||||
do VIDEO_WaitVSync();
|
do VIDEO_WaitVSync();
|
||||||
while (!VIDEO_GetNextField());
|
while (!VIDEO_GetNextField());
|
||||||
|
|
||||||
|
|
||||||
/* adjust TV width */
|
/* adjust TV width */
|
||||||
vmode->viWidth = config.screen_w;
|
vmode->viWidth = config.screen_w;
|
||||||
vmode->viXOrigin = (VI_MAX_WIDTH_NTSC - vmode->viWidth)/2;
|
vmode->viXOrigin = (VI_MAX_WIDTH_NTSC - vmode->viWidth)/2;
|
||||||
@ -1478,11 +1511,6 @@ void gx_video_Stop(void)
|
|||||||
/* Menu mode -> Emulation mode */
|
/* Menu mode -> Emulation mode */
|
||||||
void gx_video_Start(void)
|
void gx_video_Start(void)
|
||||||
{
|
{
|
||||||
#ifdef HW_RVL
|
|
||||||
VIDEO_SetTrapFilter(config.trap);
|
|
||||||
VIDEO_SetGamma((int)(config.gamma * 10.0));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* TV mode */
|
/* TV mode */
|
||||||
if ((config.tv_mode == 1) || ((config.tv_mode == 2) && vdp_pal))
|
if ((config.tv_mode == 1) || ((config.tv_mode == 2) && vdp_pal))
|
||||||
{
|
{
|
||||||
@ -1495,16 +1523,6 @@ void gx_video_Start(void)
|
|||||||
gc_pal = 0;
|
gc_pal = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* When VSYNC is set to AUTO & console TV mode matches emulated video mode, emulation is synchronized with video hardware as well */
|
|
||||||
if (config.vsync && (gc_pal == vdp_pal))
|
|
||||||
{
|
|
||||||
videoSync = audioSync;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
videoSync = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Enable progressive or interlaced video mode */
|
/* Enable progressive or interlaced video mode */
|
||||||
if (config.render == 2)
|
if (config.render == 2)
|
||||||
{
|
{
|
||||||
@ -1657,8 +1675,24 @@ void gx_video_Start(void)
|
|||||||
do VIDEO_WaitVSync();
|
do VIDEO_WaitVSync();
|
||||||
while (!VIDEO_GetNextField());
|
while (!VIDEO_GetNextField());
|
||||||
|
|
||||||
/* VSYNC callback */
|
#ifdef HW_RVL
|
||||||
VIDEO_SetPostRetraceCallback(vi_callback);
|
VIDEO_SetTrapFilter(config.trap);
|
||||||
|
VIDEO_SetGamma((int)(config.gamma * 10.0));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* XFB update is done during VBLANK */
|
||||||
|
VIDEO_SetPreRetraceCallback(xfb_update);
|
||||||
|
|
||||||
|
/* Emulation is synchronized with video hardware if VSYNC is set to AUTO & TV mode matches emulated video mode */
|
||||||
|
if (config.vsync && (gc_pal == vdp_pal))
|
||||||
|
{
|
||||||
|
VIDEO_SetPostRetraceCallback(vi_callback);
|
||||||
|
videoSync = VIDEO_WAIT;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
videoSync = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* restart frame sync */
|
/* restart frame sync */
|
||||||
videoWait = 0;
|
videoWait = 0;
|
||||||
@ -1667,177 +1701,191 @@ void gx_video_Start(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* GX render update */
|
/* GX render update */
|
||||||
int gx_video_Update(u32 done)
|
int gx_video_Update(int status)
|
||||||
{
|
{
|
||||||
if (videoWait || done) return SYNC_WAIT;
|
/* make sure current video frame has not already been updated */
|
||||||
|
if (status & VIDEO_UPDATE)
|
||||||
videoWait = videoSync;
|
|
||||||
|
|
||||||
/* check if display has changed during frame */
|
|
||||||
if (bitmap.viewport.changed & 1)
|
|
||||||
{
|
{
|
||||||
/* update texture size */
|
/* set video wait flag if VSYNC is enabled */
|
||||||
vwidth = bitmap.viewport.w + (2 * bitmap.viewport.x);
|
videoWait = videoSync;
|
||||||
vheight = bitmap.viewport.h + (2 * bitmap.viewport.y);
|
|
||||||
|
|
||||||
/* interlaced mode */
|
/* check if display has changed during frame */
|
||||||
if (config.render && interlaced)
|
if (bitmap.viewport.changed & 1)
|
||||||
{
|
{
|
||||||
vheight = vheight << 1;
|
/* update texture size */
|
||||||
}
|
vwidth = bitmap.viewport.w + (2 * bitmap.viewport.x);
|
||||||
|
vheight = bitmap.viewport.h + (2 * bitmap.viewport.y);
|
||||||
|
|
||||||
/* ntsc filter */
|
/* interlaced mode */
|
||||||
if (config.ntsc)
|
if (config.render && interlaced)
|
||||||
{
|
|
||||||
vwidth = (reg[12] & 1) ? MD_NTSC_OUT_WIDTH(vwidth) : SMS_NTSC_OUT_WIDTH(vwidth);
|
|
||||||
|
|
||||||
/* texel width must remain multiple of 4 */
|
|
||||||
vwidth = (vwidth >> 2) << 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* initialize texture object */
|
|
||||||
GXTexObj texobj;
|
|
||||||
GX_InitTexObj(&texobj, bitmap.data, vwidth, vheight, GX_TF_RGB565, GX_CLAMP, GX_CLAMP, GX_FALSE);
|
|
||||||
|
|
||||||
/* configure texture filtering */
|
|
||||||
if (!config.bilinear)
|
|
||||||
{
|
|
||||||
GX_InitTexObjLOD(&texobj,GX_NEAR,GX_NEAR_MIP_NEAR,0.0,10.0,0.0,GX_FALSE,GX_FALSE,GX_ANISO_1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* load texture object */
|
|
||||||
GX_LoadTexObj(&texobj, GX_TEXMAP0);
|
|
||||||
|
|
||||||
/* update rendering mode */
|
|
||||||
if (config.render)
|
|
||||||
{
|
|
||||||
rmode = tvmodes[gc_pal*3 + 2];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
rmode = tvmodes[gc_pal*3 + interlaced];
|
|
||||||
}
|
|
||||||
|
|
||||||
/* update aspect ratio */
|
|
||||||
gxResetScaler(vwidth);
|
|
||||||
|
|
||||||
/* update GX rendering mode */
|
|
||||||
gxResetMode(rmode, config.vfilter);
|
|
||||||
|
|
||||||
/* update VI mode */
|
|
||||||
VIDEO_Configure(rmode);
|
|
||||||
VIDEO_Flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* texture is now directly mapped by the line renderer */
|
|
||||||
|
|
||||||
/* force texture cache update */
|
|
||||||
DCFlushRange(bitmap.data, vwidth*vheight*2);
|
|
||||||
GX_InvalidateTexAll();
|
|
||||||
|
|
||||||
/* disable EFB copy until rendering is done */
|
|
||||||
drawDone = 0;
|
|
||||||
|
|
||||||
/* render textured quad */
|
|
||||||
GX_CallDispList(d_list, 32);
|
|
||||||
|
|
||||||
/* on-screen display */
|
|
||||||
if (osd)
|
|
||||||
{
|
|
||||||
/* reset GX rendering */
|
|
||||||
gxResetRendering(1);
|
|
||||||
|
|
||||||
/* lightgun # 1 screen mark */
|
|
||||||
if (crosshair[0])
|
|
||||||
{
|
|
||||||
if (input.system[0] == SYSTEM_LIGHTPHASER)
|
|
||||||
{
|
{
|
||||||
gxDrawCrosshair(crosshair[0], input.analog[0][0],input.analog[0][1]);
|
vheight = vheight << 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ntsc filter */
|
||||||
|
if (config.ntsc)
|
||||||
|
{
|
||||||
|
vwidth = (reg[12] & 1) ? MD_NTSC_OUT_WIDTH(vwidth) : SMS_NTSC_OUT_WIDTH(vwidth);
|
||||||
|
|
||||||
|
/* texel width must remain multiple of 4 */
|
||||||
|
vwidth = (vwidth >> 2) << 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* initialize texture object */
|
||||||
|
GXTexObj texobj;
|
||||||
|
GX_InitTexObj(&texobj, bitmap.data, vwidth, vheight, GX_TF_RGB565, GX_CLAMP, GX_CLAMP, GX_FALSE);
|
||||||
|
|
||||||
|
/* configure texture filtering */
|
||||||
|
if (!config.bilinear)
|
||||||
|
{
|
||||||
|
GX_InitTexObjLOD(&texobj,GX_NEAR,GX_NEAR_MIP_NEAR,0.0,10.0,0.0,GX_FALSE,GX_FALSE,GX_ANISO_1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* load texture object */
|
||||||
|
GX_LoadTexObj(&texobj, GX_TEXMAP0);
|
||||||
|
|
||||||
|
/* update rendering mode */
|
||||||
|
if (config.render)
|
||||||
|
{
|
||||||
|
rmode = tvmodes[gc_pal*3 + 2];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
gxDrawCrosshair(crosshair[0], input.analog[4][0],input.analog[4][1]);
|
rmode = tvmodes[gc_pal*3 + interlaced];
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* lightgun #2 screen mark */
|
|
||||||
if (crosshair[1])
|
|
||||||
{
|
|
||||||
if (input.system[1] == SYSTEM_LIGHTPHASER)
|
|
||||||
{
|
|
||||||
gxDrawCrosshair(crosshair[1], input.analog[4][0],input.analog[4][1]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
gxDrawCrosshair(crosshair[1], input.analog[5][0],input.analog[5][1]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* CD LEDS */
|
|
||||||
if (cd_leds[1][1])
|
|
||||||
{
|
|
||||||
/* CD LEDS status */
|
|
||||||
u8 mode = scd.regs[0x06 >> 1].byte.h;
|
|
||||||
gxDrawCdLeds(cd_leds[1][(mode >> 1) & 1], cd_leds[0][mode & 1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* FPS counter */
|
|
||||||
if (config.fps)
|
|
||||||
{
|
|
||||||
u32 delta = diff_usec(starttime, gettime());
|
|
||||||
frameCount++;
|
|
||||||
if (delta > 1000000)
|
|
||||||
{
|
|
||||||
sprintf(msg,"%3.2f FPS", (float)frameCount * 1000000.0 / (float)delta);
|
|
||||||
frameCount = 0;
|
|
||||||
starttime = gettime();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* disable EFB alpha blending for text background */
|
/* update aspect ratio */
|
||||||
GX_SetBlendMode(GX_BM_NONE,GX_BL_SRCALPHA,GX_BL_INVSRCALPHA,GX_LO_CLEAR);
|
gxResetScaler(vwidth);
|
||||||
GX_Flush();
|
|
||||||
|
|
||||||
gxDrawOnScreenText(msg);
|
/* update GX rendering mode */
|
||||||
|
gxResetMode(rmode, config.vfilter);
|
||||||
|
|
||||||
|
/* update VI mode */
|
||||||
|
VIDEO_Configure(rmode);
|
||||||
|
VIDEO_Flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* restore texture object */
|
/* texture is now directly mapped by the line renderer */
|
||||||
GXTexObj texobj;
|
|
||||||
GX_InitTexObj(&texobj, bitmap.data, vwidth, vheight, GX_TF_RGB565, GX_CLAMP, GX_CLAMP, GX_FALSE);
|
/* force texture cache update */
|
||||||
if (!config.bilinear)
|
DCFlushRange(bitmap.data, vwidth*vheight*2);
|
||||||
{
|
|
||||||
GX_InitTexObjLOD(&texobj,GX_NEAR,GX_NEAR_MIP_NEAR,0.0,10.0,0.0,GX_FALSE,GX_FALSE,GX_ANISO_1);
|
|
||||||
}
|
|
||||||
GX_LoadTexObj(&texobj, GX_TEXMAP0);
|
|
||||||
GX_InvalidateTexAll();
|
GX_InvalidateTexAll();
|
||||||
|
|
||||||
/* restore GX rendering */
|
/* disable EFB copy until rendering is done */
|
||||||
gxResetRendering(0);
|
drawDone = 0;
|
||||||
}
|
|
||||||
|
|
||||||
/* GX draw interrupt will be triggered when EFB rendering is finished */
|
/* render textured quad */
|
||||||
GX_SetDrawDone();
|
GX_CallDispList(d_list, 32);
|
||||||
|
|
||||||
if (bitmap.viewport.changed & 1)
|
/* on-screen display */
|
||||||
{
|
if (osd)
|
||||||
/* clear update flags */
|
|
||||||
bitmap.viewport.changed &= ~1;
|
|
||||||
|
|
||||||
/* field synchronization */
|
|
||||||
VIDEO_WaitVSync();
|
|
||||||
if (rmode->viTVMode & VI_NON_INTERLACE)
|
|
||||||
{
|
{
|
||||||
VIDEO_WaitVSync();
|
/* reset GX rendering */
|
||||||
}
|
gxResetRendering(1);
|
||||||
else while (VIDEO_GetNextField() != odd_frame)
|
|
||||||
{
|
/* lightgun # 1 screen mark */
|
||||||
VIDEO_WaitVSync();
|
if (crosshair[0])
|
||||||
|
{
|
||||||
|
if (input.system[0] == SYSTEM_LIGHTPHASER)
|
||||||
|
{
|
||||||
|
gxDrawCrosshair(crosshair[0], input.analog[0][0],input.analog[0][1]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gxDrawCrosshair(crosshair[0], input.analog[4][0],input.analog[4][1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* lightgun #2 screen mark */
|
||||||
|
if (crosshair[1])
|
||||||
|
{
|
||||||
|
if (input.system[1] == SYSTEM_LIGHTPHASER)
|
||||||
|
{
|
||||||
|
gxDrawCrosshair(crosshair[1], input.analog[4][0],input.analog[4][1]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gxDrawCrosshair(crosshair[1], input.analog[5][0],input.analog[5][1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* CD LEDS */
|
||||||
|
if (cd_leds[1][1])
|
||||||
|
{
|
||||||
|
/* CD LEDS status */
|
||||||
|
u8 mode = scd.regs[0x06 >> 1].byte.h;
|
||||||
|
gxDrawCdLeds(cd_leds[1][(mode >> 1) & 1], cd_leds[0][mode & 1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FPS counter */
|
||||||
|
if (config.fps)
|
||||||
|
{
|
||||||
|
u32 delta = diff_usec(starttime, gettime());
|
||||||
|
frameCount++;
|
||||||
|
if (delta > 1000000)
|
||||||
|
{
|
||||||
|
sprintf(msg,"%3.2f FPS", (float)frameCount * 1000000.0 / (float)delta);
|
||||||
|
frameCount = 0;
|
||||||
|
starttime = gettime();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* disable EFB alpha blending for text background */
|
||||||
|
GX_SetBlendMode(GX_BM_NONE,GX_BL_SRCALPHA,GX_BL_INVSRCALPHA,GX_LO_CLEAR);
|
||||||
|
GX_Flush();
|
||||||
|
|
||||||
|
/* display on-screen message */
|
||||||
|
gxDrawOnScreenText(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* restore texture object */
|
||||||
|
GXTexObj texobj;
|
||||||
|
GX_InitTexObj(&texobj, bitmap.data, vwidth, vheight, GX_TF_RGB565, GX_CLAMP, GX_CLAMP, GX_FALSE);
|
||||||
|
if (!config.bilinear)
|
||||||
|
{
|
||||||
|
GX_InitTexObjLOD(&texobj,GX_NEAR,GX_NEAR_MIP_NEAR,0.0,10.0,0.0,GX_FALSE,GX_FALSE,GX_ANISO_1);
|
||||||
|
}
|
||||||
|
GX_LoadTexObj(&texobj, GX_TEXMAP0);
|
||||||
|
GX_InvalidateTexAll();
|
||||||
|
|
||||||
|
/* restore GX rendering */
|
||||||
|
gxResetRendering(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Audio DMA need to be resynchronized with VSYNC */
|
/* Do not wait for EFB rendering, GX draw interrupt will be triggered when it is finished */
|
||||||
audioStarted = 0;
|
GX_SetDrawDone();
|
||||||
|
|
||||||
|
/* check interlaced mode change */
|
||||||
|
if (bitmap.viewport.changed & 4)
|
||||||
|
{
|
||||||
|
/* "original" mode */
|
||||||
|
if (!config.render && config.vsync && (gc_pal == vdp_pal))
|
||||||
|
{
|
||||||
|
/* framerate has changed, reinitialize audio timings */
|
||||||
|
audio_init(snd.sample_rate, get_framerate());
|
||||||
|
}
|
||||||
|
|
||||||
|
/* clear flag */
|
||||||
|
bitmap.viewport.changed &= ~4;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if video mode has changed */
|
||||||
|
if (bitmap.viewport.changed & 1)
|
||||||
|
{
|
||||||
|
/* clear viewport update flags */
|
||||||
|
bitmap.viewport.changed &= ~1;
|
||||||
|
|
||||||
|
/* field synchronization */
|
||||||
|
do VIDEO_WaitVSync();
|
||||||
|
while (VIDEO_GetNextField() != odd_frame);
|
||||||
|
|
||||||
|
/* resynchronize audio playback with video */
|
||||||
|
AUDIO_StopDMA();
|
||||||
|
AUDIO_StartDMA();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return SYNC_VIDEO;
|
/* wait until current video frame starts before emulating next frame */
|
||||||
|
return ((status & ~(VIDEO_WAIT|VIDEO_UPDATE)) | videoWait);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initialize VIDEO subsystem */
|
/* Initialize VIDEO subsystem */
|
||||||
|
@ -99,6 +99,6 @@ extern void gx_video_Init(void);
|
|||||||
extern void gx_video_Shutdown(void);
|
extern void gx_video_Shutdown(void);
|
||||||
extern void gx_video_Start(void);
|
extern void gx_video_Start(void);
|
||||||
extern void gx_video_Stop(void);
|
extern void gx_video_Stop(void);
|
||||||
extern int gx_video_Update(u32 done);
|
extern int gx_video_Update(int status);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
BIN
gx/images/Ctrl_graphic_board.png
Normal file
BIN
gx/images/Ctrl_graphic_board.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.4 KiB |
77
gx/main.c
77
gx/main.c
@ -57,9 +57,6 @@ extern bool sdio_Deinitialize();
|
|||||||
extern void USBStorage_Deinitialize();
|
extern void USBStorage_Deinitialize();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* output samplerate, adjusted to take resampler precision in account */
|
|
||||||
#define SAMPLERATE_48KHZ 47992
|
|
||||||
|
|
||||||
u32 Shutdown = 0;
|
u32 Shutdown = 0;
|
||||||
u32 ConfigRequested = 1;
|
u32 ConfigRequested = 1;
|
||||||
|
|
||||||
@ -153,28 +150,14 @@ static void run_emulation(void)
|
|||||||
system_frame_scd(0);
|
system_frame_scd(0);
|
||||||
|
|
||||||
/* audio/video sync */
|
/* audio/video sync */
|
||||||
sync = SYNC_WAIT;
|
sync = VIDEO_WAIT | VIDEO_UPDATE | AUDIO_WAIT | AUDIO_UPDATE;
|
||||||
while (sync != (SYNC_VIDEO | SYNC_AUDIO))
|
while (sync)
|
||||||
{
|
{
|
||||||
/* update video */
|
|
||||||
sync |= gx_video_Update(sync & SYNC_VIDEO);
|
|
||||||
|
|
||||||
/* update audio */
|
/* update audio */
|
||||||
sync |= gx_audio_Update();
|
sync &= gx_audio_Update(sync);
|
||||||
}
|
|
||||||
|
|
||||||
/* check interlaced mode change */
|
/* update video */
|
||||||
if (bitmap.viewport.changed & 4)
|
sync &= gx_video_Update(sync);
|
||||||
{
|
|
||||||
/* VSYNC "original" mode */
|
|
||||||
if (!config.render && config.vsync && (gc_pal == vdp_pal))
|
|
||||||
{
|
|
||||||
/* framerate has changed, reinitialize audio timings */
|
|
||||||
audio_init(SAMPLERATE_48KHZ, get_framerate());
|
|
||||||
}
|
|
||||||
|
|
||||||
/* clear flag */
|
|
||||||
bitmap.viewport.changed &= ~4;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -187,28 +170,14 @@ static void run_emulation(void)
|
|||||||
system_frame_gen(0);
|
system_frame_gen(0);
|
||||||
|
|
||||||
/* audio/video sync */
|
/* audio/video sync */
|
||||||
sync = SYNC_WAIT;
|
sync = VIDEO_WAIT | VIDEO_UPDATE | AUDIO_WAIT | AUDIO_UPDATE;
|
||||||
while (sync != (SYNC_VIDEO | SYNC_AUDIO))
|
while (sync)
|
||||||
{
|
{
|
||||||
/* update video */
|
|
||||||
sync |= gx_video_Update(sync & SYNC_VIDEO);
|
|
||||||
|
|
||||||
/* update audio */
|
/* update audio */
|
||||||
sync |= gx_audio_Update();
|
sync &= gx_audio_Update(sync);
|
||||||
}
|
|
||||||
|
|
||||||
/* check interlaced mode change */
|
/* update video */
|
||||||
if (bitmap.viewport.changed & 4)
|
sync &= gx_video_Update(sync);
|
||||||
{
|
|
||||||
/* VSYNC "original" mode */
|
|
||||||
if (!config.render && config.vsync && (gc_pal == vdp_pal))
|
|
||||||
{
|
|
||||||
/* framerate has changed, reinitialize audio timings */
|
|
||||||
audio_init(SAMPLERATE_48KHZ, get_framerate());
|
|
||||||
}
|
|
||||||
|
|
||||||
/* clear flag */
|
|
||||||
bitmap.viewport.changed &= ~4;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -221,28 +190,14 @@ static void run_emulation(void)
|
|||||||
system_frame_sms(0);
|
system_frame_sms(0);
|
||||||
|
|
||||||
/* audio/video sync */
|
/* audio/video sync */
|
||||||
sync = SYNC_WAIT;
|
sync = VIDEO_WAIT | VIDEO_UPDATE | AUDIO_WAIT | AUDIO_UPDATE;
|
||||||
while (sync != (SYNC_VIDEO | SYNC_AUDIO))
|
while (sync)
|
||||||
{
|
{
|
||||||
/* update video */
|
|
||||||
sync |= gx_video_Update(sync & SYNC_VIDEO);
|
|
||||||
|
|
||||||
/* update audio */
|
/* update audio */
|
||||||
sync |= gx_audio_Update();
|
sync &= gx_audio_Update(sync);
|
||||||
}
|
|
||||||
|
|
||||||
/* check interlaced mode change (PBC mode only) */
|
/* update video */
|
||||||
if (bitmap.viewport.changed & 4)
|
sync &= gx_video_Update(sync);
|
||||||
{
|
|
||||||
/* "original" mode */
|
|
||||||
if (!config.render && config.vsync && (gc_pal == vdp_pal))
|
|
||||||
{
|
|
||||||
/* framerate has changed, reinitialize audio timings */
|
|
||||||
audio_init(SAMPLERATE_48KHZ, get_framerate());
|
|
||||||
}
|
|
||||||
|
|
||||||
/* clear flag */
|
|
||||||
bitmap.viewport.changed &= ~4;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -316,7 +271,7 @@ void reloadrom(void)
|
|||||||
{
|
{
|
||||||
/* Initialize audio emulation */
|
/* Initialize audio emulation */
|
||||||
interlaced = 0;
|
interlaced = 0;
|
||||||
audio_init(SAMPLERATE_48KHZ, get_framerate());
|
audio_init(48000, get_framerate());
|
||||||
|
|
||||||
/* System Power-On */
|
/* System Power-On */
|
||||||
system_init();
|
system_init();
|
||||||
|
7
gx/osd.h
7
gx/osd.h
@ -71,9 +71,10 @@
|
|||||||
|
|
||||||
#define VERSION "Genesis Plus GX 1.7.5"
|
#define VERSION "Genesis Plus GX 1.7.5"
|
||||||
|
|
||||||
#define SYNC_WAIT 0
|
#define VIDEO_WAIT 0x01
|
||||||
#define SYNC_VIDEO 1
|
#define AUDIO_WAIT 0x02
|
||||||
#define SYNC_AUDIO 2
|
#define VIDEO_UPDATE 0x04
|
||||||
|
#define AUDIO_UPDATE 0x08
|
||||||
|
|
||||||
/* globals */
|
/* globals */
|
||||||
extern void legal(void);
|
extern void legal(void);
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
#define RETRO_DEVICE_PHASER RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_LIGHTGUN, 0)
|
#define RETRO_DEVICE_PHASER RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_LIGHTGUN, 0)
|
||||||
#define RETRO_DEVICE_MENACER RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_LIGHTGUN, 1)
|
#define RETRO_DEVICE_MENACER RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_LIGHTGUN, 1)
|
||||||
#define RETRO_DEVICE_JUSTIFIERS RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_LIGHTGUN, 2)
|
#define RETRO_DEVICE_JUSTIFIERS RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_LIGHTGUN, 2)
|
||||||
|
#define RETRO_DEVICE_GRAPHIC_BOARD RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_POINTER, 0)
|
||||||
|
|
||||||
#include "shared.h"
|
#include "shared.h"
|
||||||
#include "libretro.h"
|
#include "libretro.h"
|
||||||
@ -334,15 +335,6 @@ void osd_input_update(void)
|
|||||||
input.analog[i][0] = ((input_state_cb(player, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_X) + 0x7fff) * 250) / 0xfffe;
|
input.analog[i][0] = ((input_state_cb(player, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_X) + 0x7fff) * 250) / 0xfffe;
|
||||||
input.analog[i][1] = ((input_state_cb(player, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_Y) + 0x7fff) * 250) / 0xfffe;
|
input.analog[i][1] = ((input_state_cb(player, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_Y) + 0x7fff) * 250) / 0xfffe;
|
||||||
|
|
||||||
if (input.analog[0][0] < 0)
|
|
||||||
input.analog[0][0] = 0;
|
|
||||||
else if (input.analog[0][0] > 250)
|
|
||||||
input.analog[0][0] = 250;
|
|
||||||
if (input.analog[0][1] < 0)
|
|
||||||
input.analog[0][1] = 0;
|
|
||||||
else if (input.analog[0][1] > 250)
|
|
||||||
input.analog[0][1] = 250;
|
|
||||||
|
|
||||||
if (input_state_cb(player, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_LEFT))
|
if (input_state_cb(player, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_LEFT))
|
||||||
temp |= INPUT_BUTTON1;
|
temp |= INPUT_BUTTON1;
|
||||||
if (input_state_cb(player, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_MIDDLE))
|
if (input_state_cb(player, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_MIDDLE))
|
||||||
@ -352,6 +344,22 @@ void osd_input_update(void)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case DEVICE_GRAPHIC_BOARD:
|
||||||
|
{
|
||||||
|
input.analog[i][0] = ((input_state_cb(player, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_X) + 0x7fff) * 255) / 0xfffe;
|
||||||
|
input.analog[i][1] = ((input_state_cb(player, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_Y) + 0x7fff) * 255) / 0xfffe;
|
||||||
|
|
||||||
|
if (input_state_cb(player, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_LEFT))
|
||||||
|
temp |= INPUT_GRAPHIC_PEN;
|
||||||
|
if (input_state_cb(player, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_MIDDLE))
|
||||||
|
temp |= INPUT_GRAPHIC_DO;
|
||||||
|
if (input_state_cb(player, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_RIGHT))
|
||||||
|
temp |= INPUT_GRAPHIC_MENU;
|
||||||
|
|
||||||
|
player++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case DEVICE_XE_1AP:
|
case DEVICE_XE_1AP:
|
||||||
{
|
{
|
||||||
int rx = input.analog[i][0] = input_state_cb(player, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_X);
|
int rx = input.analog[i][0] = input_state_cb(player, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_X);
|
||||||
@ -960,6 +968,7 @@ void retro_set_environment(retro_environment_t cb)
|
|||||||
{ "MS Light Phaser", RETRO_DEVICE_PHASER },
|
{ "MS Light Phaser", RETRO_DEVICE_PHASER },
|
||||||
{ "MS Paddle Control", RETRO_DEVICE_PADDLE },
|
{ "MS Paddle Control", RETRO_DEVICE_PADDLE },
|
||||||
{ "MS Sports Pad", RETRO_DEVICE_SPORTSPAD },
|
{ "MS Sports Pad", RETRO_DEVICE_SPORTSPAD },
|
||||||
|
{ "MS Graphic Board", RETRO_DEVICE_GRAPHIC_BOARD },
|
||||||
{ "MD XE-1AP", RETRO_DEVICE_XE_1AP },
|
{ "MD XE-1AP", RETRO_DEVICE_XE_1AP },
|
||||||
{ "MD Mouse", RETRO_DEVICE_MOUSE },
|
{ "MD Mouse", RETRO_DEVICE_MOUSE },
|
||||||
};
|
};
|
||||||
@ -980,13 +989,14 @@ void retro_set_environment(retro_environment_t cb)
|
|||||||
{ "MS Light Phaser", RETRO_DEVICE_PHASER },
|
{ "MS Light Phaser", RETRO_DEVICE_PHASER },
|
||||||
{ "MS Paddle Control", RETRO_DEVICE_PADDLE },
|
{ "MS Paddle Control", RETRO_DEVICE_PADDLE },
|
||||||
{ "MS Sports Pad", RETRO_DEVICE_SPORTSPAD },
|
{ "MS Sports Pad", RETRO_DEVICE_SPORTSPAD },
|
||||||
|
{ "MS Graphic Board", RETRO_DEVICE_GRAPHIC_BOARD },
|
||||||
{ "MD XE-1AP", RETRO_DEVICE_XE_1AP },
|
{ "MD XE-1AP", RETRO_DEVICE_XE_1AP },
|
||||||
{ "MD Mouse", RETRO_DEVICE_MOUSE },
|
{ "MD Mouse", RETRO_DEVICE_MOUSE },
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct retro_controller_info ports[] = {
|
static const struct retro_controller_info ports[] = {
|
||||||
{ port_1, 15 },
|
{ port_1, 16 },
|
||||||
{ port_2, 17 },
|
{ port_2, 18 },
|
||||||
{ 0 },
|
{ 0 },
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1111,6 +1121,9 @@ void retro_set_controller_port_device(unsigned port, unsigned device)
|
|||||||
case RETRO_DEVICE_MOUSE:
|
case RETRO_DEVICE_MOUSE:
|
||||||
input.system[port] = SYSTEM_MOUSE;
|
input.system[port] = SYSTEM_MOUSE;
|
||||||
break;
|
break;
|
||||||
|
case RETRO_DEVICE_GRAPHIC_BOARD:
|
||||||
|
input.system[port] = SYSTEM_GRAPHIC_BOARD;
|
||||||
|
break;
|
||||||
case RETRO_DEVICE_JOYPAD:
|
case RETRO_DEVICE_JOYPAD:
|
||||||
default:
|
default:
|
||||||
config.input[port*4].padtype = DEVICE_PAD2B | DEVICE_PAD6B | DEVICE_PAD3B;
|
config.input[port*4].padtype = DEVICE_PAD2B | DEVICE_PAD6B | DEVICE_PAD3B;
|
||||||
|
21
sdl/Makefile
21
sdl/Makefile
@ -50,16 +50,17 @@ OBJECTS += $(OBJDIR)/genesis.o \
|
|||||||
$(OBJDIR)/state.o \
|
$(OBJDIR)/state.o \
|
||||||
$(OBJDIR)/loadrom.o
|
$(OBJDIR)/loadrom.o
|
||||||
|
|
||||||
OBJECTS += $(OBJDIR)/input.o \
|
OBJECTS += $(OBJDIR)/input.o \
|
||||||
$(OBJDIR)/gamepad.o \
|
$(OBJDIR)/gamepad.o \
|
||||||
$(OBJDIR)/lightgun.o \
|
$(OBJDIR)/lightgun.o \
|
||||||
$(OBJDIR)/mouse.o \
|
$(OBJDIR)/mouse.o \
|
||||||
$(OBJDIR)/activator.o \
|
$(OBJDIR)/activator.o \
|
||||||
$(OBJDIR)/xe_1ap.o \
|
$(OBJDIR)/xe_1ap.o \
|
||||||
$(OBJDIR)/teamplayer.o \
|
$(OBJDIR)/teamplayer.o \
|
||||||
$(OBJDIR)/paddle.o \
|
$(OBJDIR)/paddle.o \
|
||||||
$(OBJDIR)/sportspad.o \
|
$(OBJDIR)/sportspad.o \
|
||||||
$(OBJDIR)/terebi_oekaki.o
|
$(OBJDIR)/terebi_oekaki.o \
|
||||||
|
$(OBJDIR)/graphic_board.o
|
||||||
|
|
||||||
OBJECTS += $(OBJDIR)/sound.o \
|
OBJECTS += $(OBJDIR)/sound.o \
|
||||||
$(OBJDIR)/sn76489.o \
|
$(OBJDIR)/sn76489.o \
|
||||||
|
18
sdl/main.c
18
sdl/main.c
@ -649,6 +649,24 @@ int sdl_input_update(void)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case DEVICE_GRAPHIC_BOARD:
|
||||||
|
{
|
||||||
|
/* get mouse (absolute values) */
|
||||||
|
int x,y;
|
||||||
|
int state = SDL_GetMouseState(&x,&y);
|
||||||
|
|
||||||
|
/* Calculate X Y axis values */
|
||||||
|
input.analog[0][0] = (x * 255) / VIDEO_WIDTH;
|
||||||
|
input.analog[0][1] = (y * 255) / VIDEO_HEIGHT;
|
||||||
|
|
||||||
|
/* Map mouse buttons to player #1 inputs */
|
||||||
|
if(state & SDL_BUTTON_LMASK) input.pad[0] |= INPUT_GRAPHIC_PEN;
|
||||||
|
if(state & SDL_BUTTON_RMASK) input.pad[0] |= INPUT_GRAPHIC_MENU;
|
||||||
|
if(state & SDL_BUTTON_MMASK) input.pad[0] |= INPUT_GRAPHIC_DO;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case DEVICE_ACTIVATOR:
|
case DEVICE_ACTIVATOR:
|
||||||
{
|
{
|
||||||
if(keystate[SDLK_g]) input.pad[joynum] |= INPUT_ACTIVATOR_7L;
|
if(keystate[SDLK_g]) input.pad[joynum] |= INPUT_ACTIVATOR_7L;
|
||||||
|
Loading…
Reference in New Issue
Block a user