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.rolloff = 0.995;
config.dac_bits = 14;
config.ym2413_enabled = 1;
/* system options */
config.region_detect = 0;

View File

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

View File

@ -321,20 +321,21 @@ static gui_item items_options[5] =
};
/* 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,"FM Roll-off: 0.999", "Adjust FIR low-pass filtering", 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 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,"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 BandGain", 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: ON", "Enable/disable YM2413 chip", 56,132,276,48},
{NULL,NULL,"High-Quality FM: ON", "Enable/disable YM2612/YM2413 resampling", 56,132,276,48},
{NULL,NULL,"FM Roll-off: 0.999", "Adjust FIR low-pass filtering", 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,"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 BandGain", 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 */
@ -584,7 +585,7 @@ static gui_menu menu_audio =
{
"Audio Settings",
0,0,
8,4,6,0,
9,4,6,0,
items_audio,
buttons_list,
bg_list,
@ -755,19 +756,19 @@ static int update_snd_items(void)
if (config.hq_fm)
{
sprintf (items[0].text, "High-Quality FM: ON");
sprintf (items[1].text, "FM Roll-off: %1.2f %%",rolloff);
strcpy (items[1].comment, "Adjust FIR low-pass filtering");
offset = 2;
sprintf (items[1].text, "High-Quality FM: ON");
sprintf (items[2].text, "FM Roll-off: %1.2f %%",rolloff);
strcpy (items[2].comment, "Adjust FIR low-pass filtering");
offset = 3;
}
else
{
sprintf (items[0].text, "High-Quality FM: OFF");
offset = 1;
sprintf (items[1].text, "High-Quality FM: OFF");
offset = 2;
}
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+3].comment, "Boost SN76489 Noise Channel");
strcpy(items[offset+4].comment, "Configure Audio filtering");
@ -836,10 +837,10 @@ static void soundmenu ()
/* special case */
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);
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;
ret = 255;
if (cart.romsize)
@ -860,7 +861,7 @@ static void soundmenu ()
}
}
}
else if (ret > 1)
else if (ret > 2)
{
ret--;
}
@ -869,6 +870,11 @@ static void soundmenu ()
switch (ret)
{
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;
offset = update_snd_items();
@ -891,7 +897,7 @@ static void soundmenu ()
}
break;
case 1:
case 2:
config.dac_bits++;
if (config.dac_bits > 14)
config.dac_bits = 7;
@ -919,25 +925,25 @@ static void soundmenu ()
}
break;
case 2:
case 3:
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);
config.fm_preamp = (int)(fm_volume * 100.0 + 0.5);
break;
case 3:
case 4:
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);
config.psg_preamp = (int)(psg_volume * 100.0 + 0.5);
break;
case 4:
case 5:
config.psgBoostNoise ^= 1;
sprintf (items[offset+3].text, "PSG Noise Boost: %s", config.psgBoostNoise ? "ON":"OFF");
SN76489_BoostNoise(config.psgBoostNoise);
break;
case 5:
case 6:
config.filter = (config.filter + 1) % 3;
if (config.filter == 2)
{
@ -967,7 +973,7 @@ static void soundmenu ()
}
break;
case 6:
case 7:
if (config.filter == 1)
{
GUI_OptionBox(m,0,"Low-Pass Rate",(void *)&config.lp_range,1,0,100,1);
@ -982,27 +988,27 @@ static void soundmenu ()
}
break;
case 7:
case 8:
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);
config.mg = (int)(mg * 100.0);
audio_set_equalizer();
break;
case 8:
case 9:
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);
config.hg = (int)(hg * 100.0);
audio_set_equalizer();
break;
case 9:
case 10:
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);
audio_set_equalizer();
break;
case 10:
case 11:
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);
audio_set_equalizer();

View File

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

View File

@ -21,6 +21,7 @@
#include "state.h"
#include "sound.h"
#include "sn76489.h"
#include "ym2413.h"
#include "ym2612.h"
#include "loadrom.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_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 */
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 */
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) */
/* By default, both chips are running at the output frequency. */
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) */
/* FM stream is resampled to the output frequency at the end of a frame. */
if (config.hq_fm)
if (system_hw != SYSTEM_PBC)
{
fm_cycles_ratio = 144 * 7 * (1 << 11);
Fir_Resampler_time_ratio(mclk / (double)snd.sample_rate / (144.0 * 7.0), config.rolloff);
/* YM2612 */
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
@ -151,7 +180,7 @@ void sound_init(void)
/* Reset sound chips emulation */
void sound_reset(void)
{
YM2612ResetChip();
YM_Reset();
SN76489_Reset();
fm_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 */
do
{
YM2612Update(Fir_Resampler_buffer(), 1);
YM_Update(Fir_Resampler_buffer(), 1);
Fir_Resampler_write(2);
avail = Fir_Resampler_avail();
}
@ -250,17 +279,17 @@ int sound_update(unsigned int cycles)
void fm_reset(unsigned int cycles)
{
fm_update(cycles << 11);
YM2612ResetChip();
YM_Reset();
}
/* Write FM chip */
void fm_write(unsigned int cycles, unsigned int address, unsigned int data)
{
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)
{
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"
/* compiler dependence */
#ifndef INLINE
#define INLINE static __inline__
#endif
/* globals */
#define FREQ_SH 16 /* 16.16 fixed point (frequency calculations) */
#define EG_SH 16 /* 16.16 fixed point (envelope generator timing) */
@ -1933,18 +1938,17 @@ static void init_tables(void)
/* initialize ym2612 emulator(s) */
int YM2612Init(double clock, int rate)
void YM2612Init(double clock, int rate)
{
memset(&ym2612,0,sizeof(YM2612));
init_tables();
ym2612.OPN.ST.clock = clock;
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 */
return 0;
}
/* reset OPN registers */
int YM2612ResetChip(void)
void YM2612ResetChip(void)
{
int i;
@ -1982,9 +1986,6 @@ int YM2612ResetChip(void)
OPNWriteReg(i ,0);
OPNWriteReg(i|0x100,0);
}
return 0;
}
/* ym2612 write */
@ -2116,18 +2117,18 @@ void YM2612Update(long int *buffer, int length)
advance_eg_channel(&ym2612.CH[5].SLOT[SLOT1]);
}
/* 14-bit channel output */
if (out_fm[0] > 8191) out_fm[0] = 8192;
/* 14-bit DAC inputs (range is -8192;+8192) */
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;
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;
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;
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;
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;
/* 6-channels mixing */

View File

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