Merge pull request #8 from Oggom/master

Pull latest changes
This commit is contained in:
Twinaphex 2014-10-10 22:10:09 +02:00
commit 258329cad4
34 changed files with 903 additions and 523 deletions

View File

@ -199,6 +199,7 @@ LIBRETRO_SRC := $(GENPLUS_SRC_DIR)/genesis.c \
$(GENPLUS_SRC_DIR)/input_hw/teamplayer.c \
$(GENPLUS_SRC_DIR)/input_hw/xe_1ap.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/cdc.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

View File

@ -60,6 +60,7 @@ typedef struct
/* Function prototypes */
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_sf001_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 */
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 */
cart.hw.bankshift = 1;
@ -913,24 +922,37 @@ static void mapper_sega_w(uint32 data)
}
/*
Super Street Fighter 2 ROM bankswitch
documented by Bart Trzynadlowski (http://www.trzy.org/files/ssf2.txt)
Everdrive extended SSF ROM bankswitch
documented by Krikzz (http://krikzz.com/pub/support/mega-ed/dev/extended_ssf.txt)
*/
static void mapper_ssf2_w(uint32 address, uint32 data)
static void mapper_512k_w(uint32 address, uint32 data)
{
/* 8 x 512k banks */
address = (address << 2) & 0x38;
/* bank 0 remains unchanged */
if (address)
{
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
documented by Bart Trzynadlowski (http://emu-docs.org/Genesis/ssf2.txt)
*/
static void mapper_ssf2_w(uint32 address, uint32 data)
{
/* only banks 1-7 are remappable, bank 0 remains unchanged */
if (address)
{
mapper_512k_w(address, data);
}
}

View File

@ -258,6 +258,9 @@ static const rominfo_t game_list[] =
{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) */
/* 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 */
{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 */
@ -420,7 +423,7 @@ void sms_cart_init(void)
}
/* 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 */
cart.special = game_list[i].g_3d;

View File

@ -2,7 +2,7 @@
* Genesis Plus
* 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
* provided that the following conditions are met:
@ -150,9 +150,6 @@ static const char extensions[SUPPORTED_EXT][16] =
" - %d.wav"
};
static blip_t* blip[2];
#ifdef USE_LIBTREMOR
#ifdef DISABLE_MANY_OGG_OPEN_FILES
static void ogg_free(int i)
@ -172,14 +169,12 @@ static void ogg_free(int i)
#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 */
/* Audio stream is resampled to desired rate using Blip Buffer */
blip[0] = left;
blip[1] = right;
blip_set_rates(left, 44100, snd.sample_rate);
blip_set_rates(right, 44100, snd.sample_rate);
blip_set_rates(snd.blips[2][0], 44100, samplerate);
blip_set_rates(snd.blips[2][1], 44100, samplerate);
}
void cdd_reset(void)
@ -953,7 +948,7 @@ void cdd_read_audio(unsigned int samples)
int16 r = cdd.audio[1];
/* 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 ? */
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;
ptr++;
l += delta;
blip_add_delta_fast(blip[0], i, delta);
blip_add_delta_fast(snd.blips[2][0], i, delta);
/* right channel */
delta = ((ptr[0] * mul) / 1024) - r;
ptr++;
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) */
if (curVol < endVol)
@ -1048,7 +1043,7 @@ void cdd_read_audio(unsigned int samples)
ptr += 2;
#endif
l += delta;
blip_add_delta_fast(blip[0], i, delta);
blip_add_delta_fast(snd.blips[2][0], i, delta);
/* right channel */
#ifdef LSB_FIRST
@ -1059,7 +1054,7 @@ void cdd_read_audio(unsigned int samples)
ptr += 2;
#endif
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) */
if (curVol < endVol)
@ -1090,8 +1085,8 @@ void cdd_read_audio(unsigned int samples)
else
{
/* no audio output */
if (l) blip_add_delta_fast(blip[0], 0, -l);
if (r) blip_add_delta_fast(blip[1], 0, -r);
if (l) blip_add_delta_fast(snd.blips[2][0], 0, -l);
if (r) blip_add_delta_fast(snd.blips[2][1], 0, -r);
/* save audio output for next frame */
cdd.audio[0] = 0;
@ -1099,8 +1094,8 @@ void cdd_read_audio(unsigned int samples)
}
/* end of Blip Buffer timeframe */
blip_end_frame(blip[0], samples);
blip_end_frame(blip[1], samples);
blip_end_frame(snd.blips[2][0], samples);
blip_end_frame(snd.blips[2][1], samples);
}

