added YM2413 emulation in Master System compatibility mode

This commit is contained in:
ekeeke31 2011-04-29 13:24:33 +00:00
parent b6bc325353
commit d0eab7d8d9
10 changed files with 1871 additions and 67 deletions

View File

@ -85,6 +85,7 @@ void config_default(void)
config.hg = 1.0; config.hg = 1.0;
config.rolloff = 0.995; config.rolloff = 0.995;
config.dac_bits = 14; config.dac_bits = 14;
config.ym2413_enabled = 1;
/* system options */ /* system options */
config.region_detect = 0; config.region_detect = 0;

View File

@ -24,7 +24,7 @@
#ifndef _CONFIG_H_ #ifndef _CONFIG_H_
#define _CONFIG_H_ #define _CONFIG_H_
#define CONFIG_VERSION "GENPLUS-GX 1.4.1" #define CONFIG_VERSION "GENPLUS-GX 1.5.1"
/**************************************************************************** /****************************************************************************
* Config Option * Config Option
@ -37,6 +37,7 @@ typedef struct
uint8 filter; uint8 filter;
uint8 psgBoostNoise; uint8 psgBoostNoise;
uint8 dac_bits; uint8 dac_bits;
uint8 ym2413_enabled;
int16 psg_preamp; int16 psg_preamp;
int16 fm_preamp; int16 fm_preamp;
int16 lp_range; int16 lp_range;

View File

@ -321,20 +321,21 @@ static gui_item items_options[5] =
}; };
/* Audio options */ /* Audio options */
static gui_item items_audio[12] = static gui_item items_audio[13] =
{ {
{NULL,NULL,"High-Quality FM: ON", "Enable/disable YM2612 resampling", 56,132,276,48}, {NULL,NULL,"Master System FM: ON", "Enable/disable YM2413 chip", 56,132,276,48},
{NULL,NULL,"FM Roll-off: 0.999", "Adjust FIR low-pass filtering", 56,132,276,48}, {NULL,NULL,"High-Quality FM: ON", "Enable/disable YM2612/YM2413 resampling", 56,132,276,48},
{NULL,NULL,"FM Resolution: MAX", "Adjust YM2612 DAC precision", 56,132,276,48}, {NULL,NULL,"FM Roll-off: 0.999", "Adjust FIR low-pass filtering", 56,132,276,48},
{NULL,NULL,"FM Volume: 1.00", "Adjust YM2612 output level", 56,132,276,48}, {NULL,NULL,"FM Resolution: MAX", "Adjust YM2612 DAC precision", 56,132,276,48},
{NULL,NULL,"PSG Volume: 2.50", "Adjust SN76489 output level", 56,132,276,48}, {NULL,NULL,"FM Volume: 1.00", "Adjust YM2612/YM2413 output level", 56,132,276,48},
{NULL,NULL,"PSG Noise Boost: OFF", "Boost SN76489 Noise Channel", 56,132,276,48}, {NULL,NULL,"PSG Volume: 2.50", "Adjust SN76489 output level", 56,132,276,48},
{NULL,NULL,"Filtering: 3-BAND EQ", "Setup Audio filtering", 56,132,276,48}, {NULL,NULL,"PSG Noise Boost: OFF", "Boost SN76489 Noise Channel", 56,132,276,48},
{NULL,NULL,"Low Gain: 1.00", "Adjust EQ Low Band Gain", 56,132,276,48}, {NULL,NULL,"Filtering: 3-BAND EQ", "Setup Audio filtering", 56,132,276,48},
{NULL,NULL,"Mid Gain: 1.00", "Adjust EQ Mid Band Gain", 56,132,276,48}, {NULL,NULL,"Low Gain: 1.00", "Adjust EQ Low Band Gain", 56,132,276,48},
{NULL,NULL,"High Gain: 1.00", "Adjust EQ High BandGain", 56,132,276,48}, {NULL,NULL,"Mid Gain: 1.00", "Adjust EQ Mid Band Gain", 56,132,276,48},
{NULL,NULL,"Low Freq: 200 Hz", "Adjust EQ Lowest Frequency", 56,132,276,48}, {NULL,NULL,"High Gain: 1.00", "Adjust EQ High BandGain", 56,132,276,48},
{NULL,NULL,"High Freq: 20000 Hz", "Adjust EQ Highest Frequency", 56,132,276,48} {NULL,NULL,"Low Freq: 200 Hz", "Adjust EQ Lowest Frequency", 56,132,276,48},
{NULL,NULL,"High Freq: 20000 Hz", "Adjust EQ Highest Frequency", 56,132,276,48}
}; };
/* System options */ /* System options */
@ -584,7 +585,7 @@ static gui_menu menu_audio =
{ {
"Audio Settings", "Audio Settings",
0,0, 0,0,
8,4,6,0, 9,4,6,0,
items_audio, items_audio,
buttons_list, buttons_list,
bg_list, bg_list,
@ -755,19 +756,19 @@ static int update_snd_items(void)
if (config.hq_fm) if (config.hq_fm)
{ {
sprintf (items[0].text, "High-Quality FM: ON"); sprintf (items[1].text, "High-Quality FM: ON");
sprintf (items[1].text, "FM Roll-off: %1.2f %%",rolloff); sprintf (items[2].text, "FM Roll-off: %1.2f %%",rolloff);
strcpy (items[1].comment, "Adjust FIR low-pass filtering"); strcpy (items[2].comment, "Adjust FIR low-pass filtering");
offset = 2; offset = 3;
} }
else else
{ {
sprintf (items[0].text, "High-Quality FM: OFF"); sprintf (items[1].text, "High-Quality FM: OFF");
offset = 1; offset = 2;
} }
strcpy(items[offset].comment, "Adjust YM2612 DAC precision"); strcpy(items[offset].comment, "Adjust YM2612 DAC precision");
strcpy(items[offset+1].comment, "Adjust YM2612 output level"); strcpy(items[offset+1].comment, "Adjust YM2612/YM2413 output level");
strcpy(items[offset+2].comment, "Adjust SN76489 output level"); strcpy(items[offset+2].comment, "Adjust SN76489 output level");
strcpy(items[offset+3].comment, "Boost SN76489 Noise Channel"); strcpy(items[offset+3].comment, "Boost SN76489 Noise Channel");
strcpy(items[offset+4].comment, "Configure Audio filtering"); strcpy(items[offset+4].comment, "Configure Audio filtering");
@ -836,10 +837,10 @@ static void soundmenu ()
/* special case */ /* special case */
if (config.hq_fm) if (config.hq_fm)
{ {
if (ret == 1) if (ret == 2)
{ {
GUI_OptionBox(m,0,"FM Roll-off",(void *)&rolloff,0.1,95.0,99.9,0); GUI_OptionBox(m,0,"FM Roll-off",(void *)&rolloff,0.1,95.0,99.9,0);
sprintf (items[1].text, "FM Roll-off: %1.2f %%",rolloff); sprintf (items[2].text, "FM Roll-off: %1.2f %%",rolloff);
config.rolloff = rolloff / 100.0; config.rolloff = rolloff / 100.0;
ret = 255; ret = 255;
if (cart.romsize) if (cart.romsize)
@ -860,7 +861,7 @@ static void soundmenu ()
} }
} }
} }
else if (ret > 1) else if (ret > 2)
{ {
ret--; ret--;
} }
@ -869,6 +870,11 @@ static void soundmenu ()
switch (ret) switch (ret)
{ {
case 0: case 0:
config.ym2413_enabled ^= 1;
sprintf (items[0].text, "Master System FM: %s", config.ym2413_enabled ? "ON":"OFF");
break;
case 1:
config.hq_fm ^= 1; config.hq_fm ^= 1;
offset = update_snd_items(); offset = update_snd_items();
@ -891,7 +897,7 @@ static void soundmenu ()
} }
break; break;
case 1: case 2:
config.dac_bits++; config.dac_bits++;
if (config.dac_bits > 14) if (config.dac_bits > 14)
config.dac_bits = 7; config.dac_bits = 7;
@ -919,25 +925,25 @@ static void soundmenu ()
} }
break; break;
case 2: case 3:
GUI_OptionBox(m,0,"FM Volume",(void *)&fm_volume,0.01,0.0,5.0,0); GUI_OptionBox(m,0,"FM Volume",(void *)&fm_volume,0.01,0.0,5.0,0);
sprintf (items[offset+1].text, "FM Volume: %1.2f", fm_volume); sprintf (items[offset+1].text, "FM Volume: %1.2f", fm_volume);
config.fm_preamp = (int)(fm_volume * 100.0 + 0.5); config.fm_preamp = (int)(fm_volume * 100.0 + 0.5);
break; break;
case 3: case 4:
GUI_OptionBox(m,0,"PSG Volume",(void *)&psg_volume,0.01,0.0,5.0,0); GUI_OptionBox(m,0,"PSG Volume",(void *)&psg_volume,0.01,0.0,5.0,0);
sprintf (items[offset+2].text, "PSG Volume: %1.2f", psg_volume); sprintf (items[offset+2].text, "PSG Volume: %1.2f", psg_volume);
config.psg_preamp = (int)(psg_volume * 100.0 + 0.5); config.psg_preamp = (int)(psg_volume * 100.0 + 0.5);
break; break;
case 4: case 5:
config.psgBoostNoise ^= 1; config.psgBoostNoise ^= 1;
sprintf (items[offset+3].text, "PSG Noise Boost: %s", config.psgBoostNoise ? "ON":"OFF"); sprintf (items[offset+3].text, "PSG Noise Boost: %s", config.psgBoostNoise ? "ON":"OFF");
SN76489_BoostNoise(config.psgBoostNoise); SN76489_BoostNoise(config.psgBoostNoise);
break; break;
case 5: case 6:
config.filter = (config.filter + 1) % 3; config.filter = (config.filter + 1) % 3;
if (config.filter == 2) if (config.filter == 2)
{ {
@ -967,7 +973,7 @@ static void soundmenu ()
} }
break; break;
case 6: case 7:
if (config.filter == 1) if (config.filter == 1)
{ {
GUI_OptionBox(m,0,"Low-Pass Rate",(void *)&config.lp_range,1,0,100,1); GUI_OptionBox(m,0,"Low-Pass Rate",(void *)&config.lp_range,1,0,100,1);
@ -982,27 +988,27 @@ static void soundmenu ()
} }
break; break;
case 7: case 8:
GUI_OptionBox(m,0,"Middle Gain",(void *)&mg,0.01,0.0,2.0,0); GUI_OptionBox(m,0,"Middle Gain",(void *)&mg,0.01,0.0,2.0,0);
sprintf (items[offset+6].text, "Middle Gain: %1.2f", mg); sprintf (items[offset+6].text, "Middle Gain: %1.2f", mg);
config.mg = (int)(mg * 100.0); config.mg = (int)(mg * 100.0);
audio_set_equalizer(); audio_set_equalizer();
break; break;
case 8: case 9:
GUI_OptionBox(m,0,"High Gain",(void *)&hg,0.01,0.0,2.0,0); GUI_OptionBox(m,0,"High Gain",(void *)&hg,0.01,0.0,2.0,0);
sprintf (items[offset+7].text, "High Gain: %1.2f", hg); sprintf (items[offset+7].text, "High Gain: %1.2f", hg);
config.hg = (int)(hg * 100.0); config.hg = (int)(hg * 100.0);
audio_set_equalizer(); audio_set_equalizer();
break; break;
case 9: case 10:
GUI_OptionBox(m,0,"Low Frequency",(void *)&config.low_freq,10,0,config.high_freq,1); GUI_OptionBox(m,0,"Low Frequency",(void *)&config.low_freq,10,0,config.high_freq,1);
sprintf (items[offset+8].text, "Low Freq: %d", config.low_freq); sprintf (items[offset+8].text, "Low Freq: %d", config.low_freq);
audio_set_equalizer(); audio_set_equalizer();
break; break;
case 10: case 11:
GUI_OptionBox(m,0,"High Frequency",(void *)&config.high_freq,100,config.low_freq,30000,1); GUI_OptionBox(m,0,"High Frequency",(void *)&config.high_freq,100,config.low_freq,30000,1);
sprintf (items[offset+9].text, "High Freq: %d", config.high_freq); sprintf (items[offset+9].text, "High Freq: %d", config.high_freq);
audio_set_equalizer(); audio_set_equalizer();

