Merge remote-tracking branch 'upstream/master'

This commit is contained in:
sergiobenrocha2 2017-01-02 01:14:52 -02:00
commit 0247ea6202
59 changed files with 2664 additions and 943 deletions

5
.gitignore vendored
View File

@ -3,3 +3,8 @@ psp2/*.elf
psp2/*.velf
psp2/build_vita/*
psp2/*.a
sdl/gen_sdl
sdl/gen_sdl2
sdl/build_sdl
sdl/build_sdl2

View File

@ -28,6 +28,7 @@ Genesis Plus GX 1.7.5 (xx/xx/xxxx) (Eke-Eke)
* fixed CDD "no disc" status code (fixes boot sequence loading time when no disc is loaded)
* fixed AUDIO tracks length calculation when using separated files (WAV/OGG/BIN) with INDEX pause defined in CUE file
* fixed OGG file seeking when using with CUE file
* fixed WAV file detection to support files generated by Audacity/FFmpeg/libavformat with RIFF header metadata chunks
* fixed PRG-RAM access from MAIN-CPU side on system reset
* fixed state loading bug when SUB-CPU interrupt is pending
* fixed incorrect masking of Level 3 (GFX) interrupts (spurious freeze during Japanese BIOS intro)
@ -112,6 +113,11 @@ Genesis Plus GX 1.7.5 (xx/xx/xxxx) (Eke-Eke)
* fixed 68k cycles delay on invalid VRAM writes (fixes "Microcosm" intro loop)
* optimized tile caching
[Core/Sound]
---------------
* rewrote optimized & more accurate PSG core from scratch
* removed PSG boost noise feature & added optional high-quality PSG resampling
[Gamecube/Wii]
---------------
* added configurable BIOS & Lock-on ROM files

View File

@ -27,7 +27,7 @@ INCLUDES := core core/m68k core/z80 core/sound core/tremor core/ntsc core/input_
# options for code generation
#---------------------------------------------------------------------------------
CFLAGS = -O3 -fomit-frame-pointer -Wall -Wno-strict-aliasing $(MACHDEP) $(INCLUDE) -DUSE_LIBTREMOR -DDISABLE_MANY_OGG_OPEN_FILES -DUSE_16BPP_RENDERING -DALT_RENDERER
CFLAGS = -O3 -fomit-frame-pointer -Wall -Wno-strict-aliasing $(MACHDEP) $(INCLUDE) -DUSE_LIBTREMOR -DDISABLE_MANY_OGG_OPEN_FILES -DUSE_16BPP_RENDERING -DALT_RENDERER -DBLIP_INVERT
CXXFLAGS = $(CFLAGS)
LDFLAGS = $(MACHDEP) -Wl,-Map,$(notdir $@).map

View File

@ -27,7 +27,7 @@ INCLUDES := core core/m68k core/z80 core/sound core/tremor core/ntsc core/input_
# options for code generation
#---------------------------------------------------------------------------------
CFLAGS = -O3 -fomit-frame-pointer -Wall -Wno-strict-aliasing $(MACHDEP) $(INCLUDE) -DUSE_LIBTREMOR -DUSE_16BPP_RENDERING -DALT_RENDERER -DHW_RVL
CFLAGS = -O3 -fomit-frame-pointer -Wall -Wno-strict-aliasing $(MACHDEP) $(INCLUDE) -DUSE_LIBTREMOR -DUSE_16BPP_RENDERING -DALT_RENDERER -DBLIP_INVERT -DHW_RVL
CXXFLAGS = $(CFLAGS)
LDFLAGS = $(MACHDEP) -Wl,-Map,$(notdir $@).map,-wrap,wiiuse_set_ir,-wrap,wiiuse_handshake,-wrap,classic_ctrl_handshake,-wrap,classic_ctrl_event

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 MiB

After

Width:  |  Height:  |  Size: 3.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 MiB

After

Width:  |  Height:  |  Size: 3.3 MiB

View File

@ -2,7 +2,7 @@
* Genesis Plus
* Backup RAM support
*
* Copyright (C) 2007-2013 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2007-2016 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
@ -68,7 +68,17 @@ void sram_init()
sram.sram = cart.rom + 0x800000;
/* initialize Backup RAM */
memset(sram.sram, 0xFF, 0x10000);
if (strstr(rominfo.international,"Sonic 1 Remastered"))
{
/* Sonic 1 Remastered hack crashes if backup RAM is not initialized to zero */
memset(sram.sram, 0x00, 0x10000);
}
else
{
/* by default, assume backup RAM is initialized to 0xFF (Micro Machines 2, Dino Dini Soccer) */
memset(sram.sram, 0xFF, 0x10000);
}
sram.crc = crc32(0, sram.sram, 0x10000);
/* retrieve informations from header */

View File

@ -2,7 +2,7 @@
* Genesis Plus
* Backup RAM support
*
* Copyright (C) 2007-2013 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2007-2016 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:

View File