View File

@ -2,7 +2,7 @@
* Genesis Plus
* 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
* provided that the following conditions are met:
@ -98,7 +98,7 @@ typedef struct
} cdd_t;
/* Function prototypes */
extern void cdd_init(blip_t* left, blip_t* right);
extern void cdd_init(int samplerate);
extern void cdd_reset(void);
extern int cdd_context_save(uint8 *state);
extern int cdd_context_load(uint8 *state);

View File

@ -2,7 +2,7 @@
* Genesis Plus
* 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
* provided that the following conditions are met:
@ -41,19 +41,12 @@
#define pcm scd.pcm_hw
static blip_t* blip[2];
void pcm_init(blip_t* left, blip_t* right)
void pcm_init(double clock, int samplerate)
{
/* number of SCD master clocks run per second */
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 */
/* PCM chip is running at original rate and is synchronized with SUB-CPU */
/* Chip output is resampled to desired rate using Blip Buffer. */
blip[0] = left;
blip[1] = right;
blip_set_rates(left, mclk / PCM_SCYCLES_RATIO, snd.sample_rate);
blip_set_rates(right, mclk / PCM_SCYCLES_RATIO, snd.sample_rate);
blip_set_rates(snd.blips[1][0], clock / PCM_SCYCLES_RATIO, samplerate);
blip_set_rates(snd.blips[1][1], clock / PCM_SCYCLES_RATIO, samplerate);
}
void pcm_reset(void)
@ -78,8 +71,8 @@ void pcm_reset(void)
pcm.cycles = 0;
/* clear blip buffers */
blip_clear(blip[0]);
blip_clear(blip[1]);
blip_clear(snd.blips[1][0]);
blip_clear(snd.blips[1][1]);
}
int pcm_context_save(uint8 *state)
@ -190,14 +183,14 @@ void pcm_run(unsigned int length)
/* check if PCM left output changed */
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;
}
/* check if PCM right output changed */
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;
}
}
@ -207,21 +200,21 @@ void pcm_run(unsigned int length)
/* check if PCM left output changed */
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;
}
/* check if PCM right output changed */
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;
}
}
/* end of blip buffer frame */
blip_end_frame(blip[0], length);
blip_end_frame(blip[1], length);
blip_end_frame(snd.blips[1][0], length);
blip_end_frame(snd.blips[1][1], length);
/* update PCM master clock counter */
pcm.cycles += length * PCM_SCYCLES_RATIO;
@ -230,7 +223,7 @@ void pcm_run(unsigned int length)
void pcm_update(unsigned int samples)
{
/* 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 */
if (clocks > 0)

View File

@ -2,7 +2,7 @@
* Genesis Plus
* 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
* provided that the following conditions are met:
@ -65,7 +65,7 @@ typedef struct
} pcm_t;
/* 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 int pcm_context_save(uint8 *state);
extern int pcm_context_load(uint8 *state);

View 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;
}

View 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

View File

@ -47,6 +47,7 @@
#include "paddle.h"
#include "sportspad.h"
#include "terebi_oekaki.h"
#include "graphic_board.h"
t_input input;
int old_system[2] = {-1,-1};
@ -203,6 +204,13 @@ void input_init(void)
player++;
break;
}
case SYSTEM_GRAPHIC_BOARD:
{
input.dev[0] = DEVICE_GRAPHIC_BOARD;
player++;
break;
}
}
if (player == MAX_INPUTS)
@ -322,6 +330,13 @@ void input_init(void)
player++;
break;
}
case SYSTEM_GRAPHIC_BOARD:
{
input.dev[4] = DEVICE_GRAPHIC_BOARD;
player++;
break;
}
}
/* J-CART */
@ -405,6 +420,12 @@ void input_reset(void)
break;
}
case DEVICE_GRAPHIC_BOARD:
{
graphic_board_reset(i);
break;
}
default:
{
break;

View File

@ -54,9 +54,10 @@
#define SYSTEM_LIGHTPHASER (7) /* Sega Light Phaser */
#define SYSTEM_PADDLE (8) /* Sega Paddle Control */
#define SYSTEM_SPORTSPAD (9) /* Sega Sports Pad */
#define SYSTEM_MASTERTAP (10) /* Multi Tap -- Furrtek's Master Tap (unofficial) */
#define SYSTEM_TEAMPLAYER (11) /* Multi Tap -- Sega TeamPlayer */
#define SYSTEM_WAYPLAY (12) /* Multi Tap -- EA 4-Way Play (use both ports) */
#define SYSTEM_GRAPHIC_BOARD (10) /* Sega Graphic Board */
#define SYSTEM_MASTERTAP (11) /* Multi Tap -- Furrtek's Master Tap (unofficial) */
#define SYSTEM_TEAMPLAYER (12) /* Multi Tap -- Sega TeamPlayer */
#define SYSTEM_WAYPLAY (13) /* Multi Tap -- EA 4-Way Play (use both ports) */
/* Device type */
#define NO_DEVICE (0xff) /* unconnected device (fixed ID for Team Player) */
@ -67,10 +68,11 @@
#define DEVICE_LIGHTGUN (0x04) /* Sega Light Phaser, Menacer or Konami Justifiers */
#define DEVICE_PADDLE (0x05) /* Sega Paddle Control */
#define DEVICE_SPORTSPAD (0x06) /* Sega Sports Pad */
#define DEVICE_PICO (0x07) /* PICO tablet */
#define DEVICE_TEREBI (0x08) /* Terebi Oekaki tablet */
#define DEVICE_XE_1AP (0x09) /* XE-1AP analog controller */
#define DEVICE_ACTIVATOR (0x0a) /* Activator */
#define DEVICE_GRAPHIC_BOARD (0x07) /* Sega Graphic Board */
#define DEVICE_PICO (0x08) /* PICO tablet */
#define DEVICE_TEREBI (0x09) /* Terebi Oekaki tablet */
#define DEVICE_XE_1AP (0x0a) /* XE-1AP analog controller */
#define DEVICE_ACTIVATOR (0x0b) /* Activator */
/* Default Input bitmasks */
#define INPUT_MODE (0x0800)
@ -127,6 +129,11 @@
#define INPUT_ACTIVATOR_1U (0x0002)
#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
{
uint8 system[2]; /* can be one of the SYSTEM_* values */

View File

@ -48,6 +48,7 @@
#include "teamplayer.h"
#include "paddle.h"
#include "sportspad.h"
#include "graphic_board.h"
uint8 io_reg[0x10];
@ -150,6 +151,13 @@ void io_init(void)
break;
}
case SYSTEM_GRAPHIC_BOARD:
{
port[0].data_w = graphic_board_write;
port[0].data_r = graphic_board_read;
break;
}
default:
{
port[0].data_w = dummy_write;
@ -244,6 +252,13 @@ void io_init(void)
break;
}
case SYSTEM_GRAPHIC_BOARD:
{
port[1].data_w = graphic_board_write;
port[1].data_r = graphic_board_read;
break;
}
default:
{
port[1].data_w = dummy_write;

View File

@ -94,15 +94,10 @@ static const uint16 PSGVolumeValues[16] =
static SN76489_Context SN76489;
static blip_t* blip[2];
void SN76489_Init(blip_t* left, blip_t* right, int type)
void SN76489_Init(int type)
{
int i;
blip[0] = left;
blip[1] = right;
for (i=0; i<4; i++)
{
SN76489.PreAmp[i][0] = 100;
@ -177,7 +172,7 @@ INLINE void UpdateToneAmplitude(int i, int time)
if (delta != 0)
{
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 */
@ -185,7 +180,7 @@ INLINE void UpdateToneAmplitude(int i, int time)
if (delta != 0)
{
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)
{
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 */
@ -207,7 +202,7 @@ INLINE void UpdateNoiseAmplitude(int time)
if (delta != 0)
{
SN76489.ChanOut[3][1] += delta;
blip_add_delta_fast(blip[1], time, delta);
blip_add_delta_fast(snd.blips[0][1], time, delta);
}
}

View File

@ -12,7 +12,7 @@
#define SN_INTEGRATED 1
/* 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_Config(unsigned int clocks, int preAmp, int boostNoise, int stereo);
extern void SN76489_Write(unsigned int clocks, unsigned int data);

View File

@ -102,6 +102,7 @@ void sound_init( void )
}
/* Initialize PSG chip */
SN76489_Init((system_hw == SYSTEM_SG) ? SN_DISCRETE : SN_INTEGRATED);
SN76489_Config(0, config.psg_preamp, config.psgBoostNoise, 0xff);
}

View File

@ -116,12 +116,10 @@ int state_load(unsigned char *state)
bufferptr += sound_context_load(&state[bufferptr]);
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);
}
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]);
}