View File

@ -252,6 +252,13 @@ void z80_sms_port_w(unsigned int port, unsigned char data)
} }
return; return;
} }
if ((port >= 0xF0) && (config.ym2413_enabled))
{
fm_write(mcycles_z80, port&3, data);
return;
}
z80_unused_port_w(port, data); z80_unused_port_w(port, data);
return; return;
} }
@ -285,11 +292,17 @@ unsigned char z80_sms_port_r(unsigned int port)
default: default:
{ {
port &= 0xFF; port &= 0xFF;
if ((port == 0xC0) || (port == 0xC1) || (port == 0xDC) || (port == 0xDD) || (port == 0xDE) || (port == 0xDF)) if ((port == 0xC0) || (port == 0xC1) || (port == 0xDC) || (port == 0xDD) || (port == 0xDE) || (port == 0xDF))
{ {
return io_z80_read(port & 1); return io_z80_read(port & 1);
} }
if ((port >= 0xF0) && (config.ym2413_enabled))
{
return YM2413Read(port & 3);
}
return z80_unused_port_r(port); return z80_unused_port_r(port);
} }
} }

View File

@ -21,6 +21,7 @@
#include "state.h" #include "state.h"
#include "sound.h" #include "sound.h"
#include "sn76489.h" #include "sn76489.h"
#include "ym2413.h"
#include "ym2612.h" #include "ym2612.h"
#include "loadrom.h" #include "loadrom.h"
#include "sms_cart.h" #include "sms_cart.h"

