[Core/Sound] rewrote PSG core from scratch & replaced deprecated "PSG boot noise" option with optional Hiqh Quality PSG resampling

This commit is contained in:
EkeEke 2016-12-18 23:36:59 +01:00
parent 41285e1131
commit 9bb64c47f9
38 changed files with 759 additions and 561 deletions

View File

@ -113,6 +113,11 @@ Genesis Plus GX 1.7.5 (xx/xx/xxxx) (Eke-Eke)
* fixed 68k cycles delay on invalid VRAM writes (fixes "Microcosm" intro loop)
* optimized tile caching
[Core/Sound]
---------------
* rewrote optimized & more accurate PSG core from scratch
* removed PSG boost noise feature & added optional high-quality PSG resampling
[Gamecube/Wii]
---------------
* added configurable BIOS & Lock-on ROM files

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 MiB

After

Width:  |  Height:  |  Size: 3.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 MiB

After

Width:  |  Height:  |  Size: 3.3 MiB

View File

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

View File

@ -1218,7 +1218,7 @@ void vdp_write_byte(unsigned int address, unsigned int data)
{
if (address & 1)
{
SN76489_Write(m68k.cycles, data);
psg_write(m68k.cycles, data);
return;
}
m68k_unused_8_w(address, data);
@ -1264,7 +1264,7 @@ void vdp_write_word(unsigned int address, unsigned int data)
case 0x10: /* PSG */
case 0x14:
{
SN76489_Write(m68k.cycles, data & 0xFF);
psg_write(m68k.cycles, data & 0xFF);
return;
}

View File

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

View File

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

View File

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

View File

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

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

@ -0,0 +1,591 @@
/***************************************************************************************
* Genesis Plus
* PSG sound chip (SN76489A compatible)
*
* Support for discrete chip & integrated (ASIC) clones
*
* Noise implementation based on http://www.smspower.org/Development/SN76489#NoiseChannel
*
* Copyright (C) 2016 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
*
* - Redistributions may not be sold, nor may they be used in a commercial
* product or activity.
*
* - Redistributions that are modified from the original source must include the
* complete source code, including the source code for all components used by a
* binary built from the modified sources. However, as a special exception, the
* source code distributed need not include anything that is normally distributed
* (in either source or binary form) with the major components (compiler, kernel,
* and so on) of the operating system on which the executable runs, unless that
* component itself accompanies the executable.
*
* - Redistributions must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************************/
#include "shared.h"
#include "blip_buf.h"
/* internal clock = input clock : 16 = (master clock : 15) : 16 */
#define PSG_MCYCLES_RATIO (15*16)
/* maximal channel output (roughly adjusted to match VA4 MD1 PSG/FM balance with 1.5x amplification of PSG output) */
#define PSG_MAX_VOLUME 2800
static const uint8 noiseShiftWidth[2] = {14,15};
static const uint8 noiseBitMask[2] = {0x6,0x9};
static const uint8 noiseFeedback[10] = {0,1,1,0,1,0,0,1,1,0};
static const uint16 chanVolume[16] = {
PSG_MAX_VOLUME, /* MAX */
PSG_MAX_VOLUME * 0.794328234, /* -2dB */
PSG_MAX_VOLUME * 0.630957344, /* -4dB */
PSG_MAX_VOLUME * 0.501187233, /* -6dB */
PSG_MAX_VOLUME * 0.398107170, /* -8dB */
PSG_MAX_VOLUME * 0.316227766, /* -10dB */
PSG_MAX_VOLUME * 0.251188643, /* -12dB */
PSG_MAX_VOLUME * 0.199526231, /* -14dB */
PSG_MAX_VOLUME * 0.158489319, /* -16dB */
PSG_MAX_VOLUME * 0.125892541, /* -18dB */
PSG_MAX_VOLUME * 0.1, /* -20dB */
PSG_MAX_VOLUME * 0.079432823, /* -22dB */
PSG_MAX_VOLUME * 0.063095734, /* -24dB */
PSG_MAX_VOLUME * 0.050118723, /* -26dB */
PSG_MAX_VOLUME * 0.039810717, /* -28dB */
0 /* OFF */
};
static struct
{
int clocks;
int latch;
int noiseShiftValue;
int noiseShiftWidth;
int noiseBitMask;
int regs[8];
int freqInc[4];
int freqCounter[4];
int polarity[4];
int chanDelta[4][2];
int chanOut[4][2];
int chanAmp[4][2];
} psg;
static void psg_update(unsigned int clocks);
void psg_init(PSG_TYPE type)
{
int i;
/* Initialize stereo amplification (default) */
for (i=0; i<4; i++)
{
psg.chanAmp[i][0] = 100;
psg.chanAmp[i][1] = 100;
}
/* Initialize Noise LSFR type */
psg.noiseShiftWidth = noiseShiftWidth[type];
psg.noiseBitMask = noiseBitMask[type];
}
void psg_reset()
{
int i;
/* power-on state (verified on 315-5313A & 315-5660 integrated version only) */
for (i=0; i<4; i++)
{
psg.regs[i*2] = 0;
psg.regs[i*2+1] = 0;
psg.freqInc[i] = (i < 3) ? (1 * PSG_MCYCLES_RATIO) : (16 * PSG_MCYCLES_RATIO);
psg.freqCounter[i] = 0;
psg.polarity[i] = -1;
psg.chanDelta[i][0] = 0;
psg.chanDelta[i][1] = 0;
psg.chanOut[i][0] = 0;
psg.chanOut[i][1] = 0;
}
/* noise attenuation register is latched on power-on (verified on 315-5313A & 315-5660 integrated version only) */
psg.latch = 7;
/* reset noise shift register */
psg.noiseShiftValue = 1 << psg.noiseShiftWidth;
/* reset internal M-cycles clock counter */
psg.clocks = 0;
}
int psg_context_save(uint8 *state)
{
int bufferptr = 0;
save_param(&psg.clocks,sizeof(psg.clocks));
save_param(&psg.latch,sizeof(psg.latch));
save_param(&psg.noiseShiftValue,sizeof(psg.noiseShiftValue));
save_param(psg.regs,sizeof(psg.regs));
save_param(psg.freqInc,sizeof(psg.freqInc));
save_param(psg.freqCounter,sizeof(psg.freqCounter));
save_param(psg.polarity,sizeof(psg.polarity));
save_param(psg.chanDelta,sizeof(psg.chanDelta));
save_param(psg.chanOut,sizeof(psg.chanOut));
return bufferptr;
}
int psg_context_load(uint8 *state)
{
int chanOut[4][2], delta[2];
int i, bufferptr = 0;
/* get current tone channels output */
for (i=0; i<3; i++)
{
if (psg.polarity[i] > 0)
{
chanOut[i][0] = psg.chanOut[i][0];
chanOut[i][1] = psg.chanOut[i][1];
}
else
{
chanOut[i][0] = 0;
chanOut[i][1] = 0;
}
}
/* get current noise channel output */
if (psg.noiseShiftValue & 1)
{
chanOut[3][0] = psg.chanOut[3][0];
chanOut[3][1] = psg.chanOut[3][1];
}
else
{
chanOut[3][0] = 0;
chanOut[3][1] = 0;
}
load_param(&psg.clocks,sizeof(psg.clocks));
load_param(&psg.latch,sizeof(psg.latch));
load_param(&psg.noiseShiftValue,sizeof(psg.noiseShiftValue));
load_param(psg.regs,sizeof(psg.regs));
load_param(psg.freqInc,sizeof(psg.freqInc));
load_param(psg.freqCounter,sizeof(psg.freqCounter));
load_param(psg.polarity,sizeof(psg.polarity));
load_param(psg.chanDelta,sizeof(psg.chanDelta));
load_param(psg.chanOut,sizeof(psg.chanOut));
/* apply any pending channel volume variation */
for (i=0; i<4; i++)
{
psg.chanOut[i][0] += psg.chanDelta[i][0];
psg.chanOut[i][1] += psg.chanDelta[i][1];
psg.chanDelta[i][0] = 0;
psg.chanDelta[i][1] = 0;
}
/* calculate noise channel output variations */
if (psg.noiseShiftValue & 1)
{
/* channel output is high */
delta[0] = psg.chanOut[3][0] - chanOut[3][0];
delta[1] = psg.chanOut[3][0] - chanOut[3][1];
}
else
{
/* channel output is low */
delta[0] = -chanOut[3][0];
delta[1] = -chanOut[3][1];
}
/* add tone channels output variations */
for (i=0; i<3; i++)
{
if (psg.polarity[i] > 0)
{
/* channel output is high */
delta[0] += (psg.chanOut[i][0] - chanOut[i][0]);
delta[1] += (psg.chanOut[i][0] - chanOut[i][1]);
}
else
{
/* channel output is low */
delta[0] -= chanOut[i][0];
delta[1] -= chanOut[i][1];
}
}
/* update mixed channels output */
if (config.hq_psg)
{
blip_add_delta(snd.blips[0], psg.clocks, delta[0], delta[1]);
}
else
{
blip_add_delta_fast(snd.blips[0], psg.clocks, delta[0], delta[1]);
}
return bufferptr;
}
void psg_write(unsigned int clocks, unsigned int data)
{
int index;
/* PSG chip synchronization */
if (clocks > psg.clocks)
{
/* run PSG chip until current timestamp */
psg_update(clocks);
/* update internal M-cycles clock counter */
psg.clocks += ((clocks - psg.clocks + PSG_MCYCLES_RATIO - 1) / PSG_MCYCLES_RATIO) * PSG_MCYCLES_RATIO;
}
if (data & 0x80)
{
/* latch register index (1xxx----) */
psg.latch = index = (data >> 4) & 0x07;
}
else
{
/* restore latched register index */
index= psg.latch;
}
switch (index)
{
case 0:
case 2:
case 4: /* Tone channels frequency */
{
/* recalculate frequency register value */
if (data & 0x80)
{
/* update 10-bit register LSB (1---xxxx) */
data = (psg.regs[index] & 0x3f0) | (data & 0x0f);
}
else
{
/* update 10-bit register MSB (0-xxxxxx) */
data = (psg.regs[index] & 0x00f) | ((data & 0x3f) << 4);
}
/* update channel M-cycle counter increment */
if (data)
{
psg.freqInc[index>>1] = data * PSG_MCYCLES_RATIO;
}
else
{
/* zero value behaves the same as a value of 1 (verified on integrated version only) */
psg.freqInc[index>>1] = PSG_MCYCLES_RATIO;
}
/* update noise channel counter increment if required */
if ((index == 4) && ((psg.regs[6] & 0x03) == 0x03))
{
psg.freqInc[3] = psg.freqInc[2];
}
break;
}
case 6: /* Noise control */
{
/* noise signal generator frequency (----?xxx) */
int noiseFreq = (data & 0x03);
if (noiseFreq == 0x03)
{
/* noise generator is controlled by tone channel #3 generator */
psg.freqInc[3] = psg.freqInc[2];
psg.freqCounter[3] = psg.freqCounter[2];
}
else
{
/* noise generator is running at separate frequency */
psg.freqInc[3] = (0x10 << noiseFreq) * PSG_MCYCLES_RATIO;
}
/* reset shift register value */
psg.noiseShiftValue = 1 << psg.noiseShiftWidth;;
break;
}
case 7: /* Noise channel attenuation */
{
/* convert 4-bit attenuation value (----xxxx) to 16-bit volume value */
data = chanVolume[data & 0x0f];
/* check noise shift register output */
if (psg.noiseShiftValue & 1)
{
/* channel output is high, volume variation will be applied at next internal cycle update */
psg.chanDelta[3][0] = ((data * psg.chanAmp[3][0]) / 100) - psg.chanOut[3][0];
psg.chanDelta[3][1] = ((data * psg.chanAmp[3][1]) / 100) - psg.chanOut[3][1];
}
else
{
/* channel output is low, volume variation will be applied at next transition */
psg.chanOut[3][0] = (data * psg.chanAmp[3][0]) / 100;
psg.chanOut[3][1] = (data * psg.chanAmp[3][1]) / 100;
}
break;
}
default: /* Tone channels attenuation */
{
/* channel number (0-2) */
int i = index >> 1;
/* convert 4-bit attenuation value (----xxxx) to 16-bit volume value */
data = chanVolume[data & 0x0f];
/* check tone generator polarity */
if (psg.polarity[i] > 0)
{
/* channel output is high, volume variation will be applied at next internal cycle update */
psg.chanDelta[i][0] = ((data * psg.chanAmp[i][0]) / 100) - psg.chanOut[i][0];
psg.chanDelta[i][1] = ((data * psg.chanAmp[i][1]) / 100) - psg.chanOut[i][1];
}
else
{
/* channel output is low, volume variation will be applied at next transition */
psg.chanOut[i][0] = (data * psg.chanAmp[i][0]) / 100;
psg.chanOut[i][1] = (data * psg.chanAmp[i][1]) / 100;
}
break;
}
}
/* save register value */
psg.regs[index] = data;
}
void psg_config(unsigned int clocks, unsigned int preamp, unsigned int panning)
{
int i;
/* PSG chip synchronization */
if (clocks > psg.clocks)
{
/* run PSG chip until current timestamp */
psg_update(clocks);
/* update internal M-cycles clock counter */
psg.clocks += ((clocks - psg.clocks + PSG_MCYCLES_RATIO - 1) / PSG_MCYCLES_RATIO) * PSG_MCYCLES_RATIO;
}
for (i=0; i<4; i++)
{
/* channel internal volume */
int volume = psg.regs[i*2+1];
/* update channel stereo amplification */
psg.chanAmp[i][0] = preamp * ((panning >> (i + 4)) & 1);
psg.chanAmp[i][1] = preamp * ((panning >> (i + 0)) & 1);
/* tone channels */
if (i < 3)
{
/* check tone generator polarity */
if (psg.polarity[i] > 0)
{
/* channel output is high, volume variation will be applied at next internal cycle update */
psg.chanDelta[i][0] = ((volume * psg.chanAmp[i][0]) / 100) - psg.chanOut[i][0];
psg.chanDelta[i][1] = ((volume * psg.chanAmp[i][1]) / 100) - psg.chanOut[i][1];
}
else
{
/* channel output is low, volume variation will be applied at next transition*/
psg.chanOut[i][0] = (volume * psg.chanAmp[i][0]) / 100;
psg.chanOut[i][1] = (volume * psg.chanAmp[i][1]) / 100;
}
}
/* noise channel */
else
{
/* check noise shift register output */
if (psg.noiseShiftValue & 1)
{
/* channel output is high, volume variation will be applied at next internal cycle update */
psg.chanDelta[3][0] = ((volume * psg.chanAmp[3][0]) / 100) - psg.chanOut[3][0];
psg.chanDelta[3][1] = ((volume * psg.chanAmp[3][1]) / 100) - psg.chanOut[3][1];
}
else
{
/* channel output is low, volume variation will be applied at next transition */
psg.chanOut[3][0] = (volume * psg.chanAmp[3][0]) / 100;
psg.chanOut[3][1] = (volume * psg.chanAmp[3][1]) / 100;
}
}
}
}
void psg_end_frame(unsigned int clocks)
{
int i;
if (clocks > psg.clocks)
{
/* run PSG chip until current timestamp */
psg_update(clocks);
/* update internal M-cycles clock counter */
psg.clocks += ((clocks - psg.clocks + PSG_MCYCLES_RATIO - 1) / PSG_MCYCLES_RATIO) * PSG_MCYCLES_RATIO;
}
/* adjust internal M-cycles clock counter for next frame */
psg.clocks -= clocks;
/* adjust channels time counters for next frame */
for (i=0; i<4; ++i)
{
psg.freqCounter[i] -= clocks;
}
}
static void psg_update(unsigned int clocks)
{
int i, timestamp, polarity;
for (i=0; i<4; i++)
{
/* apply any pending channel volume variations */
if (psg.chanDelta[i][0] | psg.chanDelta[i][1])
{
/* update channel output */
if (config.hq_psg)
{
blip_add_delta(snd.blips[0], psg.clocks, psg.chanDelta[i][0], psg.chanDelta[i][1]);
}
else
{
blip_add_delta_fast(snd.blips[0], psg.clocks, psg.chanDelta[i][0], psg.chanDelta[i][1]);
}
/* update channel volume */
psg.chanOut[i][0] += psg.chanDelta[i][0];
psg.chanOut[i][1] += psg.chanDelta[i][1];
/* clear pending channel volume variations */
psg.chanDelta[i][0] = 0;
psg.chanDelta[i][1] = 0;
}
/* timestamp of next transition */
timestamp = psg.freqCounter[i];
/* current channel generator polarity */
polarity = psg.polarity[i];
/* Tone channels */
if (i < 3)
{
/* process all transitions occurring until current clock timestamp */
while (timestamp < clocks)
{
/* invert tone generator polarity */
polarity = -polarity;
/* update channel output */
if (config.hq_psg)
{
blip_add_delta(snd.blips[0], timestamp, polarity*psg.chanOut[i][0], polarity*psg.chanOut[i][1]);
}
else
{
blip_add_delta_fast(snd.blips[0], timestamp, polarity*psg.chanOut[i][0], polarity*psg.chanOut[i][1]);
}
/* timestamp of next transition */
timestamp += psg.freqInc[i];
}
}
/* Noise channel */
else
{
/* current noise shift register value */
int shiftValue = psg.noiseShiftValue;
/* process all transitions occurring until current clock timestamp */
while (timestamp < clocks)
{
/* invert noise generator polarity */
polarity = -polarity;
/* noise register is shifted on positive edge only */
if (polarity > 0)
{
/* current shift register output */
int shiftOutput = shiftValue & 0x01;
/* White noise (----1xxx) */
if (psg.regs[6] & 0x04)
{
/* shift and apply XOR feedback network */
shiftValue = (shiftValue >> 1) | (noiseFeedback[shiftValue & psg.noiseBitMask] << psg.noiseShiftWidth);
}
/* Periodic noise (----0xxx) */
else
{
/* shift and feedback current output */
shiftValue = (shiftValue >> 1) | (shiftOutput << psg.noiseShiftWidth);
}
/* shift register output variation */
shiftOutput = (shiftValue & 0x1) - shiftOutput;
/* update noise channel output */
if (config.hq_psg)
{
blip_add_delta(snd.blips[0], timestamp, shiftOutput*psg.chanOut[3][0], shiftOutput*psg.chanOut[3][1]);
}
else
{
blip_add_delta_fast(snd.blips[0], timestamp, shiftOutput*psg.chanOut[3][0], shiftOutput*psg.chanOut[3][1]);
}
}
/* timestamp of next transition */
timestamp += psg.freqInc[3];
}
/* save shift register value */
psg.noiseShiftValue = shiftValue;
}
/* save timestamp of next transition */
psg.freqCounter[i] = timestamp;
/* save channel generator polarity */
psg.polarity[i] = polarity;
}
}

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

@ -0,0 +1,60 @@
/***************************************************************************************
* Genesis Plus
* PSG sound chip (SN76489A compatible)
*
* Support for discrete chip & integrated (ASIC) clones
*
* Noise implementation based on http://www.smspower.org/Development/SN76489#NoiseChannel
*
* Copyright (C) 2016 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
*
* - Redistributions may not be sold, nor may they be used in a commercial
* product or activity.
*
* - Redistributions that are modified from the original source must include the
* complete source code, including the source code for all components used by a
* binary built from the modified sources. However, as a special exception, the
* source code distributed need not include anything that is normally distributed
* (in either source or binary form) with the major components (compiler, kernel,
* and so on) of the operating system on which the executable runs, unless that
* component itself accompanies the executable.
*
* - Redistributions must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************************/
#ifndef _PSG_H_
#define _PSG_H_
typedef enum {
PSG_DISCRETE,
PSG_INTEGRATED
} PSG_TYPE;
/* Function prototypes */
extern void psg_init(PSG_TYPE type);
extern void psg_reset(void);
extern int psg_context_save(uint8 *state);
extern int psg_context_load(uint8 *state);
extern void psg_write(unsigned int clocks, unsigned int data);
extern void psg_config(unsigned int clocks, unsigned int preamp, unsigned int panning);
extern void psg_end_frame(unsigned int clocks);
#endif /* _PSG_H_ */

View File

@ -1,418 +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
04/11/16 Eke-Eke (Genesis Plus GX)
- improved resampling quality (removes aliasing noise when using high frequency tones)
- removed cut-off value (improves emulation accuracy of highest frequency tones)
- modified channels output to 0/1 like real chip instead of -1/+1 (fixes PCM voices when cut-off value is removed)
*/
#include "shared.h"
#define PSG_MCYCLES_RATIO (16 * 15)
/* Initial state of shift register */
#define NoiseInitialState 0x8000
/* 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)
{
/* left & right output */
int delta_l = (SN76489.Channel[i][0] * SN76489.ToneFreqPos[i]) - SN76489.ChanOut[i][0];
int delta_r = (SN76489.Channel[i][1] * SN76489.ToneFreqPos[i]) - SN76489.ChanOut[i][1];
blip_add_delta(snd.blips[0], time, delta_l, delta_r);
SN76489.ChanOut[i][0] += delta_l;
SN76489.ChanOut[i][1] += delta_r;
}
/* Updates noise amplitude in delta buffer. Call whenever amplitude might have changed. */
INLINE void UpdateNoiseAmplitude(int time)
{
/* left & right output */
int delta_l = (SN76489.Channel[3][0] * ( SN76489.NoiseShiftRegister & 0x1 )) - SN76489.ChanOut[3][0];
int delta_r = (SN76489.Channel[3][1] * ( SN76489.NoiseShiftRegister & 0x1 )) - SN76489.ChanOut[3][1];
blip_add_delta(snd.blips[0], time, delta_l, delta_r);
SN76489.ChanOut[3][0] += delta_l;
SN76489.ChanOut[3][1] += delta_r;
}
/* 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)
{
/* Flip the flip-flop */
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] ^= 1;
if (SN76489.ToneFreqPos[3])
{
/* 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 (applied to all channels) */
SN76489.PreAmp[i][0] = SN76489.PreAmp[i][0] << boostNoise;
SN76489.PreAmp[i][1] = SN76489.PreAmp[i][1] << boostNoise;
/* update stereo channel amplitude */
SN76489.Channel[i][0]= (PSGVolumeValues[SN76489.Registers[i*2 + 1]] * SN76489.PreAmp[i][0]) / 100;
SN76489.Channel[i][1]= (PSGVolumeValues[SN76489.Registers[i*2 + 1]] * SN76489.PreAmp[i][1]) / 100;
}
}
void SN76489_Update(unsigned int clocks)
{
int i;
if (clocks > SN76489.clocks)
{
/* Run chip until current timestamp */
SN76489_RunUntil(clocks);
/* Update internal M-cycle counter */
SN76489.clocks += ((clocks - SN76489.clocks + PSG_MCYCLES_RATIO - 1) / PSG_MCYCLES_RATIO) * PSG_MCYCLES_RATIO;
}
/* Adjust internal M-cycle counter for next frame */
SN76489.clocks -= clocks;
/* Adjust channel time counters for new frame */
for (i=0; i<4; ++i)
{
SN76489.ToneFreqVals[i] -= clocks;
}
}
void SN76489_Write(unsigned int clocks, unsigned int data)
{
unsigned int index;
if (clocks > SN76489.clocks)
{
/* run chip until current timestamp */
SN76489_RunUntil(clocks);
/* update internal M-cycle counter */
SN76489.clocks += ((clocks - SN76489.clocks + PSG_MCYCLES_RATIO - 1) / PSG_MCYCLES_RATIO) * PSG_MCYCLES_RATIO;
}
if (data & 0x80)
{
/* latch byte %1 cc t dddd */
SN76489.LatchedRegister = index = (data >> 4) & 0x07;
}
else
{
/* restore latched register index */
index = SN76489.LatchedRegister;
}
switch (index)
{
case 0:
case 2:
case 4: /* Tone Channels frequency */
{
if (data & 0x80)
{
/* Data byte %1 cc t dddd */
SN76489.Registers[index] = (SN76489.Registers[index] & 0x3f0) | (data & 0xf);
}
else
{
/* Data byte %0 - dddddd */
SN76489.Registers[index] = (SN76489.Registers[index] & 0x00f) | ((data & 0x3f) << 4);
}
/* zero frequency behaves the same as a value of 1 */
if (SN76489.Registers[index] == 0)
{
SN76489.Registers[index] = 1;
}
break;
}
case 1:
case 3:
case 5: /* Tone Channels attenuation */
{
data &= 0x0f;
SN76489.Registers[index] = data;
data = PSGVolumeValues[data];
index >>= 1;
SN76489.Channel[index][0] = (data * SN76489.PreAmp[index][0]) / 100;
SN76489.Channel[index][1] = (data * SN76489.PreAmp[index][1]) / 100;
break;
}
case 6: /* Noise control */
{
SN76489.Registers[6] = data & 0x0f;
/* reset shift register */
SN76489.NoiseShiftRegister = NoiseInitialState;
/* set noise signal generator frequency */
SN76489.NoiseFreq = 0x10 << (data&0x3);
break;
}
case 7: /* Noise attenuation */
{
data &= 0x0f;
SN76489.Registers[7] = data;
data = PSGVolumeValues[data];
SN76489.Channel[3][0] = (data * SN76489.PreAmp[3][0]) / 100;
SN76489.Channel[3][1] = (data * SN76489.PreAmp[3][1]) / 100;
break;
}
}
}