View File

@ -60,6 +60,50 @@ static int16 llp,rrp;
/******************************************************************************************/
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. */
/* 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;
/* 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 */
/* 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 */
@ -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][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 */
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;
/* number of SCD master clocks run per second */
mclk = framerate ? (SCYCLES_PER_LINE * (vdp_pal ? 313 : 262) * framerate) : SCD_CLOCK;
/* PCM core */
pcm_init(mclk, samplerate);
/* CDD core */
cdd_init(samplerate);
}
/* Initialize PCM core */
pcm_init(snd.blips[1][0], snd.blips[1][1]);
/* Initialize CDD core */
cdd_init(snd.blips[2][0], snd.blips[2][1]);
}
/* Set audio enable flag */
snd.enabled = 1;
/* Reset audio */
audio_reset();
return (0);
/* Reinitialize internal rates */
snd.sample_rate = samplerate;
snd.frame_rate = framerate;
}
void audio_reset(void)

View File

@ -106,6 +106,7 @@ extern uint32 system_clock;
/* Function prototypes */
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_shutdown(void);
extern int audio_update(int16 *buffer);

View File

@ -214,7 +214,7 @@ static void selector_cb(void)
}
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 */
string_offset ++;
@ -231,7 +231,7 @@ static void selector_cb(void)
}
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);
}
}

