mirror of
https://github.com/ekeeke/Genesis-Plus-GX.git
synced 2024-12-27 03:31:49 +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/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 |
@ -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,25 +922,38 @@ 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)
|
||||
{
|
||||
/* 8 x 512k banks */
|
||||
address = (address << 2) & 0x38;
|
||||
|
||||
/* bank 0 remains unchanged */
|
||||
if (address)
|
||||
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
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
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 "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;
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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]);
|
||||
}
|
||||
|
||||
|
100
core/system.c
100
core/system.c
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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},
|
||||
@ -2218,6 +2219,7 @@ static void ctrlmenu(void)
|
||||
{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}
|
||||
@ -2233,6 +2235,7 @@ static void ctrlmenu(void)
|
||||
{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);
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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
|
||||
|
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 */
|
||||
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);
|
||||
|
124
gx/gx_video.c
124
gx/gx_video.c
@ -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 */
|
||||
|
@ -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
|
||||
|
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();
|
||||
#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();
|
||||
|
7
gx/osd.h
7
gx/osd.h
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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 \
|
||||
|
18
sdl/main.c
18
sdl/main.c
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user