diff --git a/.gitignore b/.gitignore
index 577fae8..550058c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -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
+
diff --git a/HISTORY.txt b/HISTORY.txt
index 8de9980..d1b1a64 100644
--- a/HISTORY.txt
+++ b/HISTORY.txt
@@ -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
diff --git a/Makefile.gc b/Makefile.gc
index d593d8f..f86e9dd 100644
--- a/Makefile.gc
+++ b/Makefile.gc
@@ -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
diff --git a/Makefile.wii b/Makefile.wii
index aff1cd7..1febf4c 100644
--- a/Makefile.wii
+++ b/Makefile.wii
@@ -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
diff --git a/builds/genesis_plus_gx_libretro.dll b/builds/genesis_plus_gx_libretro.dll
index d2c8295..1f9d29f 100644
Binary files a/builds/genesis_plus_gx_libretro.dll and b/builds/genesis_plus_gx_libretro.dll differ
diff --git a/builds/genplus_cube.dol b/builds/genplus_cube.dol
index ec11ffa..b56b9b1 100644
Binary files a/builds/genplus_cube.dol and b/builds/genplus_cube.dol differ
diff --git a/builds/genplus_wii.dol b/builds/genplus_wii.dol
index 5902708..51f5bab 100644
Binary files a/builds/genplus_wii.dol and b/builds/genplus_wii.dol differ
diff --git a/core/cart_hw/sram.c b/core/cart_hw/sram.c
index ed8bea9..c5e4d55 100644
--- a/core/cart_hw/sram.c
+++ b/core/cart_hw/sram.c
@@ -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 */
diff --git a/core/cart_hw/sram.h b/core/cart_hw/sram.h
index 64934ca..da32a95 100644
--- a/core/cart_hw/sram.h
+++ b/core/cart_hw/sram.h
@@ -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:
diff --git a/core/cd_hw/cdd.c b/core/cd_hw/cdd.c
index e29cfae..d20aa87 100644
--- a/core/cd_hw/cdd.c
+++ b/core/cd_hw/cdd.c
@@ -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)
diff --git a/core/cd_hw/pcm.c b/core/cd_hw/pcm.c
index 09f99d3..e068d70 100644
--- a/core/cd_hw/pcm.c
+++ b/core/cd_hw/pcm.c
@@ -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)
diff --git a/core/cd_hw/pcm.h b/core/cd_hw/pcm.h
index ee1a5c5..eef847d 100644
--- a/core/cd_hw/pcm.h
+++ b/core/cd_hw/pcm.h
@@ -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:
diff --git a/core/genesis.c b/core/genesis.c
index 7c36505..1ef2db9 100644
--- a/core/genesis.c
+++ b/core/genesis.c
@@ -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)
diff --git a/core/genesis.h b/core/genesis.h
index c172339..15fd52f 100644
--- a/core/genesis.h
+++ b/core/genesis.h
@@ -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:
diff --git a/core/io_ctrl.c b/core/io_ctrl.c
index 97a8964..44797fc 100644
--- a/core/io_ctrl.c
+++ b/core/io_ctrl.c
@@ -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 */
diff --git a/core/mem68k.c b/core/mem68k.c
index 3966d16..cb60ed7 100644
--- a/core/mem68k.c
+++ b/core/mem68k.c
@@ -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;
}
diff --git a/core/membnk.c b/core/membnk.c
index 64f16d8..50ffd52 100644
--- a/core/membnk.c
+++ b/core/membnk.c
@@ -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);
diff --git a/core/membnk.h b/core/membnk.h
index b4b242e..dd34631 100644
--- a/core/membnk.h
+++ b/core/membnk.h
@@ -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:
diff --git a/core/memz80.c b/core/memz80.c
index 0692ce3..b3a6ef1 100644
--- a/core/memz80.c
+++ b/core/memz80.c
@@ -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);
diff --git a/core/shared.h b/core/shared.h
index f463aa8..959f289 100644
--- a/core/shared.h
+++ b/core/shared.h
@@ -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"
diff --git a/core/sound/blip_buf.c b/core/sound/blip_buf.c
index 2f48536..ae0db45 100644
--- a/core/sound/blip_buf.c
+++ b/core/sound/blip_buf.c
@@ -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
diff --git a/core/sound/blip_buf.h b/core/sound/blip_buf.h
index 21c45d0..81b986b 100644
--- a/core/sound/blip_buf.h
+++ b/core/sound/blip_buf.h
@@ -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* );
diff --git a/core/sound/psg.c b/core/sound/psg.c
new file mode 100644
index 0000000..44c03ec
--- /dev/null
+++ b/core/sound/psg.c
@@ -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;
+ }
+}
diff --git a/core/sound/psg.h b/core/sound/psg.h
new file mode 100644
index 0000000..46370d4
--- /dev/null
+++ b/core/sound/psg.h
@@ -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_ */
diff --git a/core/sound/sn76489.c b/core/sound/sn76489.c
deleted file mode 100644
index 4c450ac..0000000
--- a/core/sound/sn76489.c
+++ /dev/null
@@ -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;
- }
- }
-}
diff --git a/core/sound/sn76489.h b/core/sound/sn76489.h
deleted file mode 100644
index 157a9f5..0000000
--- a/core/sound/sn76489.h
+++ /dev/null
@@ -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_ */
diff --git a/core/sound/sound.c b/core/sound/sound.c
index 06bea1a..f99da18 100644
--- a/core/sound/sound.c
+++ b/core/sound/sound.c
@@ -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;
diff --git a/core/sound/sound.h b/core/sound/sound.h
index a4284a7..ae7cc56 100644
--- a/core/sound/sound.h
+++ b/core/sound/sound.h
@@ -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:
diff --git a/core/state.c b/core/state.c
index f79fd3d..3bdab0b 100644
--- a/core/state.c
+++ b/core/state.c
@@ -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 */
diff --git a/core/state.h b/core/state.h
index 6b480c0..1ac9322 100644
--- a/core/state.h
+++ b/core/state.h
@@ -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:
diff --git a/core/system.c b/core/system.c
index ac20496..07d86ed 100644
--- a/core/system.c
+++ b/core/system.c
@@ -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);
diff --git a/core/system.h b/core/system.h
index 2a5a6d3..e6fe50d 100644
--- a/core/system.h
+++ b/core/system.h
@@ -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;
diff --git a/gcw0/Makefile b/gcw0/Makefile
index b17ced2..2400056 100644
--- a/gcw0/Makefile
+++ b/gcw0/Makefile
@@ -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
diff --git a/gcw0/config.c b/gcw0/config.c
index 564cfaf..16b7b15 100644
--- a/gcw0/config.c
+++ b/gcw0/config.c
@@ -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;
diff --git a/gcw0/config.h b/gcw0/config.h
index 9b522e1..9cf5ed5 100644
--- a/gcw0/config.h
+++ b/gcw0/config.h
@@ -20,7 +20,7 @@ typedef struct
{
uint8 hq_fm;
uint8 filter;
- uint8 psgBoostNoise;
+ uint8 hq_psg;
uint8 dac_bits;
uint8 ym2413;
int16 psg_preamp;
diff --git a/gx/config.c b/gx/config.c
index 3d1c67f..f3da2c2 100644
--- a/gx/config.c
+++ b/gx/config.c
@@ -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;
diff --git a/gx/config.h b/gx/config.h
index 3aad3db..9bc3097 100644
--- a/gx/config.h
+++ b/gx/config.h
@@ -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;
diff --git a/gx/gui/menu.c b/gx/gui/menu.c
index 57f9d55..0aeafb8 100644
--- a/gx/gui/menu.c
+++ b/gx/gui/menu.c
@@ -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);
diff --git a/libretro/debian/copyright b/libretro/debian/copyright
index 450a60b..5656c57 100644
--- a/libretro/debian/copyright
+++ b/libretro/debian/copyright
@@ -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
diff --git a/libretro/libretro.c b/libretro/libretro.c
index 66cb692..7621242 100644
--- a/libretro/libretro.c
+++ b/libretro/libretro.c
@@ -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);
}
}
diff --git a/libretro/msvc/msvc-2003-xbox1/msvc-2003-xbox1.vcproj b/libretro/msvc/msvc-2003-xbox1/msvc-2003-xbox1.vcproj
index 7a597ad..4563a92 100644
--- a/libretro/msvc/msvc-2003-xbox1/msvc-2003-xbox1.vcproj
+++ b/libretro/msvc/msvc-2003-xbox1/msvc-2003-xbox1.vcproj
@@ -394,7 +394,7 @@
RelativePath="..\..\..\core\sound\eq.c">
+ RelativePath="..\..\..\core\sound\psg.c">
diff --git a/libretro/msvc/msvc-2010-360/msvc-2010-360.vcxproj b/libretro/msvc/msvc-2010-360/msvc-2010-360.vcxproj
index c97d11e..41d892f 100644
--- a/libretro/msvc/msvc-2010-360/msvc-2010-360.vcxproj
+++ b/libretro/msvc/msvc-2010-360/msvc-2010-360.vcxproj
@@ -143,7 +143,7 @@
CompileAsC
-
+
diff --git a/libretro/msvc/msvc-2010-360/msvc-2010-360.vcxproj.filters b/libretro/msvc/msvc-2010-360/msvc-2010-360.vcxproj.filters
index ae6ed86..ef720ec 100644
--- a/libretro/msvc/msvc-2010-360/msvc-2010-360.vcxproj.filters
+++ b/libretro/msvc/msvc-2010-360/msvc-2010-360.vcxproj.filters
@@ -80,7 +80,7 @@
Source Files\sound
-
+
Source Files\sound
diff --git a/libretro/msvc/msvc-2010/msvc-2010.vcxproj b/libretro/msvc/msvc-2010/msvc-2010.vcxproj
index 11ed4df..f6972c0 100644
--- a/libretro/msvc/msvc-2010/msvc-2010.vcxproj
+++ b/libretro/msvc/msvc-2010/msvc-2010.vcxproj
@@ -49,7 +49,7 @@
-
+
diff --git a/libretro/msvc/msvc-2010/msvc-2010.vcxproj.filters b/libretro/msvc/msvc-2010/msvc-2010.vcxproj.filters
index 262e025..32ee69b 100644
--- a/libretro/msvc/msvc-2010/msvc-2010.vcxproj.filters
+++ b/libretro/msvc/msvc-2010/msvc-2010.vcxproj.filters
@@ -117,7 +117,7 @@
Source Files\sound
-
+
Source Files\sound
diff --git a/libretro/osd.h b/libretro/osd.h
index 03c57d4..4c02b68 100644
--- a/libretro/osd.h
+++ b/libretro/osd.h
@@ -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;
diff --git a/psp2/Makefile b/psp2/Makefile
index 36bb06a..6c6a743 100644
--- a/psp2/Makefile
+++ b/psp2/Makefile
@@ -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
diff --git a/psp2/config.c b/psp2/config.c
index 93f2ae3..b8299e2 100644
--- a/psp2/config.c
+++ b/psp2/config.c
@@ -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;
diff --git a/psp2/config.h b/psp2/config.h
index 30c2c5b..44aaddb 100644
--- a/psp2/config.h
+++ b/psp2/config.h
@@ -19,7 +19,7 @@ typedef struct
{
uint8 hq_fm;
uint8 filter;
- uint8 psgBoostNoise;
+ uint8 hq_psg;
uint8 dac_bits;
uint8 ym2413;
int16 psg_preamp;
diff --git a/sdl/Makefile b/sdl/Makefile.sdl1
similarity index 90%
rename from sdl/Makefile
rename to sdl/Makefile.sdl1
index 6134e52..dc38ca7 100644
--- a/sdl/Makefile
+++ b/sdl/Makefile.sdl1
@@ -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)
diff --git a/sdl/Makefile.sdl2 b/sdl/Makefile.sdl2
new file mode 100644
index 0000000..46b5895
--- /dev/null
+++ b/sdl/Makefile.sdl2
@@ -0,0 +1,185 @@
+
+# Makefile for genplus SDL2
+#
+# (c) 1999, 2000, 2001, 2002, 2003 Charles MacDonald
+# modified by Eke-Eke
+#
+# 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)
diff --git a/sdl/README.txt b/sdl/README.txt
index 500adec..b3bd6f5 100644
--- a/sdl/README.txt
+++ b/sdl/README.txt
@@ -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
diff --git a/sdl/config.c b/sdl/config.c
index 99aa1e8..933e669 100644
--- a/sdl/config.c
+++ b/sdl/config.c
@@ -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;
diff --git a/sdl/config.h b/sdl/config.h
index 3434204..78e7c84 100644
--- a/sdl/config.h
+++ b/sdl/config.h
@@ -15,7 +15,7 @@ typedef struct
{
uint8 hq_fm;
uint8 filter;
- uint8 psgBoostNoise;
+ uint8 hq_psg;
uint8 dac_bits;
uint8 ym2413;
int16 psg_preamp;
diff --git a/sdl/error.c b/sdl/error.c
index c731b30..4a41b5b 100644
--- a/sdl/error.c
+++ b/sdl/error.c
@@ -5,7 +5,9 @@
#include "osd.h"
+#ifdef LOGERROR
static FILE *error_log;
+#endif
void error_init(void)
{
diff --git a/sdl/main.c b/sdl/sdl1/main.c
similarity index 93%
rename from sdl/main.c
rename to sdl/sdl1/main.c
index ff68004..6831229 100644
--- a/sdl/main.c
+++ b/sdl/sdl1/main.c
@@ -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;
}
diff --git a/sdl/main.h b/sdl/sdl1/main.h
similarity index 100%
rename from sdl/main.h
rename to sdl/sdl1/main.h
diff --git a/sdl/sdl2/main.c b/sdl/sdl2/main.c
new file mode 100644
index 0000000..7224276
--- /dev/null
+++ b/sdl/sdl2/main.c
@@ -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;
+}
diff --git a/sdl/sdl2/main.h b/sdl/sdl2/main.h
new file mode 100644
index 0000000..dfa5d8d
--- /dev/null
+++ b/sdl/sdl2/main.h
@@ -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_ */