mirror of
https://github.com/ekeeke/Genesis-Plus-GX.git
synced 2025-01-14 12:19:06 +01:00
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
0247ea6202
5
.gitignore
vendored
5
.gitignore
vendored
@ -3,3 +3,8 @@ psp2/*.elf
|
|||||||
psp2/*.velf
|
psp2/*.velf
|
||||||
psp2/build_vita/*
|
psp2/build_vita/*
|
||||||
psp2/*.a
|
psp2/*.a
|
||||||
|
sdl/gen_sdl
|
||||||
|
sdl/gen_sdl2
|
||||||
|
sdl/build_sdl
|
||||||
|
sdl/build_sdl2
|
||||||
|
|
||||||
|
@ -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 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 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 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 PRG-RAM access from MAIN-CPU side on system reset
|
||||||
* fixed state loading bug when SUB-CPU interrupt is pending
|
* fixed state loading bug when SUB-CPU interrupt is pending
|
||||||
* fixed incorrect masking of Level 3 (GFX) interrupts (spurious freeze during Japanese BIOS intro)
|
* 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)
|
* fixed 68k cycles delay on invalid VRAM writes (fixes "Microcosm" intro loop)
|
||||||
* optimized tile caching
|
* 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]
|
[Gamecube/Wii]
|
||||||
---------------
|
---------------
|
||||||
* added configurable BIOS & Lock-on ROM files
|
* added configurable BIOS & Lock-on ROM files
|
||||||
|
@ -27,7 +27,7 @@ INCLUDES := core core/m68k core/z80 core/sound core/tremor core/ntsc core/input_
|
|||||||
# options for code generation
|
# 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)
|
CXXFLAGS = $(CFLAGS)
|
||||||
|
|
||||||
LDFLAGS = $(MACHDEP) -Wl,-Map,$(notdir $@).map
|
LDFLAGS = $(MACHDEP) -Wl,-Map,$(notdir $@).map
|
||||||
|
@ -27,7 +27,7 @@ INCLUDES := core core/m68k core/z80 core/sound core/tremor core/ntsc core/input_
|
|||||||
# options for code generation
|
# 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)
|
CXXFLAGS = $(CFLAGS)
|
||||||
|
|
||||||
LDFLAGS = $(MACHDEP) -Wl,-Map,$(notdir $@).map,-wrap,wiiuse_set_ir,-wrap,wiiuse_handshake,-wrap,classic_ctrl_handshake,-wrap,classic_ctrl_event
|
LDFLAGS = $(MACHDEP) -Wl,-Map,$(notdir $@).map,-wrap,wiiuse_set_ir,-wrap,wiiuse_handshake,-wrap,classic_ctrl_handshake,-wrap,classic_ctrl_event
|
||||||
|
Binary file not shown.
Binary file not shown.
Before Width: | Height: | Size: 3.2 MiB After Width: | Height: | Size: 3.2 MiB |
Binary file not shown.
Before Width: | Height: | Size: 3.3 MiB After Width: | Height: | Size: 3.3 MiB |
@ -2,7 +2,7 @@
|
|||||||
* Genesis Plus
|
* Genesis Plus
|
||||||
* Backup RAM support
|
* 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
|
* Redistribution and use of this code or any derivative works are permitted
|
||||||
* provided that the following conditions are met:
|
* provided that the following conditions are met:
|
||||||
@ -68,7 +68,17 @@ void sram_init()
|
|||||||
sram.sram = cart.rom + 0x800000;
|
sram.sram = cart.rom + 0x800000;
|
||||||
|
|
||||||
/* initialize Backup RAM */
|
/* 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);
|
sram.crc = crc32(0, sram.sram, 0x10000);
|
||||||
|
|
||||||
/* retrieve informations from header */
|
/* retrieve informations from header */
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
* Genesis Plus
|
* Genesis Plus
|
||||||
* Backup RAM support
|
* 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
|
* Redistribution and use of this code or any derivative works are permitted
|
||||||
* provided that the following conditions are met:
|
* provided that the following conditions are met:
|
||||||
|
144
core/cd_hw/cdd.c
144
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) */
|
/* 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,
|
0x57,0x41,0x56,0x45,0x66,0x6d,0x74,0x20,0x10,0x00,0x00,0x00,0x01,0x00,
|
||||||
0x44,0xac,0x00,0x00,0x10,0xb1,0x02,0x00,0x04,0x00,0x10,0x00,0x64,0x61,0x74,0x61
|
0x02,0x00,0x44,0xac,0x00,0x00,0x10,0xb1,0x02,0x00,0x04,0x00,0x10,0x00
|
||||||
};
|
};
|
||||||
|
|
||||||
/* supported WAVE file extensions */
|
/* supported WAVE file extensions */
|
||||||
@ -179,8 +179,7 @@ void cdd_init(int samplerate)
|
|||||||
{
|
{
|
||||||
/* CD-DA is running by default at 44100 Hz */
|
/* CD-DA is running by default at 44100 Hz */
|
||||||
/* Audio stream is resampled to desired rate using Blip Buffer */
|
/* Audio stream is resampled to desired rate using Blip Buffer */
|
||||||
blip_set_rates(snd.blips[2][0], 44100, samplerate);
|
blip_set_rates(snd.blips[2], 44100, samplerate);
|
||||||
blip_set_rates(snd.blips[2][1], 44100, samplerate);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void cdd_reset(void)
|
void cdd_reset(void)
|
||||||
@ -449,16 +448,39 @@ int cdd_load(char *filename, char *header)
|
|||||||
if (!strstr(lptr,"BINARY") && !strstr(lptr,"MOTOROLA"))
|
if (!strstr(lptr,"BINARY") && !strstr(lptr,"MOTOROLA"))
|
||||||
{
|
{
|
||||||
/* read file header */
|
/* read file header */
|
||||||
unsigned char head[32];
|
unsigned char head[28];
|
||||||
fseek(cdd.toc.tracks[cdd.toc.last].fd, 8, SEEK_SET);
|
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);
|
fseek(cdd.toc.tracks[cdd.toc.last].fd, 0, SEEK_SET);
|
||||||
|
|
||||||
/* autodetect WAVE file header (44.1KHz 16-bit stereo format only) */
|
/* 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 */
|
/* 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)
|
#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))
|
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)
|
while (fd)
|
||||||
{
|
{
|
||||||
/* read file HEADER */
|
/* read file HEADER */
|
||||||
unsigned char head[32];
|
unsigned char head[28];
|
||||||
fseek(fd, 8, SEEK_SET);
|
fseek(fd, 8, SEEK_SET);
|
||||||
fread(head, 32, 1, fd);
|
fread(head, 28, 1, fd);
|
||||||
fseek(fd, 0, SEEK_SET);
|
fseek(fd, 0, SEEK_SET);
|
||||||
|
|
||||||
/* check if this is a valid WAVE file (44.1KHz 16-bit stereo format only) */
|
/* 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 */
|
/* initialize current track file descriptor */
|
||||||
cdd.toc.tracks[cdd.toc.last].fd = fd;
|
cdd.toc.tracks[cdd.toc.last].fd = fd;
|
||||||
|
|
||||||
@ -718,7 +761,7 @@ int cdd_load(char *filename, char *header)
|
|||||||
|
|
||||||
/* current track end time */
|
/* current track end time */
|
||||||
fseek(fd, 0, SEEK_END);
|
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 */
|
/* initialize file read offset for current track */
|
||||||
cdd.toc.tracks[cdd.toc.last].offset = cdd.toc.tracks[cdd.toc.last].start * 2352;
|
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;
|
cdd.toc.end = cdd.toc.tracks[cdd.toc.last].end;
|
||||||
|
|
||||||
/* adjust file read offset for current track with WAVE header length */
|
/* 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 */
|
/* increment track number */
|
||||||
cdd.toc.last++;
|
cdd.toc.last++;
|
||||||
@ -1015,16 +1058,16 @@ void cdd_read_data(uint8 *dst)
|
|||||||
void cdd_read_audio(unsigned int samples)
|
void cdd_read_audio(unsigned int samples)
|
||||||
{
|
{
|
||||||
/* previous audio outputs */
|
/* previous audio outputs */
|
||||||
int16 l = cdd.audio[0];
|
int prev_l = cdd.audio[0];
|
||||||
int16 r = cdd.audio[1];
|
int prev_r = cdd.audio[1];
|
||||||
|
|
||||||
/* get number of internal clocks (samples) needed */
|
/* 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 ? */
|
/* audio track playing ? */
|
||||||
if (!scd.regs[0x36>>1].byte.h && cdd.toc.tracks[cdd.index].fd)
|
if (!scd.regs[0x36>>1].byte.h && cdd.toc.tracks[cdd.index].fd)
|
||||||
{
|
{
|
||||||
int i, mul, delta;
|
int i, mul, l, r;
|
||||||
|
|
||||||
/* current CD-DA fader volume */
|
/* current CD-DA fader volume */
|
||||||
int curVol = cdd.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) */
|
/* (MIN) 0,1,2,3,4,8,12,16,20...,1020,1024 (MAX) */
|
||||||
mul = (curVol & 0x7fc) ? (curVol & 0x7fc) : (curVol & 0x03);
|
mul = (curVol & 0x7fc) ? (curVol & 0x7fc) : (curVol & 0x03);
|
||||||
|
|
||||||
/* left channel */
|
/* left & right channels */
|
||||||
delta = ((ptr[0] * mul) / 1024) - l;
|
l = ((ptr[0] * mul) / 1024);
|
||||||
ptr++;
|
r = ((ptr[1] * mul) / 1024);
|
||||||
l += delta;
|
blip_add_delta_fast(snd.blips[2], i, l-prev_l, r-prev_r);
|
||||||
blip_add_delta_fast(snd.blips[2][0], i, delta);
|
prev_l = l;
|
||||||
|
prev_r = r;
|
||||||
/* right channel */
|
ptr+=2;
|
||||||
delta = ((ptr[0] * mul) / 1024) - r;
|
|
||||||
ptr++;
|
|
||||||
r += delta;
|
|
||||||
blip_add_delta_fast(snd.blips[2][1], i, delta);
|
|
||||||
|
|
||||||
/* update CD-DA fader volume (one step/sample) */
|
/* update CD-DA fader volume (one step/sample) */
|
||||||
if (curVol < endVol)
|
if (curVol < endVol)
|
||||||
@ -1109,27 +1148,19 @@ void cdd_read_audio(unsigned int samples)
|
|||||||
/* (MIN) 0,1,2,3,4,8,12,16,20...,1020,1024 (MAX) */
|
/* (MIN) 0,1,2,3,4,8,12,16,20...,1020,1024 (MAX) */
|
||||||
mul = (curVol & 0x7fc) ? (curVol & 0x7fc) : (curVol & 0x03);
|
mul = (curVol & 0x7fc) ? (curVol & 0x7fc) : (curVol & 0x03);
|
||||||
|
|
||||||
/* left channel */
|
/* left & right channels */
|
||||||
#ifdef LSB_FIRST
|
#ifdef LSB_FIRST
|
||||||
delta = ((ptr[0] * mul) / 1024) - l;
|
l = ((ptr[0] * mul) / 1024);
|
||||||
ptr++;
|
r = ((ptr[1] * mul) / 1024);
|
||||||
|
ptr+=2;
|
||||||
#else
|
#else
|
||||||
delta = (((int16)((ptr[0] + ptr[1]*256)) * mul) / 1024) - l;
|
l = (((int16)((ptr[0] + ptr[1]*256)) * mul) / 1024);
|
||||||
ptr += 2;
|
r = (((int16)((ptr[2] + ptr[3]*256)) * mul) / 1024);
|
||||||
|
ptr+=4;
|
||||||
#endif
|
#endif
|
||||||
l += delta;
|
blip_add_delta_fast(snd.blips[2], i, l-prev_l, r-prev_r);
|
||||||
blip_add_delta_fast(snd.blips[2][0], i, delta);
|
prev_l = l;
|
||||||
|
prev_r = r;
|
||||||
/* 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);
|
|
||||||
|
|
||||||
/* update CD-DA fader volume (one step/sample) */
|
/* update CD-DA fader volume (one step/sample) */
|
||||||
if (curVol < endVol)
|
if (curVol < endVol)
|
||||||
@ -1154,23 +1185,24 @@ void cdd_read_audio(unsigned int samples)
|
|||||||
cdd.volume = curVol;
|
cdd.volume = curVol;
|
||||||
|
|
||||||
/* save last audio output for next frame */
|
/* save last audio output for next frame */
|
||||||
cdd.audio[0] = l;
|
cdd.audio[0] = prev_l;
|
||||||
cdd.audio[1] = r;
|
cdd.audio[1] = prev_r;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* no audio output */
|
/* no audio output */
|
||||||
if (l) blip_add_delta_fast(snd.blips[2][0], 0, -l);
|
if (prev_l | prev_r)
|
||||||
if (r) blip_add_delta_fast(snd.blips[2][1], 0, -r);
|
{
|
||||||
|
blip_add_delta_fast(snd.blips[2], 0, -prev_l, -prev_r);
|
||||||
|
|
||||||
/* save audio output for next frame */
|
/* save audio output for next frame */
|
||||||
cdd.audio[0] = 0;
|
cdd.audio[0] = 0;
|
||||||
cdd.audio[1] = 0;
|
cdd.audio[1] = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* end of Blip Buffer timeframe */
|
/* end of Blip Buffer timeframe */
|
||||||
blip_end_frame(snd.blips[2][0], samples);
|
blip_end_frame(snd.blips[2], samples);
|
||||||
blip_end_frame(snd.blips[2][1], samples);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cdd_read_subcode(void)
|
static void cdd_read_subcode(void)
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
* Genesis Plus
|
* Genesis Plus
|
||||||
* PCM sound chip (315-5476A) (RF5C164 compatible)
|
* PCM sound chip (315-5476A) (RF5C164 compatible)
|
||||||
*
|
*
|
||||||
* Copyright (C) 2012-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
|
* Redistribution and use of this code or any derivative works are permitted
|
||||||
* provided that the following conditions are met:
|
* provided that the following conditions are met:
|
||||||
@ -45,8 +45,7 @@ void pcm_init(double clock, int samplerate)
|
|||||||
{
|
{
|
||||||
/* PCM chip is running at original rate and is synchronized with SUB-CPU */
|
/* PCM chip is running at original rate and is synchronized with SUB-CPU */
|
||||||
/* Chip output is resampled to desired rate using Blip Buffer. */
|
/* 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], clock / PCM_SCYCLES_RATIO, samplerate);
|
||||||
blip_set_rates(snd.blips[1][1], clock / PCM_SCYCLES_RATIO, samplerate);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void pcm_reset(void)
|
void pcm_reset(void)
|
||||||
@ -71,8 +70,7 @@ void pcm_reset(void)
|
|||||||
pcm.cycles = 0;
|
pcm.cycles = 0;
|
||||||
|
|
||||||
/* clear blip buffers */
|
/* clear blip buffers */
|
||||||
blip_clear(snd.blips[1][0]);
|
blip_clear(snd.blips[1]);
|
||||||
blip_clear(snd.blips[1][1]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int pcm_context_save(uint8 *state)
|
int pcm_context_save(uint8 *state)
|
||||||
@ -117,6 +115,11 @@ void pcm_run(unsigned int length)
|
|||||||
#ifdef LOG_PCM
|
#ifdef LOG_PCM
|
||||||
error("[%d][%d]run %d PCM samples (from %d)\n", v_counter, s68k.cycles, length, pcm.cycles);
|
error("[%d][%d]run %d PCM samples (from %d)\n", v_counter, s68k.cycles, length, pcm.cycles);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* previous audio outputs */
|
||||||
|
int prev_l = pcm.out[0];
|
||||||
|
int prev_r = pcm.out[1];
|
||||||
|
|
||||||
/* check if PCM chip is running */
|
/* check if PCM chip is running */
|
||||||
if (pcm.enabled)
|
if (pcm.enabled)
|
||||||
{
|
{
|
||||||
@ -180,41 +183,29 @@ void pcm_run(unsigned int length)
|
|||||||
if (r < -32768) r = -32768;
|
if (r < -32768) r = -32768;
|
||||||
else if (r > 32767) r = 32767;
|
else if (r > 32767) r = 32767;
|
||||||
|
|
||||||
/* check if PCM left output changed */
|
/* update Blip Buffer */
|
||||||
if (pcm.out[0] != l)
|
blip_add_delta_fast(snd.blips[1], i, l-prev_l, r-prev_r);
|
||||||
{
|
prev_l = l;
|
||||||
blip_add_delta_fast(snd.blips[1][0], i, l-pcm.out[0]);
|
prev_r = r;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* save last audio outputs */
|
||||||
|
pcm.out[0] = prev_l;
|
||||||
|
pcm.out[1] = prev_r;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* check if PCM left output changed */
|
/* check if PCM output was not muted */
|
||||||
if (pcm.out[0])
|
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;
|
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;
|
pcm.out[1] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* end of blip buffer frame */
|
/* end of blip buffer frame */
|
||||||
blip_end_frame(snd.blips[1][0], length);
|
blip_end_frame(snd.blips[1], length);
|
||||||
blip_end_frame(snd.blips[1][1], length);
|
|
||||||
|
|
||||||
/* update PCM master clock counter */
|
/* update PCM master clock counter */
|
||||||
pcm.cycles += length * PCM_SCYCLES_RATIO;
|
pcm.cycles += length * PCM_SCYCLES_RATIO;
|
||||||
@ -223,7 +214,7 @@ void pcm_run(unsigned int length)
|
|||||||
void pcm_update(unsigned int samples)
|
void pcm_update(unsigned int samples)
|
||||||
{
|
{
|
||||||
/* get number of internal clocks (samples) needed */
|
/* get number of internal clocks (samples) needed */
|
||||||
unsigned int clocks = blip_clocks_needed(snd.blips[1][0], samples);
|
unsigned int clocks = blip_clocks_needed(snd.blips[1], samples);
|
||||||
|
|
||||||
/* run PCM chip */
|
/* run PCM chip */
|
||||||
if (clocks > 0)
|
if (clocks > 0)
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
* Genesis Plus
|
* Genesis Plus
|
||||||
* PCM sound chip (315-5476A) (RF5C164 compatible)
|
* PCM sound chip (315-5476A) (RF5C164 compatible)
|
||||||
*
|
*
|
||||||
* Copyright (C) 2012-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
|
* Redistribution and use of this code or any derivative works are permitted
|
||||||
* provided that the following conditions are met:
|
* provided that the following conditions are met:
|
||||||
|
@ -4,8 +4,8 @@
|
|||||||
*
|
*
|
||||||
* Support for SG-1000, Mark-III, Master System, Game Gear, Mega Drive & Mega CD hardware
|
* 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) 1998-2003 Charles Mac Donald (original code)
|
||||||
* 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
|
* Redistribution and use of this code or any derivative works are permitted
|
||||||
* provided that the following conditions are met:
|
* provided that the following conditions are met:
|
||||||
@ -234,24 +234,39 @@ void gen_reset(int hard_reset)
|
|||||||
/* System Reset */
|
/* System Reset */
|
||||||
if (hard_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(work_ram, 0x00, sizeof (work_ram));
|
||||||
memset(zram, 0x00, sizeof (zram));
|
memset(zram, 0x00, sizeof (zram));
|
||||||
}
|
}
|
||||||
else
|
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) */
|
/* reset YM2612 (on hard reset, this is done by sound_reset) */
|
||||||
fm_reset(0);
|
fm_reset(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 68k & Z80 could be anywhere in VDP frame (Bonkers, Eternal Champions, X-Men 2) */
|
/* 68k M-cycles should be a multiple of 7 */
|
||||||
m68k.cycles = Z80.cycles = (uint32)((MCYCLES_PER_LINE * lines_per_frame) * ((double)rand() / (double)RAND_MAX));
|
|
||||||
|
|
||||||
/* 68k cycles should be a multiple of 7 */
|
|
||||||
m68k.cycles = (m68k.cycles / 7) * 7;
|
m68k.cycles = (m68k.cycles / 7) * 7;
|
||||||
|
|
||||||
/* Z80 cycles should be a multiple of 15 */
|
/* Z80 M-cycles should be a multiple of 15 */
|
||||||
Z80.cycles = (Z80.cycles / 15) * 15;
|
Z80.cycles = (m68k.cycles / 15) * 15;
|
||||||
|
|
||||||
/* 8-bit / 16-bit modes */
|
/* 8-bit / 16-bit modes */
|
||||||
if ((system_hw & SYSTEM_PBC) == SYSTEM_MD)
|
if ((system_hw & SYSTEM_PBC) == SYSTEM_MD)
|
||||||
|
@ -4,8 +4,8 @@
|
|||||||
*
|
*
|
||||||
* Support for SG-1000, Mark-III, Master System, Game Gear, Mega Drive & Mega CD hardware
|
* 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) 1998-2003 Charles Mac Donald (original code)
|
||||||
* 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
|
* Redistribution and use of this code or any derivative works are permitted
|
||||||
* provided that the following conditions are met:
|
* provided that the following conditions are met:
|
||||||
|
@ -570,7 +570,7 @@ void io_gg_write(unsigned int offset, unsigned int data)
|
|||||||
|
|
||||||
case 6: /* PSG Stereo output control */
|
case 6: /* PSG Stereo output control */
|
||||||
io_reg[6] = data;
|
io_reg[6] = data;
|
||||||
SN76489_Config(Z80.cycles, config.psg_preamp, config.psgBoostNoise, data);
|
psg_config(Z80.cycles, config.psg_preamp, data);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
default: /* Read-only */
|
default: /* Read-only */
|
||||||
|
@ -207,7 +207,7 @@ void z80_write_byte(unsigned int address, unsigned int data)
|
|||||||
default: /* ZRAM */
|
default: /* ZRAM */
|
||||||
{
|
{
|
||||||
zram[address & 0x1FFF] = data;
|
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;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1218,7 +1218,7 @@ void vdp_write_byte(unsigned int address, unsigned int data)
|
|||||||
{
|
{
|
||||||
if (address & 1)
|
if (address & 1)
|
||||||
{
|
{
|
||||||
SN76489_Write(m68k.cycles, data);
|
psg_write(m68k.cycles, data);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m68k_unused_8_w(address, data);
|
m68k_unused_8_w(address, data);
|
||||||
@ -1264,7 +1264,7 @@ void vdp_write_word(unsigned int address, unsigned int data)
|
|||||||
case 0x10: /* PSG */
|
case 0x10: /* PSG */
|
||||||
case 0x14:
|
case 0x14:
|
||||||
{
|
{
|
||||||
SN76489_Write(m68k.cycles, data & 0xFF);
|
psg_write(m68k.cycles, data & 0xFF);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
* Genesis Plus
|
* Genesis Plus
|
||||||
* Z80 bank access to 68k bus
|
* Z80 bank access to 68k bus
|
||||||
*
|
*
|
||||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald (original code)
|
* Copyright (C) 1998-2003 Charles Mac Donald (original code)
|
||||||
* Copyright (C) 2007-2011 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
|
* Redistribution and use of this code or any derivative works are permitted
|
||||||
* provided that the following conditions are met:
|
* provided that the following conditions are met:
|
||||||
@ -294,7 +294,7 @@ void zbank_write_vdp(unsigned int address, unsigned int data)
|
|||||||
{
|
{
|
||||||
if (address & 1)
|
if (address & 1)
|
||||||
{
|
{
|
||||||
SN76489_Write(Z80.cycles, data);
|
psg_write(Z80.cycles, data);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
zbank_unused_w(address, data);
|
zbank_unused_w(address, data);
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
* Genesis Plus
|
* Genesis Plus
|
||||||
* Z80 bank access to 68k bus
|
* Z80 bank access to 68k bus
|
||||||
*
|
*
|
||||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald (original code)
|
* Copyright (C) 1998-2003 Charles Mac Donald (original code)
|
||||||
* Copyright (C) 2007-2012 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
|
* Redistribution and use of this code or any derivative works are permitted
|
||||||
* provided that the following conditions are met:
|
* provided that the following conditions are met:
|
||||||
|
@ -231,7 +231,7 @@ void z80_md_port_w(unsigned int port, unsigned char data)
|
|||||||
case 0x40:
|
case 0x40:
|
||||||
case 0x41:
|
case 0x41:
|
||||||
{
|
{
|
||||||
SN76489_Write(Z80.cycles, data);
|
psg_write(Z80.cycles, data);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -345,7 +345,7 @@ void z80_gg_port_w(unsigned int port, unsigned char data)
|
|||||||
case 0x40:
|
case 0x40:
|
||||||
case 0x41:
|
case 0x41:
|
||||||
{
|
{
|
||||||
SN76489_Write(Z80.cycles, data);
|
psg_write(Z80.cycles, data);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -450,7 +450,7 @@ void z80_ms_port_w(unsigned int port, unsigned char data)
|
|||||||
case 0x40:
|
case 0x40:
|
||||||
case 0x41:
|
case 0x41:
|
||||||
{
|
{
|
||||||
SN76489_Write(Z80.cycles, data);
|
psg_write(Z80.cycles, data);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -493,7 +493,7 @@ void z80_ms_port_w(unsigned int port, unsigned char data)
|
|||||||
1 0 : disable both PSG & FM output
|
1 0 : disable both PSG & FM output
|
||||||
1 1 : enable both PSG and 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);
|
fm_write(Z80.cycles, 0x02, data);
|
||||||
io_reg[6] = data;
|
io_reg[6] = data;
|
||||||
return;
|
return;
|
||||||
@ -611,7 +611,7 @@ void z80_m3_port_w(unsigned int port, unsigned char data)
|
|||||||
case 0x40:
|
case 0x40:
|
||||||
case 0x41:
|
case 0x41:
|
||||||
{
|
{
|
||||||
SN76489_Write(Z80.cycles, data);
|
psg_write(Z80.cycles, data);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -699,7 +699,7 @@ void z80_sg_port_w(unsigned int port, unsigned char data)
|
|||||||
case 0x40:
|
case 0x40:
|
||||||
case 0x41:
|
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 !WAIT input is tied to SN76489AN chip READY pin (held low for 32 clocks after each write access) */
|
||||||
Z80.cycles += (32 * 15);
|
Z80.cycles += (32 * 15);
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
#include "io_ctrl.h"
|
#include "io_ctrl.h"
|
||||||
#include "input.h"
|
#include "input.h"
|
||||||
#include "sound.h"
|
#include "sound.h"
|
||||||
#include "sn76489.h"
|
#include "psg.h"
|
||||||
#include "ym2413.h"
|
#include "ym2413.h"
|
||||||
#include "ym2612.h"
|
#include "ym2612.h"
|
||||||
#include "sram.h"
|
#include "sram.h"
|
||||||
|
@ -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) */
|
/* Modified for Genesis Plus GX by EkeEke */
|
||||||
/* - disabled assertions checks (define #BLIP_ASSERT to re-enable) */
|
/* - disabled assertions checks (define #BLIP_ASSERT to re-enable) */
|
||||||
/* - fixed multiple time-frames support & removed m->avail */
|
/* - 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) */
|
||||||
/* - 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"
|
#include "blip_buf.h"
|
||||||
|
|
||||||
@ -61,24 +62,32 @@ enum { phase_count = 1 << phase_bits };
|
|||||||
enum { delta_bits = 15 };
|
enum { delta_bits = 15 };
|
||||||
enum { delta_unit = 1 << delta_bits };
|
enum { delta_unit = 1 << delta_bits };
|
||||||
enum { frac_bits = time_bits - pre_shift };
|
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
|
/* 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
|
limit the total buffered samples to blip_max_frame. That could only be
|
||||||
increased by decreasing time_bits, which would reduce resample ratio accuracy.
|
increased by decreasing time_bits, which would reduce resample ratio accuracy.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
typedef int buf_t;
|
||||||
|
|
||||||
struct blip_t
|
struct blip_t
|
||||||
{
|
{
|
||||||
fixed_t factor;
|
fixed_t factor;
|
||||||
fixed_t offset;
|
fixed_t offset;
|
||||||
int size;
|
int size;
|
||||||
|
#ifdef BLIP_MONO
|
||||||
int integrator;
|
int integrator;
|
||||||
|
#else
|
||||||
|
int integrator[2];
|
||||||
|
buf_t* buffer[2];
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef int buf_t;
|
#ifdef BLIP_MONO
|
||||||
|
|
||||||
/* probably not totally portable */
|
/* probably not totally portable */
|
||||||
#define SAMPLES( buf ) ((buf_t*) ((buf) + 1))
|
#define SAMPLES( blip ) ((buf_t*) ((blip) + 1))
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Arithmetic (sign-preserving) right shift */
|
/* Arithmetic (sign-preserving) right shift */
|
||||||
#define ARITH_SHIFT( n, shift ) \
|
#define ARITH_SHIFT( n, shift ) \
|
||||||
@ -124,9 +133,23 @@ blip_t* blip_new( int size )
|
|||||||
assert( size >= 0 );
|
assert( size >= 0 );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef BLIP_MONO
|
||||||
m = (blip_t*) malloc( sizeof *m + (size + buf_extra) * sizeof (buf_t) );
|
m = (blip_t*) malloc( sizeof *m + (size + buf_extra) * sizeof (buf_t) );
|
||||||
|
#else
|
||||||
|
m = (blip_t*) malloc( sizeof *m );
|
||||||
|
#endif
|
||||||
|
|
||||||
if ( m )
|
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->factor = time_unit / blip_max_ratio;
|
||||||
m->size = size;
|
m->size = size;
|
||||||
blip_clear( m );
|
blip_clear( m );
|
||||||
@ -141,7 +164,13 @@ void blip_delete( blip_t* m )
|
|||||||
{
|
{
|
||||||
if ( m != NULL )
|
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 );
|
memset( m, 0, sizeof *m );
|
||||||
free( m );
|
free( m );
|
||||||
}
|
}
|
||||||
@ -173,16 +202,23 @@ void blip_clear( blip_t* m )
|
|||||||
Since we don't know rounding direction, factor/2 accommodates either,
|
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
|
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. */
|
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;
|
m->integrator = 0;
|
||||||
memset( SAMPLES( m ), 0, (m->size + buf_extra) * sizeof (buf_t) );
|
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 )
|
int blip_clocks_needed( const blip_t* m, int samples )
|
||||||
{
|
{
|
||||||
fixed_t needed;
|
fixed_t needed;
|
||||||
|
|
||||||
#ifdef BLIP_ASSERT
|
#ifdef BLIP_ASSERT
|
||||||
/* Fails if buffer can't hold that many more samples */
|
/* Fails if buffer can't hold that many more samples */
|
||||||
assert( (samples >= 0) && (((m->offset >> time_bits) + samples) <= m->size) );
|
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;
|
needed = (fixed_t) samples * time_unit;
|
||||||
if ( needed < m->offset )
|
if ( needed < m->offset )
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return (needed - m->offset + m->factor - 1) / m->factor;
|
return (needed - m->offset + m->factor - 1) / m->factor;
|
||||||
}
|
}
|
||||||
|
|
||||||
void blip_end_frame( blip_t* m, unsigned t )
|
void blip_end_frame( blip_t* m, unsigned t )
|
||||||
{
|
{
|
||||||
m->offset += t * m->factor;
|
m->offset += t * m->factor;
|
||||||
|
|
||||||
#ifdef BLIP_ASSERT
|
#ifdef BLIP_ASSERT
|
||||||
/* Fails if buffer size was exceeded */
|
/* Fails if buffer size was exceeded */
|
||||||
assert( (m->offset >> time_bits) <= m->size );
|
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 )
|
static void remove_samples( blip_t* m, int count )
|
||||||
{
|
{
|
||||||
|
#ifdef BLIP_MONO
|
||||||
buf_t* buf = SAMPLES( m );
|
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;
|
m->offset -= count * time_unit;
|
||||||
|
|
||||||
memmove( &buf [0], &buf [count], remain * sizeof buf [0] );
|
memmove( &buf [0], &buf [count], remain * sizeof (buf_t) );
|
||||||
memset( &buf [remain], 0, count * sizeof buf [0] );
|
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)
|
int blip_read_samples( blip_t* m, short out [], int count)
|
||||||
{
|
{
|
||||||
#ifdef BLIP_ASSERT
|
#ifdef BLIP_ASSERT
|
||||||
assert( count >= 0 );
|
assert( count >= 0 );
|
||||||
|
|
||||||
if ( count > (m->offset >> time_bits) )
|
if ( count > (m->offset >> time_bits) )
|
||||||
count = m->offset >> time_bits;
|
count = m->offset >> time_bits;
|
||||||
|
|
||||||
if ( count )
|
if ( count )
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
buf_t const* in = SAMPLES( m );
|
#ifdef BLIP_MONO
|
||||||
buf_t const* end = in + count;
|
buf_t const* in = SAMPLES( m );
|
||||||
int sum = m->integrator;
|
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
|
do
|
||||||
{
|
{
|
||||||
/* Eliminate fraction */
|
/* Eliminate fraction */
|
||||||
int s = ARITH_SHIFT( sum, delta_bits );
|
int s = ARITH_SHIFT( sum, delta_bits );
|
||||||
|
|
||||||
sum += *in++;
|
sum += *in++;
|
||||||
|
|
||||||
CLAMP( s );
|
CLAMP( s );
|
||||||
|
|
||||||
*out = s;
|
*out++ = s;
|
||||||
out += 2;
|
|
||||||
|
|
||||||
/* High-pass filter */
|
/* High-pass filter */
|
||||||
sum -= s << (delta_bits - bass_shift);
|
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 );
|
while ( in != end );
|
||||||
|
|
||||||
|
#ifdef BLIP_MONO
|
||||||
m->integrator = sum;
|
m->integrator = sum;
|
||||||
|
#else
|
||||||
|
m->integrator[0] = sum;
|
||||||
|
m->integrator[1] = sum2;
|
||||||
|
#endif
|
||||||
remove_samples( m, count );
|
remove_samples( m, count );
|
||||||
}
|
}
|
||||||
|
|
||||||
return 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
|
#ifdef BLIP_ASSERT
|
||||||
assert( count >= 0 );
|
assert( count >= 0 );
|
||||||
|
|
||||||
if ( count > (m->offset >> time_bits) )
|
if ( count > (m1->offset >> time_bits) )
|
||||||
count = m->offset >> time_bits;
|
count = m1->offset >> time_bits;
|
||||||
|
if ( count > (m2->offset >> time_bits) )
|
||||||
if ( count )
|
count = m2->offset >> time_bits;
|
||||||
|
if ( count > (m3->offset >> time_bits) )
|
||||||
|
count = m3->offset >> time_bits;
|
||||||
|
|
||||||
|
if ( count )
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
buf_t const* in = SAMPLES( m );
|
buf_t const* end;
|
||||||
buf_t const* end = in + count;
|
buf_t const* in[3];
|
||||||
int sum = m->integrator;
|
#ifdef BLIP_MONO
|
||||||
do
|
int sum = m1->integrator;
|
||||||
{
|
in[0] = SAMPLES( m1 );
|
||||||
/* Eliminate fraction */
|
in[1] = SAMPLES( m2 );
|
||||||
int s = ARITH_SHIFT( sum, delta_bits );
|
in[2] = SAMPLES( m3 );
|
||||||
|
#else
|
||||||
sum += *in++;
|
int sum = m1->integrator[0];
|
||||||
|
int sum2 = m1->integrator[1];
|
||||||
/* High-pass filter */
|
buf_t const* in2[3];
|
||||||
sum -= s << (delta_bits - bass_shift);
|
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 */
|
end = in[0] + count;
|
||||||
s += *out;
|
do
|
||||||
|
{
|
||||||
CLAMP( s );
|
/* Eliminate fraction */
|
||||||
|
int s = ARITH_SHIFT( sum, delta_bits );
|
||||||
*out = s;
|
|
||||||
out += 2;
|
sum += *in[0]++;
|
||||||
}
|
sum += *in[1]++;
|
||||||
while ( in != end );
|
sum += *in[2]++;
|
||||||
m->integrator = sum;
|
|
||||||
|
CLAMP( s );
|
||||||
remove_samples( m, count );
|
|
||||||
}
|
*out++ = s;
|
||||||
|
|
||||||
return count;
|
/* 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:
|
/* 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
|
And by having pre_shift 32, a 32-bit platform can easily do the shift by
|
||||||
simply ignoring the low half. */
|
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 )
|
void blip_add_delta( blip_t* m, unsigned time, int delta )
|
||||||
{
|
{
|
||||||
unsigned fixed = (unsigned) ((time * m->factor + m->offset) >> pre_shift);
|
unsigned fixed = (unsigned) ((time * m->factor + m->offset) >> pre_shift);
|
||||||
buf_t* out = SAMPLES( m ) + (fixed >> frac_bits);
|
buf_t* out = SAMPLES( m ) + (fixed >> frac_bits);
|
||||||
|
|
||||||
int const phase_shift = frac_bits - phase_bits;
|
|
||||||
int phase = fixed >> phase_shift & (phase_count - 1);
|
int phase = fixed >> phase_shift & (phase_count - 1);
|
||||||
short const* in = bl_step [phase];
|
short const* in = bl_step [phase];
|
||||||
short const* rev = bl_step [phase_count - 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 [7] += delta * delta_unit - delta2;
|
||||||
out [8] += delta2;
|
out [8] += delta2;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
@ -28,12 +28,24 @@ blip_max_ratio = 1 << 20 };
|
|||||||
/** Clears entire buffer. Afterwards, blip_samples_avail() == 0. */
|
/** Clears entire buffer. Afterwards, blip_samples_avail() == 0. */
|
||||||
void blip_clear( blip_t* );
|
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. */
|
/** Adds positive/negative delta into buffer at specified clock time. */
|
||||||
void blip_add_delta( blip_t*, unsigned int clock_time, int delta );
|
void blip_add_delta( blip_t*, unsigned int clock_time, int delta );
|
||||||
|
|
||||||
/** Same as blip_add_delta(), but uses faster, lower-quality synthesis. */
|
/** Same as blip_add_delta(), but uses faster, lower-quality synthesis. */
|
||||||
void blip_add_delta_fast( blip_t*, unsigned int clock_time, int delta );
|
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
|
/** Length of time frame, in clocks, needed to make sample_count additional
|
||||||
samples available. */
|
samples available. */
|
||||||
int blip_clocks_needed( const blip_t*, int sample_count );
|
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. */
|
stream. Outputs 16-bit signed samples. Returns number of samples actually read. */
|
||||||
int blip_read_samples( blip_t*, short out [], int count);
|
int blip_read_samples( blip_t*, short out [], int count);
|
||||||
|
|
||||||
/* Same as above function except sample is added to output buffer previous value */
|
/* Same as above function except sample is mixed from three blip buffers source */
|
||||||
/* This allows easy mixing of different blip buffers into a single output stream */
|
int blip_mix_samples( blip_t* m1, blip_t* m2, blip_t* m3, short out [], int count);
|
||||||
int blip_mix_samples( blip_t* m, short out [], int count);
|
|
||||||
|
|
||||||
/** Frees buffer. No effect if NULL is passed. */
|
/** Frees buffer. No effect if NULL is passed. */
|
||||||
void blip_delete( blip_t* );
|
void blip_delete( blip_t* );
|
||||||
|
591
core/sound/psg.c
Normal file
591
core/sound/psg.c
Normal file
@ -0,0 +1,591 @@
|
|||||||
|
/***************************************************************************************
|
||||||
|
* Genesis Plus
|
||||||
|
* PSG sound chip (SN76489A compatible)
|
||||||
|
*
|
||||||
|
* Support for discrete chip & integrated (ASIC) clones
|
||||||
|
*
|
||||||
|
* Noise implementation based on http://www.smspower.org/Development/SN76489#NoiseChannel
|
||||||
|
*
|
||||||
|
* Copyright (C) 2016 Eke-Eke (Genesis Plus GX)
|
||||||
|
*
|
||||||
|
* Redistribution and use of this code or any derivative works are permitted
|
||||||
|
* provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* - Redistributions may not be sold, nor may they be used in a commercial
|
||||||
|
* product or activity.
|
||||||
|
*
|
||||||
|
* - Redistributions that are modified from the original source must include the
|
||||||
|
* complete source code, including the source code for all components used by a
|
||||||
|
* binary built from the modified sources. However, as a special exception, the
|
||||||
|
* source code distributed need not include anything that is normally distributed
|
||||||
|
* (in either source or binary form) with the major components (compiler, kernel,
|
||||||
|
* and so on) of the operating system on which the executable runs, unless that
|
||||||
|
* component itself accompanies the executable.
|
||||||
|
*
|
||||||
|
* - Redistributions must reproduce the above copyright notice, this list of
|
||||||
|
* conditions and the following disclaimer in the documentation and/or other
|
||||||
|
* materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
****************************************************************************************/
|
||||||
|
|
||||||
|
#include "shared.h"
|
||||||
|
#include "blip_buf.h"
|
||||||
|
|
||||||
|
/* internal clock = input clock : 16 = (master clock : 15) : 16 */
|
||||||
|
#define PSG_MCYCLES_RATIO (15*16)
|
||||||
|
|
||||||
|
/* maximal channel output (roughly adjusted to match VA4 MD1 PSG/FM balance with 1.5x amplification of PSG output) */
|
||||||
|
#define PSG_MAX_VOLUME 2800
|
||||||
|
|
||||||
|
static const uint8 noiseShiftWidth[2] = {14,15};
|
||||||
|
|
||||||
|
static const uint8 noiseBitMask[2] = {0x6,0x9};
|
||||||
|
|
||||||
|
static const uint8 noiseFeedback[10] = {0,1,1,0,1,0,0,1,1,0};
|
||||||
|
|
||||||
|
static const uint16 chanVolume[16] = {
|
||||||
|
PSG_MAX_VOLUME, /* MAX */
|
||||||
|
PSG_MAX_VOLUME * 0.794328234, /* -2dB */
|
||||||
|
PSG_MAX_VOLUME * 0.630957344, /* -4dB */
|
||||||
|
PSG_MAX_VOLUME * 0.501187233, /* -6dB */
|
||||||
|
PSG_MAX_VOLUME * 0.398107170, /* -8dB */
|
||||||
|
PSG_MAX_VOLUME * 0.316227766, /* -10dB */
|
||||||
|
PSG_MAX_VOLUME * 0.251188643, /* -12dB */
|
||||||
|
PSG_MAX_VOLUME * 0.199526231, /* -14dB */
|
||||||
|
PSG_MAX_VOLUME * 0.158489319, /* -16dB */
|
||||||
|
PSG_MAX_VOLUME * 0.125892541, /* -18dB */
|
||||||
|
PSG_MAX_VOLUME * 0.1, /* -20dB */
|
||||||
|
PSG_MAX_VOLUME * 0.079432823, /* -22dB */
|
||||||
|
PSG_MAX_VOLUME * 0.063095734, /* -24dB */
|
||||||
|
PSG_MAX_VOLUME * 0.050118723, /* -26dB */
|
||||||
|
PSG_MAX_VOLUME * 0.039810717, /* -28dB */
|
||||||
|
0 /* OFF */
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct
|
||||||
|
{
|
||||||
|
int clocks;
|
||||||
|
int latch;
|
||||||
|
int noiseShiftValue;
|
||||||
|
int noiseShiftWidth;
|
||||||
|
int noiseBitMask;
|
||||||
|
int regs[8];
|
||||||
|
int freqInc[4];
|
||||||
|
int freqCounter[4];
|
||||||
|
int polarity[4];
|
||||||
|
int chanDelta[4][2];
|
||||||
|
int chanOut[4][2];
|
||||||
|
int chanAmp[4][2];
|
||||||
|
} psg;
|
||||||
|
|
||||||
|
static void psg_update(unsigned int clocks);
|
||||||
|
|
||||||
|
void psg_init(PSG_TYPE type)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Initialize stereo amplification (default) */
|
||||||
|
for (i=0; i<4; i++)
|
||||||
|
{
|
||||||
|
psg.chanAmp[i][0] = 100;
|
||||||
|
psg.chanAmp[i][1] = 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize Noise LSFR type */
|
||||||
|
psg.noiseShiftWidth = noiseShiftWidth[type];
|
||||||
|
psg.noiseBitMask = noiseBitMask[type];
|
||||||
|
}
|
||||||
|
|
||||||
|
void psg_reset()
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* power-on state (verified on 315-5313A & 315-5660 integrated version only) */
|
||||||
|
for (i=0; i<4; i++)
|
||||||
|
{
|
||||||
|
psg.regs[i*2] = 0;
|
||||||
|
psg.regs[i*2+1] = 0;
|
||||||
|
psg.freqInc[i] = (i < 3) ? (1 * PSG_MCYCLES_RATIO) : (16 * PSG_MCYCLES_RATIO);
|
||||||
|
psg.freqCounter[i] = 0;
|
||||||
|
psg.polarity[i] = -1;
|
||||||
|
psg.chanDelta[i][0] = 0;
|
||||||
|
psg.chanDelta[i][1] = 0;
|
||||||
|
psg.chanOut[i][0] = 0;
|
||||||
|
psg.chanOut[i][1] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* noise attenuation register is latched on power-on (verified on 315-5313A & 315-5660 integrated version only) */
|
||||||
|
psg.latch = 7;
|
||||||
|
|
||||||
|
/* reset noise shift register */
|
||||||
|
psg.noiseShiftValue = 1 << psg.noiseShiftWidth;
|
||||||
|
|
||||||
|
/* reset internal M-cycles clock counter */
|
||||||
|
psg.clocks = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int psg_context_save(uint8 *state)
|
||||||
|
{
|
||||||
|
int bufferptr = 0;
|
||||||
|
|
||||||
|
save_param(&psg.clocks,sizeof(psg.clocks));
|
||||||
|
save_param(&psg.latch,sizeof(psg.latch));
|
||||||
|
save_param(&psg.noiseShiftValue,sizeof(psg.noiseShiftValue));
|
||||||
|
save_param(psg.regs,sizeof(psg.regs));
|
||||||
|
save_param(psg.freqInc,sizeof(psg.freqInc));
|
||||||
|
save_param(psg.freqCounter,sizeof(psg.freqCounter));
|
||||||
|
save_param(psg.polarity,sizeof(psg.polarity));
|
||||||
|
save_param(psg.chanDelta,sizeof(psg.chanDelta));
|
||||||
|
save_param(psg.chanOut,sizeof(psg.chanOut));
|
||||||
|
|
||||||
|
return bufferptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
int psg_context_load(uint8 *state)
|
||||||
|
{
|
||||||
|
int chanOut[4][2], delta[2];
|
||||||
|
int i, bufferptr = 0;
|
||||||
|
|
||||||
|
/* get current tone channels output */
|
||||||
|
for (i=0; i<3; i++)
|
||||||
|
{
|
||||||
|
if (psg.polarity[i] > 0)
|
||||||
|
{
|
||||||
|
chanOut[i][0] = psg.chanOut[i][0];
|
||||||
|
chanOut[i][1] = psg.chanOut[i][1];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
chanOut[i][0] = 0;
|
||||||
|
chanOut[i][1] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get current noise channel output */
|
||||||
|
if (psg.noiseShiftValue & 1)
|
||||||
|
{
|
||||||
|
chanOut[3][0] = psg.chanOut[3][0];
|
||||||
|
chanOut[3][1] = psg.chanOut[3][1];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
chanOut[3][0] = 0;
|
||||||
|
chanOut[3][1] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
load_param(&psg.clocks,sizeof(psg.clocks));
|
||||||
|
load_param(&psg.latch,sizeof(psg.latch));
|
||||||
|
load_param(&psg.noiseShiftValue,sizeof(psg.noiseShiftValue));
|
||||||
|
load_param(psg.regs,sizeof(psg.regs));
|
||||||
|
load_param(psg.freqInc,sizeof(psg.freqInc));
|
||||||
|
load_param(psg.freqCounter,sizeof(psg.freqCounter));
|
||||||
|
load_param(psg.polarity,sizeof(psg.polarity));
|
||||||
|
load_param(psg.chanDelta,sizeof(psg.chanDelta));
|
||||||
|
load_param(psg.chanOut,sizeof(psg.chanOut));
|
||||||
|
|
||||||
|
/* apply any pending channel volume variation */
|
||||||
|
for (i=0; i<4; i++)
|
||||||
|
{
|
||||||
|
psg.chanOut[i][0] += psg.chanDelta[i][0];
|
||||||
|
psg.chanOut[i][1] += psg.chanDelta[i][1];
|
||||||
|
psg.chanDelta[i][0] = 0;
|
||||||
|
psg.chanDelta[i][1] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* calculate noise channel output variations */
|
||||||
|
if (psg.noiseShiftValue & 1)
|
||||||
|
{
|
||||||
|
/* channel output is high */
|
||||||
|
delta[0] = psg.chanOut[3][0] - chanOut[3][0];
|
||||||
|
delta[1] = psg.chanOut[3][0] - chanOut[3][1];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* channel output is low */
|
||||||
|
delta[0] = -chanOut[3][0];
|
||||||
|
delta[1] = -chanOut[3][1];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* add tone channels output variations */
|
||||||
|
for (i=0; i<3; i++)
|
||||||
|
{
|
||||||
|
if (psg.polarity[i] > 0)
|
||||||
|
{
|
||||||
|
/* channel output is high */
|
||||||
|
delta[0] += (psg.chanOut[i][0] - chanOut[i][0]);
|
||||||
|
delta[1] += (psg.chanOut[i][0] - chanOut[i][1]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* channel output is low */
|
||||||
|
delta[0] -= chanOut[i][0];
|
||||||
|
delta[1] -= chanOut[i][1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* update mixed channels output */
|
||||||
|
if (config.hq_psg)
|
||||||
|
{
|
||||||
|
blip_add_delta(snd.blips[0], psg.clocks, delta[0], delta[1]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
blip_add_delta_fast(snd.blips[0], psg.clocks, delta[0], delta[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return bufferptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void psg_write(unsigned int clocks, unsigned int data)
|
||||||
|
{
|
||||||
|
int index;
|
||||||
|
|
||||||
|
/* PSG chip synchronization */
|
||||||
|
if (clocks > psg.clocks)
|
||||||
|
{
|
||||||
|
/* run PSG chip until current timestamp */
|
||||||
|
psg_update(clocks);
|
||||||
|
|
||||||
|
/* update internal M-cycles clock counter */
|
||||||
|
psg.clocks += ((clocks - psg.clocks + PSG_MCYCLES_RATIO - 1) / PSG_MCYCLES_RATIO) * PSG_MCYCLES_RATIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data & 0x80)
|
||||||
|
{
|
||||||
|
/* latch register index (1xxx----) */
|
||||||
|
psg.latch = index = (data >> 4) & 0x07;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* restore latched register index */
|
||||||
|
index= psg.latch;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (index)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
case 2:
|
||||||
|
case 4: /* Tone channels frequency */
|
||||||
|
{
|
||||||
|
/* recalculate frequency register value */
|
||||||
|
if (data & 0x80)
|
||||||
|
{
|
||||||
|
/* update 10-bit register LSB (1---xxxx) */
|
||||||
|
data = (psg.regs[index] & 0x3f0) | (data & 0x0f);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* update 10-bit register MSB (0-xxxxxx) */
|
||||||
|
data = (psg.regs[index] & 0x00f) | ((data & 0x3f) << 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* update channel M-cycle counter increment */
|
||||||
|
if (data)
|
||||||
|
{
|
||||||
|
psg.freqInc[index>>1] = data * PSG_MCYCLES_RATIO;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* zero value behaves the same as a value of 1 (verified on integrated version only) */
|
||||||
|
psg.freqInc[index>>1] = PSG_MCYCLES_RATIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* update noise channel counter increment if required */
|
||||||
|
if ((index == 4) && ((psg.regs[6] & 0x03) == 0x03))
|
||||||
|
{
|
||||||
|
psg.freqInc[3] = psg.freqInc[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 6: /* Noise control */
|
||||||
|
{
|
||||||
|
/* noise signal generator frequency (----?xxx) */
|
||||||
|
int noiseFreq = (data & 0x03);
|
||||||
|
|
||||||
|
if (noiseFreq == 0x03)
|
||||||
|
{
|
||||||
|
/* noise generator is controlled by tone channel #3 generator */
|
||||||
|
psg.freqInc[3] = psg.freqInc[2];
|
||||||
|
psg.freqCounter[3] = psg.freqCounter[2];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* noise generator is running at separate frequency */
|
||||||
|
psg.freqInc[3] = (0x10 << noiseFreq) * PSG_MCYCLES_RATIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* reset shift register value */
|
||||||
|
psg.noiseShiftValue = 1 << psg.noiseShiftWidth;;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 7: /* Noise channel attenuation */
|
||||||
|
{
|
||||||
|
/* convert 4-bit attenuation value (----xxxx) to 16-bit volume value */
|
||||||
|
data = chanVolume[data & 0x0f];
|
||||||
|
|
||||||
|
/* check noise shift register output */
|
||||||
|
if (psg.noiseShiftValue & 1)
|
||||||
|
{
|
||||||
|
/* channel output is high, volume variation will be applied at next internal cycle update */
|
||||||
|
psg.chanDelta[3][0] = ((data * psg.chanAmp[3][0]) / 100) - psg.chanOut[3][0];
|
||||||
|
psg.chanDelta[3][1] = ((data * psg.chanAmp[3][1]) / 100) - psg.chanOut[3][1];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* channel output is low, volume variation will be applied at next transition */
|
||||||
|
psg.chanOut[3][0] = (data * psg.chanAmp[3][0]) / 100;
|
||||||
|
psg.chanOut[3][1] = (data * psg.chanAmp[3][1]) / 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default: /* Tone channels attenuation */
|
||||||
|
{
|
||||||
|
/* channel number (0-2) */
|
||||||
|
int i = index >> 1;
|
||||||
|
|
||||||
|
/* convert 4-bit attenuation value (----xxxx) to 16-bit volume value */
|
||||||
|
data = chanVolume[data & 0x0f];
|
||||||
|
|
||||||
|
/* check tone generator polarity */
|
||||||
|
if (psg.polarity[i] > 0)
|
||||||
|
{
|
||||||
|
/* channel output is high, volume variation will be applied at next internal cycle update */
|
||||||
|
psg.chanDelta[i][0] = ((data * psg.chanAmp[i][0]) / 100) - psg.chanOut[i][0];
|
||||||
|
psg.chanDelta[i][1] = ((data * psg.chanAmp[i][1]) / 100) - psg.chanOut[i][1];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* channel output is low, volume variation will be applied at next transition */
|
||||||
|
psg.chanOut[i][0] = (data * psg.chanAmp[i][0]) / 100;
|
||||||
|
psg.chanOut[i][1] = (data * psg.chanAmp[i][1]) / 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* save register value */
|
||||||
|
psg.regs[index] = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void psg_config(unsigned int clocks, unsigned int preamp, unsigned int panning)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* PSG chip synchronization */
|
||||||
|
if (clocks > psg.clocks)
|
||||||
|
{
|
||||||
|
/* run PSG chip until current timestamp */
|
||||||
|
psg_update(clocks);
|
||||||
|
|
||||||
|
/* update internal M-cycles clock counter */
|
||||||
|
psg.clocks += ((clocks - psg.clocks + PSG_MCYCLES_RATIO - 1) / PSG_MCYCLES_RATIO) * PSG_MCYCLES_RATIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i=0; i<4; i++)
|
||||||
|
{
|
||||||
|
/* channel internal volume */
|
||||||
|
int volume = psg.regs[i*2+1];
|
||||||
|
|
||||||
|
/* update channel stereo amplification */
|
||||||
|
psg.chanAmp[i][0] = preamp * ((panning >> (i + 4)) & 1);
|
||||||
|
psg.chanAmp[i][1] = preamp * ((panning >> (i + 0)) & 1);
|
||||||
|
|
||||||
|
/* tone channels */
|
||||||
|
if (i < 3)
|
||||||
|
{
|
||||||
|
/* check tone generator polarity */
|
||||||
|
if (psg.polarity[i] > 0)
|
||||||
|
{
|
||||||
|
/* channel output is high, volume variation will be applied at next internal cycle update */
|
||||||
|
psg.chanDelta[i][0] = ((volume * psg.chanAmp[i][0]) / 100) - psg.chanOut[i][0];
|
||||||
|
psg.chanDelta[i][1] = ((volume * psg.chanAmp[i][1]) / 100) - psg.chanOut[i][1];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* channel output is low, volume variation will be applied at next transition*/
|
||||||
|
psg.chanOut[i][0] = (volume * psg.chanAmp[i][0]) / 100;
|
||||||
|
psg.chanOut[i][1] = (volume * psg.chanAmp[i][1]) / 100;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* noise channel */
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* check noise shift register output */
|
||||||
|
if (psg.noiseShiftValue & 1)
|
||||||
|
{
|
||||||
|
/* channel output is high, volume variation will be applied at next internal cycle update */
|
||||||
|
psg.chanDelta[3][0] = ((volume * psg.chanAmp[3][0]) / 100) - psg.chanOut[3][0];
|
||||||
|
psg.chanDelta[3][1] = ((volume * psg.chanAmp[3][1]) / 100) - psg.chanOut[3][1];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* channel output is low, volume variation will be applied at next transition */
|
||||||
|
psg.chanOut[3][0] = (volume * psg.chanAmp[3][0]) / 100;
|
||||||
|
psg.chanOut[3][1] = (volume * psg.chanAmp[3][1]) / 100;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void psg_end_frame(unsigned int clocks)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (clocks > psg.clocks)
|
||||||
|
{
|
||||||
|
/* run PSG chip until current timestamp */
|
||||||
|
psg_update(clocks);
|
||||||
|
|
||||||
|
/* update internal M-cycles clock counter */
|
||||||
|
psg.clocks += ((clocks - psg.clocks + PSG_MCYCLES_RATIO - 1) / PSG_MCYCLES_RATIO) * PSG_MCYCLES_RATIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* adjust internal M-cycles clock counter for next frame */
|
||||||
|
psg.clocks -= clocks;
|
||||||
|
|
||||||
|
/* adjust channels time counters for next frame */
|
||||||
|
for (i=0; i<4; ++i)
|
||||||
|
{
|
||||||
|
psg.freqCounter[i] -= clocks;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void psg_update(unsigned int clocks)
|
||||||
|
{
|
||||||
|
int i, timestamp, polarity;
|
||||||
|
|
||||||
|
for (i=0; i<4; i++)
|
||||||
|
{
|
||||||
|
/* apply any pending channel volume variations */
|
||||||
|
if (psg.chanDelta[i][0] | psg.chanDelta[i][1])
|
||||||
|
{
|
||||||
|
/* update channel output */
|
||||||
|
if (config.hq_psg)
|
||||||
|
{
|
||||||
|
blip_add_delta(snd.blips[0], psg.clocks, psg.chanDelta[i][0], psg.chanDelta[i][1]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
blip_add_delta_fast(snd.blips[0], psg.clocks, psg.chanDelta[i][0], psg.chanDelta[i][1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* update channel volume */
|
||||||
|
psg.chanOut[i][0] += psg.chanDelta[i][0];
|
||||||
|
psg.chanOut[i][1] += psg.chanDelta[i][1];
|
||||||
|
|
||||||
|
/* clear pending channel volume variations */
|
||||||
|
psg.chanDelta[i][0] = 0;
|
||||||
|
psg.chanDelta[i][1] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* timestamp of next transition */
|
||||||
|
timestamp = psg.freqCounter[i];
|
||||||
|
|
||||||
|
/* current channel generator polarity */
|
||||||
|
polarity = psg.polarity[i];
|
||||||
|
|
||||||
|
/* Tone channels */
|
||||||
|
if (i < 3)
|
||||||
|
{
|
||||||
|
/* process all transitions occurring until current clock timestamp */
|
||||||
|
while (timestamp < clocks)
|
||||||
|
{
|
||||||
|
/* invert tone generator polarity */
|
||||||
|
polarity = -polarity;
|
||||||
|
|
||||||
|
/* update channel output */
|
||||||
|
if (config.hq_psg)
|
||||||
|
{
|
||||||
|
blip_add_delta(snd.blips[0], timestamp, polarity*psg.chanOut[i][0], polarity*psg.chanOut[i][1]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
blip_add_delta_fast(snd.blips[0], timestamp, polarity*psg.chanOut[i][0], polarity*psg.chanOut[i][1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* timestamp of next transition */
|
||||||
|
timestamp += psg.freqInc[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Noise channel */
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* current noise shift register value */
|
||||||
|
int shiftValue = psg.noiseShiftValue;
|
||||||
|
|
||||||
|
/* process all transitions occurring until current clock timestamp */
|
||||||
|
while (timestamp < clocks)
|
||||||
|
{
|
||||||
|
/* invert noise generator polarity */
|
||||||
|
polarity = -polarity;
|
||||||
|
|
||||||
|
/* noise register is shifted on positive edge only */
|
||||||
|
if (polarity > 0)
|
||||||
|
{
|
||||||
|
/* current shift register output */
|
||||||
|
int shiftOutput = shiftValue & 0x01;
|
||||||
|
|
||||||
|
/* White noise (----1xxx) */
|
||||||
|
if (psg.regs[6] & 0x04)
|
||||||
|
{
|
||||||
|
/* shift and apply XOR feedback network */
|
||||||
|
shiftValue = (shiftValue >> 1) | (noiseFeedback[shiftValue & psg.noiseBitMask] << psg.noiseShiftWidth);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Periodic noise (----0xxx) */
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* shift and feedback current output */
|
||||||
|
shiftValue = (shiftValue >> 1) | (shiftOutput << psg.noiseShiftWidth);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* shift register output variation */
|
||||||
|
shiftOutput = (shiftValue & 0x1) - shiftOutput;
|
||||||
|
|
||||||
|
/* update noise channel output */
|
||||||
|
if (config.hq_psg)
|
||||||
|
{
|
||||||
|
blip_add_delta(snd.blips[0], timestamp, shiftOutput*psg.chanOut[3][0], shiftOutput*psg.chanOut[3][1]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
blip_add_delta_fast(snd.blips[0], timestamp, shiftOutput*psg.chanOut[3][0], shiftOutput*psg.chanOut[3][1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* timestamp of next transition */
|
||||||
|
timestamp += psg.freqInc[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* save shift register value */
|
||||||
|
psg.noiseShiftValue = shiftValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* save timestamp of next transition */
|
||||||
|
psg.freqCounter[i] = timestamp;
|
||||||
|
|
||||||
|
/* save channel generator polarity */
|
||||||
|
psg.polarity[i] = polarity;
|
||||||
|
}
|
||||||
|
}
|
60
core/sound/psg.h
Normal file
60
core/sound/psg.h
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
/***************************************************************************************
|
||||||
|
* Genesis Plus
|
||||||
|
* PSG sound chip (SN76489A compatible)
|
||||||
|
*
|
||||||
|
* Support for discrete chip & integrated (ASIC) clones
|
||||||
|
*
|
||||||
|
* Noise implementation based on http://www.smspower.org/Development/SN76489#NoiseChannel
|
||||||
|
*
|
||||||
|
* Copyright (C) 2016 Eke-Eke (Genesis Plus GX)
|
||||||
|
*
|
||||||
|
* Redistribution and use of this code or any derivative works are permitted
|
||||||
|
* provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* - Redistributions may not be sold, nor may they be used in a commercial
|
||||||
|
* product or activity.
|
||||||
|
*
|
||||||
|
* - Redistributions that are modified from the original source must include the
|
||||||
|
* complete source code, including the source code for all components used by a
|
||||||
|
* binary built from the modified sources. However, as a special exception, the
|
||||||
|
* source code distributed need not include anything that is normally distributed
|
||||||
|
* (in either source or binary form) with the major components (compiler, kernel,
|
||||||
|
* and so on) of the operating system on which the executable runs, unless that
|
||||||
|
* component itself accompanies the executable.
|
||||||
|
*
|
||||||
|
* - Redistributions must reproduce the above copyright notice, this list of
|
||||||
|
* conditions and the following disclaimer in the documentation and/or other
|
||||||
|
* materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
****************************************************************************************/
|
||||||
|
|
||||||
|
#ifndef _PSG_H_
|
||||||
|
#define _PSG_H_
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
PSG_DISCRETE,
|
||||||
|
PSG_INTEGRATED
|
||||||
|
} PSG_TYPE;
|
||||||
|
|
||||||
|
/* Function prototypes */
|
||||||
|
extern void psg_init(PSG_TYPE type);
|
||||||
|
extern void psg_reset(void);
|
||||||
|
extern int psg_context_save(uint8 *state);
|
||||||
|
extern int psg_context_load(uint8 *state);
|
||||||
|
extern void psg_write(unsigned int clocks, unsigned int data);
|
||||||
|
extern void psg_config(unsigned int clocks, unsigned int preamp, unsigned int panning);
|
||||||
|
extern void psg_end_frame(unsigned int clocks);
|
||||||
|
|
||||||
|
#endif /* _PSG_H_ */
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -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_ */
|
|
@ -2,8 +2,8 @@
|
|||||||
* Genesis Plus
|
* Genesis Plus
|
||||||
* Sound Hardware
|
* Sound Hardware
|
||||||
*
|
*
|
||||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald (original code)
|
* Copyright (C) 1998-2003 Charles Mac Donald (original code)
|
||||||
* 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
|
* Redistribution and use of this code or any derivative works are permitted
|
||||||
* provided that the following conditions are met:
|
* provided that the following conditions are met:
|
||||||
@ -86,7 +86,7 @@ void sound_init( void )
|
|||||||
YM_Update = YM2612Update;
|
YM_Update = YM2612Update;
|
||||||
YM_Write = YM2612Write;
|
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;
|
fm_cycles_ratio = 144 * 7;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -97,21 +97,20 @@ void sound_init( void )
|
|||||||
YM_Update = YM2413Update;
|
YM_Update = YM2413Update;
|
||||||
YM_Write = YM2413Write;
|
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;
|
fm_cycles_ratio = 72 * 15;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initialize PSG chip */
|
/* Initialize PSG chip */
|
||||||
SN76489_Init((system_hw == SYSTEM_SG) ? SN_DISCRETE : SN_INTEGRATED);
|
psg_init((system_hw == SYSTEM_SG) ? PSG_DISCRETE : PSG_INTEGRATED);
|
||||||
SN76489_Config(0, config.psg_preamp, config.psgBoostNoise, 0xff);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void sound_reset(void)
|
void sound_reset(void)
|
||||||
{
|
{
|
||||||
/* reset sound chips */
|
/* reset sound chips */
|
||||||
YM_Reset();
|
YM_Reset();
|
||||||
SN76489_Reset();
|
psg_reset();
|
||||||
SN76489_Config(0, config.psg_preamp, config.psgBoostNoise, 0xff);
|
psg_config(0, config.psg_preamp, 0xff);
|
||||||
|
|
||||||
/* reset FM buffer ouput */
|
/* reset FM buffer ouput */
|
||||||
fm_last[0] = fm_last[1] = 0;
|
fm_last[0] = fm_last[1] = 0;
|
||||||
@ -125,21 +124,23 @@ void sound_reset(void)
|
|||||||
|
|
||||||
int sound_update(unsigned int cycles)
|
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 */
|
/* Run PSG chip until end of frame */
|
||||||
SN76489_Update(cycles);
|
psg_end_frame(cycles);
|
||||||
|
|
||||||
|
/* Run FM chip until end of frame */
|
||||||
fm_update(cycles);
|
fm_update(cycles);
|
||||||
|
|
||||||
/* FM output pre-amplification */
|
/* FM output pre-amplification */
|
||||||
preamp = config.fm_preamp;
|
preamp = config.fm_preamp;
|
||||||
|
|
||||||
/* FM frame initial timestamp */
|
/* FM frame initial timestamp */
|
||||||
time = fm_cycles_start;
|
time = fm_cycles_start;
|
||||||
|
|
||||||
/* Restore last FM outputs from previous frame */
|
/* Restore last FM outputs from previous frame */
|
||||||
l = fm_last[0];
|
prev_l = fm_last[0];
|
||||||
r = fm_last[1];
|
prev_r = fm_last[1];
|
||||||
|
|
||||||
/* FM buffer start pointer */
|
/* FM buffer start pointer */
|
||||||
ptr = fm_buffer;
|
ptr = fm_buffer;
|
||||||
@ -150,15 +151,12 @@ int sound_update(unsigned int cycles)
|
|||||||
/* high-quality Band-Limited synthesis */
|
/* high-quality Band-Limited synthesis */
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
/* left channel */
|
/* left & right channels */
|
||||||
delta = ((*ptr++ * preamp) / 100) - l;
|
l = ((*ptr++ * preamp) / 100);
|
||||||
l += delta;
|
r = ((*ptr++ * preamp) / 100);
|
||||||
blip_add_delta(snd.blips[0][0], time, delta);
|
blip_add_delta(snd.blips[0], time, l-prev_l, r-prev_r);
|
||||||
|
prev_l = l;
|
||||||
/* right channel */
|
prev_r = r;
|
||||||
delta = ((*ptr++ * preamp) / 100) - r;
|
|
||||||
r += delta;
|
|
||||||
blip_add_delta(snd.blips[0][1], time, delta);
|
|
||||||
|
|
||||||
/* increment time counter */
|
/* increment time counter */
|
||||||
time += fm_cycles_ratio;
|
time += fm_cycles_ratio;
|
||||||
@ -170,15 +168,12 @@ int sound_update(unsigned int cycles)
|
|||||||
/* faster Linear Interpolation */
|
/* faster Linear Interpolation */
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
/* left channel */
|
/* left & right channels */
|
||||||
delta = ((*ptr++ * preamp) / 100) - l;
|
l = ((*ptr++ * preamp) / 100);
|
||||||
l += delta;
|
r = ((*ptr++ * preamp) / 100);
|
||||||
blip_add_delta_fast(snd.blips[0][0], time, delta);
|
blip_add_delta_fast(snd.blips[0], time, l-prev_l, r-prev_r);
|
||||||
|
prev_l = l;
|
||||||
/* right channel */
|
prev_r = r;
|
||||||
delta = ((*ptr++ * preamp) / 100) - r;
|
|
||||||
r += delta;
|
|
||||||
blip_add_delta_fast(snd.blips[0][1], time, delta);
|
|
||||||
|
|
||||||
/* increment time counter */
|
/* increment time counter */
|
||||||
time += fm_cycles_ratio;
|
time += fm_cycles_ratio;
|
||||||
@ -190,18 +185,17 @@ int sound_update(unsigned int cycles)
|
|||||||
fm_ptr = fm_buffer;
|
fm_ptr = fm_buffer;
|
||||||
|
|
||||||
/* save last FM output for next frame */
|
/* save last FM output for next frame */
|
||||||
fm_last[0] = l;
|
fm_last[0] = prev_l;
|
||||||
fm_last[1] = r;
|
fm_last[1] = prev_r;
|
||||||
|
|
||||||
/* adjust FM cycle counters for next frame */
|
/* adjust FM cycle counters for next frame */
|
||||||
fm_cycles_count = fm_cycles_start = time - cycles;
|
fm_cycles_count = fm_cycles_start = time - cycles;
|
||||||
|
|
||||||
/* end of blip buffers time frame */
|
/* end of blip buffer time frame */
|
||||||
blip_end_frame(snd.blips[0][0], cycles);
|
blip_end_frame(snd.blips[0], cycles);
|
||||||
blip_end_frame(snd.blips[0][1], cycles);
|
|
||||||
|
|
||||||
/* return number of available samples */
|
/* 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)
|
int sound_context_save(uint8 *state)
|
||||||
@ -217,7 +211,7 @@ int sound_context_save(uint8 *state)
|
|||||||
save_param(YM2413GetContextPtr(),YM2413GetContextSize());
|
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));
|
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(YM2413GetContextPtr(),YM2413GetContextSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
load_param(SN76489_GetContextPtr(),SN76489_GetContextSize());
|
bufferptr += psg_context_load(&state[bufferptr]);
|
||||||
|
|
||||||
load_param(&fm_cycles_start,sizeof(fm_cycles_start));
|
load_param(&fm_cycles_start,sizeof(fm_cycles_start));
|
||||||
fm_cycles_count = fm_cycles_start;
|
fm_cycles_count = fm_cycles_start;
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
* Genesis Plus
|
* Genesis Plus
|
||||||
* Sound Hardware
|
* Sound Hardware
|
||||||
*
|
*
|
||||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald (original code)
|
* Copyright (C) 1998-2003 Charles Mac Donald (original code)
|
||||||
* 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
|
* Redistribution and use of this code or any derivative works are permitted
|
||||||
* provided that the following conditions are met:
|
* provided that the following conditions are met:
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
* Genesis Plus
|
* Genesis Plus
|
||||||
* Savestate support
|
* 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
|
* Redistribution and use of this code or any derivative works are permitted
|
||||||
* provided that the following conditions are met:
|
* provided that the following conditions are met:
|
||||||
@ -116,11 +116,11 @@ int state_load(unsigned char *state)
|
|||||||
bufferptr += sound_context_load(&state[bufferptr]);
|
bufferptr += sound_context_load(&state[bufferptr]);
|
||||||
if ((system_hw & SYSTEM_PBC) == SYSTEM_MD)
|
if ((system_hw & SYSTEM_PBC) == SYSTEM_MD)
|
||||||
{
|
{
|
||||||
SN76489_Config(0, config.psg_preamp, config.psgBoostNoise, 0xff);
|
psg_config(0, config.psg_preamp, 0xff);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
SN76489_Config(0, config.psg_preamp, config.psgBoostNoise, io_reg[6]);
|
psg_config(0, config.psg_preamp, io_reg[6]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 68000 */
|
/* 68000 */
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
* Genesis Plus
|
* Genesis Plus
|
||||||
* Savestate support
|
* 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
|
* Redistribution and use of this code or any derivative works are permitted
|
||||||
* provided that the following conditions are met:
|
* provided that the following conditions are met:
|
||||||
|
176
core/system.c
176
core/system.c
@ -68,11 +68,9 @@ int audio_init(int samplerate, double framerate)
|
|||||||
memset(&snd, 0, sizeof (snd));
|
memset(&snd, 0, sizeof (snd));
|
||||||
|
|
||||||
/* Initialize Blip Buffers */
|
/* Initialize Blip Buffers */
|
||||||
snd.blips[0][0] = blip_new(samplerate / 10);
|
snd.blips[0] = blip_new(samplerate / 10);
|
||||||
snd.blips[0][1] = blip_new(samplerate / 10);
|
if (!snd.blips[0])
|
||||||
if (!snd.blips[0][0] || !snd.blips[0][1])
|
|
||||||
{
|
{
|
||||||
audio_shutdown();
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,11 +78,9 @@ int audio_init(int samplerate, double framerate)
|
|||||||
if (system_hw == SYSTEM_MCD)
|
if (system_hw == SYSTEM_MCD)
|
||||||
{
|
{
|
||||||
/* allocate blip buffers */
|
/* allocate blip buffers */
|
||||||
snd.blips[1][0] = blip_new(samplerate / 10);
|
snd.blips[1] = blip_new(samplerate / 10);
|
||||||
snd.blips[1][1] = blip_new(samplerate / 10);
|
snd.blips[2] = blip_new(samplerate / 10);
|
||||||
snd.blips[2][0] = blip_new(samplerate / 10);
|
if (!snd.blips[1] || !snd.blips[2])
|
||||||
snd.blips[2][1] = blip_new(samplerate / 10);
|
|
||||||
if (!snd.blips[1][0] || !snd.blips[1][1] || !snd.blips[2][0] || !snd.blips[2][1])
|
|
||||||
{
|
{
|
||||||
audio_shutdown();
|
audio_shutdown();
|
||||||
return -1;
|
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 */
|
/* master clock timebase so they remain perfectly synchronized together, while still */
|
||||||
/* being synchronized with 68K and Z80 CPUs as well. Mixed sound chip output is then */
|
/* being synchronized with 68K and Z80 CPUs as well. Mixed sound chip output is then */
|
||||||
/* resampled to desired rate at the end of each frame, using Blip Buffer. */
|
/* 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], mclk, samplerate);
|
||||||
blip_set_rates(snd.blips[0][1], mclk, samplerate);
|
|
||||||
|
|
||||||
/* Mega CD sound hardware */
|
/* Mega CD sound hardware */
|
||||||
if (system_hw == SYSTEM_MCD)
|
if (system_hw == SYSTEM_MCD)
|
||||||
@ -155,17 +150,14 @@ void audio_set_rate(int samplerate, double framerate)
|
|||||||
|
|
||||||
void audio_reset(void)
|
void audio_reset(void)
|
||||||
{
|
{
|
||||||
int i,j;
|
int i;
|
||||||
|
|
||||||
/* Clear blip buffers */
|
/* Clear blip buffers */
|
||||||
for (i=0; i<3; i++)
|
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]);
|
||||||
{
|
|
||||||
blip_clear(snd.blips[i][j]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -187,16 +179,13 @@ void audio_set_equalizer(void)
|
|||||||
|
|
||||||
void audio_shutdown(void)
|
void audio_shutdown(void)
|
||||||
{
|
{
|
||||||
int i,j;
|
int i;
|
||||||
|
|
||||||
/* Delete blip buffers */
|
/* Delete blip buffers */
|
||||||
for (i=0; i<3; i++)
|
for (i=0; i<3; i++)
|
||||||
{
|
{
|
||||||
for (j=0; j<2; j++)
|
blip_delete(snd.blips[i]);
|
||||||
{
|
snd.blips[i] = 0;
|
||||||
blip_delete(snd.blips[i][j]);
|
|
||||||
snd.blips[i][j] = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -213,37 +202,24 @@ int audio_update(int16 *buffer)
|
|||||||
|
|
||||||
/* read CDDA samples */
|
/* read CDDA samples */
|
||||||
cdd_read_audio(size);
|
cdd_read_audio(size);
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef ALIGN_SND
|
#ifdef ALIGN_SND
|
||||||
/* return an aligned number of samples if required */
|
/* return an aligned number of samples if required */
|
||||||
size &= ALIGN_SND;
|
size &= ALIGN_SND;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* resample FM & PSG mixed stream to output buffer */
|
/* resample & mix FM/PSG, PCM & CD-DA streams to output buffer */
|
||||||
#ifdef LSB_FIRST
|
blip_mix_samples(snd.blips[0], snd.blips[1], snd.blips[2], buffer, size);
|
||||||
blip_read_samples(snd.blips[0][0], buffer, size);
|
}
|
||||||
blip_read_samples(snd.blips[0][1], buffer + 1, size);
|
else
|
||||||
#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 PCM & CD-DA streams to output buffer */
|
#ifdef ALIGN_SND
|
||||||
#ifdef LSB_FIRST
|
/* return an aligned number of samples if required */
|
||||||
blip_mix_samples(snd.blips[1][0], buffer, size);
|
size &= ALIGN_SND;
|
||||||
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);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* resample FM/PSG mixed stream to output buffer */
|
||||||
|
blip_read_samples(snd.blips[0], buffer, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Audio filtering */
|
/* Audio filtering */
|
||||||
@ -434,13 +410,10 @@ void system_frame_gen(int do_skip)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* initialize VCounter */
|
|
||||||
v_counter = bitmap.viewport.h;
|
|
||||||
|
|
||||||
/* first line of overscan */
|
/* first line of overscan */
|
||||||
if (bitmap.viewport.y)
|
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 */
|
/* 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) */
|
/* refresh inputs just before VINT (Warriors of Eternal Sun) */
|
||||||
osd_input_update();
|
osd_input_update();
|
||||||
|
|
||||||
/* delay between VBLANK flag & Vertical Interrupt (Dracula, OutRunners, VR Troopers) */
|
/* VDP always starts after VBLANK so VINT cannot occur on first frame after a VDP reset (verified on real hardware) */
|
||||||
m68k_run(788);
|
if (v_counter != bitmap.viewport.h)
|
||||||
if (zstate == 1)
|
|
||||||
{
|
{
|
||||||
z80_run(788);
|
/* reinitialize VCounter */
|
||||||
}
|
v_counter = bitmap.viewport.h;
|
||||||
else
|
|
||||||
{
|
|
||||||
Z80.cycles = 788;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* set VINT flag */
|
/* delay between VBLANK flag & Vertical Interrupt (Dracula, OutRunners, VR Troopers) */
|
||||||
status |= 0x80;
|
m68k_run(788);
|
||||||
|
if (zstate == 1)
|
||||||
|
{
|
||||||
|
z80_run(788);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Z80.cycles = 788;
|
||||||
|
}
|
||||||
|
|
||||||
/* Vertical Interrupt */
|
/* set VINT flag */
|
||||||
vint_pending = 0x20;
|
status |= 0x80;
|
||||||
if (reg[1] & 0x20)
|
|
||||||
{
|
/* Vertical Interrupt */
|
||||||
/* level 6 interrupt */
|
vint_pending = 0x20;
|
||||||
m68k_set_irq(6);
|
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 */
|
/* run 68k & Z80 until end of line */
|
||||||
m68k_run(MCYCLES_PER_LINE);
|
m68k_run(MCYCLES_PER_LINE);
|
||||||
if (zstate == 1)
|
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 */
|
/* first line of overscan */
|
||||||
if (bitmap.viewport.y)
|
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 */
|
/* clear DMA Busy, FIFO FULL & field flags */
|
||||||
@ -836,31 +813,38 @@ void system_frame_scd(int do_skip)
|
|||||||
/* refresh inputs just before VINT */
|
/* refresh inputs just before VINT */
|
||||||
osd_input_update();
|
osd_input_update();
|
||||||
|
|
||||||
/* delay between VBLANK flag & Vertical Interrupt (Dracula, OutRunners, VR Troopers) */
|
/* VDP always starts after VBLANK so VINT cannot occur on first frame after a VDP reset (verified on real hardware) */
|
||||||
m68k_run(788);
|
if (v_counter != bitmap.viewport.h)
|
||||||
if (zstate == 1)
|
|
||||||
{
|
{
|
||||||
z80_run(788);
|
/* reinitialize VCounter */
|
||||||
}
|
v_counter = bitmap.viewport.h;
|
||||||
else
|
|
||||||
{
|
|
||||||
Z80.cycles = 788;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* set VINT flag */
|
/* delay between VBLANK flag & Vertical Interrupt (Dracula, OutRunners, VR Troopers) */
|
||||||
status |= 0x80;
|
m68k_run(788);
|
||||||
|
if (zstate == 1)
|
||||||
|
{
|
||||||
|
z80_run(788);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Z80.cycles = 788;
|
||||||
|
}
|
||||||
|
|
||||||
/* Vertical Interrupt */
|
/* set VINT flag */
|
||||||
vint_pending = 0x20;
|
status |= 0x80;
|
||||||
if (reg[1] & 0x20)
|
|
||||||
{
|
/* Vertical Interrupt */
|
||||||
/* level 6 interrupt */
|
vint_pending = 0x20;
|
||||||
m68k_set_irq(6);
|
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 */
|
/* run both 68k & CD hardware until end of line */
|
||||||
scd_update(MCYCLES_PER_LINE);
|
scd_update(MCYCLES_PER_LINE);
|
||||||
|
|
||||||
|
@ -91,7 +91,7 @@ typedef struct
|
|||||||
int sample_rate; /* Output Sample rate (8000-48000) */
|
int sample_rate; /* Output Sample rate (8000-48000) */
|
||||||
double frame_rate; /* Output Frame rate (usually 50 or 60 frames per second) */
|
double frame_rate; /* Output Frame rate (usually 50 or 60 frames per second) */
|
||||||
int enabled; /* 1= sound emulation is enabled */
|
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;
|
} t_snd;
|
||||||
|
|
||||||
|
|
||||||
|
@ -71,7 +71,7 @@ OBJECTS += $(OBJDIR)/input.o \
|
|||||||
$(OBJDIR)/graphic_board.o
|
$(OBJDIR)/graphic_board.o
|
||||||
|
|
||||||
OBJECTS += $(OBJDIR)/sound.o \
|
OBJECTS += $(OBJDIR)/sound.o \
|
||||||
$(OBJDIR)/sn76489.o \
|
$(OBJDIR)/psg.o \
|
||||||
$(OBJDIR)/ym2413.o \
|
$(OBJDIR)/ym2413.o \
|
||||||
$(OBJDIR)/ym2612.o
|
$(OBJDIR)/ym2612.o
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ void set_config_defaults(void)
|
|||||||
config.psg_preamp = 150;
|
config.psg_preamp = 150;
|
||||||
config.fm_preamp = 100;
|
config.fm_preamp = 100;
|
||||||
config.hq_fm = 1;
|
config.hq_fm = 1;
|
||||||
config.psgBoostNoise = 1;
|
config.hq_psg = 1;
|
||||||
config.filter = 1;
|
config.filter = 1;
|
||||||
config.low_freq = 200;
|
config.low_freq = 200;
|
||||||
config.high_freq = 8000;
|
config.high_freq = 8000;
|
||||||
|
@ -20,7 +20,7 @@ typedef struct
|
|||||||
{
|
{
|
||||||
uint8 hq_fm;
|
uint8 hq_fm;
|
||||||
uint8 filter;
|
uint8 filter;
|
||||||
uint8 psgBoostNoise;
|
uint8 hq_psg;
|
||||||
uint8 dac_bits;
|
uint8 dac_bits;
|
||||||
uint8 ym2413;
|
uint8 ym2413;
|
||||||
int16 psg_preamp;
|
int16 psg_preamp;
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* Genesis Plus GX configuration file support
|
* 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
|
* Redistribution and use of this code or any derivative works are permitted
|
||||||
* provided that the following conditions are met:
|
* provided that the following conditions are met:
|
||||||
@ -101,7 +101,7 @@ void config_default(void)
|
|||||||
config.psg_preamp = 150;
|
config.psg_preamp = 150;
|
||||||
config.fm_preamp = 100;
|
config.fm_preamp = 100;
|
||||||
config.hq_fm = 1;
|
config.hq_fm = 1;
|
||||||
config.psgBoostNoise = 1;
|
config.hq_psg = 1;
|
||||||
config.filter = 1;
|
config.filter = 1;
|
||||||
config.lp_range = 0x9999; /* 0.6 in 16.16 fixed point */
|
config.lp_range = 0x9999; /* 0.6 in 16.16 fixed point */
|
||||||
config.low_freq = 880;
|
config.low_freq = 880;
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* Genesis Plus GX configuration file support
|
* 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
|
* Redistribution and use of this code or any derivative works are permitted
|
||||||
* provided that the following conditions are met:
|
* provided that the following conditions are met:
|
||||||
@ -51,7 +51,7 @@ typedef struct
|
|||||||
char version[16];
|
char version[16];
|
||||||
uint8 hq_fm;
|
uint8 hq_fm;
|
||||||
uint8 filter;
|
uint8 filter;
|
||||||
uint8 psgBoostNoise;
|
uint8 hq_psg;
|
||||||
uint8 dac_bits;
|
uint8 dac_bits;
|
||||||
uint8 ym2413;
|
uint8 ym2413;
|
||||||
uint8 mono;
|
uint8 mono;
|
||||||
|
104
gx/gui/menu.c
104
gx/gui/menu.c
@ -341,19 +341,19 @@ static gui_item items_options[] =
|
|||||||
/* Audio options */
|
/* Audio options */
|
||||||
static gui_item items_audio[] =
|
static gui_item items_audio[] =
|
||||||
{
|
{
|
||||||
{NULL,NULL,"Master System FM: AUTO", "Enable/disable YM2413 chip", 56,132,276,48},
|
{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,"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 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,"FM Volume: 1.00", "Adjust YM2612/YM2413 audio balance", 56,132,276,48},
|
||||||
{NULL,NULL,"PSG Volume: 2.50", "Adjust SN76489 output level", 56,132,276,48},
|
{NULL,NULL,"PSG Volume: 2.50", "Adjust SN76489 audio balance", 56,132,276,48},
|
||||||
{NULL,NULL,"PSG Noise Boost: OFF", "Boost SN76489 Noise Channel", 56,132,276,48},
|
{NULL,NULL,"High-Quality PSG: ON", "Enable/Disable SN76489 high-quality resampling", 56,132,276,48},
|
||||||
{NULL,NULL,"Audio Out: STEREO", "Select audio mixing output type", 56,132,276,48},
|
{NULL,NULL,"Audio Output: 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,"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,"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,"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,"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,"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,"High Freq: 20000 Hz", "Adjust EQ Highest Frequency", 56,132,276,48}
|
||||||
};
|
};
|
||||||
|
|
||||||
/* System ROM paths */
|
/* 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,"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 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 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,"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,"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,"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,"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}
|
{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,"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,"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,"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,"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,"Deflickering Filter: AUTO", "Enable/Disable GX hardware framebuffer filtering", 56,132,276,48},
|
||||||
#ifdef HW_RVL
|
#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},
|
{NULL,NULL,"Gamma Correction: 1.0", "Adjust VI hardware gamma correction", 56,132,276,48},
|
||||||
#endif
|
#endif
|
||||||
{NULL,NULL,"LCD Ghosting Filter: OFF", "Enable/disable software LCD image persistence", 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 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 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 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 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 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,"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,"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,"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,"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 Position (+0,+0)", "Adjust display position", 56,132,276,48},
|
||||||
{NULL,NULL,"Screen Scaling (+0,+0)", "Adjust display scaling", 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 */
|
/* Menu options */
|
||||||
static gui_item items_prefs[] =
|
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 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 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 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,"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,"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,"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,"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,"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 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 FPS: OFF", "Enable/Disable FPS counter", 56,132,276,48},
|
||||||
#ifdef HW_RVL
|
#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},
|
{NULL,NULL,"Wiimote Calibration: AUTO","Calibrate Wii remote pointer", 56,132,276,48},
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
@ -899,16 +899,15 @@ static void soundmenu ()
|
|||||||
else if (config.ym2413 == 1) sprintf (items[0].text, "Master System FM: ON");
|
else if (config.ym2413 == 1) sprintf (items[0].text, "Master System FM: ON");
|
||||||
else sprintf (items[0].text, "Master System FM: AUTO");
|
else sprintf (items[0].text, "Master System FM: AUTO");
|
||||||
|
|
||||||
if (config.hq_fm) sprintf (items[1].text, "High-Quality FM: ON");
|
sprintf (items[1].text, "High-Quality FM: %s", config.hq_fm ? "ON":"OFF");
|
||||||
else sprintf (items[1].text, "High-Quality FM: OFF");
|
|
||||||
|
|
||||||
if (config.dac_bits < 14) sprintf (items[2].text, "FM Resolution: %d bits", config.dac_bits);
|
if (config.dac_bits < 14) sprintf (items[2].text, "FM Resolution: %d bits", config.dac_bits);
|
||||||
else sprintf (items[2].text, "FM Resolution: MAX");
|
else sprintf (items[2].text, "FM Resolution: MAX");
|
||||||
|
|
||||||
sprintf (items[3].text, "FM Volume: %1.2f", fm_volume);
|
sprintf (items[3].text, "FM Volume: %1.2f", fm_volume);
|
||||||
sprintf (items[4].text, "PSG Volume: %1.2f", psg_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[5].text, "High-Quality PSG: %s", config.hq_psg? "ON":"OFF");
|
||||||
sprintf (items[6].text, "Audio Out: %s", config.mono ? "MONO":"STEREO");
|
sprintf (items[6].text, "Audio Output: %s", config.mono ? "MONO":"STEREO");
|
||||||
|
|
||||||
if (config.filter == 2)
|
if (config.filter == 2)
|
||||||
{
|
{
|
||||||
@ -971,8 +970,7 @@ static void soundmenu ()
|
|||||||
case 1:
|
case 1:
|
||||||
{
|
{
|
||||||
config.hq_fm ^= 1;
|
config.hq_fm ^= 1;
|
||||||
if (config.hq_fm) sprintf (items[1].text, "High-Quality FM: ON");
|
sprintf (items[1].text, "High-Quality FM: %s", config.hq_fm ? "ON":"OFF");
|
||||||
else sprintf (items[1].text, "High-Quality FM: OFF");
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1001,27 +999,19 @@ static void soundmenu ()
|
|||||||
config.psg_preamp = (int)(psg_volume * 100.0 + 0.5);
|
config.psg_preamp = (int)(psg_volume * 100.0 + 0.5);
|
||||||
if ((system_hw & SYSTEM_PBC) == SYSTEM_MD)
|
if ((system_hw & SYSTEM_PBC) == SYSTEM_MD)
|
||||||
{
|
{
|
||||||
SN76489_Config(0, config.psg_preamp, config.psgBoostNoise, 0xff);
|
psg_config(0, config.psg_preamp, 0xff);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
SN76489_Config(0, config.psg_preamp, config.psgBoostNoise, io_reg[6]);
|
psg_config(0, config.psg_preamp, io_reg[6]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 5:
|
case 5:
|
||||||
{
|
{
|
||||||
config.psgBoostNoise ^= 1;
|
config.hq_psg ^= 1;
|
||||||
sprintf (items[5].text, "PSG Noise Boost: %s", config.psgBoostNoise ? "ON":"OFF");
|
sprintf (items[5].text, "High-Quality PSG: %s", config.hq_psg ? "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]);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1745,8 +1735,8 @@ static void videomenu ()
|
|||||||
else
|
else
|
||||||
sprintf (items[VI_OFFSET+1].text, "NTSC Filter: OFF");
|
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+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+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+4+ntsc_offset].comment, "Select display aspect ratio");
|
||||||
strcpy(items[VI_OFFSET+5+ntsc_offset].comment, "Adjust display position");
|
strcpy(items[VI_OFFSET+5+ntsc_offset].comment, "Adjust display position");
|
||||||
strcpy(items[VI_OFFSET+6+ntsc_offset].comment, "Adjust display scaling");
|
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);
|
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("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 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 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 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 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, 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, 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, 642 - offset, (GXColor)WHITE);
|
||||||
FONT_writeCenter("3-Band EQ implementation by Neil C", 18, 0, 640, 660 - 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("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);
|
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("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("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("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("devkitPPC by Wintermute", 18, 0, 640, 1050 - offset, (GXColor)WHITE);
|
||||||
|
|
||||||
FONT_writeCenter("Special thanks to ...", 20, 0, 640, 1090 - offset, (GXColor)LIGHT_GREEN);
|
FONT_writeCenter("Special thanks to ...", 20, 0, 640, 1090 - offset, (GXColor)LIGHT_GREEN);
|
||||||
|
@ -13,7 +13,7 @@ Upstream Authors:
|
|||||||
Files: *
|
Files: *
|
||||||
Copyright: 1998, 1999, 2000, 2001, 2002, 2003 Charles MacDonald
|
Copyright: 1998, 1999, 2000, 2001, 2002, 2003 Charles MacDonald
|
||||||
Some portions copyright Nicola Salmoria and the MAME team. All rights reserved.
|
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:
|
License:
|
||||||
Unless otherwise explicitly stated, all code in Genesis Plus GX is released
|
Unless otherwise explicitly stated, all code in Genesis Plus GX is released
|
||||||
under the following license:
|
under the following license:
|
||||||
@ -77,7 +77,6 @@ License: LGPLv2.1
|
|||||||
Files: core/sound/blip_buf.c
|
Files: core/sound/blip_buf.c
|
||||||
core/sound/blip_buf.h
|
core/sound/blip_buf.h
|
||||||
Copyright: 2003-2009 Shay Green
|
Copyright: 2003-2009 Shay Green
|
||||||
2012-2013 EkeEke
|
|
||||||
License: LGPLv2.1
|
License: LGPLv2.1
|
||||||
|
|
||||||
Files: core/sound/eq.c
|
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
|
The author assumes NO RESPONSIBILITY for any problems caused by the use of
|
||||||
this software.
|
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
|
Files: core/sound/ym2413.c
|
||||||
core/sound/ym2413.h
|
core/sound/ym2413.h
|
||||||
Copyright: 2002 Jarek Burczynski
|
Copyright: 2002 Jarek Burczynski
|
||||||
|
@ -97,6 +97,7 @@ char CART_BRAM[256];
|
|||||||
|
|
||||||
static int vwidth;
|
static int vwidth;
|
||||||
static int vheight;
|
static int vheight;
|
||||||
|
static double vaspect_ratio;
|
||||||
|
|
||||||
static uint32_t brm_crc[2];
|
static uint32_t brm_crc[2];
|
||||||
static uint8_t brm_format[0x40] =
|
static uint8_t brm_format[0x40] =
|
||||||
@ -494,8 +495,8 @@ static void config_default(void)
|
|||||||
/* sound options */
|
/* sound options */
|
||||||
config.psg_preamp = 150;
|
config.psg_preamp = 150;
|
||||||
config.fm_preamp = 100;
|
config.fm_preamp = 100;
|
||||||
config.hq_fm = 1; /* high-quality resampling */
|
config.hq_fm = 1; /* high-quality FM resampling (slower) */
|
||||||
config.psgBoostNoise = 1;
|
config.hq_psg = 1; /* high-quality PSG resampling (slower) */
|
||||||
config.filter = 0; /* no filter */
|
config.filter = 0; /* no filter */
|
||||||
config.lp_range = 0x9999; /* 0.6 in 16.16 fixed point */
|
config.lp_range = 0x9999; /* 0.6 in 16.16 fixed point */
|
||||||
config.low_freq = 880;
|
config.low_freq = 880;
|
||||||
@ -503,7 +504,7 @@ static void config_default(void)
|
|||||||
config.lg = 1.0;
|
config.lg = 1.0;
|
||||||
config.mg = 1.0;
|
config.mg = 1.0;
|
||||||
config.hg = 1.0;
|
config.hg = 1.0;
|
||||||
config.dac_bits = 14; /* MAX DEPTH */
|
config.dac_bits = 14; /* MAX DEPTH */
|
||||||
config.ym2413 = 2; /* AUTO */
|
config.ym2413 = 2; /* AUTO */
|
||||||
config.mono = 0; /* STEREO output */
|
config.mono = 0; /* STEREO output */
|
||||||
|
|
||||||
@ -520,6 +521,7 @@ static void config_default(void)
|
|||||||
|
|
||||||
/* video options */
|
/* video options */
|
||||||
config.overscan = 0;
|
config.overscan = 0;
|
||||||
|
config.aspect_ratio = 0;
|
||||||
config.gg_extra = 0;
|
config.gg_extra = 0;
|
||||||
config.ntsc = 0;
|
config.ntsc = 0;
|
||||||
config.lcd = 0;
|
config.lcd = 0;
|
||||||
@ -736,13 +738,46 @@ static void extract_directory(char *buf, const char *path, size_t size)
|
|||||||
buf[0] = '\0';
|
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)
|
static bool update_viewport(void)
|
||||||
{
|
{
|
||||||
int ow = vwidth;
|
int ow = vwidth;
|
||||||
int oh = vheight;
|
int oh = vheight;
|
||||||
|
double oar = vaspect_ratio;
|
||||||
|
|
||||||
vwidth = bitmap.viewport.w + (bitmap.viewport.x * 2);
|
vwidth = bitmap.viewport.w + (bitmap.viewport.x * 2);
|
||||||
vheight = bitmap.viewport.h + (bitmap.viewport.y * 2);
|
vheight = bitmap.viewport.h + (bitmap.viewport.y * 2);
|
||||||
|
vaspect_ratio = calculate_display_aspect_ratio();
|
||||||
|
|
||||||
if (config.ntsc)
|
if (config.ntsc)
|
||||||
{
|
{
|
||||||
@ -756,8 +791,7 @@ static bool update_viewport(void)
|
|||||||
{
|
{
|
||||||
vheight = vheight * 2;
|
vheight = vheight * 2;
|
||||||
}
|
}
|
||||||
|
return ((ow != vwidth) || (oh != vheight) || (oar != vaspect_ratio));
|
||||||
return ((ow != vwidth) || (oh != vheight));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void check_variables(void)
|
static void check_variables(void)
|
||||||
@ -933,12 +967,7 @@ static void check_variables(void)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* force overscan change */
|
update_viewports = true;
|
||||||
bitmap.viewport.changed = 3;
|
|
||||||
|
|
||||||
/* reinitialize libretro audio/video timings */
|
|
||||||
retro_get_system_av_info(&info);
|
|
||||||
environ_cb(RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO, &info);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1088,6 +1117,20 @@ static void check_variables(void)
|
|||||||
update_viewports = true;
|
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";
|
var.key = "genesis_plus_gx_render";
|
||||||
environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var);
|
environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var);
|
||||||
{
|
{
|
||||||
@ -1125,11 +1168,12 @@ static void check_variables(void)
|
|||||||
system_init();
|
system_init();
|
||||||
system_reset();
|
system_reset();
|
||||||
memcpy(sram.sram, temp, sizeof(temp));
|
memcpy(sram.sram, temp, sizeof(temp));
|
||||||
|
update_viewports = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (update_viewports)
|
if (update_viewports)
|
||||||
{
|
{
|
||||||
bitmap.viewport.changed = 3;
|
bitmap.viewport.changed = 11;
|
||||||
if ((system_hw == SYSTEM_GG) && !config.gg_extra)
|
if ((system_hw == SYSTEM_GG) && !config.gg_extra)
|
||||||
bitmap.viewport.x = (config.overscan & 2) ? 14 : -48;
|
bitmap.viewport.x = (config.overscan & 2) ? 14 : -48;
|
||||||
else
|
else
|
||||||
@ -1475,7 +1519,7 @@ unsigned retro_api_version(void) { return RETRO_API_VERSION; }
|
|||||||
|
|
||||||
void retro_set_environment(retro_environment_t cb)
|
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_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_region_detect", "System region; auto|ntsc-u|pal|ntsc-j" },
|
||||||
{ "genesis_plus_gx_force_dtack", "System lockups; enabled|disabled" },
|
{ "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_lcd_filter", "LCD Ghosting filter; disabled|enabled" },
|
||||||
{ "genesis_plus_gx_overscan", "Borders; disabled|top/bottom|left/right|full" },
|
{ "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_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_render", "Interlaced mode 2 output; single field|double field" },
|
||||||
{ "genesis_plus_gx_gun_cursor", "Show Lightgun crosshair; no|yes" },
|
{ "genesis_plus_gx_gun_cursor", "Show Lightgun crosshair; no|yes" },
|
||||||
{ "genesis_plus_gx_invert_mouse", "Invert Mouse Y-axis; no|yes" },
|
{ "genesis_plus_gx_invert_mouse", "Invert Mouse Y-axis; no|yes" },
|
||||||
{ NULL, NULL },
|
{ NULL, NULL },
|
||||||
};
|
};
|
||||||
|
|
||||||
struct retro_controller_description port_1[] = {
|
static const struct retro_controller_description port_1[] = {
|
||||||
{ "Joypad Auto", RETRO_DEVICE_JOYPAD },
|
{ "Joypad Auto", RETRO_DEVICE_JOYPAD },
|
||||||
{ "Joypad Port Empty", RETRO_DEVICE_NONE },
|
{ "Joypad Port Empty", RETRO_DEVICE_NONE },
|
||||||
{ "MD Joypad 3 Button", RETRO_DEVICE_MDPAD_3B },
|
{ "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 },
|
{ "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 Auto", RETRO_DEVICE_JOYPAD },
|
||||||
{ "Joypad Port Empty", RETRO_DEVICE_NONE },
|
{ "Joypad Port Empty", RETRO_DEVICE_NONE },
|
||||||
{ "MD Joypad 3 Button", RETRO_DEVICE_MDPAD_3B },
|
{ "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 },
|
{ "MD Mouse", RETRO_DEVICE_MOUSE },
|
||||||
};
|
};
|
||||||
|
|
||||||
struct retro_controller_info ports[] = {
|
static const struct retro_controller_info ports[] = {
|
||||||
{ port_1, 16 },
|
{ port_1, 16 },
|
||||||
{ port_2, 18 },
|
{ port_2, 18 },
|
||||||
{ 0 },
|
{ 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_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_UP, "D-Pad Up" },
|
||||||
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "D-Pad Down" },
|
{ 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.base_height = vheight;
|
||||||
info->geometry.max_width = 720;
|
info->geometry.max_width = 720;
|
||||||
info->geometry.max_height = 576;
|
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.fps = (double)(system_clock) / (double)lines_per_frame / (double)MCYCLES_PER_LINE;
|
||||||
info->timing.sample_rate = 44100;
|
info->timing.sample_rate = 44100;
|
||||||
}
|
}
|
||||||
|
|
||||||
void retro_set_controller_port_device(unsigned port, unsigned device)
|
void retro_set_controller_port_device(unsigned port, unsigned device)
|
||||||
{
|
{
|
||||||
|
if (port > 2)
|
||||||
|
return;
|
||||||
|
|
||||||
switch(device)
|
switch(device)
|
||||||
{
|
{
|
||||||
case RETRO_DEVICE_NONE:
|
case RETRO_DEVICE_NONE:
|
||||||
input.system[port] = NO_SYSTEM;
|
input.system[port] = NO_SYSTEM;
|
||||||
break;
|
break;
|
||||||
case RETRO_DEVICE_MDPAD_3B:
|
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;
|
input.system[port] = SYSTEM_GAMEPAD;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case RETRO_DEVICE_MDPAD_6B:
|
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;
|
input.system[port] = SYSTEM_GAMEPAD;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case RETRO_DEVICE_MSPAD_2B:
|
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;
|
input.system[port] = SYSTEM_GAMEPAD;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case RETRO_DEVICE_MDPAD_3B_WAYPLAY:
|
case RETRO_DEVICE_MDPAD_3B_WAYPLAY:
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
@ -1779,9 +1842,14 @@ void retro_set_controller_port_device(unsigned port, unsigned device)
|
|||||||
break;
|
break;
|
||||||
case RETRO_DEVICE_JOYPAD:
|
case RETRO_DEVICE_JOYPAD:
|
||||||
default:
|
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;
|
input.system[port] = SYSTEM_GAMEPAD;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
old_system[0] = input.system[0];
|
old_system[0] = input.system[0];
|
||||||
@ -2082,14 +2150,22 @@ void retro_run(void)
|
|||||||
else
|
else
|
||||||
system_frame_sms(0);
|
system_frame_sms(0);
|
||||||
|
|
||||||
if (bitmap.viewport.changed & 1)
|
if (bitmap.viewport.changed & 9)
|
||||||
{
|
{
|
||||||
|
bool geometry_updated = update_viewport();
|
||||||
bitmap.viewport.changed &= ~1;
|
bitmap.viewport.changed &= ~1;
|
||||||
if (update_viewport())
|
if (bitmap.viewport.changed & 8)
|
||||||
{
|
{
|
||||||
struct retro_system_av_info info;
|
struct retro_system_av_info info;
|
||||||
retro_get_system_av_info(&info);
|
bitmap.viewport.changed &= ~8;
|
||||||
environ_cb(RETRO_ENVIRONMENT_SET_GEOMETRY, &info.geometry);
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -394,7 +394,7 @@
|
|||||||
RelativePath="..\..\..\core\sound\eq.c">
|
RelativePath="..\..\..\core\sound\eq.c">
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\..\core\sound\sn76489.c">
|
RelativePath="..\..\..\core\sound\psg.c">
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\..\core\sound\sound.c">
|
RelativePath="..\..\..\core\sound\sound.c">
|
||||||
|
@ -143,7 +143,7 @@
|
|||||||
<CompileAs Condition="'$(Configuration)|$(Platform)'=='Release_LTCG|Xbox 360'">CompileAsC</CompileAs>
|
<CompileAs Condition="'$(Configuration)|$(Platform)'=='Release_LTCG|Xbox 360'">CompileAsC</CompileAs>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\..\core\sound\eq.c" />
|
<ClCompile Include="..\..\..\core\sound\eq.c" />
|
||||||
<ClCompile Include="..\..\..\core\sound\sn76489.c" />
|
<ClCompile Include="..\..\..\core\sound\psg.c" />
|
||||||
<ClCompile Include="..\..\..\core\sound\sound.c" />
|
<ClCompile Include="..\..\..\core\sound\sound.c" />
|
||||||
<ClCompile Include="..\..\..\core\sound\ym2413.c" />
|
<ClCompile Include="..\..\..\core\sound\ym2413.c" />
|
||||||
<ClCompile Include="..\..\..\core\sound\ym2612.c" />
|
<ClCompile Include="..\..\..\core\sound\ym2612.c" />
|
||||||
|
@ -80,7 +80,7 @@
|
|||||||
<ClCompile Include="..\..\..\core\sound\eq.c">
|
<ClCompile Include="..\..\..\core\sound\eq.c">
|
||||||
<Filter>Source Files\sound</Filter>
|
<Filter>Source Files\sound</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\..\core\sound\sn76489.c">
|
<ClCompile Include="..\..\..\core\sound\psg.c">
|
||||||
<Filter>Source Files\sound</Filter>
|
<Filter>Source Files\sound</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\..\core\sound\sound.c">
|
<ClCompile Include="..\..\..\core\sound\sound.c">
|
||||||
|
@ -49,7 +49,7 @@
|
|||||||
<ClCompile Include="..\..\..\core\ntsc\sms_ntsc.c" />
|
<ClCompile Include="..\..\..\core\ntsc\sms_ntsc.c" />
|
||||||
<ClCompile Include="..\..\..\core\sound\blip_buf.c" />
|
<ClCompile Include="..\..\..\core\sound\blip_buf.c" />
|
||||||
<ClCompile Include="..\..\..\core\sound\eq.c" />
|
<ClCompile Include="..\..\..\core\sound\eq.c" />
|
||||||
<ClCompile Include="..\..\..\core\sound\sn76489.c" />
|
<ClCompile Include="..\..\..\core\sound\psg.c" />
|
||||||
<ClCompile Include="..\..\..\core\sound\sound.c" />
|
<ClCompile Include="..\..\..\core\sound\sound.c" />
|
||||||
<ClCompile Include="..\..\..\core\sound\ym2413.c" />
|
<ClCompile Include="..\..\..\core\sound\ym2413.c" />
|
||||||
<ClCompile Include="..\..\..\core\sound\ym2612.c" />
|
<ClCompile Include="..\..\..\core\sound\ym2612.c" />
|
||||||
|
@ -117,7 +117,7 @@
|
|||||||
<ClCompile Include="..\..\..\core\sound\eq.c">
|
<ClCompile Include="..\..\..\core\sound\eq.c">
|
||||||
<Filter>Source Files\sound</Filter>
|
<Filter>Source Files\sound</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\..\core\sound\sn76489.c">
|
<ClCompile Include="..\..\..\core\sound\psg.c">
|
||||||
<Filter>Source Files\sound</Filter>
|
<Filter>Source Files\sound</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\..\core\sound\sound.c">
|
<ClCompile Include="..\..\..\core\sound\sound.c">
|
||||||
|
@ -84,7 +84,7 @@ struct
|
|||||||
char version[16];
|
char version[16];
|
||||||
uint8 hq_fm;
|
uint8 hq_fm;
|
||||||
uint8 filter;
|
uint8 filter;
|
||||||
uint8 psgBoostNoise;
|
uint8 hq_psg;
|
||||||
uint8 dac_bits;
|
uint8 dac_bits;
|
||||||
uint8 ym2413;
|
uint8 ym2413;
|
||||||
uint8 mono;
|
uint8 mono;
|
||||||
@ -105,6 +105,7 @@ struct
|
|||||||
uint8 bios;
|
uint8 bios;
|
||||||
uint8 lock_on;
|
uint8 lock_on;
|
||||||
uint8 overscan;
|
uint8 overscan;
|
||||||
|
uint8 aspect_ratio;
|
||||||
uint8 ntsc;
|
uint8 ntsc;
|
||||||
uint8 lcd;
|
uint8 lcd;
|
||||||
uint8 gg_extra;
|
uint8 gg_extra;
|
||||||
|
@ -69,7 +69,7 @@ OBJECTS += $(OBJDIR)/input.o \
|
|||||||
$(OBJDIR)/graphic_board.o
|
$(OBJDIR)/graphic_board.o
|
||||||
|
|
||||||
OBJECTS += $(OBJDIR)/sound.o \
|
OBJECTS += $(OBJDIR)/sound.o \
|
||||||
$(OBJDIR)/sn76489.o \
|
$(OBJDIR)/psg.o \
|
||||||
$(OBJDIR)/ym2413.o \
|
$(OBJDIR)/ym2413.o \
|
||||||
$(OBJDIR)/ym2612.o
|
$(OBJDIR)/ym2612.o
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ void set_config_defaults(void)
|
|||||||
config.psg_preamp = 150;
|
config.psg_preamp = 150;
|
||||||
config.fm_preamp = 100;
|
config.fm_preamp = 100;
|
||||||
config.hq_fm = 0;
|
config.hq_fm = 0;
|
||||||
config.psgBoostNoise = 1;
|
config.hq_psg = 0;
|
||||||
config.filter = 1;
|
config.filter = 1;
|
||||||
config.low_freq = 200;
|
config.low_freq = 200;
|
||||||
config.high_freq = 8000;
|
config.high_freq = 8000;
|
||||||
|
@ -19,7 +19,7 @@ typedef struct
|
|||||||
{
|
{
|
||||||
uint8 hq_fm;
|
uint8 hq_fm;
|
||||||
uint8 filter;
|
uint8 filter;
|
||||||
uint8 psgBoostNoise;
|
uint8 hq_psg;
|
||||||
uint8 dac_bits;
|
uint8 dac_bits;
|
||||||
uint8 ym2413;
|
uint8 ym2413;
|
||||||
int16 psg_preamp;
|
int16 psg_preamp;
|
||||||
|
@ -19,17 +19,21 @@
|
|||||||
# -D16BPP_RENDERING - configure for 16-bit pixels (RGB565)
|
# -D16BPP_RENDERING - configure for 16-bit pixels (RGB565)
|
||||||
# -D32BPP_RENDERING - configure for 32-bit pixels (RGB888)
|
# -D32BPP_RENDERING - configure for 32-bit pixels (RGB888)
|
||||||
|
|
||||||
NAME = gen_sdl.exe
|
NAME = gen_sdl
|
||||||
|
|
||||||
CC = gcc
|
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
|
#-g -ggdb -pg
|
||||||
#-fomit-frame-pointer
|
#-fomit-frame-pointer
|
||||||
#LDFLAGS = -pg
|
#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
|
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
|
LIBS = `sdl-config --libs` -lz -lm
|
||||||
|
|
||||||
OBJDIR = ./build_sdl
|
OBJDIR = ./build_sdl
|
||||||
@ -63,7 +67,7 @@ OBJECTS += $(OBJDIR)/input.o \
|
|||||||
$(OBJDIR)/graphic_board.o
|
$(OBJDIR)/graphic_board.o
|
||||||
|
|
||||||
OBJECTS += $(OBJDIR)/sound.o \
|
OBJECTS += $(OBJDIR)/sound.o \
|
||||||
$(OBJDIR)/sn76489.o \
|
$(OBJDIR)/psg.o \
|
||||||
$(OBJDIR)/ym2413.o \
|
$(OBJDIR)/ym2413.o \
|
||||||
$(OBJDIR)/ym2612.o
|
$(OBJDIR)/ym2612.o
|
||||||
|
|
||||||
@ -114,7 +118,9 @@ OBJECTS += $(OBJDIR)/bitwise.o \
|
|||||||
$(OBJDIR)/vorbisfile.o \
|
$(OBJDIR)/vorbisfile.o \
|
||||||
$(OBJDIR)/window.o
|
$(OBJDIR)/window.o
|
||||||
|
|
||||||
|
ifeq ($(OS),Windows_NT)
|
||||||
OBJECTS += $(OBJDIR)/icon.o
|
OBJECTS += $(OBJDIR)/icon.o
|
||||||
|
endif
|
||||||
|
|
||||||
all: $(NAME)
|
all: $(NAME)
|
||||||
|
|
||||||
@ -163,8 +169,13 @@ $(OBJDIR)/%.o : $(SRCDIR)/tremor/%.c
|
|||||||
$(OBJDIR)/%.o : $(SRCDIR)/../sdl/%.c $(SRCDIR)/../sdl/%.h
|
$(OBJDIR)/%.o : $(SRCDIR)/../sdl/%.c $(SRCDIR)/../sdl/%.h
|
||||||
$(CC) -c $(CFLAGS) $(INCLUDES) $(DEFINES) $< -o $@
|
$(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 :
|
$(OBJDIR)/icon.o :
|
||||||
windres $(SRCDIR)/../sdl/icon.rc $@
|
windres $(SRCDIR)/../sdl/icon.rc $@
|
||||||
|
endif
|
||||||
|
|
||||||
pack :
|
pack :
|
||||||
strip $(NAME)
|
strip $(NAME)
|
185
sdl/Makefile.sdl2
Normal file
185
sdl/Makefile.sdl2
Normal file
@ -0,0 +1,185 @@
|
|||||||
|
|
||||||
|
# Makefile for genplus SDL2
|
||||||
|
#
|
||||||
|
# (c) 1999, 2000, 2001, 2002, 2003 Charles MacDonald
|
||||||
|
# modified by Eke-Eke <eke_eke31@yahoo.fr>
|
||||||
|
#
|
||||||
|
# Defines :
|
||||||
|
# -DLSB_FIRST : for little endian systems.
|
||||||
|
# -DLOGERROR : enable message logging
|
||||||
|
# -DLOGVDP : enable VDP debug messages
|
||||||
|
# -DLOGSOUND : enable AUDIO debug messages
|
||||||
|
# -DLOG_SCD : enable SCD debug messages
|
||||||
|
# -DLOG_CDD : enable CDD debug messages
|
||||||
|
# -DLOG_CDC : enable CDC debug messages
|
||||||
|
# -DLOG_PCM : enable PCM debug messages
|
||||||
|
# -DLOGSOUND : enable AUDIO debug messages
|
||||||
|
# -D8BPP_RENDERING - configure for 8-bit pixels (RGB332)
|
||||||
|
# -D15BPP_RENDERING - configure for 15-bit pixels (RGB555)
|
||||||
|
# -D16BPP_RENDERING - configure for 16-bit pixels (RGB565)
|
||||||
|
# -D32BPP_RENDERING - configure for 32-bit pixels (RGB888)
|
||||||
|
|
||||||
|
NAME = gen_sdl2
|
||||||
|
|
||||||
|
CC = gcc
|
||||||
|
CFLAGS = `sdl2-config --cflags` -march=i686 -O6 -fomit-frame-pointer -Wall -Wno-strict-aliasing -ansi -std=c99 -pedantic-errors
|
||||||
|
#-g -ggdb -pg
|
||||||
|
#-fomit-frame-pointer
|
||||||
|
#LDFLAGS = -pg
|
||||||
|
DEFINES = -DLSB_FIRST -DUSE_16BPP_RENDERING -DUSE_LIBTREMOR -DMAXROMSIZE=33554432
|
||||||
|
|
||||||
|
ifneq ($(OS),Windows_NT)
|
||||||
|
DEFINES += -DHAVE_ALLOCA_H
|
||||||
|
endif
|
||||||
|
|
||||||
|
SRCDIR = ../core
|
||||||
|
INCLUDES = -I$(SRCDIR) -I$(SRCDIR)/z80 -I$(SRCDIR)/m68k -I$(SRCDIR)/sound -I$(SRCDIR)/input_hw -I$(SRCDIR)/cart_hw -I$(SRCDIR)/cart_hw/svp -I$(SRCDIR)/cd_hw -I$(SRCDIR)/ntsc -I$(SRCDIR)/tremor -I$(SRCDIR)/../sdl -I$(SRCDIR)/../sdl/sdl2
|
||||||
|
LIBS = `sdl2-config --libs` -lz -lm
|
||||||
|
|
||||||
|
OBJDIR = ./build_sdl2
|
||||||
|
|
||||||
|
OBJECTS = $(OBJDIR)/z80.o
|
||||||
|
|
||||||
|
OBJECTS += $(OBJDIR)/m68kcpu.o \
|
||||||
|
$(OBJDIR)/s68kcpu.o
|
||||||
|
|
||||||
|
OBJECTS += $(OBJDIR)/genesis.o \
|
||||||
|
$(OBJDIR)/vdp_ctrl.o \
|
||||||
|
$(OBJDIR)/vdp_render.o \
|
||||||
|
$(OBJDIR)/system.o \
|
||||||
|
$(OBJDIR)/io_ctrl.o \
|
||||||
|
$(OBJDIR)/mem68k.o \
|
||||||
|
$(OBJDIR)/memz80.o \
|
||||||
|
$(OBJDIR)/membnk.o \
|
||||||
|
$(OBJDIR)/state.o \
|
||||||
|
$(OBJDIR)/loadrom.o
|
||||||
|
|
||||||
|
OBJECTS += $(OBJDIR)/input.o \
|
||||||
|
$(OBJDIR)/gamepad.o \
|
||||||
|
$(OBJDIR)/lightgun.o \
|
||||||
|
$(OBJDIR)/mouse.o \
|
||||||
|
$(OBJDIR)/activator.o \
|
||||||
|
$(OBJDIR)/xe_1ap.o \
|
||||||
|
$(OBJDIR)/teamplayer.o \
|
||||||
|
$(OBJDIR)/paddle.o \
|
||||||
|
$(OBJDIR)/sportspad.o \
|
||||||
|
$(OBJDIR)/terebi_oekaki.o \
|
||||||
|
$(OBJDIR)/graphic_board.o
|
||||||
|
|
||||||
|
OBJECTS += $(OBJDIR)/sound.o \
|
||||||
|
$(OBJDIR)/psg.o \
|
||||||
|
$(OBJDIR)/ym2413.o \
|
||||||
|
$(OBJDIR)/ym2612.o
|
||||||
|
|
||||||
|
OBJECTS += $(OBJDIR)/blip_buf.o
|
||||||
|
|
||||||
|
OBJECTS += $(OBJDIR)/eq.o
|
||||||
|
|
||||||
|
OBJECTS += $(OBJDIR)/sram.o \
|
||||||
|
$(OBJDIR)/svp.o \
|
||||||
|
$(OBJDIR)/ssp16.o \
|
||||||
|
$(OBJDIR)/ggenie.o \
|
||||||
|
$(OBJDIR)/areplay.o \
|
||||||
|
$(OBJDIR)/eeprom_93c.o \
|
||||||
|
$(OBJDIR)/eeprom_i2c.o \
|
||||||
|
$(OBJDIR)/eeprom_spi.o \
|
||||||
|
$(OBJDIR)/md_cart.o \
|
||||||
|
$(OBJDIR)/sms_cart.o
|
||||||
|
|
||||||
|
OBJECTS += $(OBJDIR)/scd.o \
|
||||||
|
$(OBJDIR)/cdd.o \
|
||||||
|
$(OBJDIR)/cdc.o \
|
||||||
|
$(OBJDIR)/gfx.o \
|
||||||
|
$(OBJDIR)/pcm.o \
|
||||||
|
$(OBJDIR)/cd_cart.o
|
||||||
|
|
||||||
|
OBJECTS += $(OBJDIR)/sms_ntsc.o \
|
||||||
|
$(OBJDIR)/md_ntsc.o
|
||||||
|
|
||||||
|
OBJECTS += $(OBJDIR)/main.o \
|
||||||
|
$(OBJDIR)/config.o \
|
||||||
|
$(OBJDIR)/error.o \
|
||||||
|
$(OBJDIR)/unzip.o \
|
||||||
|
$(OBJDIR)/fileio.o
|
||||||
|
|
||||||
|
OBJECTS += $(OBJDIR)/bitwise.o \
|
||||||
|
$(OBJDIR)/block.o \
|
||||||
|
$(OBJDIR)/codebook.o \
|
||||||
|
$(OBJDIR)/floor0.o \
|
||||||
|
$(OBJDIR)/floor1.o \
|
||||||
|
$(OBJDIR)/framing.o \
|
||||||
|
$(OBJDIR)/info.o \
|
||||||
|
$(OBJDIR)/mapping0.o \
|
||||||
|
$(OBJDIR)/mdct.o \
|
||||||
|
$(OBJDIR)/registry.o \
|
||||||
|
$(OBJDIR)/res012.o \
|
||||||
|
$(OBJDIR)/sharedbook.o \
|
||||||
|
$(OBJDIR)/synthesis.o \
|
||||||
|
$(OBJDIR)/vorbisfile.o \
|
||||||
|
$(OBJDIR)/window.o
|
||||||
|
|
||||||
|
ifeq ($(OS),Windows_NT)
|
||||||
|
OBJECTS += $(OBJDIR)/icon.o
|
||||||
|
endif
|
||||||
|
|
||||||
|
all: $(NAME)
|
||||||
|
|
||||||
|
$(NAME): $(OBJDIR) $(OBJECTS)
|
||||||
|
$(CC) $(LDFLAGS) $(OBJECTS) $(LIBS) -o $@
|
||||||
|
|
||||||
|
$(OBJDIR) :
|
||||||
|
@[ -d $@ ] || mkdir -p $@
|
||||||
|
|
||||||
|
$(OBJDIR)/%.o : $(SRCDIR)/%.c $(SRCDIR)/%.h
|
||||||
|
$(CC) -c $(CFLAGS) $(INCLUDES) $(DEFINES) $< -o $@
|
||||||
|
|
||||||
|
$(OBJDIR)/%.o : $(SRCDIR)/sound/%.c $(SRCDIR)/sound/%.h
|
||||||
|
$(CC) -c $(CFLAGS) $(INCLUDES) $(DEFINES) $< -o $@
|
||||||
|
|
||||||
|
$(OBJDIR)/%.o : $(SRCDIR)/input_hw/%.c $(SRCDIR)/input_hw/%.h
|
||||||
|
$(CC) -c $(CFLAGS) $(INCLUDES) $(DEFINES) $< -o $@
|
||||||
|
|
||||||
|
$(OBJDIR)/%.o : $(SRCDIR)/cart_hw/%.c $(SRCDIR)/cart_hw/%.h
|
||||||
|
$(CC) -c $(CFLAGS) $(INCLUDES) $(DEFINES) $< -o $@
|
||||||
|
|
||||||
|
$(OBJDIR)/%.o : $(SRCDIR)/cart_hw/svp/%.c
|
||||||
|
$(CC) -c $(CFLAGS) $(INCLUDES) $(DEFINES) $< -o $@
|
||||||
|
|
||||||
|
$(OBJDIR)/%.o : $(SRCDIR)/cart_hw/svp/%.c $(SRCDIR)/cart_hw/svp/%.h
|
||||||
|
$(CC) -c $(CFLAGS) $(INCLUDES) $(DEFINES) $< -o $@
|
||||||
|
|
||||||
|
$(OBJDIR)/%.o : $(SRCDIR)/cd_hw/%.c $(SRCDIR)/cd_hw/%.h
|
||||||
|
$(CC) -c $(CFLAGS) $(INCLUDES) $(DEFINES) $< -o $@
|
||||||
|
|
||||||
|
$(OBJDIR)/%.o : $(SRCDIR)/z80/%.c $(SRCDIR)/z80/%.h
|
||||||
|
$(CC) -c $(CFLAGS) $(INCLUDES) $(DEFINES) $< -o $@
|
||||||
|
|
||||||
|
$(OBJDIR)/%.o : $(SRCDIR)/m68k/%.c
|
||||||
|
$(CC) -c $(CFLAGS) $(INCLUDES) $(DEFINES) $< -o $@
|
||||||
|
|
||||||
|
$(OBJDIR)/%.o : $(SRCDIR)/ntsc/%.c $(SRCDIR)/ntsc/%.h
|
||||||
|
$(CC) -c $(CFLAGS) $(INCLUDES) $(DEFINES) $< -o $@
|
||||||
|
|
||||||
|
$(OBJDIR)/%.o : $(SRCDIR)/tremor/%.c $(SRCDIR)/tremor/%.h
|
||||||
|
$(CC) -c $(CFLAGS) $(INCLUDES) $(DEFINES) $< -o $@
|
||||||
|
|
||||||
|
$(OBJDIR)/%.o : $(SRCDIR)/tremor/%.c
|
||||||
|
$(CC) -c $(CFLAGS) $(INCLUDES) $(DEFINES) $< -o $@
|
||||||
|
|
||||||
|
$(OBJDIR)/%.o : $(SRCDIR)/../sdl/%.c $(SRCDIR)/../sdl/%.h
|
||||||
|
$(CC) -c $(CFLAGS) $(INCLUDES) $(DEFINES) $< -o $@
|
||||||
|
|
||||||
|
$(OBJDIR)/%.o : $(SRCDIR)/../sdl/sdl2/%.c $(SRCDIR)/../sdl/sdl2/%.h
|
||||||
|
$(CC) -c $(CFLAGS) $(INCLUDES) $(DEFINES) $< -o $@
|
||||||
|
|
||||||
|
ifeq ($(OS),Windows_NT)
|
||||||
|
$(OBJDIR)/icon.o :
|
||||||
|
windres $(SRCDIR)/../sdl/icon.rc $@
|
||||||
|
endif
|
||||||
|
|
||||||
|
pack :
|
||||||
|
strip $(NAME)
|
||||||
|
upx -9 $(NAME)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f $(OBJECTS) $(NAME)
|
@ -9,7 +9,7 @@ PLEASE DO NOT DISTRIBUTE WIN32 BINARIES WITHOUT THIS NOTICE.
|
|||||||
END USERS SHOULD PREFERABLY USE LIBRETRO PORT WITH RETROARCH.
|
END USERS SHOULD PREFERABLY USE LIBRETRO PORT WITH RETROARCH.
|
||||||
|
|
||||||
----------------------------------------------------------------------------
|
----------------------------------------------------------------------------
|
||||||
Genesis Plus (Windows Port)
|
Genesis Plus (SDL Port)
|
||||||
----------------------------------------------------------------------------
|
----------------------------------------------------------------------------
|
||||||
|
|
||||||
based on the original version 1.3
|
based on the original version 1.3
|
||||||
|
@ -12,7 +12,7 @@ void set_config_defaults(void)
|
|||||||
config.psg_preamp = 150;
|
config.psg_preamp = 150;
|
||||||
config.fm_preamp = 100;
|
config.fm_preamp = 100;
|
||||||
config.hq_fm = 1;
|
config.hq_fm = 1;
|
||||||
config.psgBoostNoise = 1;
|
config.hq_psg = 1;
|
||||||
config.filter = 1;
|
config.filter = 1;
|
||||||
config.low_freq = 200;
|
config.low_freq = 200;
|
||||||
config.high_freq = 8000;
|
config.high_freq = 8000;
|
||||||
|
@ -15,7 +15,7 @@ typedef struct
|
|||||||
{
|
{
|
||||||
uint8 hq_fm;
|
uint8 hq_fm;
|
||||||
uint8 filter;
|
uint8 filter;
|
||||||
uint8 psgBoostNoise;
|
uint8 hq_psg;
|
||||||
uint8 dac_bits;
|
uint8 dac_bits;
|
||||||
uint8 ym2413;
|
uint8 ym2413;
|
||||||
int16 psg_preamp;
|
int16 psg_preamp;
|
||||||
|
@ -5,7 +5,9 @@
|
|||||||
|
|
||||||
#include "osd.h"
|
#include "osd.h"
|
||||||
|
|
||||||
|
#ifdef LOGERROR
|
||||||
static FILE *error_log;
|
static FILE *error_log;
|
||||||
|
#endif
|
||||||
|
|
||||||
void error_init(void)
|
void error_init(void)
|
||||||
{
|
{
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
#define SOUND_FREQUENCY 48000
|
#define SOUND_FREQUENCY 48000
|
||||||
#define SOUND_SAMPLES_SIZE 2048
|
#define SOUND_SAMPLES_SIZE 2048
|
||||||
|
|
||||||
#define VIDEO_WIDTH 320
|
#define VIDEO_WIDTH 320
|
||||||
#define VIDEO_HEIGHT 240
|
#define VIDEO_HEIGHT 240
|
||||||
|
|
||||||
int joynum = 0;
|
int joynum = 0;
|
||||||
@ -67,7 +67,7 @@ static int sdl_sound_init()
|
|||||||
{
|
{
|
||||||
int n;
|
int n;
|
||||||
SDL_AudioSpec as_desired, as_obtained;
|
SDL_AudioSpec as_desired, as_obtained;
|
||||||
|
|
||||||
if(SDL_Init(SDL_INIT_AUDIO) < 0) {
|
if(SDL_Init(SDL_INIT_AUDIO) < 0) {
|
||||||
MessageBox(NULL, "SDL Audio initialization failed", "Error", 0);
|
MessageBox(NULL, "SDL Audio initialization failed", "Error", 0);
|
||||||
return 0;
|
return 0;
|
||||||
@ -101,10 +101,10 @@ static int sdl_sound_init()
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sdl_sound_update(enabled)
|
static void sdl_sound_update(int enabled)
|
||||||
{
|
{
|
||||||
int size = audio_update(soundframe) * 2;
|
int size = audio_update(soundframe) * 2;
|
||||||
|
|
||||||
if (enabled)
|
if (enabled)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
@ -126,7 +126,7 @@ static void sdl_sound_close()
|
|||||||
{
|
{
|
||||||
SDL_PauseAudio(1);
|
SDL_PauseAudio(1);
|
||||||
SDL_CloseAudio();
|
SDL_CloseAudio();
|
||||||
if (sdl_sound.buffer)
|
if (sdl_sound.buffer)
|
||||||
free(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.h = sdl_video.srect.h;
|
||||||
sdl_video.drect.x = (VIDEO_WIDTH - sdl_video.drect.w) / 2;
|
sdl_video.drect.x = (VIDEO_WIDTH - sdl_video.drect.w) / 2;
|
||||||
sdl_video.drect.y = (VIDEO_HEIGHT - sdl_video.drect.h) / 2;
|
sdl_video.drect.y = (VIDEO_HEIGHT - sdl_video.drect.h) / 2;
|
||||||
|
|
||||||
/* clear destination surface */
|
/* clear destination surface */
|
||||||
SDL_FillRect(sdl_video.surf_screen, 0, 0);
|
SDL_FillRect(sdl_video.surf_screen, 0, 0);
|
||||||
|
|
||||||
@ -304,7 +304,7 @@ static void sdl_sync_close()
|
|||||||
SDL_DestroySemaphore(sdl_sync.sem_sync);
|
SDL_DestroySemaphore(sdl_sync.sem_sync);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const uint16 vc_table[4][2] =
|
static const uint16 vc_table[4][2] =
|
||||||
{
|
{
|
||||||
/* NTSC, PAL */
|
/* NTSC, PAL */
|
||||||
{0xDA , 0xF2}, /* Mode 4 (192 lines) */
|
{0xDA , 0xF2}, /* Mode 4 (192 lines) */
|
||||||
@ -332,8 +332,7 @@ static int sdl_control_update(SDLKey keystate)
|
|||||||
|
|
||||||
case SDLK_F2:
|
case SDLK_F2:
|
||||||
{
|
{
|
||||||
if (fullscreen) fullscreen = 0;
|
fullscreen = (fullscreen ? 0 : SDL_FULLSCREEN);
|
||||||
else fullscreen = SDL_FULLSCREEN;
|
|
||||||
sdl_video.surf_screen = SDL_SetVideoMode(VIDEO_WIDTH, VIDEO_HEIGHT, 16, SDL_SWSURFACE | fullscreen);
|
sdl_video.surf_screen = SDL_SetVideoMode(VIDEO_WIDTH, VIDEO_HEIGHT, 16, SDL_SWSURFACE | fullscreen);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -497,7 +496,7 @@ int sdl_input_update(void)
|
|||||||
|
|
||||||
/* reset input */
|
/* reset input */
|
||||||
input.pad[joynum] = 0;
|
input.pad[joynum] = 0;
|
||||||
|
|
||||||
switch (input.dev[joynum])
|
switch (input.dev[joynum])
|
||||||
{
|
{
|
||||||
case DEVICE_LIGHTGUN:
|
case DEVICE_LIGHTGUN:
|
||||||
@ -515,7 +514,7 @@ int sdl_input_update(void)
|
|||||||
/* TRIGGER, B, C (Menacer only), START (Menacer & Justifier only) */
|
/* TRIGGER, B, C (Menacer only), START (Menacer & Justifier only) */
|
||||||
if(state & SDL_BUTTON_LMASK) input.pad[joynum] |= INPUT_A;
|
if(state & SDL_BUTTON_LMASK) input.pad[joynum] |= INPUT_A;
|
||||||
if(state & SDL_BUTTON_RMASK) input.pad[joynum] |= INPUT_B;
|
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;
|
if(keystate[SDLK_f]) input.pad[joynum] |= INPUT_START;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -586,7 +585,7 @@ int sdl_input_update(void)
|
|||||||
if(keystate[SDLK_x]) input.pad[joynum] |= INPUT_X;
|
if(keystate[SDLK_x]) input.pad[joynum] |= INPUT_X;
|
||||||
if(keystate[SDLK_c]) input.pad[joynum] |= INPUT_MODE;
|
if(keystate[SDLK_c]) input.pad[joynum] |= INPUT_MODE;
|
||||||
if(keystate[SDLK_v]) input.pad[joynum] |= INPUT_Z;
|
if(keystate[SDLK_v]) input.pad[joynum] |= INPUT_Z;
|
||||||
|
|
||||||
/* Left Analog Stick (bidirectional) */
|
/* Left Analog Stick (bidirectional) */
|
||||||
if(keystate[SDLK_UP]) input.analog[joynum][1]-=2;
|
if(keystate[SDLK_UP]) input.analog[joynum][1]-=2;
|
||||||
else if(keystate[SDLK_DOWN]) 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 */
|
/* Calculate X Y axis values */
|
||||||
input.analog[0][0] = 0x3c + (x * (0x17c-0x03c+1)) / VIDEO_WIDTH;
|
input.analog[0][0] = 0x3c + (x * (0x17c-0x03c+1)) / VIDEO_WIDTH;
|
||||||
input.analog[0][1] = 0x1fc + (y * (0x2f7-0x1fc+1)) / VIDEO_HEIGHT;
|
input.analog[0][1] = 0x1fc + (y * (0x2f7-0x1fc+1)) / VIDEO_HEIGHT;
|
||||||
|
|
||||||
/* Map mouse buttons to player #1 inputs */
|
/* Map mouse buttons to player #1 inputs */
|
||||||
if(state & SDL_BUTTON_MMASK) pico_current = (pico_current + 1) & 7;
|
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_RMASK) input.pad[0] |= INPUT_PICO_RED;
|
||||||
@ -642,7 +641,7 @@ int sdl_input_update(void)
|
|||||||
/* Calculate X Y axis values */
|
/* Calculate X Y axis values */
|
||||||
input.analog[0][0] = (x * 250) / VIDEO_WIDTH;
|
input.analog[0][0] = (x * 250) / VIDEO_WIDTH;
|
||||||
input.analog[0][1] = (y * 250) / VIDEO_HEIGHT;
|
input.analog[0][1] = (y * 250) / VIDEO_HEIGHT;
|
||||||
|
|
||||||
/* Map mouse buttons to player #1 inputs */
|
/* Map mouse buttons to player #1 inputs */
|
||||||
if(state & SDL_BUTTON_RMASK) input.pad[0] |= INPUT_B;
|
if(state & SDL_BUTTON_RMASK) input.pad[0] |= INPUT_B;
|
||||||
|
|
||||||
@ -658,7 +657,7 @@ int sdl_input_update(void)
|
|||||||
/* Calculate X Y axis values */
|
/* Calculate X Y axis values */
|
||||||
input.analog[0][0] = (x * 255) / VIDEO_WIDTH;
|
input.analog[0][0] = (x * 255) / VIDEO_WIDTH;
|
||||||
input.analog[0][1] = (y * 255) / VIDEO_HEIGHT;
|
input.analog[0][1] = (y * 255) / VIDEO_HEIGHT;
|
||||||
|
|
||||||
/* Map mouse buttons to player #1 inputs */
|
/* Map mouse buttons to player #1 inputs */
|
||||||
if(state & SDL_BUTTON_LMASK) input.pad[0] |= INPUT_GRAPHIC_PEN;
|
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_RMASK) input.pad[0] |= INPUT_GRAPHIC_MENU;
|
||||||
@ -711,7 +710,7 @@ int main (int argc, char **argv)
|
|||||||
char caption[256];
|
char caption[256];
|
||||||
sprintf(caption, "Genesis Plus GX\\SDL\nusage: %s gamename\n", argv[0]);
|
sprintf(caption, "Genesis Plus GX\\SDL\nusage: %s gamename\n", argv[0]);
|
||||||
MessageBox(NULL, caption, "Information", 0);
|
MessageBox(NULL, caption, "Information", 0);
|
||||||
exit(1);
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* set default config */
|
/* set default config */
|
||||||
@ -751,10 +750,8 @@ int main (int argc, char **argv)
|
|||||||
/* initialize SDL */
|
/* initialize SDL */
|
||||||
if(SDL_Init(0) < 0)
|
if(SDL_Init(0) < 0)
|
||||||
{
|
{
|
||||||
char caption[256];
|
MessageBox(NULL, "SDL initialization failed", "Error", 0);
|
||||||
sprintf(caption, "SDL initialization failed");
|
return 1;
|
||||||
MessageBox(NULL, caption, "Error", 0);
|
|
||||||
exit(1);
|
|
||||||
}
|
}
|
||||||
sdl_video_init();
|
sdl_video_init();
|
||||||
if (use_sound) sdl_sound_init();
|
if (use_sound) sdl_sound_init();
|
||||||
@ -784,7 +781,7 @@ int main (int argc, char **argv)
|
|||||||
char caption[256];
|
char caption[256];
|
||||||
sprintf(caption, "Error loading file `%s'.", argv[1]);
|
sprintf(caption, "Error loading file `%s'.", argv[1]);
|
||||||
MessageBox(NULL, caption, "Error", 0);
|
MessageBox(NULL, caption, "Error", 0);
|
||||||
exit(1);
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* initialize system hardware */
|
/* initialize system hardware */
|
||||||
@ -866,14 +863,14 @@ int main (int argc, char **argv)
|
|||||||
while(running)
|
while(running)
|
||||||
{
|
{
|
||||||
SDL_Event event;
|
SDL_Event event;
|
||||||
if (SDL_PollEvent(&event))
|
if (SDL_PollEvent(&event))
|
||||||
{
|
{
|
||||||
switch(event.type)
|
switch(event.type)
|
||||||
{
|
{
|
||||||
case SDL_USEREVENT:
|
case SDL_USEREVENT:
|
||||||
{
|
{
|
||||||
char caption[100];
|
char caption[100];
|
||||||
sprintf(caption,"Genesis Plus GX - %d fps - %s)", event.user.code, (rominfo.international[0] != 0x20) ? rominfo.international : rominfo.domestic);
|
sprintf(caption,"Genesis Plus GX - %d fps - %s", event.user.code, (rominfo.international[0] != 0x20) ? rominfo.international : rominfo.domestic);
|
||||||
SDL_WM_SetCaption(caption, NULL);
|
SDL_WM_SetCaption(caption, NULL);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
945
sdl/sdl2/main.c
Normal file
945
sdl/sdl2/main.c
Normal file
@ -0,0 +1,945 @@
|
|||||||
|
#include "SDL.h"
|
||||||
|
#include "SDL_thread.h"
|
||||||
|
|
||||||
|
#include "shared.h"
|
||||||
|
#include "sms_ntsc.h"
|
||||||
|
#include "md_ntsc.h"
|
||||||
|
|
||||||
|
#define SOUND_FREQUENCY 48000
|
||||||
|
#define SOUND_SAMPLES_SIZE 2048
|
||||||
|
|
||||||
|
#define VIDEO_WIDTH 320
|
||||||
|
#define VIDEO_HEIGHT 240
|
||||||
|
|
||||||
|
int joynum = 0;
|
||||||
|
|
||||||
|
int log_error = 0;
|
||||||
|
int debug_on = 0;
|
||||||
|
int turbo_mode = 0;
|
||||||
|
int use_sound = 1;
|
||||||
|
int fullscreen = 0; /* SDL_WINDOW_FULLSCREEN */
|
||||||
|
|
||||||
|
struct {
|
||||||
|
SDL_Window* window;
|
||||||
|
SDL_Surface* surf_screen;
|
||||||
|
SDL_Surface* surf_bitmap;
|
||||||
|
SDL_Rect srect;
|
||||||
|
SDL_Rect drect;
|
||||||
|
Uint32 frames_rendered;
|
||||||
|
} sdl_video;
|
||||||
|
|
||||||
|
/* sound */
|
||||||
|
|
||||||
|
struct {
|
||||||
|
char* current_pos;
|
||||||
|
char* buffer;
|
||||||
|
int current_emulated_samples;
|
||||||
|
} sdl_sound;
|
||||||
|
|
||||||
|
|
||||||
|
static uint8 brm_format[0x40] =
|
||||||
|
{
|
||||||
|
0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x00,0x00,0x00,0x00,0x40,
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x53,0x45,0x47,0x41,0x5f,0x43,0x44,0x5f,0x52,0x4f,0x4d,0x00,0x01,0x00,0x00,0x00,
|
||||||
|
0x52,0x41,0x4d,0x5f,0x43,0x41,0x52,0x54,0x52,0x49,0x44,0x47,0x45,0x5f,0x5f,0x5f
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static short soundframe[SOUND_SAMPLES_SIZE];
|
||||||
|
|
||||||
|
static void sdl_sound_callback(void *userdata, Uint8 *stream, int len)
|
||||||
|
{
|
||||||
|
if(sdl_sound.current_emulated_samples < len) {
|
||||||
|
memset(stream, 0, len);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
memcpy(stream, sdl_sound.buffer, len);
|
||||||
|
/* loop to compensate desync */
|
||||||
|
do {
|
||||||
|
sdl_sound.current_emulated_samples -= len;
|
||||||
|
} while(sdl_sound.current_emulated_samples > 2 * len);
|
||||||
|
memcpy(sdl_sound.buffer,
|
||||||
|
sdl_sound.current_pos - sdl_sound.current_emulated_samples,
|
||||||
|
sdl_sound.current_emulated_samples);
|
||||||
|
sdl_sound.current_pos = sdl_sound.buffer + sdl_sound.current_emulated_samples;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sdl_sound_init()
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
SDL_AudioSpec as_desired, as_obtained;
|
||||||
|
|
||||||
|
if(SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) {
|
||||||
|
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error", "SDL Audio initialization failed", sdl_video.window);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
as_desired.freq = SOUND_FREQUENCY;
|
||||||
|
as_desired.format = AUDIO_S16LSB;
|
||||||
|
as_desired.channels = 2;
|
||||||
|
as_desired.samples = SOUND_SAMPLES_SIZE;
|
||||||
|
as_desired.callback = sdl_sound_callback;
|
||||||
|
|
||||||
|
if(SDL_OpenAudio(&as_desired, &as_obtained) == -1) {
|
||||||
|
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error", "SDL Audio open failed", sdl_video.window);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(as_desired.samples != as_obtained.samples) {
|
||||||
|
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error", "SDL Audio wrong setup", sdl_video.window);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
sdl_sound.current_emulated_samples = 0;
|
||||||
|
n = SOUND_SAMPLES_SIZE * 2 * sizeof(short) * 20;
|
||||||
|
sdl_sound.buffer = (char*)malloc(n);
|
||||||
|
if(!sdl_sound.buffer) {
|
||||||
|
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error", "Can't allocate audio buffer", sdl_video.window);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
memset(sdl_sound.buffer, 0, n);
|
||||||
|
sdl_sound.current_pos = sdl_sound.buffer;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sdl_sound_update(int enabled)
|
||||||
|
{
|
||||||
|
int size = audio_update(soundframe) * 2;
|
||||||
|
|
||||||
|
if (enabled)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
short *out;
|
||||||
|
|
||||||
|
SDL_LockAudio();
|
||||||
|
out = (short*)sdl_sound.current_pos;
|
||||||
|
for(i = 0; i < size; i++)
|
||||||
|
{
|
||||||
|
*out++ = soundframe[i];
|
||||||
|
}
|
||||||
|
sdl_sound.current_pos = (char*)out;
|
||||||
|
sdl_sound.current_emulated_samples += size * sizeof(short);
|
||||||
|
SDL_UnlockAudio();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sdl_sound_close()
|
||||||
|
{
|
||||||
|
SDL_PauseAudio(1);
|
||||||
|
SDL_CloseAudio();
|
||||||
|
if (sdl_sound.buffer)
|
||||||
|
free(sdl_sound.buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* video */
|
||||||
|
md_ntsc_t *md_ntsc;
|
||||||
|
sms_ntsc_t *sms_ntsc;
|
||||||
|
|
||||||
|
static int sdl_video_init()
|
||||||
|
{
|
||||||
|
if(SDL_InitSubSystem(SDL_INIT_VIDEO) < 0) {
|
||||||
|
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error", "SDL Video initialization failed", sdl_video.window);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
sdl_video.window = SDL_CreateWindow("Genesis Plus GX", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, VIDEO_WIDTH, VIDEO_HEIGHT, 0);
|
||||||
|
sdl_video.surf_screen = SDL_GetWindowSurface(sdl_video.window);
|
||||||
|
sdl_video.surf_bitmap = SDL_CreateRGBSurface(SDL_SWSURFACE, 720, 576, 16, 0, 0, 0, 0);
|
||||||
|
sdl_video.frames_rendered = 0;
|
||||||
|
SDL_ShowCursor(0);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sdl_video_update()
|
||||||
|
{
|
||||||
|
if (system_hw == SYSTEM_MCD)
|
||||||
|
{
|
||||||
|
system_frame_scd(0);
|
||||||
|
}
|
||||||
|
else if ((system_hw & SYSTEM_PBC) == SYSTEM_MD)
|
||||||
|
{
|
||||||
|
system_frame_gen(0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
system_frame_sms(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* viewport size changed */
|
||||||
|
if(bitmap.viewport.changed & 1)
|
||||||
|
{
|
||||||
|
bitmap.viewport.changed &= ~1;
|
||||||
|
|
||||||
|
/* source bitmap */
|
||||||
|
sdl_video.srect.w = bitmap.viewport.w+2*bitmap.viewport.x;
|
||||||
|
sdl_video.srect.h = bitmap.viewport.h+2*bitmap.viewport.y;
|
||||||
|
sdl_video.srect.x = 0;
|
||||||
|
sdl_video.srect.y = 0;
|
||||||
|
if (sdl_video.srect.w > VIDEO_WIDTH)
|
||||||
|
{
|
||||||
|
sdl_video.srect.x = (sdl_video.srect.w - VIDEO_WIDTH) / 2;
|
||||||
|
sdl_video.srect.w = VIDEO_WIDTH;
|
||||||
|
}
|
||||||
|
if (sdl_video.srect.h > VIDEO_HEIGHT)
|
||||||
|
{
|
||||||
|
sdl_video.srect.y = (sdl_video.srect.h - VIDEO_HEIGHT) / 2;
|
||||||
|
sdl_video.srect.h = VIDEO_HEIGHT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* destination bitmap */
|
||||||
|
sdl_video.drect.w = sdl_video.srect.w;
|
||||||
|
sdl_video.drect.h = sdl_video.srect.h;
|
||||||
|
sdl_video.drect.x = (VIDEO_WIDTH - sdl_video.drect.w) / 2;
|
||||||
|
sdl_video.drect.y = (VIDEO_HEIGHT - sdl_video.drect.h) / 2;
|
||||||
|
|
||||||
|
/* clear destination surface */
|
||||||
|
SDL_FillRect(sdl_video.surf_screen, 0, 0);
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
if (config.render && (interlaced || config.ntsc)) rect.h *= 2;
|
||||||
|
if (config.ntsc) rect.w = (reg[12]&1) ? MD_NTSC_OUT_WIDTH(rect.w) : SMS_NTSC_OUT_WIDTH(rect.w);
|
||||||
|
if (config.ntsc)
|
||||||
|
{
|
||||||
|
sms_ntsc = (sms_ntsc_t *)malloc(sizeof(sms_ntsc_t));
|
||||||
|
md_ntsc = (md_ntsc_t *)malloc(sizeof(md_ntsc_t));
|
||||||
|
|
||||||
|
switch (config.ntsc)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
sms_ntsc_init(sms_ntsc, &sms_ntsc_composite);
|
||||||
|
md_ntsc_init(md_ntsc, &md_ntsc_composite);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
sms_ntsc_init(sms_ntsc, &sms_ntsc_svideo);
|
||||||
|
md_ntsc_init(md_ntsc, &md_ntsc_svideo);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
sms_ntsc_init(sms_ntsc, &sms_ntsc_rgb);
|
||||||
|
md_ntsc_init(md_ntsc, &md_ntsc_rgb);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (sms_ntsc)
|
||||||
|
{
|
||||||
|
free(sms_ntsc);
|
||||||
|
sms_ntsc = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (md_ntsc)
|
||||||
|
{
|
||||||
|
free(md_ntsc);
|
||||||
|
md_ntsc = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_BlitSurface(sdl_video.surf_bitmap, &sdl_video.srect, sdl_video.surf_screen, &sdl_video.drect);
|
||||||
|
SDL_UpdateWindowSurface(sdl_video.window);
|
||||||
|
|
||||||
|
++sdl_video.frames_rendered;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sdl_video_close()
|
||||||
|
{
|
||||||
|
if (sdl_video.surf_bitmap)
|
||||||
|
SDL_FreeSurface(sdl_video.surf_bitmap);
|
||||||
|
if (sdl_video.surf_screen)
|
||||||
|
SDL_FreeSurface(sdl_video.surf_screen);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Timer Sync */
|
||||||
|
|
||||||
|
struct {
|
||||||
|
SDL_sem* sem_sync;
|
||||||
|
unsigned ticks;
|
||||||
|
} sdl_sync;
|
||||||
|
|
||||||
|
static Uint32 sdl_sync_timer_callback(Uint32 interval, void *param)
|
||||||
|
{
|
||||||
|
SDL_SemPost(sdl_sync.sem_sync);
|
||||||
|
sdl_sync.ticks++;
|
||||||
|
if (sdl_sync.ticks == (vdp_pal ? 50 : 20))
|
||||||
|
{
|
||||||
|
SDL_Event event;
|
||||||
|
SDL_UserEvent userevent;
|
||||||
|
|
||||||
|
userevent.type = SDL_USEREVENT;
|
||||||
|
userevent.code = vdp_pal ? (sdl_video.frames_rendered / 3) : sdl_video.frames_rendered;
|
||||||
|
userevent.data1 = NULL;
|
||||||
|
userevent.data2 = NULL;
|
||||||
|
sdl_sync.ticks = sdl_video.frames_rendered = 0;
|
||||||
|
|
||||||
|
event.type = SDL_USEREVENT;
|
||||||
|
event.user = userevent;
|
||||||
|
|
||||||
|
SDL_PushEvent(&event);
|
||||||
|
}
|
||||||
|
return interval;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sdl_sync_init()
|
||||||
|
{
|
||||||
|
if(SDL_InitSubSystem(SDL_INIT_TIMER|SDL_INIT_EVENTS) < 0)
|
||||||
|
{
|
||||||
|
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error", "SDL Timer initialization failed", sdl_video.window);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
sdl_sync.sem_sync = SDL_CreateSemaphore(0);
|
||||||
|
sdl_sync.ticks = 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sdl_sync_close()
|
||||||
|
{
|
||||||
|
if(sdl_sync.sem_sync)
|
||||||
|
SDL_DestroySemaphore(sdl_sync.sem_sync);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const uint16 vc_table[4][2] =
|
||||||
|
{
|
||||||
|
/* NTSC, PAL */
|
||||||
|
{0xDA , 0xF2}, /* Mode 4 (192 lines) */
|
||||||
|
{0xEA , 0x102}, /* Mode 5 (224 lines) */
|
||||||
|
{0xDA , 0xF2}, /* Mode 4 (192 lines) */
|
||||||
|
{0x106, 0x10A} /* Mode 5 (240 lines) */
|
||||||
|
};
|
||||||
|
|
||||||
|
static int sdl_control_update(SDL_Keycode keystate)
|
||||||
|
{
|
||||||
|
switch (keystate)
|
||||||
|
{
|
||||||
|
case SDLK_TAB:
|
||||||
|
{
|
||||||
|
system_reset();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case SDLK_F1:
|
||||||
|
{
|
||||||
|
if (SDL_ShowCursor(-1)) SDL_ShowCursor(0);
|
||||||
|
else SDL_ShowCursor(1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case SDLK_F2:
|
||||||
|
{
|
||||||
|
fullscreen = (fullscreen ? 0 : SDL_WINDOW_FULLSCREEN);
|
||||||
|
SDL_SetWindowFullscreen(sdl_video.window, fullscreen);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case SDLK_F3:
|
||||||
|
{
|
||||||
|
if (config.bios == 0) config.bios = 3;
|
||||||
|
else if (config.bios == 3) config.bios = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case SDLK_F4:
|
||||||
|
{
|
||||||
|
if (!turbo_mode) use_sound ^= 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case SDLK_F5:
|
||||||
|
{
|
||||||
|
log_error ^= 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case SDLK_F6:
|
||||||
|
{
|
||||||
|
if (!use_sound)
|
||||||
|
{
|
||||||
|
turbo_mode ^=1;
|
||||||
|
sdl_sync.ticks = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case SDLK_F7:
|
||||||
|
{
|
||||||
|
FILE *f = fopen("game.gp0","rb");
|
||||||
|
if (f)
|
||||||
|
{
|
||||||
|
uint8 buf[STATE_SIZE];
|
||||||
|
fread(&buf, STATE_SIZE, 1, f);
|
||||||
|
state_load(buf);
|
||||||
|
fclose(f);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case SDLK_F8:
|
||||||
|
{
|
||||||
|
FILE *f = fopen("game.gp0","wb");
|
||||||
|
if (f)
|
||||||
|
{
|
||||||
|
uint8 buf[STATE_SIZE];
|
||||||
|
int len = state_save(buf);
|
||||||
|
fwrite(&buf, len, 1, f);
|
||||||
|
fclose(f);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case SDLK_F9:
|
||||||
|
{
|
||||||
|
config.region_detect = (config.region_detect + 1) % 5;
|
||||||
|
get_region(0);
|
||||||
|
|
||||||
|
/* framerate has changed, reinitialize audio timings */
|
||||||
|
audio_init(snd.sample_rate, 0);
|
||||||
|
|
||||||
|
/* system with region BIOS should be reinitialized */
|
||||||
|
if ((system_hw == SYSTEM_MCD) || ((system_hw & SYSTEM_SMS) && (config.bios & 1)))
|
||||||
|
{
|
||||||
|
system_init();
|
||||||
|
system_reset();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* reinitialize I/O region register */
|
||||||
|
if (system_hw == SYSTEM_MD)
|
||||||
|
{
|
||||||
|
io_reg[0x00] = 0x20 | region_code | (config.bios & 1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
io_reg[0x00] = 0x80 | (region_code >> 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* reinitialize VDP */
|
||||||
|
if (vdp_pal)
|
||||||
|
{
|
||||||
|
status |= 1;
|
||||||
|
lines_per_frame = 313;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
status &= ~1;
|
||||||
|
lines_per_frame = 262;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* reinitialize VC max value */
|
||||||
|
switch (bitmap.viewport.h)
|
||||||
|
{
|
||||||
|
case 192:
|
||||||
|
vc_max = vc_table[0][vdp_pal];
|
||||||
|
break;
|
||||||
|
case 224:
|
||||||
|
vc_max = vc_table[1][vdp_pal];
|
||||||
|
break;
|
||||||
|
case 240:
|
||||||
|
vc_max = vc_table[3][vdp_pal];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case SDLK_F10:
|
||||||
|
{
|
||||||
|
gen_reset(0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case SDLK_F11:
|
||||||
|
{
|
||||||
|
config.overscan = (config.overscan + 1) & 3;
|
||||||
|
if ((system_hw == SYSTEM_GG) && !config.gg_extra)
|
||||||
|
{
|
||||||
|
bitmap.viewport.x = (config.overscan & 2) ? 14 : -48;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bitmap.viewport.x = (config.overscan & 2) * 7;
|
||||||
|
}
|
||||||
|
bitmap.viewport.changed = 3;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case SDLK_F12:
|
||||||
|
{
|
||||||
|
joynum = (joynum + 1) % MAX_DEVICES;
|
||||||
|
while (input.dev[joynum] == NO_DEVICE)
|
||||||
|
{
|
||||||
|
joynum = (joynum + 1) % MAX_DEVICES;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case SDLK_ESCAPE:
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sdl_input_update(void)
|
||||||
|
{
|
||||||
|
const uint8 *keystate = SDL_GetKeyboardState(NULL);
|
||||||
|
|
||||||
|
/* reset input */
|
||||||
|
input.pad[joynum] = 0;
|
||||||
|
|
||||||
|
switch (input.dev[joynum])
|
||||||
|
{
|
||||||
|
case DEVICE_LIGHTGUN:
|
||||||
|
{
|
||||||
|
/* get mouse coordinates (absolute values) */
|
||||||
|
int x,y;
|
||||||
|
int state = SDL_GetMouseState(&x,&y);
|
||||||
|
|
||||||
|
/* X axis */
|
||||||
|
input.analog[joynum][0] = x - (VIDEO_WIDTH-bitmap.viewport.w)/2;
|
||||||
|
|
||||||
|
/* Y axis */
|
||||||
|
input.analog[joynum][1] = y - (VIDEO_HEIGHT-bitmap.viewport.h)/2;
|
||||||
|
|
||||||
|
/* TRIGGER, B, C (Menacer only), START (Menacer & Justifier only) */
|
||||||
|
if(state & SDL_BUTTON_LMASK) input.pad[joynum] |= INPUT_A;
|
||||||
|
if(state & SDL_BUTTON_RMASK) input.pad[joynum] |= INPUT_B;
|
||||||
|
if(state & SDL_BUTTON_MMASK) input.pad[joynum] |= INPUT_C;
|
||||||
|
if(keystate[SDL_SCANCODE_F]) input.pad[joynum] |= INPUT_START;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case DEVICE_PADDLE:
|
||||||
|
{
|
||||||
|
/* get mouse (absolute values) */
|
||||||
|
int x;
|
||||||
|
int state = SDL_GetMouseState(&x, NULL);
|
||||||
|
|
||||||
|
/* Range is [0;256], 128 being middle position */
|
||||||
|
input.analog[joynum][0] = x * 256 /VIDEO_WIDTH;
|
||||||
|
|
||||||
|
/* Button I -> 0 0 0 0 0 0 0 I*/
|
||||||
|
if(state & SDL_BUTTON_LMASK) input.pad[joynum] |= INPUT_B;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case DEVICE_SPORTSPAD:
|
||||||
|
{
|
||||||
|
/* get mouse (relative values) */
|
||||||
|
int x,y;
|
||||||
|
int state = SDL_GetRelativeMouseState(&x,&y);
|
||||||
|
|
||||||
|
/* Range is [0;256] */
|
||||||
|
input.analog[joynum][0] = (unsigned char)(-x & 0xFF);
|
||||||
|
input.analog[joynum][1] = (unsigned char)(-y & 0xFF);
|
||||||
|
|
||||||
|
/* Buttons I & II -> 0 0 0 0 0 0 II I*/
|
||||||
|
if(state & SDL_BUTTON_LMASK) input.pad[joynum] |= INPUT_B;
|
||||||
|
if(state & SDL_BUTTON_RMASK) input.pad[joynum] |= INPUT_C;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case DEVICE_MOUSE:
|
||||||
|
{
|
||||||
|
/* get mouse (relative values) */
|
||||||
|
int x,y;
|
||||||
|
int state = SDL_GetRelativeMouseState(&x,&y);
|
||||||
|
|
||||||
|
/* Sega Mouse range is [-256;+256] */
|
||||||
|
input.analog[joynum][0] = x * 2;
|
||||||
|
input.analog[joynum][1] = y * 2;
|
||||||
|
|
||||||
|
/* Vertical movement is upsidedown */
|
||||||
|
if (!config.invert_mouse)
|
||||||
|
input.analog[joynum][1] = 0 - input.analog[joynum][1];
|
||||||
|
|
||||||
|
/* Start,Left,Right,Middle buttons -> 0 0 0 0 START MIDDLE RIGHT LEFT */
|
||||||
|
if(state & SDL_BUTTON_LMASK) input.pad[joynum] |= INPUT_B;
|
||||||
|
if(state & SDL_BUTTON_RMASK) input.pad[joynum] |= INPUT_C;
|
||||||
|
if(state & SDL_BUTTON_MMASK) input.pad[joynum] |= INPUT_A;
|
||||||
|
if(keystate[SDL_SCANCODE_F]) input.pad[joynum] |= INPUT_START;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case DEVICE_XE_1AP:
|
||||||
|
{
|
||||||
|
/* A,B,C,D,Select,START,E1,E2 buttons -> E1(?) E2(?) START SELECT(?) A B C D */
|
||||||
|
if(keystate[SDL_SCANCODE_A]) input.pad[joynum] |= INPUT_START;
|
||||||
|
if(keystate[SDL_SCANCODE_S]) input.pad[joynum] |= INPUT_A;
|
||||||
|
if(keystate[SDL_SCANCODE_D]) input.pad[joynum] |= INPUT_C;
|
||||||
|
if(keystate[SDL_SCANCODE_F]) input.pad[joynum] |= INPUT_Y;
|
||||||
|
if(keystate[SDL_SCANCODE_Z]) input.pad[joynum] |= INPUT_B;
|
||||||
|
if(keystate[SDL_SCANCODE_X]) input.pad[joynum] |= INPUT_X;
|
||||||
|
if(keystate[SDL_SCANCODE_C]) input.pad[joynum] |= INPUT_MODE;
|
||||||
|
if(keystate[SDL_SCANCODE_V]) input.pad[joynum] |= INPUT_Z;
|
||||||
|
|
||||||
|
/* Left Analog Stick (bidirectional) */
|
||||||
|
if(keystate[SDL_SCANCODE_UP]) input.analog[joynum][1]-=2;
|
||||||
|
else if(keystate[SDL_SCANCODE_DOWN]) input.analog[joynum][1]+=2;
|
||||||
|
else input.analog[joynum][1] = 128;
|
||||||
|
if(keystate[SDL_SCANCODE_LEFT]) input.analog[joynum][0]-=2;
|
||||||
|
else if(keystate[SDL_SCANCODE_RIGHT]) input.analog[joynum][0]+=2;
|
||||||
|
else input.analog[joynum][0] = 128;
|
||||||
|
|
||||||
|
/* Right Analog Stick (unidirectional) */
|
||||||
|
if(keystate[SDL_SCANCODE_KP_8]) input.analog[joynum+1][0]-=2;
|
||||||
|
else if(keystate[SDL_SCANCODE_KP_2]) input.analog[joynum+1][0]+=2;
|
||||||
|
else if(keystate[SDL_SCANCODE_KP_4]) input.analog[joynum+1][0]-=2;
|
||||||
|
else if(keystate[SDL_SCANCODE_KP_6]) input.analog[joynum+1][0]+=2;
|
||||||
|
else input.analog[joynum+1][0] = 128;
|
||||||
|
|
||||||
|
/* Limiters */
|
||||||
|
if (input.analog[joynum][0] > 0xFF) input.analog[joynum][0] = 0xFF;
|
||||||
|
else if (input.analog[joynum][0] < 0) input.analog[joynum][0] = 0;
|
||||||
|
if (input.analog[joynum][1] > 0xFF) input.analog[joynum][1] = 0xFF;
|
||||||
|
else if (input.analog[joynum][1] < 0) input.analog[joynum][1] = 0;
|
||||||
|
if (input.analog[joynum+1][0] > 0xFF) input.analog[joynum+1][0] = 0xFF;
|
||||||
|
else if (input.analog[joynum+1][0] < 0) input.analog[joynum+1][0] = 0;
|
||||||
|
if (input.analog[joynum+1][1] > 0xFF) input.analog[joynum+1][1] = 0xFF;
|
||||||
|
else if (input.analog[joynum+1][1] < 0) input.analog[joynum+1][1] = 0;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case DEVICE_PICO:
|
||||||
|
{
|
||||||
|
/* get mouse (absolute values) */
|
||||||
|
int x,y;
|
||||||
|
int state = SDL_GetMouseState(&x,&y);
|
||||||
|
|
||||||
|
/* Calculate X Y axis values */
|
||||||
|
input.analog[0][0] = 0x3c + (x * (0x17c-0x03c+1)) / VIDEO_WIDTH;
|
||||||
|
input.analog[0][1] = 0x1fc + (y * (0x2f7-0x1fc+1)) / VIDEO_HEIGHT;
|
||||||
|
|
||||||
|
/* Map mouse buttons to player #1 inputs */
|
||||||
|
if(state & SDL_BUTTON_MMASK) pico_current = (pico_current + 1) & 7;
|
||||||
|
if(state & SDL_BUTTON_RMASK) input.pad[0] |= INPUT_PICO_RED;
|
||||||
|
if(state & SDL_BUTTON_LMASK) input.pad[0] |= INPUT_PICO_PEN;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case DEVICE_TEREBI:
|
||||||
|
{
|
||||||
|
/* get mouse (absolute values) */
|
||||||
|
int x,y;
|
||||||
|
int state = SDL_GetMouseState(&x,&y);
|
||||||
|
|
||||||
|
/* Calculate X Y axis values */
|
||||||
|
input.analog[0][0] = (x * 250) / VIDEO_WIDTH;
|
||||||
|
input.analog[0][1] = (y * 250) / VIDEO_HEIGHT;
|
||||||
|
|
||||||
|
/* Map mouse buttons to player #1 inputs */
|
||||||
|
if(state & SDL_BUTTON_RMASK) input.pad[0] |= INPUT_B;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case DEVICE_GRAPHIC_BOARD:
|
||||||
|
{
|
||||||
|
/* get mouse (absolute values) */
|
||||||
|
int x,y;
|
||||||
|
int state = SDL_GetMouseState(&x,&y);
|
||||||
|
|
||||||
|
/* Calculate X Y axis values */
|
||||||
|
input.analog[0][0] = (x * 255) / VIDEO_WIDTH;
|
||||||
|
input.analog[0][1] = (y * 255) / VIDEO_HEIGHT;
|
||||||
|
|
||||||
|
/* Map mouse buttons to player #1 inputs */
|
||||||
|
if(state & SDL_BUTTON_LMASK) input.pad[0] |= INPUT_GRAPHIC_PEN;
|
||||||
|
if(state & SDL_BUTTON_RMASK) input.pad[0] |= INPUT_GRAPHIC_MENU;
|
||||||
|
if(state & SDL_BUTTON_MMASK) input.pad[0] |= INPUT_GRAPHIC_DO;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case DEVICE_ACTIVATOR:
|
||||||
|
{
|
||||||
|
if(keystate[SDL_SCANCODE_G]) input.pad[joynum] |= INPUT_ACTIVATOR_7L;
|
||||||
|
if(keystate[SDL_SCANCODE_H]) input.pad[joynum] |= INPUT_ACTIVATOR_7U;
|
||||||
|
if(keystate[SDL_SCANCODE_J]) input.pad[joynum] |= INPUT_ACTIVATOR_8L;
|
||||||
|
if(keystate[SDL_SCANCODE_K]) input.pad[joynum] |= INPUT_ACTIVATOR_8U;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
if(keystate[SDL_SCANCODE_A]) input.pad[joynum] |= INPUT_A;
|
||||||
|
if(keystate[SDL_SCANCODE_S]) input.pad[joynum] |= INPUT_B;
|
||||||
|
if(keystate[SDL_SCANCODE_D]) input.pad[joynum] |= INPUT_C;
|
||||||
|
if(keystate[SDL_SCANCODE_F]) input.pad[joynum] |= INPUT_START;
|
||||||
|
if(keystate[SDL_SCANCODE_Z]) input.pad[joynum] |= INPUT_X;
|
||||||
|
if(keystate[SDL_SCANCODE_X]) input.pad[joynum] |= INPUT_Y;
|
||||||
|
if(keystate[SDL_SCANCODE_C]) input.pad[joynum] |= INPUT_Z;
|
||||||
|
if(keystate[SDL_SCANCODE_V]) input.pad[joynum] |= INPUT_MODE;
|
||||||
|
|
||||||
|
if(keystate[SDL_SCANCODE_UP]) input.pad[joynum] |= INPUT_UP;
|
||||||
|
else
|
||||||
|
if(keystate[SDL_SCANCODE_DOWN]) input.pad[joynum] |= INPUT_DOWN;
|
||||||
|
if(keystate[SDL_SCANCODE_LEFT]) input.pad[joynum] |= INPUT_LEFT;
|
||||||
|
else
|
||||||
|
if(keystate[SDL_SCANCODE_RIGHT]) input.pad[joynum] |= INPUT_RIGHT;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main (int argc, char **argv)
|
||||||
|
{
|
||||||
|
FILE *fp;
|
||||||
|
int running = 1;
|
||||||
|
|
||||||
|
/* Print help if no game specified */
|
||||||
|
if(argc < 2)
|
||||||
|
{
|
||||||
|
char caption[256];
|
||||||
|
sprintf(caption, "Genesis Plus GX\\SDL\nusage: %s gamename\n", argv[0]);
|
||||||
|
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_INFORMATION, "Information", caption, sdl_video.window);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set default config */
|
||||||
|
error_init();
|
||||||
|
set_config_defaults();
|
||||||
|
|
||||||
|
/* mark all BIOS as unloaded */
|
||||||
|
system_bios = 0;
|
||||||
|
|
||||||
|
/* Genesis BOOT ROM support (2KB max) */
|
||||||
|
memset(boot_rom, 0xFF, 0x800);
|
||||||
|
fp = fopen(MD_BIOS, "rb");
|
||||||
|
if (fp != NULL)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* read BOOT ROM */
|
||||||
|
fread(boot_rom, 1, 0x800, fp);
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
/* check BOOT ROM */
|
||||||
|
if (!memcmp((char *)(boot_rom + 0x120),"GENESIS OS", 10))
|
||||||
|
{
|
||||||
|
/* mark Genesis BIOS as loaded */
|
||||||
|
system_bios = SYSTEM_MD;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Byteswap ROM */
|
||||||
|
for (i=0; i<0x800; i+=2)
|
||||||
|
{
|
||||||
|
uint8 temp = boot_rom[i];
|
||||||
|
boot_rom[i] = boot_rom[i+1];
|
||||||
|
boot_rom[i+1] = temp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* initialize SDL */
|
||||||
|
if(SDL_Init(0) < 0)
|
||||||
|
{
|
||||||
|
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error", "SDL initialization failed", sdl_video.window);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
sdl_video_init();
|
||||||
|
if (use_sound) sdl_sound_init();
|
||||||
|
sdl_sync_init();
|
||||||
|
|
||||||
|
/* initialize Genesis virtual system */
|
||||||
|
SDL_LockSurface(sdl_video.surf_bitmap);
|
||||||
|
memset(&bitmap, 0, sizeof(t_bitmap));
|
||||||
|
bitmap.width = 720;
|
||||||
|
bitmap.height = 576;
|
||||||
|
#if defined(USE_8BPP_RENDERING)
|
||||||
|
bitmap.pitch = (bitmap.width * 1);
|
||||||
|
#elif defined(USE_15BPP_RENDERING)
|
||||||
|
bitmap.pitch = (bitmap.width * 2);
|
||||||
|
#elif defined(USE_16BPP_RENDERING)
|
||||||
|
bitmap.pitch = (bitmap.width * 2);
|
||||||
|
#elif defined(USE_32BPP_RENDERING)
|
||||||
|
bitmap.pitch = (bitmap.width * 4);
|
||||||
|
#endif
|
||||||
|
bitmap.data = sdl_video.surf_bitmap->pixels;
|
||||||
|
SDL_UnlockSurface(sdl_video.surf_bitmap);
|
||||||
|
bitmap.viewport.changed = 3;
|
||||||
|
|
||||||
|
/* Load game file */
|
||||||
|
if(!load_rom(argv[1]))
|
||||||
|
{
|
||||||
|
char caption[256];
|
||||||
|
sprintf(caption, "Error loading file `%s'.", argv[1]);
|
||||||
|
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error", caption, sdl_video.window);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* initialize system hardware */
|
||||||
|
audio_init(SOUND_FREQUENCY, 0);
|
||||||
|
system_init();
|
||||||
|
|
||||||
|
/* Mega CD specific */
|
||||||
|
if (system_hw == SYSTEM_MCD)
|
||||||
|
{
|
||||||
|
/* load internal backup RAM */
|
||||||
|
fp = fopen("./scd.brm", "rb");
|
||||||
|
if (fp!=NULL)
|
||||||
|
{
|
||||||
|
fread(scd.bram, 0x2000, 1, fp);
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check if internal backup RAM is formatted */
|
||||||
|
if (memcmp(scd.bram + 0x2000 - 0x20, brm_format + 0x20, 0x20))
|
||||||
|
{
|
||||||
|
/* clear internal backup RAM */
|
||||||
|
memset(scd.bram, 0x00, 0x200);
|
||||||
|
|
||||||
|
/* Internal Backup RAM size fields */
|
||||||
|
brm_format[0x10] = brm_format[0x12] = brm_format[0x14] = brm_format[0x16] = 0x00;
|
||||||
|
brm_format[0x11] = brm_format[0x13] = brm_format[0x15] = brm_format[0x17] = (sizeof(scd.bram) / 64) - 3;
|
||||||
|
|
||||||
|
/* format internal backup RAM */
|
||||||
|
memcpy(scd.bram + 0x2000 - 0x40, brm_format, 0x40);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* load cartridge backup RAM */
|
||||||
|
if (scd.cartridge.id)
|
||||||
|
{
|
||||||
|
fp = fopen("./cart.brm", "rb");
|
||||||
|
if (fp!=NULL)
|
||||||
|
{
|
||||||
|
fread(scd.cartridge.area, scd.cartridge.mask + 1, 1, fp);
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check if cartridge backup RAM is formatted */
|
||||||
|
if (memcmp(scd.cartridge.area + scd.cartridge.mask + 1 - 0x20, brm_format + 0x20, 0x20))
|
||||||
|
{
|
||||||
|
/* clear cartridge backup RAM */
|
||||||
|
memset(scd.cartridge.area, 0x00, scd.cartridge.mask + 1);
|
||||||
|
|
||||||
|
/* Cartridge Backup RAM size fields */
|
||||||
|
brm_format[0x10] = brm_format[0x12] = brm_format[0x14] = brm_format[0x16] = (((scd.cartridge.mask + 1) / 64) - 3) >> 8;
|
||||||
|
brm_format[0x11] = brm_format[0x13] = brm_format[0x15] = brm_format[0x17] = (((scd.cartridge.mask + 1) / 64) - 3) & 0xff;
|
||||||
|
|
||||||
|
/* format cartridge backup RAM */
|
||||||
|
memcpy(scd.cartridge.area + scd.cartridge.mask + 1 - sizeof(brm_format), brm_format, sizeof(brm_format));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sram.on)
|
||||||
|
{
|
||||||
|
/* load SRAM */
|
||||||
|
fp = fopen("./game.srm", "rb");
|
||||||
|
if (fp!=NULL)
|
||||||
|
{
|
||||||
|
fread(sram.sram,0x10000,1, fp);
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* reset system hardware */
|
||||||
|
system_reset();
|
||||||
|
|
||||||
|
if(use_sound) SDL_PauseAudio(0);
|
||||||
|
|
||||||
|
/* 3 frames = 50 ms (60hz) or 60 ms (50hz) */
|
||||||
|
if(sdl_sync.sem_sync)
|
||||||
|
SDL_AddTimer(vdp_pal ? 60 : 50, sdl_sync_timer_callback, NULL);
|
||||||
|
|
||||||
|
/* emulation loop */
|
||||||
|
while(running)
|
||||||
|
{
|
||||||
|
SDL_Event event;
|
||||||
|
if (SDL_PollEvent(&event))
|
||||||
|
{
|
||||||
|
switch(event.type)
|
||||||
|
{
|
||||||
|
case SDL_USEREVENT:
|
||||||
|
{
|
||||||
|
char caption[100];
|
||||||
|
sprintf(caption,"Genesis Plus GX - %d fps - %s", event.user.code, (rominfo.international[0] != 0x20) ? rominfo.international : rominfo.domestic);
|
||||||
|
SDL_SetWindowTitle(sdl_video.window, caption);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case SDL_QUIT:
|
||||||
|
{
|
||||||
|
running = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case SDL_KEYDOWN:
|
||||||
|
{
|
||||||
|
running = sdl_control_update(event.key.keysym.sym);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sdl_video_update();
|
||||||
|
sdl_sound_update(use_sound);
|
||||||
|
|
||||||
|
if(!turbo_mode && sdl_sync.sem_sync && sdl_video.frames_rendered % 3 == 0)
|
||||||
|
{
|
||||||
|
SDL_SemWait(sdl_sync.sem_sync);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (system_hw == SYSTEM_MCD)
|
||||||
|
{
|
||||||
|
/* save internal backup RAM (if formatted) */
|
||||||
|
if (!memcmp(scd.bram + 0x2000 - 0x20, brm_format + 0x20, 0x20))
|
||||||
|
{
|
||||||
|
fp = fopen("./scd.brm", "wb");
|
||||||
|
if (fp!=NULL)
|
||||||
|
{
|
||||||
|
fwrite(scd.bram, 0x2000, 1, fp);
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* save cartridge backup RAM (if formatted) */
|
||||||
|
if (scd.cartridge.id)
|
||||||
|
{
|
||||||
|
if (!memcmp(scd.cartridge.area + scd.cartridge.mask + 1 - 0x20, brm_format + 0x20, 0x20))
|
||||||
|
{
|
||||||
|
fp = fopen("./cart.brm", "wb");
|
||||||
|
if (fp!=NULL)
|
||||||
|
{
|
||||||
|
fwrite(scd.cartridge.area, scd.cartridge.mask + 1, 1, fp);
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sram.on)
|
||||||
|
{
|
||||||
|
/* save SRAM */
|
||||||
|
fp = fopen("./game.srm", "wb");
|
||||||
|
if (fp!=NULL)
|
||||||
|
{
|
||||||
|
fwrite(sram.sram,0x10000,1, fp);
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
audio_shutdown();
|
||||||
|
error_shutdown();
|
||||||
|
|
||||||
|
sdl_video_close();
|
||||||
|
sdl_sound_close();
|
||||||
|
sdl_sync_close();
|
||||||
|
SDL_Quit();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
11
sdl/sdl2/main.h
Normal file
11
sdl/sdl2/main.h
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
|
||||||
|
#ifndef _MAIN_H_
|
||||||
|
#define _MAIN_H_
|
||||||
|
|
||||||
|
#define MAX_INPUTS 8
|
||||||
|
|
||||||
|
extern int debug_on;
|
||||||
|
extern int log_error;
|
||||||
|
extern int sdl_input_update(void);
|
||||||
|
|
||||||
|
#endif /* _MAIN_H_ */
|
Loading…
x
Reference in New Issue
Block a user