@ -123,10 +123,10 @@ static const uint32 toc_ffightj[29] =
};
/* supported WAVE file header (16-bit stereo samples @44.1kHz) */
static const unsigned char waveHeader[32] =
static const unsigned char waveHeader[28] =
{
0x57,0x41,0x56,0x45,0x66,0x6d,0x74,0x20,0x10,0x00,0x00,0x00,0x01,0x00,0x02,0x00,
0x44,0xac,0x00,0x00,0x10,0xb1,0x02,0x00,0x04,0x00,0x10,0x00,0x64,0x61,0x74,0x61
0x57,0x41,0x56,0x45,0x66,0x6d,0x74,0x20,0x10,0x00,0x00,0x00,0x01,0x00,
0x02,0x00,0x44,0xac,0x00,0x00,0x10,0xb1,0x02,0x00,0x04,0x00,0x10,0x00
};
/* supported WAVE file extensions */
@ -179,8 +179,7 @@ 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_set_rates(snd.blips[2][0], 44100, samplerate);
blip_set_rates(snd.blips[2][1], 44100, samplerate);
blip_set_rates(snd.blips[2], 44100, samplerate);
}
void cdd_reset(void)
@ -449,16 +448,39 @@ int cdd_load(char *filename, char *header)
if (!strstr(lptr,"BINARY") && !strstr(lptr,"MOTOROLA"))
{
/* read file header */
unsigned char head[32];
unsigned char head[28];
fseek(cdd.toc.tracks[cdd.toc.last].fd, 8, SEEK_SET);
fread(head, 32, 1, cdd.toc.tracks[cdd.toc.last].fd);
fread(head, 28, 1, cdd.toc.tracks[cdd.toc.last].fd);
fseek(cdd.toc.tracks[cdd.toc.last].fd, 0, SEEK_SET);
/* autodetect WAVE file header (44.1KHz 16-bit stereo format only) */
if (!memcmp(head, waveHeader, 32))
if (!memcmp(head, waveHeader, 28))
{
/* look for 'data' chunk id */
int dataOffset = 0;
fseek(cdd.toc.tracks[cdd.toc.last].fd, 36, SEEK_SET);
while (fread(head, 4, 1, cdd.toc.tracks[cdd.toc.last].fd))
{
if (!memcmp(head, "data", 4))
{
dataOffset = ftell(cdd.toc.tracks[cdd.toc.last].fd) + 4;
fseek(cdd.toc.tracks[cdd.toc.last].fd, 0, SEEK_SET);
break;
}
fseek(cdd.toc.tracks[cdd.toc.last].fd, -2, SEEK_CUR);
}
/* check if 'data' chunk has not been found */
if (!dataOffset)
{
/* invalid WAVE file */
fclose(cdd.toc.tracks[cdd.toc.last].fd);
cdd.toc.tracks[cdd.toc.last].fd = 0;
break;
}
/* adjust current track file read offset with WAVE header length */
cdd.toc.tracks[cdd.toc.last].offset -= 44;
cdd.toc.tracks[cdd.toc.last].offset -= dataOffset;
}
#if defined(USE_LIBTREMOR) || defined(USE_LIBVORBIS)
else if (!ov_open(cdd.toc.tracks[cdd.toc.last].fd,&cdd.toc.tracks[cdd.toc.last].vf,0,0))
@ -699,14 +721,35 @@ int cdd_load(char *filename, char *header)
while (fd)
{
/* read file HEADER */
unsigned char head[32];
unsigned char head[28];
fseek(fd, 8, SEEK_SET);
fread(head, 32, 1, fd);
fread(head, 28, 1, fd);
fseek(fd, 0, SEEK_SET);
/* check if this is a valid WAVE file (44.1KHz 16-bit stereo format only) */
if (!memcmp(head, waveHeader, 32))
if (!memcmp(head, waveHeader, 28))
{
/* look for 'data' chunk id */
int dataOffset = 0;
fseek(fd, 36, SEEK_SET);
while (fread(head, 4, 1, fd))
{
if (!memcmp(head, "data", 4))
{
dataOffset = ftell(fd) + 4;
break;
}
fseek(fd, -2, SEEK_CUR);
}
/* check if 'data' chunk has not been found */
if (!dataOffset)
{
/* invalid WAVE file */
fclose(fd);
break;
}
/* initialize current track file descriptor */
cdd.toc.tracks[cdd.toc.last].fd = fd;
@ -718,7 +761,7 @@ int cdd_load(char *filename, char *header)
/* current track end time */
fseek(fd, 0, SEEK_END);
cdd.toc.tracks[cdd.toc.last].end = cdd.toc.tracks[cdd.toc.last].start + ((ftell(fd) - 44 + 2351) / 2352);
cdd.toc.tracks[cdd.toc.last].end = cdd.toc.tracks[cdd.toc.last].start + ((ftell(fd) - dataOffset + 2351) / 2352);
/* initialize file read offset for current track */
cdd.toc.tracks[cdd.toc.last].offset = cdd.toc.tracks[cdd.toc.last].start * 2352;
@ -738,7 +781,7 @@ int cdd_load(char *filename, char *header)
cdd.toc.end = cdd.toc.tracks[cdd.toc.last].end;
/* adjust file read offset for current track with WAVE header length */
cdd.toc.tracks[cdd.toc.last].offset -= 44;
cdd.toc.tracks[cdd.toc.last].offset -= dataOffset;
/* increment track number */
cdd.toc.last++;
@ -1015,16 +1058,16 @@ void cdd_read_data(uint8 *dst)
void cdd_read_audio(unsigned int samples)
{
/* previous audio outputs */
int16 l = cdd.audio[0];
int16 r = cdd.audio[1];
int prev_l = cdd.audio[0];
int prev_r = cdd.audio[1];
/* get number of internal clocks (samples) needed */
samples = blip_clocks_needed(snd.blips[2][0], samples);
samples = blip_clocks_needed(snd.blips[2], samples);
/* audio track playing ? */
if (!scd.regs[0x36>>1].byte.h && cdd.toc.tracks[cdd.index].fd)
{
int i, mul, delta;
int i, mul, l, r;
/* current CD-DA fader volume */
int curVol = cdd.volume;
@ -1062,17 +1105,13 @@ void cdd_read_audio(unsigned int samples)
/* (MIN) 0,1,2,3,4,8,12,16,20...,1020,1024 (MAX) */
mul = (curVol & 0x7fc) ? (curVol & 0x7fc) : (curVol & 0x03);
/* left channel */
delta = ((ptr[0] * mul) / 1024) - l;
ptr++;
l += 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(snd.blips[2][1], i, delta);
/* left & right channels */
l = ((ptr[0] * mul) / 1024);
r = ((ptr[1] * mul) / 1024);
blip_add_delta_fast(snd.blips[2], i, l-prev_l, r-prev_r);
prev_l = l;
prev_r = r;
ptr+=2;
/* update CD-DA fader volume (one step/sample) */
if (curVol < endVol)
@ -1109,27 +1148,19 @@ void cdd_read_audio(unsigned int samples)
/* (MIN) 0,1,2,3,4,8,12,16,20...,1020,1024 (MAX) */
mul = (curVol & 0x7fc) ? (curVol & 0x7fc) : (curVol & 0x03);
/* left channel */
/* left & right channels */
#ifdef LSB_FIRST
delta = ((ptr[0] * mul) / 1024) - l;
ptr++;
l = ((ptr[0] * mul) / 1024);
r = ((ptr[1] * mul) / 1024);
ptr+=2;
#else
delta = (((int16)((ptr[0] + ptr[1]*256)) * mul) / 1024) - l;
ptr += 2;
l = (((int16)((ptr[0] + ptr[1]*256)) * mul) / 1024);
r = (((int16)((ptr[2] + ptr[3]*256)) * mul) / 1024);
ptr+=4;
#endif
l += delta;
blip_add_delta_fast(snd.blips[2][0], i, delta);
/* right channel */
#ifdef LSB_FIRST
delta = ((ptr[0] * mul) / 1024) - r;
ptr++;
#else
delta = (((int16)((ptr[0] + ptr[1]*256)) * mul) / 1024) - r;
ptr += 2;
#endif
r += delta;
blip_add_delta_fast(snd.blips[2][1], i, delta);
blip_add_delta_fast(snd.blips[2], i, l-prev_l, r-prev_r);
prev_l = l;
prev_r = r;
/* update CD-DA fader volume (one step/sample) */
if (curVol < endVol)
@ -1154,23 +1185,24 @@ void cdd_read_audio(unsigned int samples)
cdd.volume = curVol;
/* save last audio output for next frame */
cdd.audio[0] = l;
cdd.audio[1] = r;
cdd.audio[0] = prev_l;
cdd.audio[1] = prev_r;
}
else
{
/* no audio output */
if (l) blip_add_delta_fast(snd.blips[2][0], 0, -l);
if (r) blip_add_delta_fast(snd.blips[2][1], 0, -r);
if (prev_l | prev_r)
{
blip_add_delta_fast(snd.blips[2], 0, -prev_l, -prev_r);
/* save audio output for next frame */
cdd.audio[0] = 0;
cdd.audio[1] = 0;
/* save audio output for next frame */
cdd.audio[0] = 0;
cdd.audio[1] = 0;
}
}
/* end of Blip Buffer timeframe */
blip_end_frame(snd.blips[2][0], samples);
blip_end_frame(snd.blips[2][1], samples);
blip_end_frame(snd.blips[2], samples);
}
static void cdd_read_subcode(void)

View File

@ -2,7 +2,7 @@
* Genesis Plus
* PCM sound chip (315-5476A) (RF5C164 compatible)
*
* Copyright (C) 2012-2014 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2012-2016 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
@ -45,8 +45,7 @@ void pcm_init(double clock, int samplerate)
{
/* PCM chip is running at original rate and is synchronized with SUB-CPU */
/* Chip output is resampled to desired rate using Blip Buffer. */
blip_set_rates(snd.blips[1][0], clock / PCM_SCYCLES_RATIO, samplerate);
blip_set_rates(snd.blips[1][1], clock / PCM_SCYCLES_RATIO, samplerate);
blip_set_rates(snd.blips[1], clock / PCM_SCYCLES_RATIO, samplerate);
}
void pcm_reset(void)
@ -71,8 +70,7 @@ void pcm_reset(void)
pcm.cycles = 0;
/* clear blip buffers */
blip_clear(snd.blips[1][0]);
blip_clear(snd.blips[1][1]);
blip_clear(snd.blips[1]);
}
int pcm_context_save(uint8 *state)
@ -117,6 +115,11 @@ void pcm_run(unsigned int length)
#ifdef LOG_PCM
error("[%d][%d]run %d PCM samples (from %d)\n", v_counter, s68k.cycles, length, pcm.cycles);
#endif
/* previous audio outputs */
int prev_l = pcm.out[0];
int prev_r = pcm.out[1];
/* check if PCM chip is running */
if (pcm.enabled)
{
@ -180,41 +183,29 @@ void pcm_run(unsigned int length)
if (r < -32768) r = -32768;
else if (r > 32767) r = 32767;
/* check if PCM left output changed */
if (pcm.out[0] != l)
{
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(snd.blips[1][1], i, r-pcm.out[1]);
pcm.out[1] = r;
}
/* update Blip Buffer */
blip_add_delta_fast(snd.blips[1], i, l-prev_l, r-prev_r);
prev_l = l;
prev_r = r;
}
/* save last audio outputs */
pcm.out[0] = prev_l;
pcm.out[1] = prev_r;
}
else
{
/* check if PCM left output changed */
if (pcm.out[0])
/* check if PCM output was not muted */
if (prev_l | prev_r)
{
blip_add_delta_fast(snd.blips[1][0], 0, -pcm.out[0]);
blip_add_delta_fast(snd.blips[1], 0, -prev_l, -prev_r);
pcm.out[0] = 0;
}
/* check if PCM right output changed */
if (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(snd.blips[1][0], length);
blip_end_frame(snd.blips[1][1], length);
blip_end_frame(snd.blips[1], length);
/* update PCM master clock counter */
pcm.cycles += length * PCM_SCYCLES_RATIO;
@ -223,7 +214,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(snd.blips[1][0], samples);
unsigned int clocks = blip_clocks_needed(snd.blips[1], 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-2014 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2012-2016 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:

View File

@ -4,8 +4,8 @@
*
* Support for SG-1000, Mark-III, Master System, Game Gear, Mega Drive & Mega CD hardware
*
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald (original code)
* Copyright (C) 2007-2014 Eke-Eke (Genesis Plus GX)
* Copyright (C) 1998-2003 Charles Mac Donald (original code)
* Copyright (C) 2007-2016 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
@ -234,24 +234,39 @@ void gen_reset(int hard_reset)
/* System Reset */
if (hard_reset)
{
/* clear RAM (TODO: use random bit patterns for all systems, like on real hardware) */
/* On hard reset, 68k CPU always starts at the same point in VDP frame */
/* Tests performed on VA4 PAL MD1 showed that the first HVC value read */
/* with 'move.w #0x8104,0xC00004' , 'move.w 0xC00008,%d0' sequence was */
/* 0x9F21 in 60HZ mode (0x9F00 if Mode 5 is not enabled by first MOVE) */
/* 0x8421 in 50HZ mode (0x8400 if Mode 5 is not enabled by first MOVE) */
/* Same value is returned on every power ON, indicating VDP is always */
/* starting at the same fixed point in frame (probably at the start of */
/* VSYNC and HSYNC) while 68k /VRES line remains asserted a fixed time */
/* after /SRES line has been released (13 msec approx). The difference */
/* between PAL & NTSC is caused by the top border area being 27 lines */
/* larger in PAL mode than in NTSC mode. CPU cycle counter is adjusted */
/* to match these results (taking in account emulated frame is started */
/* on line 192 */
m68k.cycles = ((lines_per_frame - 192 + 159 - (27 * vdp_pal)) * MCYCLES_PER_LINE) + 1004;
/* clear RAM (on real hardware, RAM values are random / undetermined on Power ON) */
memset(work_ram, 0x00, sizeof (work_ram));
memset(zram, 0x00, sizeof (zram));
}
else
{
/* when RESET button is pressed, 68k could be anywhere in VDP frame (Bonkers, Eternal Champions, X-Men 2) */
m68k.cycles = (uint32)((MCYCLES_PER_LINE * lines_per_frame) * ((double)rand() / (double)RAND_MAX));
/* reset YM2612 (on hard reset, this is done by sound_reset) */
fm_reset(0);
}
/* 68k & Z80 could be anywhere in VDP frame (Bonkers, Eternal Champions, X-Men 2) */
m68k.cycles = Z80.cycles = (uint32)((MCYCLES_PER_LINE * lines_per_frame) * ((double)rand() / (double)RAND_MAX));
/* 68k cycles should be a multiple of 7 */
/* 68k M-cycles should be a multiple of 7 */
m68k.cycles = (m68k.cycles / 7) * 7;
/* Z80 cycles should be a multiple of 15 */
Z80.cycles = (Z80.cycles / 15) * 15;
/* Z80 M-cycles should be a multiple of 15 */
Z80.cycles = (m68k.cycles / 15) * 15;
/* 8-bit / 16-bit modes */
if ((system_hw & SYSTEM_PBC) == SYSTEM_MD)

View File

@ -4,8 +4,8 @@
*
* Support for SG-1000, Mark-III, Master System, Game Gear, Mega Drive & Mega CD hardware
*
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald (original code)
* Copyright (C) 2007-2014 Eke-Eke (Genesis Plus GX)
* Copyright (C) 1998-2003 Charles Mac Donald (original code)
* Copyright (C) 2007-2016 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:

View File

@ -570,7 +570,7 @@ void io_gg_write(unsigned int offset, unsigned int data)
case 6: /* PSG Stereo output control */
io_reg[6] = data;
SN76489_Config(Z80.cycles, config.psg_preamp, config.psgBoostNoise, data);
psg_config(Z80.cycles, config.psg_preamp, data);
return;
default: /* Read-only */

View File

@ -207,7 +207,7 @@ void z80_write_byte(unsigned int address, unsigned int data)
default: /* ZRAM */
{
zram[address & 0x1FFF] = data;
m68k.cycles += 8; /* ZRAM access latency (fixes Pacman 2: New Adventures) */
m68k.cycles += 2 * 7; /* ZRAM access latency (fixes Pacman 2: New Adventures & Puyo Puyo 2) */
return;
}
}
@ -1218,7 +1218,7 @@ void vdp_write_byte(unsigned int address, unsigned int data)
{
if (address & 1)
{
SN76489_Write(m68k.cycles, data);
psg_write(m68k.cycles, data);
return;
}
m68k_unused_8_w(address, data);
@ -1264,7 +1264,7 @@ void vdp_write_word(unsigned int address, unsigned int data)
case 0x10: /* PSG */
case 0x14:
{
SN76489_Write(m68k.cycles, data & 0xFF);
psg_write(m68k.cycles, data & 0xFF);
return;
}

View File

@ -2,8 +2,8 @@
* Genesis Plus
* Z80 bank access to 68k bus
*
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald (original code)
* Copyright (C) 2007-2011 Eke-Eke (Genesis Plus GX)
* Copyright (C) 1998-2003 Charles Mac Donald (original code)
* Copyright (C) 2007-2016 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
@ -294,7 +294,7 @@ void zbank_write_vdp(unsigned int address, unsigned int data)
{
if (address & 1)
{
SN76489_Write(Z80.cycles, data);
psg_write(Z80.cycles, data);
return;
}
zbank_unused_w(address, data);

View File

@ -2,8 +2,8 @@
* Genesis Plus
* Z80 bank access to 68k bus
*
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald (original code)
* Copyright (C) 2007-2012 Eke-Eke (Genesis Plus GX)
* Copyright (C) 1998-2003 Charles Mac Donald (original code)
* Copyright (C) 2007-2016 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:

View File

@ -231,7 +231,7 @@ void z80_md_port_w(unsigned int port, unsigned char data)
case 0x40:
case 0x41:
{
SN76489_Write(Z80.cycles, data);
psg_write(Z80.cycles, data);
return;
}
@ -345,7 +345,7 @@ void z80_gg_port_w(unsigned int port, unsigned char data)
case 0x40:
case 0x41:
{
SN76489_Write(Z80.cycles, data);
psg_write(Z80.cycles, data);
return;
}
@ -450,7 +450,7 @@ void z80_ms_port_w(unsigned int port, unsigned char data)
case 0x40:
case 0x41:
{
SN76489_Write(Z80.cycles, data);
psg_write(Z80.cycles, data);
return;
}
@ -493,7 +493,7 @@ void z80_ms_port_w(unsigned int port, unsigned char data)
1 0 : disable both PSG & FM output
1 1 : enable both PSG and FM output
*/
SN76489_Config(Z80.cycles, config.psg_preamp, config.psgBoostNoise, ((data + 1) & 0x02) ? 0x00 : 0xFF);
psg_config(Z80.cycles, config.psg_preamp, ((data + 1) & 0x02) ? 0x00 : 0xFF);
fm_write(Z80.cycles, 0x02, data);
io_reg[6] = data;
return;
@ -611,7 +611,7 @@ void z80_m3_port_w(unsigned int port, unsigned char data)
case 0x40:
case 0x41:
{
SN76489_Write(Z80.cycles, data);
psg_write(Z80.cycles, data);
return;
}
@ -699,7 +699,7 @@ void z80_sg_port_w(unsigned int port, unsigned char data)
case 0x40:
case 0x41:
{
SN76489_Write(Z80.cycles, data);
psg_write(Z80.cycles, data);
/* Z80 !WAIT input is tied to SN76489AN chip READY pin (held low for 32 clocks after each write access) */
Z80.cycles += (32 * 15);

View File

@ -22,7 +22,7 @@
#include "io_ctrl.h"
#include "input.h"
#include "sound.h"
#include "sn76489.h"
#include "psg.h"
#include "ym2413.h"
#include "ym2612.h"
#include "sram.h"

View File

@ -1,10 +1,11 @@
/* blip_buf $vers. http://www.slack.net/~ant/ */
/* blip_buf $vers. http://www.slack.net/~ant/ */
/* Modified for Genesis Plus GX by EkeEke (01/09/12) */
/* - disabled assertions checks (define #BLIP_ASSERT to re-enable) */
/* - fixed multiple time-frames support & removed m->avail */
/* - modified blip_read_samples to always output to stereo streams */
/* - added blip_mix_samples function (see blip_buf.h) */
/* Modified for Genesis Plus GX by EkeEke */
/* - disabled assertions checks (define #BLIP_ASSERT to re-enable) */
/* - fixed multiple time-frames support & removed m->avail */
/* - added blip_mix_samples function (see blip_buf.h) */
/* - added stereo buffer support (define #BLIP_MONO to disable) */
/* - added inverted stereo output (define #BLIP_INVERT to enable)*/
#include "blip_buf.h"
@ -61,24 +62,32 @@ enum { phase_count = 1 << phase_bits };
enum { delta_bits = 15 };
enum { delta_unit = 1 << delta_bits };
enum { frac_bits = time_bits - pre_shift };
enum { phase_shift = frac_bits - phase_bits };
/* We could eliminate avail and encode whole samples in offset, but that would
limit the total buffered samples to blip_max_frame. That could only be
increased by decreasing time_bits, which would reduce resample ratio accuracy.
*/
typedef int buf_t;
struct blip_t
{
fixed_t factor;
fixed_t offset;
int size;
#ifdef BLIP_MONO
int integrator;
#else
int integrator[2];
buf_t* buffer[2];
#endif
};
typedef int buf_t;
#ifdef BLIP_MONO
/* probably not totally portable */
#define SAMPLES( buf ) ((buf_t*) ((buf) + 1))
#define SAMPLES( blip ) ((buf_t*) ((blip) + 1))
#endif
/* Arithmetic (sign-preserving) right shift */
#define ARITH_SHIFT( n, shift ) \
@ -124,9 +133,23 @@ blip_t* blip_new( int size )
assert( size >= 0 );
#endif
#ifdef BLIP_MONO
m = (blip_t*) malloc( sizeof *m + (size + buf_extra) * sizeof (buf_t) );
#else
m = (blip_t*) malloc( sizeof *m );
#endif
if ( m )
{
#ifndef BLIP_MONO
m->buffer[0] = (buf_t*) malloc( (size + buf_extra) * sizeof (buf_t));
m->buffer[1] = (buf_t*) malloc( (size + buf_extra) * sizeof (buf_t));
if ((m->buffer[0] == NULL) || (m->buffer[1] == NULL))
{
blip_delete(m);
return 0;
}
#endif
m->factor = time_unit / blip_max_ratio;
m->size = size;
blip_clear( m );
@ -141,7 +164,13 @@ void blip_delete( blip_t* m )
{
if ( m != NULL )
{
/* Clear fields in case user tries to use after freeing */
#ifndef BLIP_MONO
if (m->buffer[0] != NULL)
free(m->buffer[0]);
if (m->buffer[1] != NULL)
free(m->buffer[1]);
#endif
/* Clear fields in case user tries to use after freeing */
memset( m, 0, sizeof *m );
free( m );
}
@ -173,16 +202,23 @@ void blip_clear( blip_t* m )
Since we don't know rounding direction, factor/2 accommodates either,
with the slight loss of showing an error in half the time. Since for
a 64-bit factor this is years, the halving isn't a problem. */
m->offset = m->factor / 2;
m->offset = m->factor / 2;
#ifdef BLIP_MONO
m->integrator = 0;
memset( SAMPLES( m ), 0, (m->size + buf_extra) * sizeof (buf_t) );
#else
m->integrator[0] = 0;
m->integrator[1] = 0;
memset( m->buffer[0], 0, (m->size + buf_extra) * sizeof (buf_t) );
memset( m->buffer[1], 0, (m->size + buf_extra) * sizeof (buf_t) );
#endif
}
int blip_clocks_needed( const blip_t* m, int samples )
{
fixed_t needed;
#ifdef BLIP_ASSERT
/* Fails if buffer can't hold that many more samples */
assert( (samples >= 0) && (((m->offset >> time_bits) + samples) <= m->size) );
@ -191,14 +227,14 @@ int blip_clocks_needed( const blip_t* m, int samples )
needed = (fixed_t) samples * time_unit;
if ( needed < m->offset )
return 0;
return (needed - m->offset + m->factor - 1) / m->factor;
}
void blip_end_frame( blip_t* m, unsigned t )
{
m->offset += t * m->factor;
#ifdef BLIP_ASSERT
/* Fails if buffer size was exceeded */
assert( (m->offset >> time_bits) <= m->size );
@ -212,91 +248,167 @@ int blip_samples_avail( const blip_t* m )
static void remove_samples( blip_t* m, int count )
{
#ifdef BLIP_MONO
buf_t* buf = SAMPLES( m );
int remain = (m->offset >> time_bits) + buf_extra - count;
#else
buf_t* buf = m->buffer[0];
#endif
int remain = (m->offset >> time_bits) + buf_extra - count;
m->offset -= count * time_unit;
memmove( &buf [0], &buf [count], remain * sizeof buf [0] );
memset( &buf [remain], 0, count * sizeof buf [0] );
memmove( &buf [0], &buf [count], remain * sizeof (buf_t) );
memset( &buf [remain], 0, count * sizeof (buf_t) );
#ifndef BLIP_MONO
buf = m->buffer[1];
memmove( &buf [0], &buf [count], remain * sizeof (buf_t) );
memset( &buf [remain], 0, count * sizeof (buf_t) );
#endif
}
int blip_read_samples( blip_t* m, short out [], int count)
{
#ifdef BLIP_ASSERT
assert( count >= 0 );
if ( count > (m->offset >> time_bits) )
count = m->offset >> time_bits;
if ( count )
#endif
{
buf_t const* in = SAMPLES( m );
buf_t const* end = in + count;
#ifdef BLIP_MONO
buf_t const* in = SAMPLES( m );
int sum = m->integrator;
#else
buf_t const* in = m->buffer[0];
buf_t const* in2 = m->buffer[1];
int sum = m->integrator[0];
int sum2 = m->integrator[1];
#endif
buf_t const* end = in + count;
do
{
/* Eliminate fraction */
int s = ARITH_SHIFT( sum, delta_bits );
sum += *in++;
CLAMP( s );
*out = s;
out += 2;
*out++ = s;
/* High-pass filter */
sum -= s << (delta_bits - bass_shift);
#ifndef BLIP_MONO
/* Eliminate fraction */
s = ARITH_SHIFT( sum2, delta_bits );
sum2 += *in2++;
CLAMP( s );
*out++ = s;
/* High-pass filter */
sum2 -= s << (delta_bits - bass_shift);
#endif
}
while ( in != end );
#ifdef BLIP_MONO
m->integrator = sum;
#else
m->integrator[0] = sum;
m->integrator[1] = sum2;
#endif
remove_samples( m, count );
}
return count;
}
int blip_mix_samples( blip_t* m, short out [], int count)
int blip_mix_samples( blip_t* m1, blip_t* m2, blip_t* m3, short out [], int count)
{
#ifdef BLIP_ASSERT
assert( count >= 0 );
if ( count > (m->offset >> time_bits) )
count = m->offset >> time_bits;
if ( count )
assert( count >= 0 );
if ( count > (m1->offset >> time_bits) )
count = m1->offset >> time_bits;
if ( count > (m2->offset >> time_bits) )
count = m2->offset >> time_bits;
if ( count > (m3->offset >> time_bits) )
count = m3->offset >> time_bits;
if ( count )
#endif
{
buf_t const* in = SAMPLES( m );
buf_t const* end = in + count;
int sum = m->integrator;
do
{
/* Eliminate fraction */
int s = ARITH_SHIFT( sum, delta_bits );
sum += *in++;
/* High-pass filter */
sum -= s << (delta_bits - bass_shift);
buf_t const* end;
buf_t const* in[3];
#ifdef BLIP_MONO
int sum = m1->integrator;
in[0] = SAMPLES( m1 );
in[1] = SAMPLES( m2 );
in[2] = SAMPLES( m3 );
#else
int sum = m1->integrator[0];
int sum2 = m1->integrator[1];
buf_t const* in2[3];
in[0] = m1->buffer[0];
in[1] = m2->buffer[0];
in[2] = m3->buffer[0];
in2[0] = m1->buffer[1];
in2[1] = m2->buffer[1];
in2[2] = m3->buffer[1];
#endif
/* Add current buffer value */
s += *out;
CLAMP( s );
*out = s;
out += 2;
}
while ( in != end );
m->integrator = sum;
remove_samples( m, count );
}
return count;
end = in[0] + count;
do
{
/* Eliminate fraction */
int s = ARITH_SHIFT( sum, delta_bits );
sum += *in[0]++;
sum += *in[1]++;
sum += *in[2]++;
CLAMP( s );
*out++ = s;
/* High-pass filter */
sum -= s << (delta_bits - bass_shift);
#ifndef BLIP_MONO
/* Eliminate fraction */
s = ARITH_SHIFT( sum2, delta_bits );
sum2 += *in2[0]++;
sum2 += *in2[1]++;
sum2 += *in2[2]++;
CLAMP( s );
*out++ = s;
/* High-pass filter */
sum2 -= s << (delta_bits - bass_shift);
#endif
}
while ( in[0] != end );
#ifdef BLIP_MONO
m1->integrator = sum;
#else
m1->integrator[0] = sum;
m1->integrator[1] = sum2;
#endif
remove_samples( m1, count );
remove_samples( m2, count );
remove_samples( m3, count );
}
return count;
}
/* Things that didn't help performance on x86:
@ -348,12 +460,180 @@ possibly-wider fixed_t. On 32-bit platforms, this is likely more efficient.
And by having pre_shift 32, a 32-bit platform can easily do the shift by
simply ignoring the low half. */
#ifndef BLIP_MONO
void blip_add_delta( blip_t* m, unsigned time, int delta_l, int delta_r )
{
if (delta_l | delta_r)
{
unsigned fixed = (unsigned) ((time * m->factor + m->offset) >> pre_shift);
int phase = fixed >> phase_shift & (phase_count - 1);
short const* in = bl_step [phase];
short const* rev = bl_step [phase_count - phase];
int interp = fixed >> (phase_shift - delta_bits) & (delta_unit - 1);
int pos = fixed >> frac_bits;
#ifdef BLIP_INVERT
buf_t* out_l = m->buffer[1] + pos;
buf_t* out_r = m->buffer[0] + pos;
#else
buf_t* out_l = m->buffer[0] + pos;
buf_t* out_r = m->buffer[1] + pos;
#endif
int delta;
#ifdef BLIP_ASSERT
/* Fails if buffer size was exceeded */
assert( pos <= m->size + end_frame_extra );
#endif
if (delta_l == delta_r)
{
buf_t out;
delta = (delta_l * interp) >> delta_bits;
delta_l -= delta;
out = in[0]*delta_l + in[half_width+0]*delta;
out_l[0] += out;
out_r[0] += out;
out = in[1]*delta_l + in[half_width+1]*delta;
out_l[1] += out;
out_r[1] += out;
out = in[2]*delta_l + in[half_width+2]*delta;
out_l[2] += out;
out_r[2] += out;
out = in[3]*delta_l + in[half_width+3]*delta;
out_l[3] += out;
out_r[3] += out;
out = in[4]*delta_l + in[half_width+4]*delta;
out_l[4] += out;
out_r[4] += out;
out = in[5]*delta_l + in[half_width+5]*delta;
out_l[5] += out;
out_r[5] += out;
out = in[6]*delta_l + in[half_width+6]*delta;
out_l[6] += out;
out_r[6] += out;
out = in[7]*delta_l + in[half_width+7]*delta;
out_l[7] += out;
out_r[7] += out;
out = rev[7]*delta_l + rev[7-half_width]*delta;
out_l[8] += out;
out_r[8] += out;
out = rev[6]*delta_l + rev[6-half_width]*delta;
out_l[9] += out;
out_r[9] += out;
out = rev[5]*delta_l + rev[5-half_width]*delta;
out_l[10] += out;
out_r[10] += out;
out = rev[4]*delta_l + rev[4-half_width]*delta;
out_l[11] += out;
out_r[11] += out;
out = rev[3]*delta_l + rev[3-half_width]*delta;
out_l[12] += out;
out_r[12] += out;
out = rev[2]*delta_l + rev[2-half_width]*delta;
out_l[13] += out;
out_r[13] += out;
out = rev[1]*delta_l + rev[1-half_width]*delta;
out_l[14] += out;
out_r[14] += out;
out = rev[0]*delta_l + rev[0-half_width]*delta;
out_l[15] += out;
out_r[15] += out;
}
else
{
delta = (delta_l * interp) >> delta_bits;
delta_l -= delta;
out_l [0] += in[0]*delta_l + in[half_width+0]*delta;
out_l [1] += in[1]*delta_l + in[half_width+1]*delta;
out_l [2] += in[2]*delta_l + in[half_width+2]*delta;
out_l [3] += in[3]*delta_l + in[half_width+3]*delta;
out_l [4] += in[4]*delta_l + in[half_width+4]*delta;
out_l [5] += in[5]*delta_l + in[half_width+5]*delta;
out_l [6] += in[6]*delta_l + in[half_width+6]*delta;
out_l [7] += in[7]*delta_l + in[half_width+7]*delta;
out_l [8] += rev[7]*delta_l + rev[7-half_width]*delta;
out_l [9] += rev[6]*delta_l + rev[6-half_width]*delta;
out_l [10] += rev[5]*delta_l + rev[5-half_width]*delta;
out_l [11] += rev[4]*delta_l + rev[4-half_width]*delta;
out_l [12] += rev[3]*delta_l + rev[3-half_width]*delta;
out_l [13] += rev[2]*delta_l + rev[2-half_width]*delta;
out_l [14] += rev[1]*delta_l + rev[1-half_width]*delta;
out_l [15] += rev[0]*delta_l + rev[0-half_width]*delta;
delta = (delta_r * interp) >> delta_bits;
delta_r -= delta;
out_r [0] += in[0]*delta_r + in[half_width+0]*delta;
out_r [1] += in[1]*delta_r + in[half_width+1]*delta;
out_r [2] += in[2]*delta_r + in[half_width+2]*delta;
out_r [3] += in[3]*delta_r + in[half_width+3]*delta;
out_r [4] += in[4]*delta_r + in[half_width+4]*delta;
out_r [5] += in[5]*delta_r + in[half_width+5]*delta;
out_r [6] += in[6]*delta_r + in[half_width+6]*delta;
out_r [7] += in[7]*delta_r + in[half_width+7]*delta;
out_r [8] += rev[7]*delta_r + rev[7-half_width]*delta;
out_r [9] += rev[6]*delta_r + rev[6-half_width]*delta;
out_r [10] += rev[5]*delta_r + rev[5-half_width]*delta;
out_r [11] += rev[4]*delta_r + rev[4-half_width]*delta;
out_r [12] += rev[3]*delta_r + rev[3-half_width]*delta;
out_r [13] += rev[2]*delta_r + rev[2-half_width]*delta;
out_r [14] += rev[1]*delta_r + rev[1-half_width]*delta;
out_r [15] += rev[0]*delta_r + rev[0-half_width]*delta;
}
}
}
void blip_add_delta_fast( blip_t* m, unsigned time, int delta_l, int delta_r )
{
if (delta_l | delta_r)
{
unsigned fixed = (unsigned) ((time * m->factor + m->offset) >> pre_shift);
int interp = fixed >> (frac_bits - delta_bits) & (delta_unit - 1);
int pos = fixed >> frac_bits;
#ifdef STEREO_INVERT
buf_t* out_l = m->buffer[1] + pos;
buf_t* out_r = m->buffer[0] + pos;
#else
buf_t* out_l = m->buffer[0] + pos;
buf_t* out_r = m->buffer[1] + pos;
#endif
int delta = delta_l * interp;
#ifdef BLIP_ASSERT
/* Fails if buffer size was exceeded */
assert( pos <= m->size + end_frame_extra );
#endif
if (delta_l == delta_r)
{
delta_l = delta_l * delta_unit - delta;
out_l[7] += delta_l;
out_l[8] += delta;
out_r[7] += delta_l;
out_r[8] += delta;
}
else
{
out_l[7] += delta_l * delta_unit - delta;
out_l[8] += delta;
delta = delta_r * interp;
out_r[7] += delta_r * delta_unit - delta;
out_r[8] += delta;
}
}
}
#else
void blip_add_delta( blip_t* m, unsigned time, int delta )
{
unsigned fixed = (unsigned) ((time * m->factor + m->offset) >> pre_shift);
buf_t* out = SAMPLES( m ) + (fixed >> frac_bits);
int const phase_shift = frac_bits - phase_bits;
int phase = fixed >> phase_shift & (phase_count - 1);
short const* in = bl_step [phase];
short const* rev = bl_step [phase_count - phase];
@ -403,3 +683,4 @@ void blip_add_delta_fast( blip_t* m, unsigned time, int delta )
out [7] += delta * delta_unit - delta2;
out [8] += delta2;
}
#endif

View File

@ -28,12 +28,24 @@ blip_max_ratio = 1 << 20 };
/** Clears entire buffer. Afterwards, blip_samples_avail() == 0. */
void blip_clear( blip_t* );
#ifndef BLIP_MONO
/** Adds positive/negative deltas into stereo buffers at specified clock time. */
void blip_add_delta( blip_t*, unsigned time, int delta_l, int delta_r );
/** Same as blip_add_delta(), but uses faster, lower-quality synthesis. */
void blip_add_delta_fast( blip_t*, unsigned int clock_time, int delta_l, int delta_r );
#else
/** Adds positive/negative delta into buffer at specified clock time. */
void blip_add_delta( blip_t*, unsigned int clock_time, int delta );
/** Same as blip_add_delta(), but uses faster, lower-quality synthesis. */
void blip_add_delta_fast( blip_t*, unsigned int clock_time, int delta );
#endif
/** Length of time frame, in clocks, needed to make sample_count additional
samples available. */
int blip_clocks_needed( const blip_t*, int sample_count );
@ -56,9 +68,8 @@ element of 'out', allowing easy interleaving of two buffers into a stereo sample
stream. Outputs 16-bit signed samples. Returns number of samples actually read. */
int blip_read_samples( blip_t*, short out [], int count);
/* Same as above function except sample is added to output buffer previous value */
/* This allows easy mixing of different blip buffers into a single output stream */
int blip_mix_samples( blip_t* m, short out [], int count);
/* Same as above function except sample is mixed from three blip buffers source */
int blip_mix_samples( blip_t* m1, blip_t* m2, blip_t* m3, short out [], int count);
/** Frees buffer. No effect if NULL is passed. */
void blip_delete( blip_t* );

591
core/sound/psg.c Normal file
View File

@ -0,0 +1,591 @@
/***************************************************************************************
* Genesis Plus
* PSG sound chip (SN76489A compatible)
*
* Support for discrete chip & integrated (ASIC) clones
*
* Noise implementation based on http://www.smspower.org/Development/SN76489#NoiseChannel
*
* Copyright (C) 2016 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"
#include "blip_buf.h"
/* internal clock = input clock : 16 = (master clock : 15) : 16 */
#define PSG_MCYCLES_RATIO (15*16)
/* maximal channel output (roughly adjusted to match VA4 MD1 PSG/FM balance with 1.5x amplification of PSG output) */
#define PSG_MAX_VOLUME 2800
static const uint8 noiseShiftWidth[2] = {14,15};
static const uint8 noiseBitMask[2] = {0x6,0x9};
static const uint8 noiseFeedback[10] = {0,1,1,0,1,0,0,1,1,0};
static const uint16 chanVolume[16] = {
PSG_MAX_VOLUME, /* MAX */
PSG_MAX_VOLUME * 0.794328234, /* -2dB */
PSG_MAX_VOLUME * 0.630957344, /* -4dB */
PSG_MAX_VOLUME * 0.501187233, /* -6dB */
PSG_MAX_VOLUME * 0.398107170, /* -8dB */
PSG_MAX_VOLUME * 0.316227766, /* -10dB */
PSG_MAX_VOLUME * 0.251188643, /* -12dB */
PSG_MAX_VOLUME * 0.199526231, /* -14dB */
PSG_MAX_VOLUME * 0.158489319, /* -16dB */
PSG_MAX_VOLUME * 0.125892541, /* -18dB */
PSG_MAX_VOLUME * 0.1, /* -20dB */
PSG_MAX_VOLUME * 0.079432823, /* -22dB */
PSG_MAX_VOLUME * 0.063095734, /* -24dB */
PSG_MAX_VOLUME * 0.050118723, /* -26dB */
PSG_MAX_VOLUME * 0.039810717, /* -28dB */
0 /* OFF */
};
static struct
{
int clocks;
int latch;
int noiseShiftValue;
int noiseShiftWidth;
int noiseBitMask;
int regs[8];
int freqInc[4];
int freqCounter[4];
int polarity[4];
int chanDelta[4][2];
int chanOut[4][2];
int chanAmp[4][2];
} psg;
static void psg_update(unsigned int clocks);
void psg_init(PSG_TYPE type)
{
int i;
/* Initialize stereo amplification (default) */
for (i=0; i<4; i++)
{
psg.chanAmp[i][0] = 100;
psg.chanAmp[i][1] = 100;
}
/* Initialize Noise LSFR type */
psg.noiseShiftWidth = noiseShiftWidth[type];
psg.noiseBitMask = noiseBitMask[type];
}
void psg_reset()
{
int i;
/* power-on state (verified on 315-5313A & 315-5660 integrated version only) */
for (i=0; i<4; i++)
{
psg.regs[i*2] = 0;
psg.regs[i*2+1] = 0;
psg.freqInc[i] = (i < 3) ? (1 * PSG_MCYCLES_RATIO) : (16 * PSG_MCYCLES_RATIO);
psg.freqCounter[i] = 0;
psg.polarity[i] = -1;
psg.chanDelta[i][0] = 0;
psg.chanDelta[i][1] = 0;
psg.chanOut[i][0] = 0;
psg.chanOut[i][1] = 0;
}
/* noise attenuation register is latched on power-on (verified on 315-5313A & 315-5660 integrated version only) */
psg.latch = 7;
/* reset noise shift register */
psg.noiseShiftValue = 1 << psg.noiseShiftWidth;
/* reset internal M-cycles clock counter */
psg.clocks = 0;
}
int psg_context_save(uint8 *state)
{
int bufferptr = 0;
save_param(&psg.clocks,sizeof(psg.clocks));
save_param(&psg.latch,sizeof(psg.latch));
save_param(&psg.noiseShiftValue,sizeof(psg.noiseShiftValue));
save_param(psg.regs,sizeof(psg.regs));
save_param(psg.freqInc,sizeof(psg.freqInc));
save_param(psg.freqCounter,sizeof(psg.freqCounter));
save_param(psg.polarity,sizeof(psg.polarity));
save_param(psg.chanDelta,sizeof(psg.chanDelta));
save_param(psg.chanOut,sizeof(psg.chanOut));
return bufferptr;
}
int psg_context_load(uint8 *state)
{
int chanOut[4][2], delta[2];
int i, bufferptr = 0;
/* get current tone channels output */
for (i=0; i<3; i++)
{
if (psg.polarity[i] > 0)
{
chanOut[i][0] = psg.chanOut[i][0];
chanOut[i][1] = psg.chanOut[i][1];
}
else
{
chanOut[i][0] = 0;
chanOut[i][1] = 0;
}
}
/* get current noise channel output */
if (psg.noiseShiftValue & 1)
{
chanOut[3][0] = psg.chanOut[3][0];
chanOut[3][1] = psg.chanOut[3][1];
}
else
{
chanOut[3][0] = 0;
chanOut[3][1] = 0;
}
load_param(&psg.clocks,sizeof(psg.clocks));
load_param(&psg.latch,sizeof(psg.latch));
load_param(&psg.noiseShiftValue,sizeof(psg.noiseShiftValue));
load_param(psg.regs,sizeof(psg.regs));
load_param(psg.freqInc,sizeof(psg.freqInc));
load_param(psg.freqCounter,sizeof(psg.freqCounter));
load_param(psg.polarity,sizeof(psg.polarity));
load_param(psg.chanDelta,sizeof(psg.chanDelta));
load_param(psg.chanOut,sizeof(psg.chanOut));
/* apply any pending channel volume variation */
for (i=0; i<4; i++)
{
psg.chanOut[i][0] += psg.chanDelta[i][0];
psg.chanOut[i][1] += psg.chanDelta[i][1];
psg.chanDelta[i][0] = 0;
psg.chanDelta[i][1] = 0;
}
/* calculate noise channel output variations */
if (psg.noiseShiftValue & 1)
{
/* channel output is high */
delta[0] = psg.chanOut[3][0] - chanOut[3][0];
delta[1] = psg.chanOut[3][0] - chanOut[3][1];
}
else
{
/* channel output is low */
delta[0] = -chanOut[3][0];
delta[1] = -chanOut[3][1];
}
/* add tone channels output variations */
for (i=0; i<3; i++)
{
if (psg.polarity[i] > 0)
{
/* channel output is high */
delta[0] += (psg.chanOut[i][0] - chanOut[i][0]);
delta[1] += (psg.chanOut[i][0] - chanOut[i][1]);
}
else
{
/* channel output is low */
delta[0] -= chanOut[i][0];
delta[1] -= chanOut[i][1];
}
}
/* update mixed channels output */
if (config.hq_psg)
{
blip_add_delta(snd.blips[0], psg.clocks, delta[0], delta[1]);
}
else
{
blip_add_delta_fast(snd.blips[0], psg.clocks, delta[0], delta[1]);
}
return bufferptr;
}
void psg_write(unsigned int clocks, unsigned int data)
{
int index;
/* PSG chip synchronization */
if (clocks > psg.clocks)
{
/* run PSG chip until current timestamp */
psg_update(clocks);
/* update internal M-cycles clock counter */
psg.clocks += ((clocks - psg.clocks + PSG_MCYCLES_RATIO - 1) / PSG_MCYCLES_RATIO) * PSG_MCYCLES_RATIO;
}
if (data & 0x80)
{
/* latch register index (1xxx----) */
psg.latch = index = (data >> 4) & 0x07;
}
else
{
/* restore latched register index */
index= psg.latch;
}
switch (index)
{
case 0:
case 2:
case 4: /* Tone channels frequency */
{
/* recalculate frequency register value */
if (data & 0x80)
{
/* update 10-bit register LSB (1---xxxx) */
data = (psg.regs[index] & 0x3f0) | (data & 0x0f);
}
else
{
/* update 10-bit register MSB (0-xxxxxx) */
data = (psg.regs[index] & 0x00f) | ((data & 0x3f) << 4);
}
/* update channel M-cycle counter increment */
if (data)
{
psg.freqInc[index>>1] = data * PSG_MCYCLES_RATIO;
}
else
{
/* zero value behaves the same as a value of 1 (verified on integrated version only) */
psg.freqInc[index>>1] = PSG_MCYCLES_RATIO;
}
/* update noise channel counter increment if required */
if ((index == 4) && ((psg.regs[6] & 0x03) == 0x03))
{
psg.freqInc[3] = psg.freqInc[2];
}
break;
}
case 6: /* Noise control */
{
/* noise signal generator frequency (----?xxx) */
int noiseFreq = (data & 0x03);
if (noiseFreq == 0x03)
{
/* noise generator is controlled by tone channel #3 generator */
psg.freqInc[3] = psg.freqInc[2];
psg.freqCounter[3] = psg.freqCounter[2];
}
else
{
/* noise generator is running at separate frequency */
psg.freqInc[3] = (0x10 << noiseFreq) * PSG_MCYCLES_RATIO;
}
/* reset shift register value */
psg.noiseShiftValue = 1 << psg.noiseShiftWidth;;
break;
}
case 7: /* Noise channel attenuation */
{
/* convert 4-bit attenuation value (----xxxx) to 16-bit volume value */
data = chanVolume[data & 0x0f];
/* check noise shift register output */
if (psg.noiseShiftValue & 1)
{
/* channel output is high, volume variation will be applied at next internal cycle update */
psg.chanDelta[3][0] = ((data * psg.chanAmp[3][0]) / 100) - psg.chanOut[3][0];
psg.chanDelta[3][1] = ((data * psg.chanAmp[3][1]) / 100) - psg.chanOut[3][1];
}
else
{
/* channel output is low, volume variation will be applied at next transition */
psg.chanOut[3][0] = (data * psg.chanAmp[3][0]) / 100;
psg.chanOut[3][1] = (data * psg.chanAmp[3][1]) / 100;
}
break;
}
default: /* Tone channels attenuation */
{
/* channel number (0-2) */
int i = index >> 1;
/* convert 4-bit attenuation value (----xxxx) to 16-bit volume value */
data = chanVolume[data & 0x0f];
/* check tone generator polarity */
if (psg.polarity[i] > 0)
{
/* channel output is high, volume variation will be applied at next internal cycle update */
psg.chanDelta[i][0] = ((data * psg.chanAmp[i][0]) / 100) - psg.chanOut[i][0];
psg.chanDelta[i][1] = ((data * psg.chanAmp[i][1]) / 100) - psg.chanOut[i][1];
}
else
{
/* channel output is low, volume variation will be applied at next transition */
psg.chanOut[i][0] = (data * psg.chanAmp[i][0]) / 100;
psg.chanOut[i][1] = (data * psg.chanAmp[i][1]) / 100;
}
break;
}
}
/* save register value */
psg.regs[index] = data;
}
void psg_config(unsigned int clocks, unsigned int preamp, unsigned int panning)
{
int i;
/* PSG chip synchronization */
if (clocks > psg.clocks)
{
/* run PSG chip until current timestamp */
psg_update(clocks);
/* update internal M-cycles clock counter */
psg.clocks += ((clocks - psg.clocks + PSG_MCYCLES_RATIO - 1) / PSG_MCYCLES_RATIO) * PSG_MCYCLES_RATIO;
}
for (i=0; i<4; i++)
{
/* channel internal volume */
int volume = psg.regs[i*2+1];
/* update channel stereo amplification */
psg.chanAmp[i][0] = preamp * ((panning >> (i + 4)) & 1);
psg.chanAmp[i][1] = preamp * ((panning >> (i + 0)) & 1);
/* tone channels */
if (i < 3)
{
/* check tone generator polarity */
if (psg.polarity[i] > 0)
{
/* channel output is high, volume variation will be applied at next internal cycle update */
psg.chanDelta[i][0] = ((volume * psg.chanAmp[i][0]) / 100) - psg.chanOut[i][0];
psg.chanDelta[i][1] = ((volume * psg.chanAmp[i][1]) / 100) - psg.chanOut[i][1];
}
else
{
/* channel output is low, volume variation will be applied at next transition*/
psg.chanOut[i][0] = (volume * psg.chanAmp[i][0]) / 100;
psg.chanOut[i][1] = (volume * psg.chanAmp[i][1]) / 100;
}
}
/* noise channel */
else
{
/* check noise shift register output */
if (psg.noiseShiftValue & 1)
{
/* channel output is high, volume variation will be applied at next internal cycle update */
psg.chanDelta[3][0] = ((volume * psg.chanAmp[3][0]) / 100) - psg.chanOut[3][0];
psg.chanDelta[3][1] = ((volume * psg.chanAmp[3][1]) / 100) - psg.chanOut[3][1];
}
else
{
/* channel output is low, volume variation will be applied at next transition */
psg.chanOut[3][0] = (volume * psg.chanAmp[3][0]) / 100;
psg.chanOut[3][1] = (volume * psg.chanAmp[3][1]) / 100;
}
}
}
}
void psg_end_frame(unsigned int clocks)
{
int i;
if (clocks > psg.clocks)
{
/* run PSG chip until current timestamp */
psg_update(clocks);
/* update internal M-cycles clock counter */
psg.clocks += ((clocks - psg.clocks + PSG_MCYCLES_RATIO - 1) / PSG_MCYCLES_RATIO) * PSG_MCYCLES_RATIO;
}
/* adjust internal M-cycles clock counter for next frame */
psg.clocks -= clocks;
/* adjust channels time counters for next frame */
for (i=0; i<4; ++i)
{
psg.freqCounter[i] -= clocks;
}
}
static void psg_update(unsigned int clocks)
{
int i, timestamp, polarity;
for (i=0; i<4; i++)
{
/* apply any pending channel volume variations */
if (psg.chanDelta[i][0] | psg.chanDelta[i][1])
{
/* update channel output */
if (config.hq_psg)
{
blip_add_delta(snd.blips[0], psg.clocks, psg.chanDelta[i][0], psg.chanDelta[i][1]);
}
else
{
blip_add_delta_fast(snd.blips[0], psg.clocks, psg.chanDelta[i][0], psg.chanDelta[i][1]);
}
/* update channel volume */
psg.chanOut[i][0] += psg.chanDelta[i][0];
psg.chanOut[i][1] += psg.chanDelta[i][1];
/* clear pending channel volume variations */
psg.chanDelta[i][0] = 0;
psg.chanDelta[i][1] = 0;
}
/* timestamp of next transition */
timestamp = psg.freqCounter[i];
/* current channel generator polarity */
polarity = psg.polarity[i];
/* Tone channels */
if (i < 3)
{
/* process all transitions occurring until current clock timestamp */
while (timestamp < clocks)
{
/* invert tone generator polarity */
polarity = -polarity;
/* update channel output */
if (config.hq_psg)
{
blip_add_delta(snd.blips[0], timestamp, polarity*psg.chanOut[i][0], polarity*psg.chanOut[i][1]);
}
else
{
blip_add_delta_fast(snd.blips[0], timestamp, polarity*psg.chanOut[i][0], polarity*psg.chanOut[i][1]);
}
/* timestamp of next transition */
timestamp += psg.freqInc[i];
}
}
/* Noise channel */
else
{
/* current noise shift register value */
int shiftValue = psg.noiseShiftValue;
/* process all transitions occurring until current clock timestamp */
while (timestamp < clocks)
{
/* invert noise generator polarity */
polarity = -polarity;
/* noise register is shifted on positive edge only */
if (polarity > 0)
{
/* current shift register output */
int shiftOutput = shiftValue & 0x01;
/* White noise (----1xxx) */
if (psg.regs[6] & 0x04)
{
/* shift and apply XOR feedback network */
shiftValue = (shiftValue >> 1) | (noiseFeedback[shiftValue & psg.noiseBitMask] << psg.noiseShiftWidth);
}
/* Periodic noise (----0xxx) */
else
{
/* shift and feedback current output */
shiftValue = (shiftValue >> 1) | (shiftOutput << psg.noiseShiftWidth);
}
/* shift register output variation */
shiftOutput = (shiftValue & 0x1) - shiftOutput;
/* update noise channel output */
if (config.hq_psg)
{
blip_add_delta(snd.blips[0], timestamp, shiftOutput*psg.chanOut[3][0], shiftOutput*psg.chanOut[3][1]);
}
else
{
blip_add_delta_fast(snd.blips[0], timestamp, shiftOutput*psg.chanOut[3][0], shiftOutput*psg.chanOut[3][1]);
}
}
/* timestamp of next transition */
timestamp += psg.freqInc[3];
}
/* save shift register value */
psg.noiseShiftValue = shiftValue;
}
/* save timestamp of next transition */
psg.freqCounter[i] = timestamp;
/* save channel generator polarity */
psg.polarity[i] = polarity;
}
}

60
core/sound/psg.h Normal file
View File

@ -0,0 +1,60 @@
/***************************************************************************************
* Genesis Plus
* PSG sound chip (SN76489A compatible)
*
* Support for discrete chip & integrated (ASIC) clones
*
* Noise implementation based on http://www.smspower.org/Development/SN76489#NoiseChannel
*
* Copyright (C) 2016 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 _PSG_H_
#define _PSG_H_
typedef enum {
PSG_DISCRETE,
PSG_INTEGRATED
} PSG_TYPE;
/* Function prototypes */
extern void psg_init(PSG_TYPE type);
extern void psg_reset(void);
extern int psg_context_save(uint8 *state);
extern int psg_context_load(uint8 *state);
extern void psg_write(unsigned int clocks, unsigned int data);
extern void psg_config(unsigned int clocks, unsigned int preamp, unsigned int panning);
extern void psg_end_frame(unsigned int clocks);
#endif /* _PSG_H_ */

View File

@ -1,446 +0,0 @@
/*
SN76489 emulation
by Maxim in 2001 and 2002
converted from my original Delphi implementation
I'm a C newbie so I'm sure there are loads of stupid things
in here which I'll come back to some day and redo
Includes:
- Super-high quality tone channel "oversampling" by calculating fractional positions on transitions
- Noise output pattern reverse engineered from actual SMS output
- Volume levels taken from actual SMS output
07/08/04 Charles MacDonald
Modified for use with SMS Plus:
- Added support for multiple PSG chips.
- Added reset/config/update routines.
- Added context management routines.
- Removed SN76489_GetValues().
- Removed some unused variables.
25/04/07 Eke-Eke (Genesis Plus GX)
- Removed stereo GG support (unused)
- Made SN76489_Update outputs 16bits mono samples
- Replaced volume table with VGM plugin's one
05/01/09 Eke-Eke (Genesis Plus GX)
- Modified Cut-Off frequency (according to Steve Snake: http://www.smspower.org/forums/viewtopic.php?t=1746)
24/08/10 Eke-Eke (Genesis Plus GX)
- Removed multichip support (unused)
- Removed alternate volume table, panning & mute support (unused)
- Removed configurable Feedback and Shift Register Width (always use Sega ones)
- Added linear resampling using Blip Buffer (based on Blargg's implementation: http://www.smspower.org/forums/viewtopic.php?t=11376)
01/09/12 Eke-Eke (Genesis Plus GX)
- Added generic Blip-Buffer support internally, using common Master Clock as timebase
- Re-added stereo GG support
- Re-added configurable Feedback and Shift Register Width
- Rewrote core with various optimizations
*/
#include "shared.h"
#define PSG_MCYCLES_RATIO (16 * 15)
/* Initial state of shift register */
#define NoiseInitialState 0x8000
/* Value below which PSG does not output */
/*#define PSG_CUTOFF 0x6*/
#define PSG_CUTOFF 0x1
/* original Texas Instruments TMS SN76489AN (rev. A) used in SG-1000, SC-3000H & SF-7000 computers */
#define FB_DISCRETE 0x0006
#define SRW_DISCRETE 15
/* SN76489AN clone integrated in Sega's VDP chips (315-5124, 315-5246, 315-5313, Game Gear) */
#define FB_SEGAVDP 0x0009
#define SRW_SEGAVDP 16
typedef struct
{
/* Configuration */
int PreAmp[4][2]; /* stereo channels pre-amplification ratio (%) */
int NoiseFeedback;
int SRWidth;
/* PSG registers: */
int Registers[8]; /* Tone, vol x4 */
int LatchedRegister;
int NoiseShiftRegister;
int NoiseFreq; /* Noise channel signal generator frequency */
/* Output calculation variables */
int ToneFreqVals[4]; /* Frequency register values (counters) */
int ToneFreqPos[4]; /* Frequency channel flip-flops */
int Channel[4][2]; /* current amplitude of each (stereo) channel */
int ChanOut[4][2]; /* current output value of each (stereo) channel */
/* Internal M-clock counter */
unsigned long clocks;
} SN76489_Context;
static const uint16 PSGVolumeValues[16] =
{
/* These values are taken from a real SMS2's output */
/*{892,892,892,760,623,497,404,323,257,198,159,123,96,75,60,0}, */
/* I can't remember why 892... :P some scaling I did at some point */
/* these values are true volumes for 2dB drops at each step (multiply previous by 10^-0.1) */
1516,1205,957,760,603,479,381,303,240,191,152,120,96,76,60,0
};
static SN76489_Context SN76489;
void SN76489_Init(int type)
{
int i;
for (i=0; i<4; i++)
{
SN76489.PreAmp[i][0] = 100;
SN76489.PreAmp[i][1] = 100;
}
if (type == SN_DISCRETE)
{
SN76489.NoiseFeedback = FB_DISCRETE;
SN76489.SRWidth = SRW_DISCRETE;
}
else
{
SN76489.NoiseFeedback = FB_SEGAVDP;
SN76489.SRWidth = SRW_SEGAVDP;
}
}
void SN76489_Reset()
{
int i;
for(i = 0; i <= 3; i++)
{
/* Initialise PSG state */
SN76489.Registers[2*i] = 1; /* tone freq=1 */
SN76489.Registers[2*i+1] = 0xf; /* vol=off */
/* Set counters to 0 */
SN76489.ToneFreqVals[i] = 0;
/* Set flip-flops to 1 */
SN76489.ToneFreqPos[i] = 1;
/* Clear stereo channels amplitude */
SN76489.Channel[i][0] = 0;
SN76489.Channel[i][1] = 0;
/* Clear stereo channel outputs in delta buffer */
SN76489.ChanOut[i][0] = 0;
SN76489.ChanOut[i][1] = 0;
}
/* Initialise latched register index */
SN76489.LatchedRegister = 0;
/* Initialise noise generator */
SN76489.NoiseShiftRegister=NoiseInitialState;
SN76489.NoiseFreq = 0x10;
/* Reset internal M-cycle counter */
SN76489.clocks = 0;
}
void *SN76489_GetContextPtr(void)
{
return (uint8 *)&SN76489;
}
int SN76489_GetContextSize(void)
{
return sizeof(SN76489_Context);
}
/* Updates tone amplitude in delta buffer. Call whenever amplitude might have changed. */
INLINE void UpdateToneAmplitude(int i, int time)
{
int delta;
/* left output */
delta = (SN76489.Channel[i][0] * SN76489.ToneFreqPos[i]) - SN76489.ChanOut[i][0];
if (delta != 0)
{
SN76489.ChanOut[i][0] += delta;
blip_add_delta_fast(snd.blips[0][0], time, delta);
}
/* right output */
delta = (SN76489.Channel[i][1] * SN76489.ToneFreqPos[i]) - SN76489.ChanOut[i][1];
if (delta != 0)
{
SN76489.ChanOut[i][1] += delta;
blip_add_delta_fast(snd.blips[0][1], time, delta);
}
}
/* Updates noise amplitude in delta buffer. Call whenever amplitude might have changed. */
INLINE void UpdateNoiseAmplitude(int time)
{
int delta;
/* left output */
delta = (SN76489.Channel[3][0] * ( SN76489.NoiseShiftRegister & 0x1 )) - SN76489.ChanOut[3][0];
if (delta != 0)
{
SN76489.ChanOut[3][0] += delta;
blip_add_delta_fast(snd.blips[0][0], time, delta);
}
/* right output */
delta = (SN76489.Channel[3][1] * ( SN76489.NoiseShiftRegister & 0x1 )) - SN76489.ChanOut[3][1];
if (delta != 0)
{
SN76489.ChanOut[3][1] += delta;
blip_add_delta_fast(snd.blips[0][1], time, delta);
}
}
/* Runs tone channel for clock_length clocks */
static void RunTone(int i, int clocks)
{
int time;
/* Update in case a register changed etc. */
UpdateToneAmplitude(i, SN76489.clocks);
/* Time of next transition */
time = SN76489.ToneFreqVals[i];
/* Process any transitions that occur within clocks we're running */
while (time < clocks)
{
if (SN76489.Registers[i*2]>PSG_CUTOFF) {
/* Flip the flip-flop */
SN76489.ToneFreqPos[i] = -SN76489.ToneFreqPos[i];
} else {
/* stuck value */
SN76489.ToneFreqPos[i] = 1;
}
UpdateToneAmplitude(i, time);
/* Advance to time of next transition */
time += SN76489.Registers[i*2] * PSG_MCYCLES_RATIO;
}
/* Update channel tone counter */
SN76489.ToneFreqVals[i] = time;
}
/* Runs noise channel for clock_length clocks */
static void RunNoise(int clocks)
{
int time;
/* Noise channel: match to tone2 if in slave mode */
int NoiseFreq = SN76489.NoiseFreq;
if (NoiseFreq == 0x80)
{
NoiseFreq = SN76489.Registers[2*2];
SN76489.ToneFreqVals[3] = SN76489.ToneFreqVals[2];
}
/* Update in case a register changed etc. */
UpdateNoiseAmplitude(SN76489.clocks);
/* Time of next transition */
time = SN76489.ToneFreqVals[3];
/* Process any transitions that occur within clocks we're running */
while (time < clocks)
{
/* Flip the flip-flop */
SN76489.ToneFreqPos[3] = -SN76489.ToneFreqPos[3];
if (SN76489.ToneFreqPos[3] == 1)
{
/* On the positive edge of the square wave (only once per cycle) */
int Feedback = SN76489.NoiseShiftRegister;
if ( SN76489.Registers[6] & 0x4 )
{
/* White noise */
/* Calculate parity of fed-back bits for feedback */
/* Do some optimised calculations for common (known) feedback values */
/* If two bits fed back, I can do Feedback=(nsr & fb) && (nsr & fb ^ fb) */
/* since that's (one or more bits set) && (not all bits set) */
Feedback = ((Feedback & SN76489.NoiseFeedback) && ((Feedback & SN76489.NoiseFeedback) ^ SN76489.NoiseFeedback));
}
else /* Periodic noise */
Feedback = Feedback & 1;
SN76489.NoiseShiftRegister = (SN76489.NoiseShiftRegister >> 1) | (Feedback << (SN76489.SRWidth - 1));
UpdateNoiseAmplitude(time);
}
/* Advance to time of next transition */
time += NoiseFreq * PSG_MCYCLES_RATIO;
}
/* Update channel tone counter */
SN76489.ToneFreqVals[3] = time;
}
static void SN76489_RunUntil(unsigned int clocks)
{
int i;
/* Run noise first, since it might use current value of third tone frequency counter */
RunNoise(clocks);
/* Run tone channels */
for (i=0; i<3; ++i)
{
RunTone(i, clocks);
}
}
void SN76489_Config(unsigned int clocks, int preAmp, int boostNoise, int stereo)
{
int i;
/* cycle-accurate Game Gear stereo */
if (clocks > SN76489.clocks)
{
/* Run chip until current timestamp */
SN76489_RunUntil(clocks);
/* Update internal M-cycle counter */
SN76489.clocks += ((clocks - SN76489.clocks + PSG_MCYCLES_RATIO - 1) / PSG_MCYCLES_RATIO) * PSG_MCYCLES_RATIO;
}
for (i=0; i<4; i++)
{
/* stereo channel pre-amplification */
SN76489.PreAmp[i][0] = preAmp * ((stereo >> (i + 4)) & 1);
SN76489.PreAmp[i][1] = preAmp * ((stereo >> (i + 0)) & 1);
/* noise channel boost */
if (i == 3)
{
SN76489.PreAmp[3][0] = SN76489.PreAmp[3][0] << boostNoise;
SN76489.PreAmp[3][1] = SN76489.PreAmp[3][1] << boostNoise;
}
/* update stereo channel amplitude */
SN76489.Channel[i][0]= (PSGVolumeValues[SN76489.Registers[i*2 + 1]] * SN76489.PreAmp[i][0]) / 100;
SN76489.Channel[i][1]= (PSGVolumeValues[SN76489.Registers[i*2 + 1]] * SN76489.PreAmp[i][1]) / 100;
}
}
void SN76489_Update(unsigned int clocks)
{
int i;
if (clocks > SN76489.clocks)
{
/* Run chip until current timestamp */
SN76489_RunUntil(clocks);
/* Update internal M-cycle counter */
SN76489.clocks += ((clocks - SN76489.clocks + PSG_MCYCLES_RATIO - 1) / PSG_MCYCLES_RATIO) * PSG_MCYCLES_RATIO;
}
/* Adjust internal M-cycle counter for next frame */
SN76489.clocks -= clocks;
/* Adjust channel time counters for new frame */
for (i=0; i<4; ++i)
{
SN76489.ToneFreqVals[i] -= clocks;
}
}
void SN76489_Write(unsigned int clocks, unsigned int data)
{
unsigned int index;
if (clocks > SN76489.clocks)
{
/* run chip until current timestamp */
SN76489_RunUntil(clocks);
/* update internal M-cycle counter */
SN76489.clocks += ((clocks - SN76489.clocks + PSG_MCYCLES_RATIO - 1) / PSG_MCYCLES_RATIO) * PSG_MCYCLES_RATIO;
}
if (data & 0x80)
{
/* latch byte %1 cc t dddd */
SN76489.LatchedRegister = index = (data >> 4) & 0x07;
}
else
{
/* restore latched register index */
index = SN76489.LatchedRegister;
}
switch (index)
{
case 0:
case 2:
case 4: /* Tone Channels frequency */
{
if (data & 0x80)
{
/* Data byte %1 cc t dddd */
SN76489.Registers[index] = (SN76489.Registers[index] & 0x3f0) | (data & 0xf);
}
else
{
/* Data byte %0 - dddddd */
SN76489.Registers[index] = (SN76489.Registers[index] & 0x00f) | ((data & 0x3f) << 4);
}
/* zero frequency behaves the same as a value of 1 */
if (SN76489.Registers[index] == 0)
{
SN76489.Registers[index] = 1;
}
break;
}
case 1:
case 3:
case 5: /* Tone Channels attenuation */
{
data &= 0x0f;
SN76489.Registers[index] = data;
data = PSGVolumeValues[data];
index >>= 1;
SN76489.Channel[index][0] = (data * SN76489.PreAmp[index][0]) / 100;
SN76489.Channel[index][1] = (data * SN76489.PreAmp[index][1]) / 100;
break;
}
case 6: /* Noise control */
{
SN76489.Registers[6] = data & 0x0f;
/* reset shift register */
SN76489.NoiseShiftRegister = NoiseInitialState;
/* set noise signal generator frequency */
SN76489.NoiseFreq = 0x10 << (data&0x3);
break;
}
case 7: /* Noise attenuation */
{
data &= 0x0f;
SN76489.Registers[7] = data;
data = PSGVolumeValues[data];
SN76489.Channel[3][0] = (data * SN76489.PreAmp[3][0]) / 100;
SN76489.Channel[3][1] = (data * SN76489.PreAmp[3][1]) / 100;
break;
}
}
}

View File

@ -1,23 +0,0 @@
/*
SN76489 emulation
by Maxim in 2001 and 2002
*/
#ifndef _SN76489_H_
#define _SN76489_H_
#include "blip_buf.h"
#define SN_DISCRETE 0
#define SN_INTEGRATED 1
/* Function prototypes */
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);
extern void SN76489_Update(unsigned int cycles);
extern void *SN76489_GetContextPtr(void);
extern int SN76489_GetContextSize(void);
#endif /* _SN76489_H_ */

View File

@ -2,8 +2,8 @@
* Genesis Plus
* Sound Hardware
*
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald (original code)
* Copyright (C) 2007-2013 Eke-Eke (Genesis Plus GX)
* Copyright (C) 1998-2003 Charles Mac Donald (original code)
* Copyright (C) 2007-2016 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
@ -86,7 +86,7 @@ void sound_init( void )
YM_Update = YM2612Update;
YM_Write = YM2612Write;
/* chip is running a VCLK / 144 = MCLK / 7 / 144 */
/* chip is running at VCLK / 144 = MCLK / 7 / 144 */
fm_cycles_ratio = 144 * 7;
}
else
@ -97,21 +97,20 @@ void sound_init( void )
YM_Update = YM2413Update;
YM_Write = YM2413Write;
/* chip is running a ZCLK / 72 = MCLK / 15 / 72 */
/* chip is running at ZCLK / 72 = MCLK / 15 / 72 */
fm_cycles_ratio = 72 * 15;
}
/* Initialize PSG chip */
SN76489_Init((system_hw == SYSTEM_SG) ? SN_DISCRETE : SN_INTEGRATED);
SN76489_Config(0, config.psg_preamp, config.psgBoostNoise, 0xff);
psg_init((system_hw == SYSTEM_SG) ? PSG_DISCRETE : PSG_INTEGRATED);
}
void sound_reset(void)
{
/* reset sound chips */
YM_Reset();
SN76489_Reset();
SN76489_Config(0, config.psg_preamp, config.psgBoostNoise, 0xff);
psg_reset();
psg_config(0, config.psg_preamp, 0xff);
/* reset FM buffer ouput */
fm_last[0] = fm_last[1] = 0;
@ -125,21 +124,23 @@ void sound_reset(void)
int sound_update(unsigned int cycles)
{
int delta, preamp, time, l, r, *ptr;
int prev_l, prev_r, preamp, time, l, r, *ptr;
/* Run PSG & FM chips until end of frame */
SN76489_Update(cycles);
/* Run PSG chip until end of frame */
psg_end_frame(cycles);
/* Run FM chip until end of frame */
fm_update(cycles);
/* FM output pre-amplification */
/* FM output pre-amplification */
preamp = config.fm_preamp;
/* FM frame initial timestamp */
time = fm_cycles_start;
/* Restore last FM outputs from previous frame */
l = fm_last[0];
r = fm_last[1];
prev_l = fm_last[0];
prev_r = fm_last[1];
/* FM buffer start pointer */
ptr = fm_buffer;
@ -150,15 +151,12 @@ int sound_update(unsigned int cycles)
/* high-quality Band-Limited synthesis */
do
{
/* left channel */
delta = ((*ptr++ * preamp) / 100) - l;
l += delta;
blip_add_delta(snd.blips[0][0], time, delta);
/* right channel */
delta = ((*ptr++ * preamp) / 100) - r;
r += delta;
blip_add_delta(snd.blips[0][1], time, delta);
/* left & right channels */
l = ((*ptr++ * preamp) / 100);
r = ((*ptr++ * preamp) / 100);
blip_add_delta(snd.blips[0], time, l-prev_l, r-prev_r);
prev_l = l;
prev_r = r;
/* increment time counter */
time += fm_cycles_ratio;
@ -170,15 +168,12 @@ int sound_update(unsigned int cycles)
/* faster Linear Interpolation */
do
{
/* left channel */
delta = ((*ptr++ * preamp) / 100) - l;
l += delta;
blip_add_delta_fast(snd.blips[0][0], time, delta);
/* right channel */
delta = ((*ptr++ * preamp) / 100) - r;
r += delta;
blip_add_delta_fast(snd.blips[0][1], time, delta);
/* left & right channels */
l = ((*ptr++ * preamp) / 100);
r = ((*ptr++ * preamp) / 100);
blip_add_delta_fast(snd.blips[0], time, l-prev_l, r-prev_r);
prev_l = l;
prev_r = r;
/* increment time counter */
time += fm_cycles_ratio;
@ -190,18 +185,17 @@ int sound_update(unsigned int cycles)
fm_ptr = fm_buffer;
/* save last FM output for next frame */
fm_last[0] = l;
fm_last[1] = r;
fm_last[0] = prev_l;
fm_last[1] = prev_r;
/* adjust FM cycle counters for next frame */
fm_cycles_count = fm_cycles_start = time - cycles;
/* end of blip buffers time frame */
blip_end_frame(snd.blips[0][0], cycles);
blip_end_frame(snd.blips[0][1], cycles);
/* end of blip buffer time frame */
blip_end_frame(snd.blips[0], cycles);
/* return number of available samples */
return blip_samples_avail(snd.blips[0][0]);
return blip_samples_avail(snd.blips[0]);
}
int sound_context_save(uint8 *state)
@ -217,7 +211,7 @@ int sound_context_save(uint8 *state)
save_param(YM2413GetContextPtr(),YM2413GetContextSize());
}
save_param(SN76489_GetContextPtr(),SN76489_GetContextSize());
bufferptr += psg_context_save(&state[bufferptr]);
save_param(&fm_cycles_start,sizeof(fm_cycles_start));
@ -238,7 +232,7 @@ int sound_context_load(uint8 *state)
load_param(YM2413GetContextPtr(),YM2413GetContextSize());
}
load_param(SN76489_GetContextPtr(),SN76489_GetContextSize());
bufferptr += psg_context_load(&state[bufferptr]);
load_param(&fm_cycles_start,sizeof(fm_cycles_start));
fm_cycles_count = fm_cycles_start;

View File

@ -2,8 +2,8 @@
* Genesis Plus
* Sound Hardware
*
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald (original code)
* Copyright (C) 2007-2013 Eke-Eke (Genesis Plus GX)
* Copyright (C) 1998-2003 Charles Mac Donald (original code)
* Copyright (C) 2007-2016 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:

View File

@ -2,7 +2,7 @@
* Genesis Plus
* Savestate support
*
* Copyright (C) 2007-2014 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2007-2016 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
@ -116,11 +116,11 @@ int state_load(unsigned char *state)
bufferptr += sound_context_load(&state[bufferptr]);
if ((system_hw & SYSTEM_PBC) == SYSTEM_MD)
{
SN76489_Config(0, config.psg_preamp, config.psgBoostNoise, 0xff);
psg_config(0, config.psg_preamp, 0xff);
}
else
{
SN76489_Config(0, config.psg_preamp, config.psgBoostNoise, io_reg[6]);
psg_config(0, config.psg_preamp, io_reg[6]);
}
/* 68000 */

View File

@ -2,7 +2,7 @@
* Genesis Plus
* Savestate support
*
* Copyright (C) 2007-2014 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2007-2016 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:

View File

@ -68,11 +68,9 @@ int audio_init(int samplerate, double framerate)
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])
snd.blips[0] = blip_new(samplerate / 10);
if (!snd.blips[0])
{
audio_shutdown();
return -1;
}
@ -80,11 +78,9 @@ int audio_init(int samplerate, double framerate)
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])
snd.blips[1] = blip_new(samplerate / 10);
snd.blips[2] = blip_new(samplerate / 10);
if (!snd.blips[1] || !snd.blips[2])
{
audio_shutdown();
return -1;
@ -132,8 +128,7 @@ void audio_set_rate(int samplerate, double framerate)
/* 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 */
/* resampled to desired rate at the end of each frame, using Blip Buffer. */
blip_set_rates(snd.blips[0][0], mclk, samplerate);
blip_set_rates(snd.blips[0][1], mclk, samplerate);
blip_set_rates(snd.blips[0], mclk, samplerate);
/* Mega CD sound hardware */
if (system_hw == SYSTEM_MCD)
@ -155,17 +150,14 @@ void audio_set_rate(int samplerate, double framerate)
void audio_reset(void)
{
int i,j;
int i;
/* Clear blip buffers */
for (i=0; i<3; i++)
{
for (j=0; j<2; j++)
if (snd.blips[i])
{
if (snd.blips[i][j])
{
blip_clear(snd.blips[i][j]);
}
blip_clear(snd.blips[i]);
}
}
@ -187,16 +179,13 @@ void audio_set_equalizer(void)
void audio_shutdown(void)
{
int i,j;
int i;
/* Delete blip buffers */
for (i=0; i<3; i++)
{
for (j=0; j<2; j++)
{
blip_delete(snd.blips[i][j]);
snd.blips[i][j] = 0;
}
blip_delete(snd.blips[i]);
snd.blips[i] = 0;
}
}
@ -213,37 +202,24 @@ int audio_update(int16 *buffer)
/* read CDDA samples */
cdd_read_audio(size);
}
#ifdef ALIGN_SND
/* return an aligned number of samples if required */
size &= ALIGN_SND;
/* return an aligned number of samples if required */
size &= ALIGN_SND;
#endif
/* resample FM & PSG mixed stream to output buffer */
#ifdef LSB_FIRST
blip_read_samples(snd.blips[0][0], buffer, size);
blip_read_samples(snd.blips[0][1], buffer + 1, size);
#else
blip_read_samples(snd.blips[0][0], buffer + 1, size);
blip_read_samples(snd.blips[0][1], buffer, size);
#endif
/* Mega CD specific */
if (system_hw == SYSTEM_MCD)
/* resample & mix FM/PSG, PCM & CD-DA streams to output buffer */
blip_mix_samples(snd.blips[0], snd.blips[1], snd.blips[2], buffer, size);
}
else
{
/* resample PCM & CD-DA streams to output buffer */
#ifdef LSB_FIRST
blip_mix_samples(snd.blips[1][0], buffer, size);
blip_mix_samples(snd.blips[1][1], buffer + 1, size);
blip_mix_samples(snd.blips[2][0], buffer, size);
blip_mix_samples(snd.blips[2][1], buffer + 1, size);
#else
blip_mix_samples(snd.blips[1][0], buffer + 1, size);
blip_mix_samples(snd.blips[1][1], buffer, size);
blip_mix_samples(snd.blips[2][0], buffer + 1, size);
blip_mix_samples(snd.blips[2][1], buffer, size);
#ifdef ALIGN_SND
/* return an aligned number of samples if required */
size &= ALIGN_SND;
#endif
/* resample FM/PSG mixed stream to output buffer */
blip_read_samples(snd.blips[0], buffer, size);
}
/* Audio filtering */
@ -434,13 +410,10 @@ void system_frame_gen(int do_skip)
}
}
/* initialize VCounter */
v_counter = bitmap.viewport.h;
/* first line of overscan */
if (bitmap.viewport.y)
{
blank_line(v_counter, -bitmap.viewport.x, bitmap.viewport.w + 2*bitmap.viewport.x);
blank_line(bitmap.viewport.h, -bitmap.viewport.x, bitmap.viewport.w + 2*bitmap.viewport.x);
}
/* clear DMA Busy, FIFO FULL & field flags */
@ -481,31 +454,38 @@ void system_frame_gen(int do_skip)
/* refresh inputs just before VINT (Warriors of Eternal Sun) */
osd_input_update();
/* delay between VBLANK flag & Vertical Interrupt (Dracula, OutRunners, VR Troopers) */
m68k_run(788);
if (zstate == 1)
/* VDP always starts after VBLANK so VINT cannot occur on first frame after a VDP reset (verified on real hardware) */
if (v_counter != bitmap.viewport.h)
{
z80_run(788);
}
else
{
Z80.cycles = 788;
}
/* reinitialize VCounter */
v_counter = bitmap.viewport.h;
/* set VINT flag */
status |= 0x80;
/* delay between VBLANK flag & Vertical Interrupt (Dracula, OutRunners, VR Troopers) */
m68k_run(788);
if (zstate == 1)
{
z80_run(788);
}
else
{
Z80.cycles = 788;
}
/* Vertical Interrupt */
vint_pending = 0x20;
if (reg[1] & 0x20)
{
/* level 6 interrupt */
m68k_set_irq(6);
/* set VINT flag */
status |= 0x80;
/* Vertical Interrupt */
vint_pending = 0x20;
if (reg[1] & 0x20)
{
/* level 6 interrupt */
m68k_set_irq(6);
}
/* assert Z80 interrupt */
Z80.irq_state = ASSERT_LINE;
}
/* assert Z80 interrupt */
Z80.irq_state = ASSERT_LINE;
/* run 68k & Z80 until end of line */
m68k_run(MCYCLES_PER_LINE);
if (zstate == 1)
@ -789,13 +769,10 @@ void system_frame_scd(int do_skip)
}
}
/* initialize VCounter */
v_counter = bitmap.viewport.h;
/* first line of overscan */
if (bitmap.viewport.y)
{
blank_line(v_counter, -bitmap.viewport.x, bitmap.viewport.w + 2*bitmap.viewport.x);
blank_line(bitmap.viewport.h, -bitmap.viewport.x, bitmap.viewport.w + 2*bitmap.viewport.x);
}
/* clear DMA Busy, FIFO FULL & field flags */
@ -836,31 +813,38 @@ void system_frame_scd(int do_skip)
/* refresh inputs just before VINT */
osd_input_update();
/* delay between VBLANK flag & Vertical Interrupt (Dracula, OutRunners, VR Troopers) */
m68k_run(788);
if (zstate == 1)
/* VDP always starts after VBLANK so VINT cannot occur on first frame after a VDP reset (verified on real hardware) */
if (v_counter != bitmap.viewport.h)
{
z80_run(788);
}
else
{
Z80.cycles = 788;
}
/* reinitialize VCounter */
v_counter = bitmap.viewport.h;
/* set VINT flag */
status |= 0x80;
/* delay between VBLANK flag & Vertical Interrupt (Dracula, OutRunners, VR Troopers) */
m68k_run(788);
if (zstate == 1)
{
z80_run(788);
}
else
{
Z80.cycles = 788;
}
/* Vertical Interrupt */
vint_pending = 0x20;
if (reg[1] & 0x20)
{
/* level 6 interrupt */
m68k_set_irq(6);
/* set VINT flag */
status |= 0x80;
/* Vertical Interrupt */
vint_pending = 0x20;
if (reg[1] & 0x20)
{
/* level 6 interrupt */
m68k_set_irq(6);
}
/* assert Z80 interrupt */
Z80.irq_state = ASSERT_LINE;
}
/* assert Z80 interrupt */
Z80.irq_state = ASSERT_LINE;
/* run both 68k & CD hardware until end of line */
scd_update(MCYCLES_PER_LINE);