View File

@ -30,6 +30,11 @@ static unsigned int psg_cycles_count;
static unsigned int fm_cycles_ratio; static unsigned int fm_cycles_ratio;
static unsigned int fm_cycles_count; static unsigned int fm_cycles_count;
/* YM chip function pointers */
static void (*YM_Reset)(void);
static void (*YM_Update)(long int *buffer, int length);
static void (*YM_Write)(unsigned int a, unsigned int v);
/* Run FM chip for required M-cycles */ /* Run FM chip for required M-cycles */
static inline void fm_update(unsigned int cycles) static inline void fm_update(unsigned int cycles)
{ {
@ -66,7 +71,7 @@ static inline void fm_update(unsigned int cycles)
} }
/* run FM chip & get samples */ /* run FM chip & get samples */
YM2612Update(buffer, cnt); YM_Update(buffer, cnt);
} }
} }
@ -132,14 +137,38 @@ void sound_init(void)
/* Initialize core emulation (input clock based on input frequency for 100% accuracy) */ /* Initialize core emulation (input clock based on input frequency for 100% accuracy) */
/* By default, both chips are running at the output frequency. */ /* By default, both chips are running at the output frequency. */
SN76489_Init(mclk/15.0,snd.sample_rate); SN76489_Init(mclk/15.0,snd.sample_rate);
YM2612Init(mclk/7.0,snd.sample_rate);
/* In HQ mode, YM2612 is running at its original rate (one sample each 144*7 M-cycles) */ if (system_hw != SYSTEM_PBC)
/* FM stream is resampled to the output frequency at the end of a frame. */
if (config.hq_fm)
{ {
fm_cycles_ratio = 144 * 7 * (1 << 11); /* YM2612 */
Fir_Resampler_time_ratio(mclk / (double)snd.sample_rate / (144.0 * 7.0), config.rolloff); YM2612Init(mclk/7.0,snd.sample_rate);
YM_Reset = YM2612ResetChip;
YM_Update = YM2612Update;
YM_Write = YM2612Write;
/* In HQ mode, YM2612 is running at its original rate (one sample each 144*7 M-cycles) */
/* FM stream is resampled to the output frequency at the end of a frame. */
if (config.hq_fm)
{
fm_cycles_ratio = 144 * 7 * (1 << 11);
Fir_Resampler_time_ratio(mclk / (double)snd.sample_rate / (144.0 * 7.0), config.rolloff);
}
}
else
{
/* YM2413 */
YM2413Init(mclk/15.0,snd.sample_rate);
YM_Reset = YM2413ResetChip;
YM_Update = YM2413Update;
YM_Write = YM2413Write;
/* In HQ mode, YM2413 is running at its original rate (one sample each 72*15 M-cycles) */
/* FM stream is resampled to the output frequency at the end of a frame. */
if (config.hq_fm)
{
fm_cycles_ratio = 72 * 15 * (1 << 11);
Fir_Resampler_time_ratio(mclk / (double)snd.sample_rate / (72.0 * 15.0), config.rolloff);
}
} }
#ifdef LOGSOUND #ifdef LOGSOUND
@ -151,7 +180,7 @@ void sound_init(void)
/* Reset sound chips emulation */ /* Reset sound chips emulation */
void sound_reset(void) void sound_reset(void)
{ {
YM2612ResetChip(); YM_Reset();
SN76489_Reset(); SN76489_Reset();
fm_cycles_count = 0; fm_cycles_count = 0;
psg_cycles_count = 0; psg_cycles_count = 0;
@ -209,7 +238,7 @@ int sound_update(unsigned int cycles)
/* FM chip is late for one (or two) samples */ /* FM chip is late for one (or two) samples */
do do
{ {
YM2612Update(Fir_Resampler_buffer(), 1); YM_Update(Fir_Resampler_buffer(), 1);
Fir_Resampler_write(2); Fir_Resampler_write(2);
avail = Fir_Resampler_avail(); avail = Fir_Resampler_avail();
} }
@ -250,17 +279,17 @@ int sound_update(unsigned int cycles)
void fm_reset(unsigned int cycles) void fm_reset(unsigned int cycles)
{ {
fm_update(cycles << 11); fm_update(cycles << 11);
YM2612ResetChip(); YM_Reset();
} }
/* Write FM chip */ /* Write FM chip */
void fm_write(unsigned int cycles, unsigned int address, unsigned int data) void fm_write(unsigned int cycles, unsigned int address, unsigned int data)
{ {
if (address & 1) fm_update(cycles << 11); if (address & 1) fm_update(cycles << 11);
YM2612Write(address, data); YM_Write(address, data);
} }
/* Read FM status */ /* Read FM status (YM2612 only) */
unsigned int fm_read(unsigned int cycles, unsigned int address) unsigned int fm_read(unsigned int cycles, unsigned int address)
{ {
fm_update(cycles << 11); fm_update(cycles << 11);

1735
source/sound/ym2413.c Normal file

File diff suppressed because it is too large Load Diff

22
source/sound/ym2413.h Normal file
View File

@ -0,0 +1,22 @@
/*
**
** File: ym2413.c - software implementation of YM2413
** FM sound generator type OPLL
**
** Copyright (C) 2002 Jarek Burczynski
**
** Version 1.0
**
*/
#ifndef _H_YM2413_
#define _H_YM2413_
extern void YM2413Init(double clock, int rate);
extern void YM2413ResetChip(void);
extern void YM2413Update(long int *buffer, int length);
extern void YM2413Write(unsigned int a, unsigned int v);
extern unsigned int YM2413Read(unsigned int a);
#endif /*_H_YM2413_*/

View File

@ -133,6 +133,11 @@
#include "shared.h" #include "shared.h"
/* compiler dependence */
#ifndef INLINE
#define INLINE static __inline__
#endif
/* globals */ /* globals */
#define FREQ_SH 16 /* 16.16 fixed point (frequency calculations) */ #define FREQ_SH 16 /* 16.16 fixed point (frequency calculations) */
#define EG_SH 16 /* 16.16 fixed point (envelope generator timing) */ #define EG_SH 16 /* 16.16 fixed point (envelope generator timing) */
@ -1933,18 +1938,17 @@ static void init_tables(void)
/* initialize ym2612 emulator(s) */ /* initialize ym2612 emulator(s) */
int YM2612Init(double clock, int rate) void YM2612Init(double clock, int rate)
{ {
memset(&ym2612,0,sizeof(YM2612)); memset(&ym2612,0,sizeof(YM2612));
init_tables(); init_tables();
ym2612.OPN.ST.clock = clock; ym2612.OPN.ST.clock = clock;
ym2612.OPN.ST.rate = rate; ym2612.OPN.ST.rate = rate;
OPNSetPres(6*24); /* YM2612 prescaler is fixed to 1/6, one sample (6 mixed channels) is output for each 24 FM clocks */ OPNSetPres(6*24); /* YM2612 prescaler is fixed to 1/6, one sample (6 mixed channels) is output for each 24 FM clocks */
return 0;
} }
/* reset OPN registers */ /* reset OPN registers */
int YM2612ResetChip(void) void YM2612ResetChip(void)
{ {
int i; int i;
@ -1982,9 +1986,6 @@ int YM2612ResetChip(void)
OPNWriteReg(i ,0); OPNWriteReg(i ,0);
OPNWriteReg(i|0x100,0); OPNWriteReg(i|0x100,0);
} }
return 0;
} }
/* ym2612 write */ /* ym2612 write */
@ -2116,18 +2117,18 @@ void YM2612Update(long int *buffer, int length)
advance_eg_channel(&ym2612.CH[5].SLOT[SLOT1]); advance_eg_channel(&ym2612.CH[5].SLOT[SLOT1]);
} }
/* 14-bit channel output */ /* 14-bit DAC inputs (range is -8192;+8192) */
if (out_fm[0] > 8191) out_fm[0] = 8192; if (out_fm[0] > 8192) out_fm[0] = 8192;
else if (out_fm[0] < -8192) out_fm[0] = -8192; else if (out_fm[0] < -8192) out_fm[0] = -8192;
if (out_fm[1] > 8191) out_fm[1] = 8192; if (out_fm[1] > 8192) out_fm[1] = 8192;
else if (out_fm[1] < -8192) out_fm[1] = -8192; else if (out_fm[1] < -8192) out_fm[1] = -8192;
if (out_fm[2] > 8191) out_fm[2] = 8192; if (out_fm[2] > 8192) out_fm[2] = 8192;
else if (out_fm[2] < -8192) out_fm[2] = -8192; else if (out_fm[2] < -8192) out_fm[2] = -8192;
if (out_fm[3] > 8191) out_fm[3] = 8192; if (out_fm[3] > 8192) out_fm[3] = 8192;
else if (out_fm[3] < -8192) out_fm[3] = -8192; else if (out_fm[3] < -8192) out_fm[3] = -8192;
if (out_fm[4] > 8191) out_fm[4] = 8192; if (out_fm[4] > 8192) out_fm[4] = 8192;
else if (out_fm[4] < -8192) out_fm[4] = -8192; else if (out_fm[4] < -8192) out_fm[4] = -8192;
if (out_fm[5] > 8191) out_fm[5] = 8192; if (out_fm[5] > 8192) out_fm[5] = 8192;
else if (out_fm[5] < -8192) out_fm[5] = -8192; else if (out_fm[5] < -8192) out_fm[5] = -8192;
/* 6-channels mixing */ /* 6-channels mixing */

View File

@ -16,13 +16,8 @@
#ifndef _H_YM2612_ #ifndef _H_YM2612_
#define _H_YM2612_ #define _H_YM2612_
/* compiler dependence */ extern void YM2612Init(double clock, int rate);
#ifndef INLINE extern void YM2612ResetChip(void);
#define INLINE static __inline__
#endif
extern int YM2612Init(double clock, int rate);
extern int YM2612ResetChip(void);
extern void YM2612Update(long int *buffer, int length); extern void YM2612Update(long int *buffer, int length);
extern void YM2612Write(unsigned int a, unsigned int v); extern void YM2612Write(unsigned int a, unsigned int v);
extern unsigned int YM2612Read(void); extern unsigned int YM2612Read(void);