View File

@ -109,6 +109,7 @@ extern const u8 Ctrl_sportspad_png[];
extern const u8 Ctrl_none_png[];
extern const u8 Ctrl_teamplayer_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_pad2b_png[];
extern const u8 Ctrl_pad3b_png[];
@ -2205,7 +2206,7 @@ static void ctrlmenu(void)
u32 exp, index = 0;
/* 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},
@ -2215,9 +2216,10 @@ static void ctrlmenu(void)
{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_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_sportspad_png ,"","Select Port 1 device", 95,117,76,84},
{NULL,Ctrl_graphic_board_png ,"","Select Port 1 device", 90,105,88,96},
{NULL,Ctrl_mastertap_png ,"","Select Port 1 device", 96,104,76,96},
{NULL,Ctrl_teamplayer_png ,"","Select Port 1 device", 94,109,80,92},
{NULL,Ctrl_4wayplay_png ,"","Select Port 1 device", 98,110,72,92}
@ -2230,9 +2232,10 @@ static void ctrlmenu(void)
{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_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_sportspad_png ,"","Select Port 2 device", 95,287,76,84},
{NULL,Ctrl_graphic_board_png ,"","Select Port 2 device", 90,275,88,96},
{NULL,Ctrl_mastertap_png ,"","Select Port 1 device", 96,274,76,96},
{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);
/* 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);
}
@ -2378,6 +2381,12 @@ static void ctrlmenu(void)
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 */
if (input.system[0] == SYSTEM_WAYPLAY)
{
@ -2471,6 +2480,12 @@ static void ctrlmenu(void)
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 */
if (input.system[1] == SYSTEM_WAYPLAY)
{
@ -2852,7 +2867,7 @@ static void ctrlmenu(void)
if (config.input[player].device >= 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 */
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]);
/* delete custom images */
for (i=0; i<13; i++)
for (i=0; i<14; i++)
{
gxTextureClose(&items_sys[0][i].texture);
}

View File

@ -45,14 +45,12 @@
/* Number of sound buffers */
#define SOUND_BUFFER_NUM 3
/* audio DMA status */
u32 audioStarted;
/* DMA soundbuffers (required to be 32-bytes aligned) */
static u8 soundbuffer[SOUND_BUFFER_NUM][SOUND_BUFFER_LEN] ATTRIBUTE_ALIGN(32);
/* Current work soundbuffer */
static u8 mixbuffer;
static int bufferIndex;
static int bufferSize;
/* Background music */
static u8 *Bg_music_ogg = NULL;
@ -96,9 +94,6 @@ void gx_audio_Init(void)
}
fclose(f);
}
/* emulation is synchronized with audio hardware by default */
audioSync = 1;
}
/* 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
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)
/* Current available soundbuffer */
s16 *sb = (s16 *)(soundbuffer[bufferIndex]);
/* Make sure current audio frame has not already been updated */
if (status & AUDIO_UPDATE)
{
return SYNC_WAIT;
/* Retrieve audio samples (size must be multiple of 32 bytes) */
bufferSize = audio_update(sb) * 4;
DCFlushRange((void *)sb, bufferSize);
/* Mark current audio frame as being updated */
status &= ~AUDIO_UPDATE;
}
/* Current available soundbuffer */
s16 *sb = (s16 *)(soundbuffer[mixbuffer]);
/* 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);
/* Retrieve audio samples (size must be multiple of 32 bytes) */
int size = audio_update(sb) * 4;
/* Update DMA settings */
DCFlushRange((void *)sb, size);
AUDIO_InitDMA((u32) sb, size);
mixbuffer = (mixbuffer + 1) % SOUND_BUFFER_NUM;
/* Next soundbuffer */
bufferIndex = (bufferIndex + 1) % SOUND_BUFFER_NUM;
/* Set audio wait flag */
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 */
AUDIO_StopDMA();
AUDIO_StartDMA();
audioStarted = 1;
/* Current audio frame is ready for upcoming DMA */
status &= ~AUDIO_WAIT;
}
return SYNC_AUDIO;
return status;
}
/***
gx_audio_Start
This function restart the audio engine
This function restarts the audio engine
This is called when coming back from Main Menu
***/
void gx_audio_Start(void)
@ -181,11 +190,14 @@ void gx_audio_Start(void)
/* DMA Interrupt callback */
AUDIO_RegisterDMACallback(ai_callback);
/* emulation is synchronized with audio hardware by default */
audioSync = AUDIO_WAIT;
/* reset emulation audio processing */
memset(soundbuffer, 0, sizeof(soundbuffer));
audioStarted = 0;
mixbuffer = 0;
audioWait = 0;
bufferSize = 0;
bufferIndex = 0;
}
/***
@ -193,7 +205,6 @@ void gx_audio_Start(void)
This function stops current Audio DMA process
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)
{

View File

@ -40,13 +40,12 @@
#ifndef _GC_AUDIO_H_
#define _GC_AUDIO_H_
extern u32 audioStarted;
extern u32 audioSync;
extern void gx_audio_Init(void);
extern void gx_audio_Shutdown(void);
extern void gx_audio_Start(void);
extern void gx_audio_Stop(void);
extern int gx_audio_Update(void);
extern int gx_audio_Update(int status);
#endif

View File

@ -221,8 +221,8 @@ static void pad_update(s8 chan, u8 i)
/* Default fast-forward key combo */
if ((p & PAD_TRIGGER_R) && (PAD_ButtonsDown(0) & PAD_BUTTON_START))
{
audioSync ^= 1;
videoSync = audioSync & config.vsync & !(gc_pal ^ vdp_pal);
audioSync ^= AUDIO_WAIT;
videoSync = (audioSync && config.vsync && (gc_pal != vdp_pal)) ? VIDEO_WAIT : 0;
return;
}
@ -386,10 +386,8 @@ static void pad_update(s8 chan, u8 i)
if (input.analog[0][1] < 0x1fc) input.analog[0][1] = 0x1fc;
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;
/* RED button */
if (p & pad_keymap[KEY_BUTTONB]) input.pad[0] |= INPUT_PICO_PEN;
/* PAGE index increment */
@ -416,6 +414,26 @@ static void pad_update(s8 chan, u8 i)
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:
{
/* Left & right analog stick angle [0-360] */
@ -893,12 +911,25 @@ static void wpad_update(s8 chan, u8 i, u32 exp)
case DEVICE_MOUSE:
{
/* Mouse relative movement (-255,255) */
input.analog[i][0] = (x / ANALOG_SENSITIVITY) * 2;
input.analog[i][1] = (y / ANALOG_SENSITIVITY) * 2;
/* Wiimote IR (buggy) */
if (exp != WPAD_EXP_CLASSIC)
if (MOUSE_IsConnected())
{
/* 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;
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);
}
}
/* USB mouse support */
if (MOUSE_IsConnected())
else
{
/* read mouse data */
mouse_event event;
MOUSE_GetEvent(&event);
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;
/* Classic Controller analog stick position (-127;+127) -> (-255;+255) */
input.analog[i][0] = (x / ANALOG_SENSITIVITY) * 2;
input.analog[i][1] = (y / ANALOG_SENSITIVITY) * 2;
}
/* 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;
/* 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)
{
/* Wiimote IR */
struct ir_t ir;
WPAD_IR(chan, &ir);
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;
}
}
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;
/* RED button */
if (p & wpad_keymap[KEY_BUTTONB]) input.pad[0] |= INPUT_PICO_RED;
/* PAGE index increment */
@ -988,18 +1008,9 @@ static void wpad_update(s8 chan, u8 i, u32 exp)
case DEVICE_TEREBI:
{
/* 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)
{
/* Wiimote IR */
struct ir_t ir;
WPAD_IR(chan, &ir);
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;
}
}
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 */
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;
}
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:
{
/* Classic Controller only */
@ -1421,6 +1479,17 @@ void gx_input_Config(u8 chan, u8 device, u8 type)
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:
{
first_key = KEY_BUTTONA;
@ -1465,8 +1534,8 @@ void gx_input_UpdateEmu(void)
/* Default fast-forward key combo */
if (WPAD_ButtonsHeld(0) & (WPAD_BUTTON_MINUS | WPAD_CLASSIC_BUTTON_MINUS))
{
audioSync ^= 1;
videoSync = audioSync & config.vsync & !(gc_pal ^ vdp_pal);
audioSync ^= AUDIO_WAIT;
videoSync = (audioSync && config.vsync && (gc_pal != vdp_pal)) ? VIDEO_WAIT : 0;
return;
}
@ -1539,6 +1608,36 @@ void gx_input_UpdateMenu(void)
/* WPAD held keys (direction/selection) */
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) */
x = wpad_StickX(data, 0);
y = wpad_StickY(data, 0);

View File

@ -357,9 +357,42 @@ static u8 d_list[32] ATTRIBUTE_ALIGN(32) =
/* VSYNC callback */
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 */
videoWait = 0;
}
/* XFB update */
static void xfb_update(u32 cnt)
{
/* check if EFB rendering is finished */
if (drawDone)
{
@ -493,8 +526,8 @@ static void gxSetAspectRatio(int *xscale, int *yscale)
/* Horizontal Scaling */
/* Wii/Gamecube pixel clock = 13.5 Mhz */
/* "H32" pixel clock = Master Clock / 10 = 5.3693175 Mhz (NTSC) or 5.3203424 (PAL) */
/* "H40" pixel clock = Master Clock / 8 = 6,711646875 Mhz (NTSC) or 6,650428 Mhz (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) */
if (config.overscan & 2)
{
/* Horizontal borders are emulated */
@ -505,7 +538,7 @@ static void gxSetAspectRatio(int *xscale, int *yscale)
}
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;
}
}
@ -1424,15 +1457,15 @@ void gxTextureClose(gx_texture **p_texture)
/* Emulation mode -> Menu mode */
void gx_video_Stop(void)
{
/* disable VSYNC callback */
/* disable VSYNC callbacks */
VIDEO_SetPostRetraceCallback(NULL);
VIDEO_SetPreRetraceCallback(NULL);
/* wait for next even field */
/* this prevents screen artefacts when switching between interlaced & non-interlaced modes */
do VIDEO_WaitVSync();
while (!VIDEO_GetNextField());
/* adjust TV width */
vmode->viWidth = config.screen_w;
vmode->viXOrigin = (VI_MAX_WIDTH_NTSC - vmode->viWidth)/2;
@ -1478,11 +1511,6 @@ void gx_video_Stop(void)
/* Menu mode -> Emulation mode */
void gx_video_Start(void)
{
#ifdef HW_RVL
VIDEO_SetTrapFilter(config.trap);
VIDEO_SetGamma((int)(config.gamma * 10.0));
#endif
/* TV mode */
if ((config.tv_mode == 1) || ((config.tv_mode == 2) && vdp_pal))
{
@ -1495,16 +1523,6 @@ void gx_video_Start(void)
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 */
if (config.render == 2)
{
@ -1657,8 +1675,24 @@ void gx_video_Start(void)
do VIDEO_WaitVSync();
while (!VIDEO_GetNextField());
/* VSYNC callback */
#ifdef HW_RVL
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 */
videoWait = 0;
@ -1667,10 +1701,12 @@ void gx_video_Start(void)
}
/* 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)
{
/* set video wait flag if VSYNC is enabled */
videoWait = videoSync;
/* check if display has changed during frame */
@ -1797,6 +1833,7 @@ int gx_video_Update(u32 done)
GX_SetBlendMode(GX_BM_NONE,GX_BL_SRCALPHA,GX_BL_INVSRCALPHA,GX_LO_CLEAR);
GX_Flush();
/* display on-screen message */
gxDrawOnScreenText(msg);
}
@ -1814,30 +1851,41 @@ int gx_video_Update(u32 done)
gxResetRendering(0);
}
/* GX draw interrupt will be triggered when EFB rendering is finished */
/* Do not wait for EFB rendering, GX draw interrupt will be triggered when it is finished */
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 update flags */
/* clear viewport update flags */
bitmap.viewport.changed &= ~1;
/* field synchronization */
VIDEO_WaitVSync();
if (rmode->viTVMode & VI_NON_INTERLACE)
{
VIDEO_WaitVSync();
do VIDEO_WaitVSync();
while (VIDEO_GetNextField() != odd_frame);
/* resynchronize audio playback with video */
AUDIO_StopDMA();
AUDIO_StartDMA();
}
else while (VIDEO_GetNextField() != odd_frame)
{
VIDEO_WaitVSync();
}
/* Audio DMA need to be resynchronized with VSYNC */
audioStarted = 0;
}
return SYNC_VIDEO;
/* wait until current video frame starts before emulating next frame */
return ((status & ~(VIDEO_WAIT|VIDEO_UPDATE)) | videoWait);
}
/* Initialize VIDEO subsystem */