View File

@ -91,7 +91,7 @@ typedef struct
int sample_rate; /* Output Sample rate (8000-48000) */
double frame_rate; /* Output Frame rate (usually 50 or 60 frames per second) */
int enabled; /* 1= sound emulation is enabled */
blip_t* blips[3][2]; /* Blip Buffer resampling */
blip_t* blips[3]; /* Blip Buffer resampling (stereo) */
} t_snd;

View File

@ -71,7 +71,7 @@ OBJECTS += $(OBJDIR)/input.o \
$(OBJDIR)/graphic_board.o
OBJECTS += $(OBJDIR)/sound.o \
$(OBJDIR)/sn76489.o \
$(OBJDIR)/psg.o \
$(OBJDIR)/ym2413.o \
$(OBJDIR)/ym2612.o

View File

@ -42,7 +42,7 @@ void set_config_defaults(void)
config.psg_preamp = 150;
config.fm_preamp = 100;
config.hq_fm = 1;
config.psgBoostNoise = 1;
config.hq_psg = 1;
config.filter = 1;
config.low_freq = 200;
config.high_freq = 8000;

View File

@ -20,7 +20,7 @@ typedef struct
{
uint8 hq_fm;
uint8 filter;
uint8 psgBoostNoise;
uint8 hq_psg;
uint8 dac_bits;
uint8 ym2413;
int16 psg_preamp;

View File

@ -3,7 +3,7 @@
*
* Genesis Plus GX configuration file support
*
* Copyright Eke-Eke (2007-2015)
* Copyright Eke-Eke (2007-2016)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
@ -101,7 +101,7 @@ void config_default(void)
config.psg_preamp = 150;
config.fm_preamp = 100;
config.hq_fm = 1;
config.psgBoostNoise = 1;
config.hq_psg = 1;
config.filter = 1;
config.lp_range = 0x9999; /* 0.6 in 16.16 fixed point */
config.low_freq = 880;

View File

@ -3,7 +3,7 @@
*
* Genesis Plus GX configuration file support
*
* Copyright Eke-Eke (2007-2015)
* Copyright Eke-Eke (2007-2016)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
@ -51,7 +51,7 @@ typedef struct
char version[16];
uint8 hq_fm;
uint8 filter;
uint8 psgBoostNoise;
uint8 hq_psg;
uint8 dac_bits;
uint8 ym2413;
uint8 mono;

View File

@ -341,19 +341,19 @@ static gui_item items_options[] =
/* Audio options */
static gui_item items_audio[] =
{
{NULL,NULL,"Master System FM: AUTO", "Enable/disable YM2413 chip", 56,132,276,48},
{NULL,NULL,"High-Quality FM: ON", "Adjust YM2612/YM2413 resampling quality", 56,132,276,48},
{NULL,NULL,"FM Resolution: MAX", "Adjust YM2612 DAC precision", 56,132,276,48},
{NULL,NULL,"FM Volume: 1.00", "Adjust YM2612/YM2413 output level", 56,132,276,48},
{NULL,NULL,"PSG Volume: 2.50", "Adjust SN76489 output level", 56,132,276,48},
{NULL,NULL,"PSG Noise Boost: OFF", "Boost SN76489 Noise Channel", 56,132,276,48},
{NULL,NULL,"Audio Out: STEREO", "Select audio mixing output type", 56,132,276,48},
{NULL,NULL,"Filtering: 3-BAND EQ", "Setup Audio filtering", 56,132,276,48},
{NULL,NULL,"Low Gain: 1.00", "Adjust EQ Low Band Gain", 56,132,276,48},
{NULL,NULL,"Mid Gain: 1.00", "Adjust EQ Mid Band Gain", 56,132,276,48},
{NULL,NULL,"High Gain: 1.00", "Adjust EQ High Band Gain", 56,132,276,48},
{NULL,NULL,"Low Freq: 200 Hz", "Adjust EQ Lowest Frequency", 56,132,276,48},
{NULL,NULL,"High Freq: 20000 Hz", "Adjust EQ Highest Frequency", 56,132,276,48}
{NULL,NULL,"Master System FM: AUTO", "Enable/Disable YM2413 chip", 56,132,276,48},
{NULL,NULL,"High-Quality FM: ON", "Enable/Disable YM2612/YM2413 high-quality resampling", 56,132,276,48},
{NULL,NULL,"FM Resolution: MAX", "Adjust YM2612 DAC precision", 56,132,276,48},
{NULL,NULL,"FM Volume: 1.00", "Adjust YM2612/YM2413 audio balance", 56,132,276,48},
{NULL,NULL,"PSG Volume: 2.50", "Adjust SN76489 audio balance", 56,132,276,48},
{NULL,NULL,"High-Quality PSG: ON", "Enable/Disable SN76489 high-quality resampling", 56,132,276,48},
{NULL,NULL,"Audio Output: STEREO", "Select audio mixing output type", 56,132,276,48},
{NULL,NULL,"Filtering: 3-BAND EQ", "Select audio filtering type", 56,132,276,48},
{NULL,NULL,"Low Gain: 1.00", "Adjust EQ Low Band Gain", 56,132,276,48},
{NULL,NULL,"Mid Gain: 1.00", "Adjust EQ Mid Band Gain", 56,132,276,48},
{NULL,NULL,"High Gain: 1.00", "Adjust EQ High Band Gain", 56,132,276,48},
{NULL,NULL,"Low Freq: 200 Hz", "Adjust EQ Lowest Frequency", 56,132,276,48},
{NULL,NULL,"High Freq: 20000 Hz", "Adjust EQ Highest Frequency", 56,132,276,48}
};
/* System ROM paths */
@ -381,10 +381,10 @@ static gui_item items_system[] =
{NULL,NULL,"VDP Mode: AUTO", "Select VDP mode", 56,132,276,48},
{NULL,NULL,"System Clock: AUTO", "Select system clock frequency", 56,132,276,48},
{NULL,NULL,"System Boot: BIOS&CART", "Select system booting method", 56,132,276,48},
{NULL,NULL,"System Lockups: ON", "Enable/disable original system lock-ups", 56,132,276,48},
{NULL,NULL,"68k Address Error: ON", "Enable/disable 68k address error exceptions", 56,132,276,48},
{NULL,NULL,"System Lockups: ON", "Enable/Disable original system lock-ups", 56,132,276,48},
{NULL,NULL,"68k Address Error: ON", "Enable/Disable 68k address error exceptions", 56,132,276,48},
{NULL,NULL,"Lock-on: OFF", "Select Lock-On cartridge type", 56,132,276,48},
{NULL,NULL,"Cartridge Swap: OFF", "Enable/disable cartridge hot swap", 56,132,276,48},
{NULL,NULL,"Cartridge Swap: OFF", "Enable/Disable cartridge hot swap", 56,132,276,48},
{NULL,NULL,"BIOS & Lock-On ROM paths","Configure BIOS & Lock-On ROM paths", 56,132,276,48},
{NULL,NULL,"SVP Cycles: 1500", "Adjust SVP chip emulation speed", 56,132,276,48}
};
@ -394,22 +394,22 @@ static gui_item items_video[] =
{
{NULL,NULL,"Display: PROGRESSIVE", "Select video mode", 56,132,276,48},
{NULL,NULL,"TV mode: 50/60HZ", "Select video refresh rate", 56,132,276,48},
{NULL,NULL,"VSYNC: AUTO", "Enable/disable sync with video hardware", 56,132,276,48},
{NULL,NULL,"Bilinear Filter: OFF", "Enable/disable GX hardware texture filtering", 56,132,276,48},
{NULL,NULL,"Deflickering Filter: AUTO", "Enable/disable GX hardware framebuffer filtering", 56,132,276,48},
{NULL,NULL,"VSYNC: AUTO", "Enable/Disable sync with video hardware", 56,132,276,48},
{NULL,NULL,"Bilinear Filter: OFF", "Enable/Disable GX hardware texture filtering", 56,132,276,48},
{NULL,NULL,"Deflickering Filter: AUTO", "Enable/Disable GX hardware framebuffer filtering", 56,132,276,48},
#ifdef HW_RVL
{NULL,NULL,"Trap Filter: ON", "Enable/disable VI hardware composite out filtering",56,132,276,48},
{NULL,NULL,"Trap Filter: ON", "Enable/Disable VI hardware composite out filtering",56,132,276,48},
{NULL,NULL,"Gamma Correction: 1.0", "Adjust VI hardware gamma correction", 56,132,276,48},
#endif
{NULL,NULL,"LCD Ghosting Filter: OFF", "Enable/disable software LCD image persistence", 56,132,276,48},
{NULL,NULL,"NTSC Filter: COMPOSITE", "Enable/disable software NTSC filtering", 56,132,276,48},
{NULL,NULL,"LCD Ghosting Filter: OFF", "Enable/Disable software LCD image persistence", 56,132,276,48},
{NULL,NULL,"NTSC Filter: COMPOSITE", "Enable/Disable software NTSC filtering", 56,132,276,48},
{NULL,NULL,"NTSC Sharpness: 0.0", "Adjust edge contrast enhancement/blurring", 56,132,276,48},
{NULL,NULL,"NTSC Resolution: 0.0", "Adjust image resolution", 56,132,276,48},
{NULL,NULL,"NTSC Artifacts: 0.0", "Adjust artifacts caused by color changes", 56,132,276,48},
{NULL,NULL,"NTSC Color Bleed: 0.0", "Adjust color resolution reduction", 56,132,276,48},
{NULL,NULL,"NTSC Color Fringing: 0.0", "Adjust artifacts caused by brightness changes", 56,132,276,48},
{NULL,NULL,"Borders: OFF", "Enable/disable overscan emulation", 56,132,276,48},
{NULL,NULL,"GG screen: ORIGINAL", "Enable/disable Game Gear extended screen", 56,132,276,48},
{NULL,NULL,"Borders: OFF", "Enable/Disable overscan emulation", 56,132,276,48},
{NULL,NULL,"GG screen: ORIGINAL", "Enable/Disable Game Gear extended screen", 56,132,276,48},
{NULL,NULL,"Aspect: ORIGINAL (4:3)", "Select display aspect ratio", 56,132,276,48},
{NULL,NULL,"Screen Position (+0,+0)", "Adjust display position", 56,132,276,48},
{NULL,NULL,"Screen Scaling (+0,+0)", "Adjust display scaling", 56,132,276,48}
@ -418,19 +418,19 @@ static gui_item items_video[] =
/* Menu options */
static gui_item items_prefs[] =
{
{NULL,NULL,"Auto ROM Load: OFF", "Enable/disable automatic ROM loading on startup", 56,132,276,48},
{NULL,NULL,"Auto Cheats: OFF", "Enable/disable automatic cheats activation", 56,132,276,48},
{NULL,NULL,"Auto Saves: OFF", "Enable/disable automatic saves", 56,132,276,48},
{NULL,NULL,"Auto ROM Load: OFF", "Enable/Disable automatic ROM loading on startup", 56,132,276,48},
{NULL,NULL,"Auto Cheats: OFF", "Enable/Disable automatic cheats activation", 56,132,276,48},
{NULL,NULL,"Auto Saves: OFF", "Enable/Disable automatic saves", 56,132,276,48},
{NULL,NULL,"ROM Load Device: SD", "Configure default device for ROM files", 56,132,276,48},
{NULL,NULL,"Saves Device: FAT", "Configure default device for Save files", 56,132,276,48},
{NULL,NULL,"SFX Volume: 100", "Adjust sound effects volume", 56,132,276,48},
{NULL,NULL,"BGM Volume: 100", "Adjust background music volume", 56,132,276,48},
{NULL,NULL,"BG Overlay: ON", "Enable/disable background overlay", 56,132,276,48},
{NULL,NULL,"BG Overlay: ON", "Enable/Disable background overlay", 56,132,276,48},
{NULL,NULL,"Screen Width: 658", "Adjust menu screen width in pixels", 56,132,276,48},
{NULL,NULL,"Show CD Leds: OFF", "Enable/disable CD leds display", 56,132,276,48},
{NULL,NULL,"Show FPS: OFF", "Enable/disable FPS counter", 56,132,276,48},
{NULL,NULL,"Show CD Leds: OFF", "Enable/Disable CD leds display", 56,132,276,48},
{NULL,NULL,"Show FPS: OFF", "Enable/Disable FPS counter", 56,132,276,48},
#ifdef HW_RVL
{NULL,NULL,"Wiimote Timeout: OFF","Enable/disable Wii remote automatic shutodwn", 56,132,276,48},
{NULL,NULL,"Wiimote Timeout: OFF","Enable/Disable Wii remote automatic shutodwn", 56,132,276,48},
{NULL,NULL,"Wiimote Calibration: AUTO","Calibrate Wii remote pointer", 56,132,276,48},
#endif
};
@ -899,16 +899,15 @@ static void soundmenu ()
else if (config.ym2413 == 1) sprintf (items[0].text, "Master System FM: ON");
else sprintf (items[0].text, "Master System FM: AUTO");
if (config.hq_fm) sprintf (items[1].text, "High-Quality FM: ON");
else sprintf (items[1].text, "High-Quality FM: OFF");
sprintf (items[1].text, "High-Quality FM: %s", config.hq_fm ? "ON":"OFF");
if (config.dac_bits < 14) sprintf (items[2].text, "FM Resolution: %d bits", config.dac_bits);
else sprintf (items[2].text, "FM Resolution: MAX");
sprintf (items[3].text, "FM Volume: %1.2f", fm_volume);
sprintf (items[4].text, "PSG Volume: %1.2f", psg_volume);
sprintf (items[5].text, "PSG Noise Boost: %s", config.psgBoostNoise ? "ON":"OFF");
sprintf (items[6].text, "Audio Out: %s", config.mono ? "MONO":"STEREO");
sprintf (items[5].text, "High-Quality PSG: %s", config.hq_psg? "ON":"OFF");
sprintf (items[6].text, "Audio Output: %s", config.mono ? "MONO":"STEREO");
if (config.filter == 2)
{
@ -971,8 +970,7 @@ static void soundmenu ()
case 1:
{
config.hq_fm ^= 1;
if (config.hq_fm) sprintf (items[1].text, "High-Quality FM: ON");
else sprintf (items[1].text, "High-Quality FM: OFF");
sprintf (items[1].text, "High-Quality FM: %s", config.hq_fm ? "ON":"OFF");
break;
}
@ -1001,27 +999,19 @@ static void soundmenu ()
config.psg_preamp = (int)(psg_volume * 100.0 + 0.5);
if ((system_hw & SYSTEM_PBC) == SYSTEM_MD)
{
SN76489_Config(0, config.psg_preamp, config.psgBoostNoise, 0xff);
psg_config(0, config.psg_preamp, 0xff);
}
else
{
SN76489_Config(0, config.psg_preamp, config.psgBoostNoise, io_reg[6]);
psg_config(0, config.psg_preamp, io_reg[6]);
}
break;
}
case 5:
{
config.psgBoostNoise ^= 1;
sprintf (items[5].text, "PSG Noise Boost: %s", config.psgBoostNoise ? "ON":"OFF");
if ((system_hw & SYSTEM_PBC) == SYSTEM_MD)
{
SN76489_Config(0, config.psg_preamp, config.psgBoostNoise, 0xff);
}
else
{
SN76489_Config(0, config.psg_preamp, config.psgBoostNoise, io_reg[6]);
}
config.hq_psg ^= 1;
sprintf (items[5].text, "High-Quality PSG: %s", config.hq_psg ? "ON":"OFF");
break;
}
@ -1745,8 +1735,8 @@ static void videomenu ()
else
sprintf (items[VI_OFFSET+1].text, "NTSC Filter: OFF");
strcpy(items[VI_OFFSET+2+ntsc_offset].comment, "Enable/disable overscan emulation");
strcpy(items[VI_OFFSET+3+ntsc_offset].comment, "Enable/disable Game Gear extended screen");
strcpy(items[VI_OFFSET+2+ntsc_offset].comment, "Enable/Disable overscan emulation");
strcpy(items[VI_OFFSET+3+ntsc_offset].comment, "Enable/Disable Game Gear extended screen");
strcpy(items[VI_OFFSET+4+ntsc_offset].comment, "Select display aspect ratio");
strcpy(items[VI_OFFSET+5+ntsc_offset].comment, "Adjust display position");
strcpy(items[VI_OFFSET+6+ntsc_offset].comment, "Adjust display scaling");
@ -3645,15 +3635,15 @@ static void showcredits(void)
gxDrawTexture(texture, (640-texture->width)/2, (480-texture->height)/2, texture->width, texture->height,255);
FONT_writeCenter("Genesis Plus Core", 24, 0, 640, 480 - offset, (GXColor)LIGHT_BLUE);
FONT_writeCenter("improved emulation code, fixes & extra features by Eke-Eke", 18, 0, 640, 516 - offset, (GXColor)WHITE);
FONT_writeCenter("improved emulation code & extra features by Eke-Eke", 18, 0, 640, 516 - offset, (GXColor)WHITE);
FONT_writeCenter("original 1.3 version by Charles MacDonald", 18, 0, 640, 534 - offset, (GXColor)WHITE);
FONT_writeCenter("original Z80 core by Juergen Buchmueller", 18, 0, 640, 552 - offset, (GXColor)WHITE);
FONT_writeCenter("original 68k core (Musashi) by Karl Stenerud", 18, 0, 640, 570 - offset, (GXColor)WHITE);
FONT_writeCenter("original YM2612/2413 cores by Jarek Burczynski, Tatsuyuki Satoh", 18, 0, 640, 588 - offset, (GXColor)WHITE);
FONT_writeCenter("original SN76489 core by Maxim", 18, 0, 640, 606 - offset, (GXColor)WHITE);
FONT_writeCenter("SVP core by Gravydas Ignotas (Notaz)", 18, 0, 640, 624 - offset, (GXColor)WHITE);
FONT_writeCenter("Blip Buffer Library & NTSC Video Filter by Shay Green (Blargg)", 18, 0, 640, 642 - offset, (GXColor)WHITE);
FONT_writeCenter("3-Band EQ implementation by Neil C", 18, 0, 640, 660 - offset, (GXColor)WHITE);
FONT_writeCenter("SVP core by Gravydas Ignotas (Notaz)", 18, 0, 640, 606 - offset, (GXColor)WHITE);
FONT_writeCenter("Blip Buffer Library & NTSC Video Filter by Shay Green (Blargg)", 18, 0, 640, 624 - offset, (GXColor)WHITE);
FONT_writeCenter("3-Band EQ implementation by Neil C", 18, 0, 640, 642 - offset, (GXColor)WHITE);
FONT_writeCenter("Ogg Vorbis 'Tremor' Library by Xiph.org Foundation", 18, 0, 640, 660 - offset, (GXColor)WHITE);
FONT_writeCenter("Special thanks to ...", 20, 0, 640, 700 - offset, (GXColor)LIGHT_GREEN);
FONT_writeCenter("Nemesis, Tasco Deluxe, Bart Trzynadlowski, Jorge Cwik, Haze,", 18, 0, 640, 736 - offset, (GXColor)WHITE);
@ -3670,7 +3660,7 @@ static void showcredits(void)
FONT_writeCenter("libfat by Chism", 18, 0, 640, 978 - offset, (GXColor)WHITE);
FONT_writeCenter("wiiuse by Michael Laforest (Para)", 18, 0, 640, 996 - offset, (GXColor)WHITE);
FONT_writeCenter("asndlib & OGG player by Francisco Muñoz (Hermes)", 18, 0, 640, 1014 - offset, (GXColor)WHITE);
FONT_writeCenter("zlib, libpng & libtremor by their respective authors", 18, 0, 640, 1032 - offset, (GXColor)WHITE);
FONT_writeCenter("zlib & libpng by their respective authors", 18, 0, 640, 1032 - offset, (GXColor)WHITE);
FONT_writeCenter("devkitPPC by Wintermute", 18, 0, 640, 1050 - offset, (GXColor)WHITE);
FONT_writeCenter("Special thanks to ...", 20, 0, 640, 1090 - offset, (GXColor)LIGHT_GREEN);

View File

@ -13,7 +13,7 @@ Upstream Authors:
Files: *
Copyright: 1998, 1999, 2000, 2001, 2002, 2003 Charles MacDonald
Some portions copyright Nicola Salmoria and the MAME team. All rights reserved.
2007-2015 Eke-Eke. All rights reserved.
2007-2016 Eke-Eke. All rights reserved.
License:
Unless otherwise explicitly stated, all code in Genesis Plus GX is released
under the following license:
@ -77,7 +77,6 @@ License: LGPLv2.1
Files: core/sound/blip_buf.c
core/sound/blip_buf.h
Copyright: 2003-2009 Shay Green
2012-2013 EkeEke
License: LGPLv2.1
Files: core/sound/eq.c
@ -90,13 +89,6 @@ License: Public domain
The author assumes NO RESPONSIBILITY for any problems caused by the use of
this software.
Files: core/sound/sn76489.c
core/sound/sn76489.h
Copyright: 2001, 2002 Maxim
2004 Charles MacDonald
2007, 2009, 2010, 2012 Eke-Eke
License: Genesis Plus GX license
Files: core/sound/ym2413.c
core/sound/ym2413.h
Copyright: 2002 Jarek Burczynski

View File

@ -97,6 +97,7 @@ char CART_BRAM[256];
static int vwidth;
static int vheight;
static double vaspect_ratio;
static uint32_t brm_crc[2];
static uint8_t brm_format[0x40] =
@ -494,8 +495,8 @@ static void config_default(void)
/* sound options */
config.psg_preamp = 150;
config.fm_preamp = 100;
config.hq_fm = 1; /* high-quality resampling */
config.psgBoostNoise = 1;
config.hq_fm = 1; /* high-quality FM resampling (slower) */
config.hq_psg = 1; /* high-quality PSG resampling (slower) */
config.filter = 0; /* no filter */
config.lp_range = 0x9999; /* 0.6 in 16.16 fixed point */
config.low_freq = 880;
@ -503,7 +504,7 @@ static void config_default(void)
config.lg = 1.0;
config.mg = 1.0;
config.hg = 1.0;
config.dac_bits = 14; /* MAX DEPTH */
config.dac_bits = 14; /* MAX DEPTH */
config.ym2413 = 2; /* AUTO */
config.mono = 0; /* STEREO output */
@ -520,6 +521,7 @@ static void config_default(void)
/* video options */
config.overscan = 0;
config.aspect_ratio = 0;
config.gg_extra = 0;
config.ntsc = 0;
config.lcd = 0;
@ -736,13 +738,46 @@ static void extract_directory(char *buf, const char *path, size_t size)
buf[0] = '\0';
}
static double calculate_display_aspect_ratio(void)
{
if (config.aspect_ratio == 0)
{
if ((system_hw == SYSTEM_GG || system_hw == SYSTEM_GGMS) && config.overscan == 0 && config.gg_extra == 0)
{
return (6.0 / 5.0) * ((double)vwidth / (double)vheight);
}
}
bool is_h40 = bitmap.viewport.w == 320; /* Could be read directly from the register as well. */
double dotrate = system_clock / (is_h40 ? 8.0 : 10.0);
double videosamplerate;
if (config.aspect_ratio == 1) /* Force NTSC PAR */
{
videosamplerate = 135000000.0 / 11.0;
}
else if (config.aspect_ratio == 2) /* Force PAL PAR */
{
videosamplerate = 14750000.0;
}
else
{
videosamplerate = vdp_pal ? 14750000.0 : 135000000.0 / 11.0;
}
return (videosamplerate / dotrate) * ((double)vwidth / ((double)vheight * 2.0));
}
static bool update_viewport(void)
{
int ow = vwidth;
int oh = vheight;
double oar = vaspect_ratio;
vwidth = bitmap.viewport.w + (bitmap.viewport.x * 2);
vheight = bitmap.viewport.h + (bitmap.viewport.y * 2);
vaspect_ratio = calculate_display_aspect_ratio();
if (config.ntsc)
{
@ -756,8 +791,7 @@ static bool update_viewport(void)
{
vheight = vheight * 2;
}
return ((ow != vwidth) || (oh != vheight));
return ((ow != vwidth) || (oh != vheight) || (oar != vaspect_ratio));
}
static void check_variables(void)
@ -933,12 +967,7 @@ static void check_variables(void)
break;
}
/* force overscan change */
bitmap.viewport.changed = 3;
/* reinitialize libretro audio/video timings */
retro_get_system_av_info(&info);
environ_cb(RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO, &info);
update_viewports = true;
}
}
}
@ -1088,6 +1117,20 @@ static void check_variables(void)
update_viewports = true;
}
var.key = "genesis_plus_gx_aspect_ratio";
environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var);
{
orig_value = config.aspect_ratio;
if (strcmp(var.value, "NTSC PAR") == 0)
config.aspect_ratio = 1;
else if (strcmp(var.value, "PAL PAR") == 0)
config.aspect_ratio = 2;
else
config.aspect_ratio = 0;
if (orig_value != config.aspect_ratio)
update_viewports = true;
}
var.key = "genesis_plus_gx_render";
environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var);
{
@ -1125,11 +1168,12 @@ static void check_variables(void)
system_init();
system_reset();
memcpy(sram.sram, temp, sizeof(temp));
update_viewports = true;
}
if (update_viewports)
{
bitmap.viewport.changed = 3;
bitmap.viewport.changed = 11;
if ((system_hw == SYSTEM_GG) && !config.gg_extra)
bitmap.viewport.x = (config.overscan & 2) ? 14 : -48;
else
@ -1475,7 +1519,7 @@ unsigned retro_api_version(void) { return RETRO_API_VERSION; }
void retro_set_environment(retro_environment_t cb)
{
struct retro_variable vars[] = {
static const struct retro_variable vars[] = {
{ "genesis_plus_gx_system_hw", "System hardware; auto|sg-1000|sg-1000 II|mark-III|master system|master system II|game gear|mega drive / genesis" },
{ "genesis_plus_gx_region_detect", "System region; auto|ntsc-u|pal|ntsc-j" },
{ "genesis_plus_gx_force_dtack", "System lockups; enabled|disabled" },
@ -1489,13 +1533,14 @@ void retro_set_environment(retro_environment_t cb)
{ "genesis_plus_gx_lcd_filter", "LCD Ghosting filter; disabled|enabled" },
{ "genesis_plus_gx_overscan", "Borders; disabled|top/bottom|left/right|full" },
{ "genesis_plus_gx_gg_extra", "Game Gear extended screen; disabled|enabled" },
{ "genesis_plus_gx_aspect_ratio", "Core-provided aspect ratio; auto|NTSC PAR|PAL PAR" },
{ "genesis_plus_gx_render", "Interlaced mode 2 output; single field|double field" },
{ "genesis_plus_gx_gun_cursor", "Show Lightgun crosshair; no|yes" },
{ "genesis_plus_gx_invert_mouse", "Invert Mouse Y-axis; no|yes" },
{ NULL, NULL },
};
struct retro_controller_description port_1[] = {
static const struct retro_controller_description port_1[] = {
{ "Joypad Auto", RETRO_DEVICE_JOYPAD },
{ "Joypad Port Empty", RETRO_DEVICE_NONE },
{ "MD Joypad 3 Button", RETRO_DEVICE_MDPAD_3B },
@ -1514,7 +1559,7 @@ void retro_set_environment(retro_environment_t cb)
{ "MD Mouse", RETRO_DEVICE_MOUSE },
};
struct retro_controller_description port_2[] = {
static const struct retro_controller_description port_2[] = {
{ "Joypad Auto", RETRO_DEVICE_JOYPAD },
{ "Joypad Port Empty", RETRO_DEVICE_NONE },
{ "MD Joypad 3 Button", RETRO_DEVICE_MDPAD_3B },
@ -1535,13 +1580,13 @@ void retro_set_environment(retro_environment_t cb)
{ "MD Mouse", RETRO_DEVICE_MOUSE },
};
struct retro_controller_info ports[] = {
static const struct retro_controller_info ports[] = {
{ port_1, 16 },
{ port_2, 18 },
{ 0 },
};
struct retro_input_descriptor desc[] = {
static const struct retro_input_descriptor desc[] = {
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "D-Pad Left" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "D-Pad Up" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "D-Pad Down" },
@ -1679,30 +1724,48 @@ void retro_get_system_av_info(struct retro_system_av_info *info)
info->geometry.base_height = vheight;
info->geometry.max_width = 720;
info->geometry.max_height = 576;
info->geometry.aspect_ratio = 4.0 / 3.0;
info->geometry.aspect_ratio = vaspect_ratio;
info->timing.fps = (double)(system_clock) / (double)lines_per_frame / (double)MCYCLES_PER_LINE;
info->timing.sample_rate = 44100;
}
void retro_set_controller_port_device(unsigned port, unsigned device)
{
if (port > 2)
return;
switch(device)
{
case RETRO_DEVICE_NONE:
input.system[port] = NO_SYSTEM;
break;
case RETRO_DEVICE_MDPAD_3B:
config.input[port*4].padtype = DEVICE_PAD3B;
{
if (port && (input.system[0] >= RETRO_DEVICE_MDPAD_3B_WAYPLAY) && (input.system[0] <= RETRO_DEVICE_MSPAD_2B_MASTERTAP))
config.input[4].padtype = DEVICE_PAD3B;
else
config.input[port].padtype = DEVICE_PAD3B;
input.system[port] = SYSTEM_GAMEPAD;
break;
}
case RETRO_DEVICE_MDPAD_6B:
config.input[port*4].padtype = DEVICE_PAD6B;
{
if (port && (input.system[0] >= RETRO_DEVICE_MDPAD_3B_WAYPLAY) && (input.system[0] <= RETRO_DEVICE_MSPAD_2B_MASTERTAP))
config.input[4].padtype = DEVICE_PAD6B;
else
config.input[port].padtype = DEVICE_PAD6B;
input.system[port] = SYSTEM_GAMEPAD;
break;
}
case RETRO_DEVICE_MSPAD_2B:
config.input[port*4].padtype = DEVICE_PAD2B;
{
if (port && (input.system[0] >= RETRO_DEVICE_MDPAD_3B_WAYPLAY) && (input.system[0] <= RETRO_DEVICE_MSPAD_2B_MASTERTAP))
config.input[4].padtype = DEVICE_PAD2B;
else
config.input[port].padtype = DEVICE_PAD2B;
input.system[port] = SYSTEM_GAMEPAD;
break;
}
case RETRO_DEVICE_MDPAD_3B_WAYPLAY:
{
int i;
@ -1779,9 +1842,14 @@ void retro_set_controller_port_device(unsigned port, unsigned device)
break;
case RETRO_DEVICE_JOYPAD:
default:
config.input[port*4].padtype = DEVICE_PAD2B | DEVICE_PAD6B | DEVICE_PAD3B;
{
if (port && (input.system[0] >= RETRO_DEVICE_MDPAD_3B_WAYPLAY) && (input.system[0] <= RETRO_DEVICE_MSPAD_2B_MASTERTAP))
config.input[4].padtype = DEVICE_PAD2B | DEVICE_PAD6B | DEVICE_PAD3B;
else
config.input[port].padtype = DEVICE_PAD2B | DEVICE_PAD6B | DEVICE_PAD3B;
input.system[port] = SYSTEM_GAMEPAD;
break;
}
}
old_system[0] = input.system[0];
@ -2082,14 +2150,22 @@ void retro_run(void)
else
system_frame_sms(0);
if (bitmap.viewport.changed & 1)
if (bitmap.viewport.changed & 9)
{
bool geometry_updated = update_viewport();
bitmap.viewport.changed &= ~1;
if (update_viewport())
if (bitmap.viewport.changed & 8)
{
struct retro_system_av_info info;
retro_get_system_av_info(&info);
environ_cb(RETRO_ENVIRONMENT_SET_GEOMETRY, &info.geometry);
struct retro_system_av_info info;
bitmap.viewport.changed &= ~8;
retro_get_system_av_info(&info);
environ_cb(RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO, &info);
}
else if (geometry_updated)
{
struct retro_system_av_info info;
retro_get_system_av_info(&info);
environ_cb(RETRO_ENVIRONMENT_SET_GEOMETRY, &info.geometry);
}
}

View File

@ -394,7 +394,7 @@
RelativePath="..\..\..\core\sound\eq.c">
</File>
<File
RelativePath="..\..\..\core\sound\sn76489.c">
RelativePath="..\..\..\core\sound\psg.c">
</File>
<File
RelativePath="..\..\..\core\sound\sound.c">

View File

@ -143,7 +143,7 @@
<CompileAs Condition="'$(Configuration)|$(Platform)'=='Release_LTCG|Xbox 360'">CompileAsC</CompileAs>
</ClCompile>
<ClCompile Include="..\..\..\core\sound\eq.c" />
<ClCompile Include="..\..\..\core\sound\sn76489.c" />
<ClCompile Include="..\..\..\core\sound\psg.c" />
<ClCompile Include="..\..\..\core\sound\sound.c" />
<ClCompile Include="..\..\..\core\sound\ym2413.c" />
<ClCompile Include="..\..\..\core\sound\ym2612.c" />

View File

@ -80,7 +80,7 @@
<ClCompile Include="..\..\..\core\sound\eq.c">
<Filter>Source Files\sound</Filter>
</ClCompile>
<ClCompile Include="..\..\..\core\sound\sn76489.c">
<ClCompile Include="..\..\..\core\sound\psg.c">
<Filter>Source Files\sound</Filter>
</ClCompile>
<ClCompile Include="..\..\..\core\sound\sound.c">

View File

@ -49,7 +49,7 @@
<ClCompile Include="..\..\..\core\ntsc\sms_ntsc.c" />
<ClCompile Include="..\..\..\core\sound\blip_buf.c" />
<ClCompile Include="..\..\..\core\sound\eq.c" />
<ClCompile Include="..\..\..\core\sound\sn76489.c" />
<ClCompile Include="..\..\..\core\sound\psg.c" />
<ClCompile Include="..\..\..\core\sound\sound.c" />
<ClCompile Include="..\..\..\core\sound\ym2413.c" />
<ClCompile Include="..\..\..\core\sound\ym2612.c" />

View File

@ -117,7 +117,7 @@
<ClCompile Include="..\..\..\core\sound\eq.c">
<Filter>Source Files\sound</Filter>
</ClCompile>
<ClCompile Include="..\..\..\core\sound\sn76489.c">
<ClCompile Include="..\..\..\core\sound\psg.c">
<Filter>Source Files\sound</Filter>
</ClCompile>
<ClCompile Include="..\..\..\core\sound\sound.c">

View File

@ -84,7 +84,7 @@ struct
char version[16];
uint8 hq_fm;
uint8 filter;
uint8 psgBoostNoise;
uint8 hq_psg;
uint8 dac_bits;
uint8 ym2413;
uint8 mono;
@ -105,6 +105,7 @@ struct
uint8 bios;
uint8 lock_on;
uint8 overscan;
uint8 aspect_ratio;
uint8 ntsc;
uint8 lcd;
uint8 gg_extra;

View File

@ -69,7 +69,7 @@ OBJECTS += $(OBJDIR)/input.o \
$(OBJDIR)/graphic_board.o
OBJECTS += $(OBJDIR)/sound.o \
$(OBJDIR)/sn76489.o \
$(OBJDIR)/psg.o \
$(OBJDIR)/ym2413.o \
$(OBJDIR)/ym2612.o

View File

@ -11,7 +11,7 @@ void set_config_defaults(void)
config.psg_preamp = 150;
config.fm_preamp = 100;
config.hq_fm = 0;
config.psgBoostNoise = 1;
config.hq_psg = 0;
config.filter = 1;
config.low_freq = 200;
config.high_freq = 8000;

View File

@ -19,7 +19,7 @@ typedef struct
{
uint8 hq_fm;
uint8 filter;
uint8 psgBoostNoise;
uint8 hq_psg;
uint8 dac_bits;
uint8 ym2413;
int16 psg_preamp;

View File

@ -19,17 +19,21 @@
# -D16BPP_RENDERING - configure for 16-bit pixels (RGB565)
# -D32BPP_RENDERING - configure for 32-bit pixels (RGB888)
NAME = gen_sdl.exe
NAME = gen_sdl
CC = gcc
CFLAGS = `sdl-config --cflags` -march=i686 -O6 -fomit-frame-pointer -Wall -Wno-strict-aliasing -ansi -std=c89 -pedantic-errors
CFLAGS = `sdl-config --cflags` -march=i686 -O6 -fomit-frame-pointer -Wall -Wno-strict-aliasing -ansi -std=c99 -pedantic-errors
#-g -ggdb -pg
#-fomit-frame-pointer
#LDFLAGS = -pg
DEFINES = -DLSB_FIRST -DUSE_16BPP_RENDERING -DUSE_LIBTREMOR
DEFINES = -DLSB_FIRST -DUSE_16BPP_RENDERING -DUSE_LIBTREMOR -DMAXROMSIZE=33554432
ifneq ($(OS),Windows_NT)
DEFINES += -DHAVE_ALLOCA_H
endif
SRCDIR = ../core
INCLUDES = -I$(SRCDIR) -I$(SRCDIR)/z80 -I$(SRCDIR)/m68k -I$(SRCDIR)/sound -I$(SRCDIR)/input_hw -I$(SRCDIR)/cart_hw -I$(SRCDIR)/cart_hw/svp -I$(SRCDIR)/cd_hw -I$(SRCDIR)/ntsc -I$(SRCDIR)/tremor -I$(SRCDIR)/../sdl
INCLUDES = -I$(SRCDIR) -I$(SRCDIR)/z80 -I$(SRCDIR)/m68k -I$(SRCDIR)/sound -I$(SRCDIR)/input_hw -I$(SRCDIR)/cart_hw -I$(SRCDIR)/cart_hw/svp -I$(SRCDIR)/cd_hw -I$(SRCDIR)/ntsc -I$(SRCDIR)/tremor -I$(SRCDIR)/../sdl -I$(SRCDIR)/../sdl/sdl1
LIBS = `sdl-config --libs` -lz -lm
OBJDIR = ./build_sdl
@ -63,7 +67,7 @@ OBJECTS += $(OBJDIR)/input.o \
$(OBJDIR)/graphic_board.o
OBJECTS += $(OBJDIR)/sound.o \
$(OBJDIR)/sn76489.o \
$(OBJDIR)/psg.o \
$(OBJDIR)/ym2413.o \
$(OBJDIR)/ym2612.o
@ -114,7 +118,9 @@ OBJECTS += $(OBJDIR)/bitwise.o \
$(OBJDIR)/vorbisfile.o \
$(OBJDIR)/window.o
ifeq ($(OS),Windows_NT)
OBJECTS += $(OBJDIR)/icon.o
endif
all: $(NAME)
@ -163,8 +169,13 @@ $(OBJDIR)/%.o : $(SRCDIR)/tremor/%.c
$(OBJDIR)/%.o : $(SRCDIR)/../sdl/%.c $(SRCDIR)/../sdl/%.h
$(CC) -c $(CFLAGS) $(INCLUDES) $(DEFINES) $< -o $@
$(OBJDIR)/%.o : $(SRCDIR)/../sdl/sdl1/%.c $(SRCDIR)/../sdl/sdl1/%.h
$(CC) -c $(CFLAGS) $(INCLUDES) $(DEFINES) $< -o $@
ifeq ($(OS),Windows_NT)
$(OBJDIR)/icon.o :
windres $(SRCDIR)/../sdl/icon.rc $@
endif
pack :
strip $(NAME)

185
sdl/Makefile.sdl2 Normal file
View File

@ -0,0 +1,185 @@
# Makefile for genplus SDL2
#
# (c) 1999, 2000, 2001, 2002, 2003 Charles MacDonald
# modified by Eke-Eke <eke_eke31@yahoo.fr>
#
# Defines :
# -DLSB_FIRST : for little endian systems.
# -DLOGERROR : enable message logging
# -DLOGVDP : enable VDP debug messages
# -DLOGSOUND : enable AUDIO debug messages
# -DLOG_SCD : enable SCD debug messages
# -DLOG_CDD : enable CDD debug messages
# -DLOG_CDC : enable CDC debug messages
# -DLOG_PCM : enable PCM debug messages
# -DLOGSOUND : enable AUDIO debug messages
# -D8BPP_RENDERING - configure for 8-bit pixels (RGB332)
# -D15BPP_RENDERING - configure for 15-bit pixels (RGB555)
# -D16BPP_RENDERING - configure for 16-bit pixels (RGB565)
# -D32BPP_RENDERING - configure for 32-bit pixels (RGB888)
NAME = gen_sdl2
CC = gcc
CFLAGS = `sdl2-config --cflags` -march=i686 -O6 -fomit-frame-pointer -Wall -Wno-strict-aliasing -ansi -std=c99 -pedantic-errors
#-g -ggdb -pg
#-fomit-frame-pointer
#LDFLAGS = -pg
DEFINES = -DLSB_FIRST -DUSE_16BPP_RENDERING -DUSE_LIBTREMOR -DMAXROMSIZE=33554432
ifneq ($(OS),Windows_NT)
DEFINES += -DHAVE_ALLOCA_H
endif
SRCDIR = ../core
INCLUDES = -I$(SRCDIR) -I$(SRCDIR)/z80 -I$(SRCDIR)/m68k -I$(SRCDIR)/sound -I$(SRCDIR)/input_hw -I$(SRCDIR)/cart_hw -I$(SRCDIR)/cart_hw/svp -I$(SRCDIR)/cd_hw -I$(SRCDIR)/ntsc -I$(SRCDIR)/tremor -I$(SRCDIR)/../sdl -I$(SRCDIR)/../sdl/sdl2
LIBS = `sdl2-config --libs` -lz -lm
OBJDIR = ./build_sdl2
OBJECTS = $(OBJDIR)/z80.o
OBJECTS += $(OBJDIR)/m68kcpu.o \
$(OBJDIR)/s68kcpu.o
OBJECTS += $(OBJDIR)/genesis.o \
$(OBJDIR)/vdp_ctrl.o \
$(OBJDIR)/vdp_render.o \
$(OBJDIR)/system.o \
$(OBJDIR)/io_ctrl.o \
$(OBJDIR)/mem68k.o \
$(OBJDIR)/memz80.o \
$(OBJDIR)/membnk.o \
$(OBJDIR)/state.o \
$(OBJDIR)/loadrom.o
OBJECTS += $(OBJDIR)/input.o \
$(OBJDIR)/gamepad.o \
$(OBJDIR)/lightgun.o \
$(OBJDIR)/mouse.o \
$(OBJDIR)/activator.o \
$(OBJDIR)/xe_1ap.o \
$(OBJDIR)/teamplayer.o \
$(OBJDIR)/paddle.o \
$(OBJDIR)/sportspad.o \
$(OBJDIR)/terebi_oekaki.o \
$(OBJDIR)/graphic_board.o
OBJECTS += $(OBJDIR)/sound.o \
$(OBJDIR)/psg.o \
$(OBJDIR)/ym2413.o \
$(OBJDIR)/ym2612.o
OBJECTS += $(OBJDIR)/blip_buf.o
OBJECTS += $(OBJDIR)/eq.o
OBJECTS += $(OBJDIR)/sram.o \
$(OBJDIR)/svp.o \
$(OBJDIR)/ssp16.o \
$(OBJDIR)/ggenie.o \
$(OBJDIR)/areplay.o \
$(OBJDIR)/eeprom_93c.o \
$(OBJDIR)/eeprom_i2c.o \
$(OBJDIR)/eeprom_spi.o \
$(OBJDIR)/md_cart.o \
$(OBJDIR)/sms_cart.o
OBJECTS += $(OBJDIR)/scd.o \
$(OBJDIR)/cdd.o \
$(OBJDIR)/cdc.o \
$(OBJDIR)/gfx.o \
$(OBJDIR)/pcm.o \
$(OBJDIR)/cd_cart.o
OBJECTS += $(OBJDIR)/sms_ntsc.o \
$(OBJDIR)/md_ntsc.o
OBJECTS += $(OBJDIR)/main.o \
$(OBJDIR)/config.o \
$(OBJDIR)/error.o \
$(OBJDIR)/unzip.o \
$(OBJDIR)/fileio.o
OBJECTS += $(OBJDIR)/bitwise.o \
$(OBJDIR)/block.o \
$(OBJDIR)/codebook.o \
$(OBJDIR)/floor0.o \
$(OBJDIR)/floor1.o \
$(OBJDIR)/framing.o \
$(OBJDIR)/info.o \
$(OBJDIR)/mapping0.o \
$(OBJDIR)/mdct.o \
$(OBJDIR)/registry.o \
$(OBJDIR)/res012.o \
$(OBJDIR)/sharedbook.o \
$(OBJDIR)/synthesis.o \
$(OBJDIR)/vorbisfile.o \
$(OBJDIR)/window.o
ifeq ($(OS),Windows_NT)
OBJECTS += $(OBJDIR)/icon.o
endif
all: $(NAME)
$(NAME): $(OBJDIR) $(OBJECTS)
$(CC) $(LDFLAGS) $(OBJECTS) $(LIBS) -o $@
$(OBJDIR) :
@[ -d $@ ] || mkdir -p $@
$(OBJDIR)/%.o : $(SRCDIR)/%.c $(SRCDIR)/%.h
$(CC) -c $(CFLAGS) $(INCLUDES) $(DEFINES) $< -o $@
$(OBJDIR)/%.o : $(SRCDIR)/sound/%.c $(SRCDIR)/sound/%.h
$(CC) -c $(CFLAGS) $(INCLUDES) $(DEFINES) $< -o $@
$(OBJDIR)/%.o : $(SRCDIR)/input_hw/%.c $(SRCDIR)/input_hw/%.h
$(CC) -c $(CFLAGS) $(INCLUDES) $(DEFINES) $< -o $@
$(OBJDIR)/%.o : $(SRCDIR)/cart_hw/%.c $(SRCDIR)/cart_hw/%.h
$(CC) -c $(CFLAGS) $(INCLUDES) $(DEFINES) $< -o $@
$(OBJDIR)/%.o : $(SRCDIR)/cart_hw/svp/%.c
$(CC) -c $(CFLAGS) $(INCLUDES) $(DEFINES) $< -o $@
$(OBJDIR)/%.o : $(SRCDIR)/cart_hw/svp/%.c $(SRCDIR)/cart_hw/svp/%.h
$(CC) -c $(CFLAGS) $(INCLUDES) $(DEFINES) $< -o $@
$(OBJDIR)/%.o : $(SRCDIR)/cd_hw/%.c $(SRCDIR)/cd_hw/%.h
$(CC) -c $(CFLAGS) $(INCLUDES) $(DEFINES) $< -o $@
$(OBJDIR)/%.o : $(SRCDIR)/z80/%.c $(SRCDIR)/z80/%.h
$(CC) -c $(CFLAGS) $(INCLUDES) $(DEFINES) $< -o $@
$(OBJDIR)/%.o : $(SRCDIR)/m68k/%.c
$(CC) -c $(CFLAGS) $(INCLUDES) $(DEFINES) $< -o $@
$(OBJDIR)/%.o : $(SRCDIR)/ntsc/%.c $(SRCDIR)/ntsc/%.h
$(CC) -c $(CFLAGS) $(INCLUDES) $(DEFINES) $< -o $@
$(OBJDIR)/%.o : $(SRCDIR)/tremor/%.c $(SRCDIR)/tremor/%.h
$(CC) -c $(CFLAGS) $(INCLUDES) $(DEFINES) $< -o $@
$(OBJDIR)/%.o : $(SRCDIR)/tremor/%.c
$(CC) -c $(CFLAGS) $(INCLUDES) $(DEFINES) $< -o $@
$(OBJDIR)/%.o : $(SRCDIR)/../sdl/%.c $(SRCDIR)/../sdl/%.h
$(CC) -c $(CFLAGS) $(INCLUDES) $(DEFINES) $< -o $@
$(OBJDIR)/%.o : $(SRCDIR)/../sdl/sdl2/%.c $(SRCDIR)/../sdl/sdl2/%.h
$(CC) -c $(CFLAGS) $(INCLUDES) $(DEFINES) $< -o $@
ifeq ($(OS),Windows_NT)
$(OBJDIR)/icon.o :
windres $(SRCDIR)/../sdl/icon.rc $@
endif
pack :
strip $(NAME)
upx -9 $(NAME)
clean:
rm -f $(OBJECTS) $(NAME)

View File

@ -9,7 +9,7 @@ PLEASE DO NOT DISTRIBUTE WIN32 BINARIES WITHOUT THIS NOTICE.
END USERS SHOULD PREFERABLY USE LIBRETRO PORT WITH RETROARCH.
----------------------------------------------------------------------------
Genesis Plus (Windows Port)
Genesis Plus (SDL Port)
----------------------------------------------------------------------------
based on the original version 1.3

View File

@ -12,7 +12,7 @@ void set_config_defaults(void)
config.psg_preamp = 150;
config.fm_preamp = 100;
config.hq_fm = 1;
config.psgBoostNoise = 1;
config.hq_psg = 1;
config.filter = 1;
config.low_freq = 200;
config.high_freq = 8000;

View File

@ -15,7 +15,7 @@ typedef struct
{
uint8 hq_fm;
uint8 filter;
uint8 psgBoostNoise;
uint8 hq_psg;
uint8 dac_bits;
uint8 ym2413;
int16 psg_preamp;

View File

@ -5,7 +5,9 @@
#include "osd.h"
#ifdef LOGERROR
static FILE *error_log;
#endif
void error_init(void)
{

View File

@ -14,7 +14,7 @@
#define SOUND_FREQUENCY 48000
#define SOUND_SAMPLES_SIZE 2048
#define VIDEO_WIDTH 320
#define VIDEO_WIDTH 320
#define VIDEO_HEIGHT 240
int joynum = 0;
@ -67,7 +67,7 @@ static int sdl_sound_init()
{
int n;
SDL_AudioSpec as_desired, as_obtained;
if(SDL_Init(SDL_INIT_AUDIO) < 0) {
MessageBox(NULL, "SDL Audio initialization failed", "Error", 0);
return 0;
@ -101,10 +101,10 @@ static int sdl_sound_init()
return 1;
}
static void sdl_sound_update(enabled)
static void sdl_sound_update(int enabled)
{
int size = audio_update(soundframe) * 2;
if (enabled)
{
int i;
@ -126,7 +126,7 @@ static void sdl_sound_close()
{
SDL_PauseAudio(1);
SDL_CloseAudio();
if (sdl_sound.buffer)
if (sdl_sound.buffer)
free(sdl_sound.buffer);
}
@ -196,7 +196,7 @@ static void sdl_video_update()
sdl_video.drect.h = sdl_video.srect.h;
sdl_video.drect.x = (VIDEO_WIDTH - sdl_video.drect.w) / 2;
sdl_video.drect.y = (VIDEO_HEIGHT - sdl_video.drect.h) / 2;
/* clear destination surface */
SDL_FillRect(sdl_video.surf_screen, 0, 0);
@ -304,7 +304,7 @@ static void sdl_sync_close()
SDL_DestroySemaphore(sdl_sync.sem_sync);
}
static const uint16 vc_table[4][2] =
static const uint16 vc_table[4][2] =
{
/* NTSC, PAL */
{0xDA , 0xF2}, /* Mode 4 (192 lines) */
@ -332,8 +332,7 @@ static int sdl_control_update(SDLKey keystate)
case SDLK_F2:
{
if (fullscreen) fullscreen = 0;
else fullscreen = SDL_FULLSCREEN;
fullscreen = (fullscreen ? 0 : SDL_FULLSCREEN);
sdl_video.surf_screen = SDL_SetVideoMode(VIDEO_WIDTH, VIDEO_HEIGHT, 16, SDL_SWSURFACE | fullscreen);
break;
}
@ -497,7 +496,7 @@ int sdl_input_update(void)
/* reset input */
input.pad[joynum] = 0;
switch (input.dev[joynum])
{
case DEVICE_LIGHTGUN:
@ -515,7 +514,7 @@ int sdl_input_update(void)
/* TRIGGER, B, C (Menacer only), START (Menacer & Justifier only) */
if(state & SDL_BUTTON_LMASK) input.pad[joynum] |= INPUT_A;
if(state & SDL_BUTTON_RMASK) input.pad[joynum] |= INPUT_B;
if(state & SDL_BUTTON_MMASK) input.pad[joynum] |= INPUT_C;
if(state & SDL_BUTTON_MMASK) input.pad[joynum] |= INPUT_C;
if(keystate[SDLK_f]) input.pad[joynum] |= INPUT_START;
break;
}
@ -586,7 +585,7 @@ int sdl_input_update(void)
if(keystate[SDLK_x]) input.pad[joynum] |= INPUT_X;
if(keystate[SDLK_c]) input.pad[joynum] |= INPUT_MODE;
if(keystate[SDLK_v]) input.pad[joynum] |= INPUT_Z;
/* Left Analog Stick (bidirectional) */
if(keystate[SDLK_UP]) input.analog[joynum][1]-=2;
else if(keystate[SDLK_DOWN]) input.analog[joynum][1]+=2;
@ -624,7 +623,7 @@ int sdl_input_update(void)
/* Calculate X Y axis values */
input.analog[0][0] = 0x3c + (x * (0x17c-0x03c+1)) / VIDEO_WIDTH;
input.analog[0][1] = 0x1fc + (y * (0x2f7-0x1fc+1)) / VIDEO_HEIGHT;
/* Map mouse buttons to player #1 inputs */
if(state & SDL_BUTTON_MMASK) pico_current = (pico_current + 1) & 7;
if(state & SDL_BUTTON_RMASK) input.pad[0] |= INPUT_PICO_RED;
@ -642,7 +641,7 @@ int sdl_input_update(void)
/* Calculate X Y axis values */
input.analog[0][0] = (x * 250) / VIDEO_WIDTH;
input.analog[0][1] = (y * 250) / VIDEO_HEIGHT;
/* Map mouse buttons to player #1 inputs */
if(state & SDL_BUTTON_RMASK) input.pad[0] |= INPUT_B;
@ -658,7 +657,7 @@ int sdl_input_update(void)
/* 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;
@ -711,7 +710,7 @@ int main (int argc, char **argv)
char caption[256];
sprintf(caption, "Genesis Plus GX\\SDL\nusage: %s gamename\n", argv[0]);
MessageBox(NULL, caption, "Information", 0);
exit(1);
return 1;
}
/* set default config */
@ -751,10 +750,8 @@ int main (int argc, char **argv)
/* initialize SDL */
if(SDL_Init(0) < 0)
{
char caption[256];
sprintf(caption, "SDL initialization failed");
MessageBox(NULL, caption, "Error", 0);
exit(1);
MessageBox(NULL, "SDL initialization failed", "Error", 0);
return 1;
}
sdl_video_init();
if (use_sound) sdl_sound_init();
@ -784,7 +781,7 @@ int main (int argc, char **argv)
char caption[256];
sprintf(caption, "Error loading file `%s'.", argv[1]);
MessageBox(NULL, caption, "Error", 0);
exit(1);
return 1;
}
/* initialize system hardware */
@ -866,14 +863,14 @@ int main (int argc, char **argv)
while(running)
{
SDL_Event event;
if (SDL_PollEvent(&event))
if (SDL_PollEvent(&event))
{
switch(event.type)
switch(event.type)
{
case SDL_USEREVENT:
{
char caption[100];
sprintf(caption,"Genesis Plus GX - %d fps - %s)", event.user.code, (rominfo.international[0] != 0x20) ? rominfo.international : rominfo.domestic);
char caption[100];
sprintf(caption,"Genesis Plus GX - %d fps - %s", event.user.code, (rominfo.international[0] != 0x20) ? rominfo.international : rominfo.domestic);
SDL_WM_SetCaption(caption, NULL);
break;
}

945
sdl/sdl2/main.c Normal file
View File

@ -0,0 +1,945 @@
#include "SDL.h"
#include "SDL_thread.h"
#include "shared.h"
#include "sms_ntsc.h"
#include "md_ntsc.h"
#define SOUND_FREQUENCY 48000
#define SOUND_SAMPLES_SIZE 2048
#define VIDEO_WIDTH 320
#define VIDEO_HEIGHT 240
int joynum = 0;
int log_error = 0;
int debug_on = 0;
int turbo_mode = 0;
int use_sound = 1;
int fullscreen = 0; /* SDL_WINDOW_FULLSCREEN */
struct {
SDL_Window* window;
SDL_Surface* surf_screen;
SDL_Surface* surf_bitmap;
SDL_Rect srect;
SDL_Rect drect;
Uint32 frames_rendered;
} sdl_video;
/* sound */
struct {
char* current_pos;
char* buffer;
int current_emulated_samples;
} sdl_sound;
static uint8 brm_format[0x40] =
{
0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x00,0x00,0x00,0x00,0x40,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x53,0x45,0x47,0x41,0x5f,0x43,0x44,0x5f,0x52,0x4f,0x4d,0x00,0x01,0x00,0x00,0x00,
0x52,0x41,0x4d,0x5f,0x43,0x41,0x52,0x54,0x52,0x49,0x44,0x47,0x45,0x5f,0x5f,0x5f
};
static short soundframe[SOUND_SAMPLES_SIZE];
static void sdl_sound_callback(void *userdata, Uint8 *stream, int len)
{
if(sdl_sound.current_emulated_samples < len) {
memset(stream, 0, len);
}
else {
memcpy(stream, sdl_sound.buffer, len);
/* loop to compensate desync */
do {
sdl_sound.current_emulated_samples -= len;
} while(sdl_sound.current_emulated_samples > 2 * len);
memcpy(sdl_sound.buffer,
sdl_sound.current_pos - sdl_sound.current_emulated_samples,
sdl_sound.current_emulated_samples);
sdl_sound.current_pos = sdl_sound.buffer + sdl_sound.current_emulated_samples;
}
}
static int sdl_sound_init()
{
int n;
SDL_AudioSpec as_desired, as_obtained;
if(SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) {
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error", "SDL Audio initialization failed", sdl_video.window);
return 0;
}
as_desired.freq = SOUND_FREQUENCY;
as_desired.format = AUDIO_S16LSB;
as_desired.channels = 2;
as_desired.samples = SOUND_SAMPLES_SIZE;
as_desired.callback = sdl_sound_callback;
if(SDL_OpenAudio(&as_desired, &as_obtained) == -1) {
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error", "SDL Audio open failed", sdl_video.window);
return 0;
}
if(as_desired.samples != as_obtained.samples) {
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error", "SDL Audio wrong setup", sdl_video.window);
return 0;
}
sdl_sound.current_emulated_samples = 0;
n = SOUND_SAMPLES_SIZE * 2 * sizeof(short) * 20;
sdl_sound.buffer = (char*)malloc(n);
if(!sdl_sound.buffer) {
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error", "Can't allocate audio buffer", sdl_video.window);
return 0;
}
memset(sdl_sound.buffer, 0, n);
sdl_sound.current_pos = sdl_sound.buffer;
return 1;
}
static void sdl_sound_update(int enabled)
{
int size = audio_update(soundframe) * 2;
if (enabled)
{
int i;
short *out;
SDL_LockAudio();
out = (short*)sdl_sound.current_pos;
for(i = 0; i < size; i++)
{
*out++ = soundframe[i];
}
sdl_sound.current_pos = (char*)out;
sdl_sound.current_emulated_samples += size * sizeof(short);
SDL_UnlockAudio();
}
}
static void sdl_sound_close()
{
SDL_PauseAudio(1);
SDL_CloseAudio();
if (sdl_sound.buffer)
free(sdl_sound.buffer);
}
/* video */
md_ntsc_t *md_ntsc;
sms_ntsc_t *sms_ntsc;
static int sdl_video_init()
{
if(SDL_InitSubSystem(SDL_INIT_VIDEO) < 0) {
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error", "SDL Video initialization failed", sdl_video.window);
return 0;
}
sdl_video.window = SDL_CreateWindow("Genesis Plus GX", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, VIDEO_WIDTH, VIDEO_HEIGHT, 0);
sdl_video.surf_screen = SDL_GetWindowSurface(sdl_video.window);
sdl_video.surf_bitmap = SDL_CreateRGBSurface(SDL_SWSURFACE, 720, 576, 16, 0, 0, 0, 0);
sdl_video.frames_rendered = 0;
SDL_ShowCursor(0);
return 1;
}
static void sdl_video_update()
{
if (system_hw == SYSTEM_MCD)
{
system_frame_scd(0);
}
else if ((system_hw & SYSTEM_PBC) == SYSTEM_MD)
{
system_frame_gen(0);
}
else
{
system_frame_sms(0);
}
/* viewport size changed */
if(bitmap.viewport.changed & 1)
{
bitmap.viewport.changed &= ~1;
/* source bitmap */
sdl_video.srect.w = bitmap.viewport.w+2*bitmap.viewport.x;
sdl_video.srect.h = bitmap.viewport.h+2*bitmap.viewport.y;
sdl_video.srect.x = 0;
sdl_video.srect.y = 0;
if (sdl_video.srect.w > VIDEO_WIDTH)
{
sdl_video.srect.x = (sdl_video.srect.w - VIDEO_WIDTH) / 2;
sdl_video.srect.w = VIDEO_WIDTH;
}
if (sdl_video.srect.h > VIDEO_HEIGHT)
{
sdl_video.srect.y = (sdl_video.srect.h - VIDEO_HEIGHT) / 2;
sdl_video.srect.h = VIDEO_HEIGHT;
}
/* destination bitmap */
sdl_video.drect.w = sdl_video.srect.w;
sdl_video.drect.h = sdl_video.srect.h;
sdl_video.drect.x = (VIDEO_WIDTH - sdl_video.drect.w) / 2;
sdl_video.drect.y = (VIDEO_HEIGHT - sdl_video.drect.h) / 2;
/* clear destination surface */
SDL_FillRect(sdl_video.surf_screen, 0, 0);
#if 0
if (config.render && (interlaced || config.ntsc)) rect.h *= 2;
if (config.ntsc) rect.w = (reg[12]&1) ? MD_NTSC_OUT_WIDTH(rect.w) : SMS_NTSC_OUT_WIDTH(rect.w);
if (config.ntsc)
{
sms_ntsc = (sms_ntsc_t *)malloc(sizeof(sms_ntsc_t));
md_ntsc = (md_ntsc_t *)malloc(sizeof(md_ntsc_t));
switch (config.ntsc)
{
case 1:
sms_ntsc_init(sms_ntsc, &sms_ntsc_composite);
md_ntsc_init(md_ntsc, &md_ntsc_composite);
break;
case 2:
sms_ntsc_init(sms_ntsc, &sms_ntsc_svideo);
md_ntsc_init(md_ntsc, &md_ntsc_svideo);
break;
case 3:
sms_ntsc_init(sms_ntsc, &sms_ntsc_rgb);
md_ntsc_init(md_ntsc, &md_ntsc_rgb);
break;
}
}
else
{
if (sms_ntsc)
{
free(sms_ntsc);
sms_ntsc = NULL;
}
if (md_ntsc)
{
free(md_ntsc);
md_ntsc = NULL;
}
}
#endif
}
SDL_BlitSurface(sdl_video.surf_bitmap, &sdl_video.srect, sdl_video.surf_screen, &sdl_video.drect);
SDL_UpdateWindowSurface(sdl_video.window);
++sdl_video.frames_rendered;
}
static void sdl_video_close()
{
if (sdl_video.surf_bitmap)
SDL_FreeSurface(sdl_video.surf_bitmap);
if (sdl_video.surf_screen)
SDL_FreeSurface(sdl_video.surf_screen);
}
/* Timer Sync */
struct {
SDL_sem* sem_sync;
unsigned ticks;
} sdl_sync;
static Uint32 sdl_sync_timer_callback(Uint32 interval, void *param)
{
SDL_SemPost(sdl_sync.sem_sync);
sdl_sync.ticks++;
if (sdl_sync.ticks == (vdp_pal ? 50 : 20))
{
SDL_Event event;
SDL_UserEvent userevent;
userevent.type = SDL_USEREVENT;
userevent.code = vdp_pal ? (sdl_video.frames_rendered / 3) : sdl_video.frames_rendered;
userevent.data1 = NULL;
userevent.data2 = NULL;
sdl_sync.ticks = sdl_video.frames_rendered = 0;
event.type = SDL_USEREVENT;
event.user = userevent;
SDL_PushEvent(&event);
}
return interval;
}
static int sdl_sync_init()
{
if(SDL_InitSubSystem(SDL_INIT_TIMER|SDL_INIT_EVENTS) < 0)
{
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error", "SDL Timer initialization failed", sdl_video.window);
return 0;
}
sdl_sync.sem_sync = SDL_CreateSemaphore(0);
sdl_sync.ticks = 0;
return 1;
}
static void sdl_sync_close()
{
if(sdl_sync.sem_sync)
SDL_DestroySemaphore(sdl_sync.sem_sync);
}
static const uint16 vc_table[4][2] =
{
/* NTSC, PAL */
{0xDA , 0xF2}, /* Mode 4 (192 lines) */
{0xEA , 0x102}, /* Mode 5 (224 lines) */
{0xDA , 0xF2}, /* Mode 4 (192 lines) */
{0x106, 0x10A} /* Mode 5 (240 lines) */
};
static int sdl_control_update(SDL_Keycode keystate)
{
switch (keystate)
{
case SDLK_TAB:
{
system_reset();
break;
}
case SDLK_F1:
{
if (SDL_ShowCursor(-1)) SDL_ShowCursor(0);
else SDL_ShowCursor(1);
break;
}
case SDLK_F2:
{
fullscreen = (fullscreen ? 0 : SDL_WINDOW_FULLSCREEN);
SDL_SetWindowFullscreen(sdl_video.window, fullscreen);
break;
}
case SDLK_F3:
{
if (config.bios == 0) config.bios = 3;
else if (config.bios == 3) config.bios = 1;
break;
}
case SDLK_F4:
{
if (!turbo_mode) use_sound ^= 1;
break;
}
case SDLK_F5:
{
log_error ^= 1;
break;
}
case SDLK_F6:
{
if (!use_sound)
{
turbo_mode ^=1;
sdl_sync.ticks = 0;
}
break;
}
case SDLK_F7:
{
FILE *f = fopen("game.gp0","rb");
if (f)
{
uint8 buf[STATE_SIZE];
fread(&buf, STATE_SIZE, 1, f);
state_load(buf);
fclose(f);
}
break;
}
case SDLK_F8:
{
FILE *f = fopen("game.gp0","wb");
if (f)
{
uint8 buf[STATE_SIZE];
int len = state_save(buf);
fwrite(&buf, len, 1, f);
fclose(f);
}
break;
}
case SDLK_F9:
{
config.region_detect = (config.region_detect + 1) % 5;
get_region(0);
/* framerate has changed, reinitialize audio timings */
audio_init(snd.sample_rate, 0);
/* system with region BIOS should be reinitialized */
if ((system_hw == SYSTEM_MCD) || ((system_hw & SYSTEM_SMS) && (config.bios & 1)))
{
system_init();
system_reset();
}
else
{
/* reinitialize I/O region register */
if (system_hw == SYSTEM_MD)
{
io_reg[0x00] = 0x20 | region_code | (config.bios & 1);
}
else
{
io_reg[0x00] = 0x80 | (region_code >> 1);
}
/* reinitialize VDP */
if (vdp_pal)
{
status |= 1;
lines_per_frame = 313;
}
else
{
status &= ~1;
lines_per_frame = 262;
}
/* reinitialize VC max value */
switch (bitmap.viewport.h)
{
case 192:
vc_max = vc_table[0][vdp_pal];
break;
case 224:
vc_max = vc_table[1][vdp_pal];
break;
case 240:
vc_max = vc_table[3][vdp_pal];
break;
}
}
break;
}
case SDLK_F10:
{
gen_reset(0);
break;
}
case SDLK_F11:
{
config.overscan = (config.overscan + 1) & 3;
if ((system_hw == SYSTEM_GG) && !config.gg_extra)
{
bitmap.viewport.x = (config.overscan & 2) ? 14 : -48;
}
else
{
bitmap.viewport.x = (config.overscan & 2) * 7;
}
bitmap.viewport.changed = 3;
break;
}
case SDLK_F12:
{
joynum = (joynum + 1) % MAX_DEVICES;
while (input.dev[joynum] == NO_DEVICE)
{
joynum = (joynum + 1) % MAX_DEVICES;
}
break;
}
case SDLK_ESCAPE:
{
return 0;
}
default:
break;
}
return 1;
}
int sdl_input_update(void)
{
const uint8 *keystate = SDL_GetKeyboardState(NULL);
/* reset input */
input.pad[joynum] = 0;
switch (input.dev[joynum])
{
case DEVICE_LIGHTGUN:
{
/* get mouse coordinates (absolute values) */
int x,y;
int state = SDL_GetMouseState(&x,&y);
/* X axis */
input.analog[joynum][0] = x - (VIDEO_WIDTH-bitmap.viewport.w)/2;
/* Y axis */
input.analog[joynum][1] = y - (VIDEO_HEIGHT-bitmap.viewport.h)/2;
/* TRIGGER, B, C (Menacer only), START (Menacer & Justifier only) */
if(state & SDL_BUTTON_LMASK) input.pad[joynum] |= INPUT_A;
if(state & SDL_BUTTON_RMASK) input.pad[joynum] |= INPUT_B;
if(state & SDL_BUTTON_MMASK) input.pad[joynum] |= INPUT_C;
if(keystate[SDL_SCANCODE_F]) input.pad[joynum] |= INPUT_START;
break;
}
case DEVICE_PADDLE:
{
/* get mouse (absolute values) */
int x;
int state = SDL_GetMouseState(&x, NULL);
/* Range is [0;256], 128 being middle position */
input.analog[joynum][0] = x * 256 /VIDEO_WIDTH;
/* Button I -> 0 0 0 0 0 0 0 I*/
if(state & SDL_BUTTON_LMASK) input.pad[joynum] |= INPUT_B;
break;
}
case DEVICE_SPORTSPAD:
{
/* get mouse (relative values) */
int x,y;
int state = SDL_GetRelativeMouseState(&x,&y);
/* Range is [0;256] */
input.analog[joynum][0] = (unsigned char)(-x & 0xFF);
input.analog[joynum][1] = (unsigned char)(-y & 0xFF);
/* Buttons I & II -> 0 0 0 0 0 0 II I*/
if(state & SDL_BUTTON_LMASK) input.pad[joynum] |= INPUT_B;
if(state & SDL_BUTTON_RMASK) input.pad[joynum] |= INPUT_C;
break;
}
case DEVICE_MOUSE:
{
/* get mouse (relative values) */
int x,y;
int state = SDL_GetRelativeMouseState(&x,&y);
/* Sega Mouse range is [-256;+256] */
input.analog[joynum][0] = x * 2;
input.analog[joynum][1] = y * 2;
/* Vertical movement is upsidedown */
if (!config.invert_mouse)
input.analog[joynum][1] = 0 - input.analog[joynum][1];
/* Start,Left,Right,Middle buttons -> 0 0 0 0 START MIDDLE RIGHT LEFT */
if(state & SDL_BUTTON_LMASK) input.pad[joynum] |= INPUT_B;
if(state & SDL_BUTTON_RMASK) input.pad[joynum] |= INPUT_C;
if(state & SDL_BUTTON_MMASK) input.pad[joynum] |= INPUT_A;
if(keystate[SDL_SCANCODE_F]) input.pad[joynum] |= INPUT_START;
break;
}
case DEVICE_XE_1AP:
{
/* A,B,C,D,Select,START,E1,E2 buttons -> E1(?) E2(?) START SELECT(?) A B C D */
if(keystate[SDL_SCANCODE_A]) input.pad[joynum] |= INPUT_START;
if(keystate[SDL_SCANCODE_S]) input.pad[joynum] |= INPUT_A;
if(keystate[SDL_SCANCODE_D]) input.pad[joynum] |= INPUT_C;
if(keystate[SDL_SCANCODE_F]) input.pad[joynum] |= INPUT_Y;
if(keystate[SDL_SCANCODE_Z]) input.pad[joynum] |= INPUT_B;
if(keystate[SDL_SCANCODE_X]) input.pad[joynum] |= INPUT_X;
if(keystate[SDL_SCANCODE_C]) input.pad[joynum] |= INPUT_MODE;
if(keystate[SDL_SCANCODE_V]) input.pad[joynum] |= INPUT_Z;
/* Left Analog Stick (bidirectional) */
if(keystate[SDL_SCANCODE_UP]) input.analog[joynum][1]-=2;
else if(keystate[SDL_SCANCODE_DOWN]) input.analog[joynum][1]+=2;
else input.analog[joynum][1] = 128;
if(keystate[SDL_SCANCODE_LEFT]) input.analog[joynum][0]-=2;
else if(keystate[SDL_SCANCODE_RIGHT]) input.analog[joynum][0]+=2;
else input.analog[joynum][0] = 128;
/* Right Analog Stick (unidirectional) */
if(keystate[SDL_SCANCODE_KP_8]) input.analog[joynum+1][0]-=2;
else if(keystate[SDL_SCANCODE_KP_2]) input.analog[joynum+1][0]+=2;
else if(keystate[SDL_SCANCODE_KP_4]) input.analog[joynum+1][0]-=2;
else if(keystate[SDL_SCANCODE_KP_6]) input.analog[joynum+1][0]+=2;
else input.analog[joynum+1][0] = 128;
/* Limiters */
if (input.analog[joynum][0] > 0xFF) input.analog[joynum][0] = 0xFF;
else if (input.analog[joynum][0] < 0) input.analog[joynum][0] = 0;
if (input.analog[joynum][1] > 0xFF) input.analog[joynum][1] = 0xFF;
else if (input.analog[joynum][1] < 0) input.analog[joynum][1] = 0;
if (input.analog[joynum+1][0] > 0xFF) input.analog[joynum+1][0] = 0xFF;
else if (input.analog[joynum+1][0] < 0) input.analog[joynum+1][0] = 0;
if (input.analog[joynum+1][1] > 0xFF) input.analog[joynum+1][1] = 0xFF;
else if (input.analog[joynum+1][1] < 0) input.analog[joynum+1][1] = 0;
break;
}
case DEVICE_PICO:
{
/* get mouse (absolute values) */
int x,y;
int state = SDL_GetMouseState(&x,&y);
/* Calculate X Y axis values */
input.analog[0][0] = 0x3c + (x * (0x17c-0x03c+1)) / VIDEO_WIDTH;
input.analog[0][1] = 0x1fc + (y * (0x2f7-0x1fc+1)) / VIDEO_HEIGHT;
/* Map mouse buttons to player #1 inputs */
if(state & SDL_BUTTON_MMASK) pico_current = (pico_current + 1) & 7;
if(state & SDL_BUTTON_RMASK) input.pad[0] |= INPUT_PICO_RED;
if(state & SDL_BUTTON_LMASK) input.pad[0] |= INPUT_PICO_PEN;
break;
}
case DEVICE_TEREBI:
{
/* get mouse (absolute values) */
int x,y;
int state = SDL_GetMouseState(&x,&y);
/* Calculate X Y axis values */
input.analog[0][0] = (x * 250) / VIDEO_WIDTH;
input.analog[0][1] = (y * 250) / VIDEO_HEIGHT;
/* Map mouse buttons to player #1 inputs */
if(state & SDL_BUTTON_RMASK) input.pad[0] |= INPUT_B;
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[SDL_SCANCODE_G]) input.pad[joynum] |= INPUT_ACTIVATOR_7L;
if(keystate[SDL_SCANCODE_H]) input.pad[joynum] |= INPUT_ACTIVATOR_7U;
if(keystate[SDL_SCANCODE_J]) input.pad[joynum] |= INPUT_ACTIVATOR_8L;
if(keystate[SDL_SCANCODE_K]) input.pad[joynum] |= INPUT_ACTIVATOR_8U;
}
default:
{
if(keystate[SDL_SCANCODE_A]) input.pad[joynum] |= INPUT_A;
if(keystate[SDL_SCANCODE_S]) input.pad[joynum] |= INPUT_B;
if(keystate[SDL_SCANCODE_D]) input.pad[joynum] |= INPUT_C;
if(keystate[SDL_SCANCODE_F]) input.pad[joynum] |= INPUT_START;
if(keystate[SDL_SCANCODE_Z]) input.pad[joynum] |= INPUT_X;
if(keystate[SDL_SCANCODE_X]) input.pad[joynum] |= INPUT_Y;
if(keystate[SDL_SCANCODE_C]) input.pad[joynum] |= INPUT_Z;
if(keystate[SDL_SCANCODE_V]) input.pad[joynum] |= INPUT_MODE;
if(keystate[SDL_SCANCODE_UP]) input.pad[joynum] |= INPUT_UP;
else
if(keystate[SDL_SCANCODE_DOWN]) input.pad[joynum] |= INPUT_DOWN;
if(keystate[SDL_SCANCODE_LEFT]) input.pad[joynum] |= INPUT_LEFT;
else
if(keystate[SDL_SCANCODE_RIGHT]) input.pad[joynum] |= INPUT_RIGHT;
break;
}
}
return 1;
}
int main (int argc, char **argv)
{
FILE *fp;
int running = 1;
/* Print help if no game specified */
if(argc < 2)
{
char caption[256];
sprintf(caption, "Genesis Plus GX\\SDL\nusage: %s gamename\n", argv[0]);
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_INFORMATION, "Information", caption, sdl_video.window);
return 1;
}
/* set default config */
error_init();
set_config_defaults();
/* mark all BIOS as unloaded */
system_bios = 0;
/* Genesis BOOT ROM support (2KB max) */
memset(boot_rom, 0xFF, 0x800);
fp = fopen(MD_BIOS, "rb");
if (fp != NULL)
{
int i;
/* read BOOT ROM */
fread(boot_rom, 1, 0x800, fp);
fclose(fp);
/* check BOOT ROM */
if (!memcmp((char *)(boot_rom + 0x120),"GENESIS OS", 10))
{
/* mark Genesis BIOS as loaded */
system_bios = SYSTEM_MD;
}
/* Byteswap ROM */
for (i=0; i<0x800; i+=2)
{
uint8 temp = boot_rom[i];
boot_rom[i] = boot_rom[i+1];
boot_rom[i+1] = temp;
}
}
/* initialize SDL */
if(SDL_Init(0) < 0)
{
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error", "SDL initialization failed", sdl_video.window);
return 1;
}
sdl_video_init();
if (use_sound) sdl_sound_init();
sdl_sync_init();
/* initialize Genesis virtual system */
SDL_LockSurface(sdl_video.surf_bitmap);
memset(&bitmap, 0, sizeof(t_bitmap));
bitmap.width = 720;
bitmap.height = 576;
#if defined(USE_8BPP_RENDERING)
bitmap.pitch = (bitmap.width * 1);
#elif defined(USE_15BPP_RENDERING)
bitmap.pitch = (bitmap.width * 2);
#elif defined(USE_16BPP_RENDERING)
bitmap.pitch = (bitmap.width * 2);
#elif defined(USE_32BPP_RENDERING)
bitmap.pitch = (bitmap.width * 4);
#endif
bitmap.data = sdl_video.surf_bitmap->pixels;
SDL_UnlockSurface(sdl_video.surf_bitmap);
bitmap.viewport.changed = 3;
/* Load game file */
if(!load_rom(argv[1]))
{
char caption[256];
sprintf(caption, "Error loading file `%s'.", argv[1]);
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error", caption, sdl_video.window);
return 1;
}
/* initialize system hardware */
audio_init(SOUND_FREQUENCY, 0);
system_init();
/* Mega CD specific */
if (system_hw == SYSTEM_MCD)
{
/* load internal backup RAM */
fp = fopen("./scd.brm", "rb");
if (fp!=NULL)
{
fread(scd.bram, 0x2000, 1, fp);
fclose(fp);
}
/* check if internal backup RAM is formatted */
if (memcmp(scd.bram + 0x2000 - 0x20, brm_format + 0x20, 0x20))
{
/* clear internal backup RAM */
memset(scd.bram, 0x00, 0x200);
/* Internal Backup RAM size fields */
brm_format[0x10] = brm_format[0x12] = brm_format[0x14] = brm_format[0x16] = 0x00;
brm_format[0x11] = brm_format[0x13] = brm_format[0x15] = brm_format[0x17] = (sizeof(scd.bram) / 64) - 3;
/* format internal backup RAM */
memcpy(scd.bram + 0x2000 - 0x40, brm_format, 0x40);
}
/* load cartridge backup RAM */
if (scd.cartridge.id)
{
fp = fopen("./cart.brm", "rb");
if (fp!=NULL)
{
fread(scd.cartridge.area, scd.cartridge.mask + 1, 1, fp);
fclose(fp);
}
/* check if cartridge backup RAM is formatted */
if (memcmp(scd.cartridge.area + scd.cartridge.mask + 1 - 0x20, brm_format + 0x20, 0x20))
{
/* clear cartridge backup RAM */
memset(scd.cartridge.area, 0x00, scd.cartridge.mask + 1);
/* Cartridge Backup RAM size fields */
brm_format[0x10] = brm_format[0x12] = brm_format[0x14] = brm_format[0x16] = (((scd.cartridge.mask + 1) / 64) - 3) >> 8;
brm_format[0x11] = brm_format[0x13] = brm_format[0x15] = brm_format[0x17] = (((scd.cartridge.mask + 1) / 64) - 3) & 0xff;
/* format cartridge backup RAM */
memcpy(scd.cartridge.area + scd.cartridge.mask + 1 - sizeof(brm_format), brm_format, sizeof(brm_format));
}
}
}
if (sram.on)
{
/* load SRAM */
fp = fopen("./game.srm", "rb");
if (fp!=NULL)
{
fread(sram.sram,0x10000,1, fp);
fclose(fp);
}
}
/* reset system hardware */
system_reset();
if(use_sound) SDL_PauseAudio(0);
/* 3 frames = 50 ms (60hz) or 60 ms (50hz) */
if(sdl_sync.sem_sync)
SDL_AddTimer(vdp_pal ? 60 : 50, sdl_sync_timer_callback, NULL);
/* emulation loop */
while(running)
{
SDL_Event event;
if (SDL_PollEvent(&event))
{
switch(event.type)
{
case SDL_USEREVENT:
{
char caption[100];
sprintf(caption,"Genesis Plus GX - %d fps - %s", event.user.code, (rominfo.international[0] != 0x20) ? rominfo.international : rominfo.domestic);
SDL_SetWindowTitle(sdl_video.window, caption);
break;
}
case SDL_QUIT:
{
running = 0;
break;
}
case SDL_KEYDOWN:
{
running = sdl_control_update(event.key.keysym.sym);
break;
}
}
}
sdl_video_update();
sdl_sound_update(use_sound);
if(!turbo_mode && sdl_sync.sem_sync && sdl_video.frames_rendered % 3 == 0)
{
SDL_SemWait(sdl_sync.sem_sync);
}
}
if (system_hw == SYSTEM_MCD)
{
/* save internal backup RAM (if formatted) */
if (!memcmp(scd.bram + 0x2000 - 0x20, brm_format + 0x20, 0x20))
{
fp = fopen("./scd.brm", "wb");
if (fp!=NULL)
{
fwrite(scd.bram, 0x2000, 1, fp);
fclose(fp);
}
}
/* save cartridge backup RAM (if formatted) */
if (scd.cartridge.id)
{
if (!memcmp(scd.cartridge.area + scd.cartridge.mask + 1 - 0x20, brm_format + 0x20, 0x20))
{
fp = fopen("./cart.brm", "wb");
if (fp!=NULL)
{
fwrite(scd.cartridge.area, scd.cartridge.mask + 1, 1, fp);
fclose(fp);
}
}
}
}
if (sram.on)
{
/* save SRAM */
fp = fopen("./game.srm", "wb");
if (fp!=NULL)
{
fwrite(sram.sram,0x10000,1, fp);
fclose(fp);
}
}
audio_shutdown();
error_shutdown();
sdl_video_close();
sdl_sound_close();
sdl_sync_close();
SDL_Quit();
return 0;
}

11
sdl/sdl2/main.h Normal file
View File

@ -0,0 +1,11 @@
#ifndef _MAIN_H_
#define _MAIN_H_
#define MAX_INPUTS 8
extern int debug_on;
extern int log_error;
extern int sdl_input_update(void);
#endif /* _MAIN_H_ */