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