View File

@ -1,23 +0,0 @@
/*
SN76489 emulation
by Maxim in 2001 and 2002
*/
#ifndef _SN76489_H_
#define _SN76489_H_
#include "blip_buf.h"
#define SN_DISCRETE 0
#define SN_INTEGRATED 1
/* Function prototypes */
extern void SN76489_Init(int type);
extern void SN76489_Reset(void);
extern void SN76489_Config(unsigned int clocks, int preAmp, int boostNoise, int stereo);
extern void SN76489_Write(unsigned int clocks, unsigned int data);
extern void SN76489_Update(unsigned int cycles);
extern void *SN76489_GetContextPtr(void);
extern int SN76489_GetContextSize(void);
#endif /* _SN76489_H_ */

View File

@ -86,7 +86,7 @@ void sound_init( void )
YM_Update = YM2612Update;
YM_Write = YM2612Write;
/* chip is running a VCLK / 144 = MCLK / 7 / 144 */
/* chip is running at VCLK / 144 = MCLK / 7 / 144 */
fm_cycles_ratio = 144 * 7;
}
else
@ -97,21 +97,20 @@ void sound_init( void )
YM_Update = YM2413Update;
YM_Write = YM2413Write;
/* chip is running a ZCLK / 72 = MCLK / 15 / 72 */
/* chip is running at ZCLK / 72 = MCLK / 15 / 72 */
fm_cycles_ratio = 72 * 15;
}
/* Initialize PSG chip */
SN76489_Init((system_hw == SYSTEM_SG) ? SN_DISCRETE : SN_INTEGRATED);
SN76489_Config(0, config.psg_preamp, config.psgBoostNoise, 0xff);
psg_init((system_hw == SYSTEM_SG) ? PSG_DISCRETE : PSG_INTEGRATED);
}
void sound_reset(void)
{
/* reset sound chips */
YM_Reset();
SN76489_Reset();
SN76489_Config(0, config.psg_preamp, config.psgBoostNoise, 0xff);
psg_reset();
psg_config(0, config.psg_preamp, 0xff);
/* reset FM buffer ouput */
fm_last[0] = fm_last[1] = 0;
@ -127,8 +126,10 @@ int sound_update(unsigned int cycles)
{
int prev_l, prev_r, preamp, time, l, r, *ptr;
/* Run PSG & FM chips until end of frame */
SN76489_Update(cycles);
/* Run PSG chip until end of frame */
psg_end_frame(cycles);
/* Run FM chip until end of frame */
fm_update(cycles);
/* FM output pre-amplification */
@ -210,7 +211,7 @@ int sound_context_save(uint8 *state)
save_param(YM2413GetContextPtr(),YM2413GetContextSize());
}
save_param(SN76489_GetContextPtr(),SN76489_GetContextSize());
bufferptr += psg_context_save(&state[bufferptr]);
save_param(&fm_cycles_start,sizeof(fm_cycles_start));
@ -231,7 +232,7 @@ int sound_context_load(uint8 *state)
load_param(YM2413GetContextPtr(),YM2413GetContextSize());
}
load_param(SN76489_GetContextPtr(),SN76489_GetContextSize());
bufferptr += psg_context_load(&state[bufferptr]);
load_param(&fm_cycles_start,sizeof(fm_cycles_start));
fm_cycles_count = fm_cycles_start;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -3,7 +3,7 @@
*
* Genesis Plus GX libretro port
*
* Copyright Eke-Eke (2007-2015)
* Copyright Eke-Eke (2007-2016)
*
* Copyright Daniel De Matteis (2012-2016)
*
@ -495,8 +495,8 @@ static void config_default(void)
/* sound options */
config.psg_preamp = 150;
config.fm_preamp = 100;
config.hq_fm = 1; /* high-quality resampling */
config.psgBoostNoise = 1;
config.hq_fm = 1; /* high-quality FM resampling (slower) */
config.hq_psg = 1; /* high-quality PSG resampling (slower) */
config.filter = 0; /* no filter */
config.lp_range = 0x9999; /* 0.6 in 16.16 fixed point */
config.low_freq = 880;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -3,7 +3,7 @@
*
* Genesis Plus GX libretro port
*
* Copyright Eke-Eke (2007-2015)
* Copyright Eke-Eke (2007-2016)
*
* Copyright Daniel De Matteis (2012-2016)
*
@ -84,7 +84,7 @@ struct
char version[16];
uint8 hq_fm;
uint8 filter;
uint8 psgBoostNoise;
uint8 hq_psg;
uint8 dac_bits;
uint8 ym2413;
uint8 mono;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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