View File

@ -99,6 +99,6 @@ extern void gx_video_Init(void);
extern void gx_video_Shutdown(void);
extern void gx_video_Start(void);
extern void gx_video_Stop(void);
extern int gx_video_Update(u32 done);
extern int gx_video_Update(int status);
#endif

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

View File

@ -57,9 +57,6 @@ extern bool sdio_Deinitialize();
extern void USBStorage_Deinitialize();
#endif
/* output samplerate, adjusted to take resampler precision in account */
#define SAMPLERATE_48KHZ 47992
u32 Shutdown = 0;
u32 ConfigRequested = 1;
@ -153,28 +150,14 @@ static void run_emulation(void)
system_frame_scd(0);
/* audio/video sync */
sync = SYNC_WAIT;
while (sync != (SYNC_VIDEO | SYNC_AUDIO))
sync = VIDEO_WAIT | VIDEO_UPDATE | AUDIO_WAIT | AUDIO_UPDATE;
while (sync)
{
/* update video */
sync |= gx_video_Update(sync & SYNC_VIDEO);
/* update audio */
sync |= gx_audio_Update();
}
sync &= gx_audio_Update(sync);
/* check interlaced mode change */
if (bitmap.viewport.changed & 4)
{
/* 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;
/* update video */
sync &= gx_video_Update(sync);
}
}
}
@ -187,28 +170,14 @@ static void run_emulation(void)
system_frame_gen(0);
/* audio/video sync */
sync = SYNC_WAIT;
while (sync != (SYNC_VIDEO | SYNC_AUDIO))
sync = VIDEO_WAIT | VIDEO_UPDATE | AUDIO_WAIT | AUDIO_UPDATE;
while (sync)
{
/* update video */
sync |= gx_video_Update(sync & SYNC_VIDEO);
/* update audio */
sync |= gx_audio_Update();
}
sync &= gx_audio_Update(sync);
/* check interlaced mode change */
if (bitmap.viewport.changed & 4)
{
/* 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;
/* update video */
sync &= gx_video_Update(sync);
}
}
}
@ -221,28 +190,14 @@ static void run_emulation(void)
system_frame_sms(0);
/* audio/video sync */
sync = SYNC_WAIT;
while (sync != (SYNC_VIDEO | SYNC_AUDIO))
sync = VIDEO_WAIT | VIDEO_UPDATE | AUDIO_WAIT | AUDIO_UPDATE;
while (sync)
{
/* update video */
sync |= gx_video_Update(sync & SYNC_VIDEO);
/* update audio */
sync |= gx_audio_Update();
}
sync &= gx_audio_Update(sync);
/* check interlaced mode change (PBC mode only) */
if (bitmap.viewport.changed & 4)
{
/* "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;
/* update video */
sync &= gx_video_Update(sync);
}
}
}
@ -316,7 +271,7 @@ void reloadrom(void)
{
/* Initialize audio emulation */
interlaced = 0;
audio_init(SAMPLERATE_48KHZ, get_framerate());
audio_init(48000, get_framerate());
/* System Power-On */
system_init();

View File

@ -71,9 +71,10 @@
#define VERSION "Genesis Plus GX 1.7.5"
#define SYNC_WAIT 0
#define SYNC_VIDEO 1
#define SYNC_AUDIO 2
#define VIDEO_WAIT 0x01
#define AUDIO_WAIT 0x02
#define VIDEO_UPDATE 0x04
#define AUDIO_UPDATE 0x08
/* globals */
extern void legal(void);

View File

@ -27,6 +27,7 @@
#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_JUSTIFIERS RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_LIGHTGUN, 2)
#define RETRO_DEVICE_GRAPHIC_BOARD RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_POINTER, 0)
#include "shared.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][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))
temp |= INPUT_BUTTON1;
if (input_state_cb(player, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_MIDDLE))
@ -352,6 +344,22 @@ void osd_input_update(void)
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:
{
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 Paddle Control", RETRO_DEVICE_PADDLE },
{ "MS Sports Pad", RETRO_DEVICE_SPORTSPAD },
{ "MS Graphic Board", RETRO_DEVICE_GRAPHIC_BOARD },
{ "MD XE-1AP", RETRO_DEVICE_XE_1AP },
{ "MD Mouse", RETRO_DEVICE_MOUSE },
};
@ -980,13 +989,14 @@ void retro_set_environment(retro_environment_t cb)
{ "MS Light Phaser", RETRO_DEVICE_PHASER },
{ "MS Paddle Control", RETRO_DEVICE_PADDLE },
{ "MS Sports Pad", RETRO_DEVICE_SPORTSPAD },
{ "MS Graphic Board", RETRO_DEVICE_GRAPHIC_BOARD },
{ "MD XE-1AP", RETRO_DEVICE_XE_1AP },
{ "MD Mouse", RETRO_DEVICE_MOUSE },
};
static const struct retro_controller_info ports[] = {
{ port_1, 15 },
{ port_2, 17 },
{ port_1, 16 },
{ port_2, 18 },
{ 0 },
};
@ -1111,6 +1121,9 @@ void retro_set_controller_port_device(unsigned port, unsigned device)
case RETRO_DEVICE_MOUSE:
input.system[port] = SYSTEM_MOUSE;
break;
case RETRO_DEVICE_GRAPHIC_BOARD:
input.system[port] = SYSTEM_GRAPHIC_BOARD;
break;
case RETRO_DEVICE_JOYPAD:
default:
config.input[port*4].padtype = DEVICE_PAD2B | DEVICE_PAD6B | DEVICE_PAD3B;

View File

@ -59,7 +59,8 @@ OBJECTS += $(OBJDIR)/input.o \
$(OBJDIR)/teamplayer.o \
$(OBJDIR)/paddle.o \
$(OBJDIR)/sportspad.o \
$(OBJDIR)/terebi_oekaki.o
$(OBJDIR)/terebi_oekaki.o \
$(OBJDIR)/graphic_board.o
OBJECTS += $(OBJDIR)/sound.o \
$(OBJDIR)/sn76489.o \

View File

@ -649,6 +649,24 @@ int sdl_input_update(void)
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:
{
if(keystate[SDLK_g]) input.pad[joynum] |= INPUT_ACTIVATOR_7L;