summaryrefslogtreecommitdiffstatshomepage
path: root/src
diff options
context:
space:
mode:
author Derrick Renaud <derrickr@mamedev.org>2010-10-19 03:14:33 +0000
committer Derrick Renaud <derrickr@mamedev.org>2010-10-19 03:14:33 +0000
commit4c4fd7e8623046050d69e247cd0b9560ca5b7c05 (patch)
treecb667668bd3fde330913aab49390094b275c1fad /src
parentbb26dc08165b9deed30fdb96d81422eefcbe0d4f (diff)
03074: dkongjr and clones: Discrete audio output is lower pitched than normal (Derrick Renaud)
Diffstat (limited to 'src')
-rw-r--r--src/emu/sound/disc_dev.c166
-rw-r--r--src/emu/sound/discrete.h2
-rw-r--r--src/mame/audio/dkong.c33
3 files changed, 108 insertions, 93 deletions
diff --git a/src/emu/sound/disc_dev.c b/src/emu/sound/disc_dev.c
index ee3abee869b..d8b632d8ab1 100644
--- a/src/emu/sound/disc_dev.c
+++ b/src/emu/sound/disc_dev.c
@@ -14,6 +14,8 @@
* DSD_555_CC - NE555 Constant Current VCO
* DSD_555_VCO1 - Op-Amp linear ramp based 555 VCO
* DSD_566 - NE566 Simulation
+ * DSD_LS624
+ * DSD_LS629
*
************************************************************************
*
@@ -135,12 +137,12 @@ struct dsd_ls624_context
struct dsd_ls629_context
{
- double v_bias;
- double v_cap;
- double v_peak;
- double v_threshold;
- double k_vmod_to_i;
+ double exponent;
+ double t_used;
+ double vmod_scale;
+ double v_cap_freq_in;
int flip_flop;
+ int has_freq_in_cap;
int out_type;
};
@@ -1813,11 +1815,12 @@ static DISCRETE_RESET(dsd_ls624)
#define DSD_LS629__VRNG DISCRETE_INPUT(2)
#define DSD_LS629__C DISCRETE_INPUT(3)
#define DSD_LS629__R_FREQ_IN DISCRETE_INPUT(4)
-#define DSD_LS629__OUTTYPE DISCRETE_INPUT(5)
+#define DSD_LS629__C_FREQ_IN DISCRETE_INPUT(5)
+#define DSD_LS629__OUTTYPE DISCRETE_INPUT(6)
#define LS624_R_EXT 600.0 /* as specified in data sheet */
#define LS624_OUT_HIGH 4.5 /* measured */
-#define LS624_FREQ_R_IN RES_K(95) /* measured */
+#define LS624_FREQ_R_IN RES_K(90) /* measured & 70K + 20k per data sheet */
/*
* The 74LS624 series are constant current based VCOs. The Freq Control voltage
@@ -1835,97 +1838,103 @@ static DISCRETE_RESET(dsd_ls624)
* The Range voltage adjusts the threshold voltage. The higher the Range voltage,
* the lower the threshold voltage, the longer the cap can charge, the lower the frequency.
*
+ * In a perfect world it would work like this:
* The current is based on the mysterious Rext mentioned in the data sheet.
- * I = (VfreqControl / 5) / Rext
+ * I = (VfreqControl * 20k/90k) / Rext
* where Rext = 600 ohms or external Rext on a 74LS628
- * The Freq Control has an input impedance of approximately 100k, so any input resistance
+ * The Freq Control has an input impedance of approximately 90k, so any input resistance
* connected to the Freq Control pin works as a voltage divider.
- * I = (VfreqControl / 5 * 100000 / (RfreqControl + 100000)) / Rext
+ * I = (VfreqControl * 20k/(90k + RfreqControlIn)) / Rext
* That gives us a change in voltage on the cap of
* dV = I / sampleRate / C_inFarads
+ *
+ * Unfortunately the chip does not behave linearly do to internal interactions,
+ * so I have just worked out the formula (using zunzun.com) of FreqControl and
+ * range to frequency out for a fixed cap value of 0.1uf. Other cap values can just
+ * scale from that. From the freq, we calculate the time of 1/2 cycle using 1/Freq/2.
+ * Then just use that to toggle a waveform.
*/
-/* The range to bias and threshold routines were created from testing a real chip.
- * This data was entered into the function finder routine at www.zunzun.com
- * to create the following 2 routines
- */
-
-double range_to_bias(double range)
-{
- /* Quadratic2D_model */
- double bias;
-
- // coefficients
- const double a = 2.3107142857142846E+00;
- const double b = -1.0714285714278806E-03;
- const double c = -1.7857142857144002E-03;
-
- bias = a;
- bias += b * range;
- bias += c * pow(range, 2.0);
- return bias;
-}
-
-double range_to_threshold(double range)
-{
- /* Polyfunctional2D_model */
- double threshold;
-
- // coefficients
- const double a = -1.6124587587173614E-01;
- const double b = -1.3501987413150401E-01;
- const double offset = 2.2550390868489893E+00;
-
- threshold = a * range;
- threshold += b * exp(-1.0 * range);
- threshold += offset;
- return threshold;
-}
-
static DISCRETE_STEP(dsd_ls629)
{
struct dsd_ls629_context *context = (struct dsd_ls629_context *)node->context;
- double i; /* Charging current created by Freq Control */
- double dt; /* change in time */
double x_time = 0;
- double v_cap; /* Current voltage on capacitor, before dt */
+ double freq, t1;
+ double t_used = context->t_used;
+ double dt = node->info->sample_time;;
+ double vmod = DSD_LS629__VMOD;
+ double vmod_2, vmod_3, vmod_4;
+ double range = DSD_LS629__VRNG;
int count_f = 0, count_r = 0;
+ /* coefficients */
+ const double k1 = 1.9904769024796283E+03;
+ const double k2 = 1.2070059213983407E+03;
+ const double k3 = 1.3266985579561108E+03;
+ const double k4 = -1.5500979825922698E+02;
+ const double k5 = 2.8184536266938172E+00;
+ const double k6 = -2.3503421582744556E+02;
+ const double k7 = -3.3836786704527788E+02;
+ const double k8 = -1.3569136703258670E+02;
+ const double k9 = 2.9914575453819188E+00;
+ const double k10 = 1.6855569086173170E+00;
+
if (UNEXPECTED(DSD_LS629__ENABLE == 0))
return;
- dt = node->info->sample_time; /* Change in time */
- v_cap = context->v_cap; /* Set to voltage before change */
+ /* scale due to input resistance */
+ if ((EXPECTED(DSD_LS629__R_FREQ_IN > 0)))
+ vmod *= context->vmod_scale;
+ /* apply cap if needed */
+ if (context->has_freq_in_cap)
+ {
+ context->v_cap_freq_in += (vmod - context->v_cap_freq_in) * context->exponent;
+ vmod = context->v_cap_freq_in;
+ }
- /* Calculate charging current */
- i = DSD_LS629__VMOD * context->k_vmod_to_i;
-
- /* Keep looping until all toggling in this time sample is used up. */
+ /* Polyfunctional3D_model created by zunzun.com using sum of squared absolute error */
+ vmod_2 = vmod * vmod;
+ vmod_3 = vmod_2 * vmod;
+ vmod_4 = vmod_3 * vmod;
+ freq = k1;
+ freq += k2 * vmod;
+ freq += k3 * vmod_2;
+ freq += k4 * vmod_3;
+ freq += k5 * vmod_4;
+ freq += k6 * range;
+ freq += k7 * range * vmod;
+ freq += k8 * range * vmod_2;
+ freq += k9 * range * vmod_3;
+ freq += k10 * range * vmod_4;
+
+ freq *= CAP_U(0.1) / DSD_LS629__C;
+
+ t1 = 0.5 / freq ;
+ t_used += node->info->sample_time;
do
{
- /* Always Discharging */
- v_cap -= i * dt / DSD_LS629__C;
- dt = 0;
-
- /* has it discharged past lower limit? */
- if (UNEXPECTED(v_cap < context->v_threshold))
+ dt = 0;
+ if (t_used > t1)
{
/* calculate the overshoot time */
- dt = DSD_LS629__C * (context->v_threshold - v_cap) / i;
- v_cap = context->v_peak;
+ t_used -= t1;
context->flip_flop ^= 1;
if (context->flip_flop)
count_r++;
else
count_f++;
- x_time = dt;
+ /* fix up any frequency increase change errors */
+ while(t_used > node->info->sample_time)
+ t_used -= node->info->sample_time;
+ x_time = t_used;
+ dt = t_used;
}
- } while(dt);
+ }while(dt);
- context->v_cap = v_cap;
+ context->t_used = t_used;
/* Convert last switch time to a ratio */
x_time = x_time / node->info->sample_time;
@@ -1937,7 +1946,7 @@ static DISCRETE_STEP(dsd_ls629)
break;
case DISC_LS624_OUT_ENERGY:
if (x_time == 0) x_time = 1.0;
- node->output[0] = LS624_OUT_HIGH * (context->flip_flop ? x_time : (1.0 - x_time));
+ node->output[0] = LS624_OUT_HIGH * (context->flip_flop ? x_time : (1.0 - x_time));
break;
case DISC_LS624_OUT_LOGIC:
node->output[0] = context->flip_flop;
@@ -1957,23 +1966,24 @@ static DISCRETE_STEP(dsd_ls629)
}
}
-#define LS624_LOSS_FACTOR 0.92
-
static DISCRETE_RESET(dsd_ls629)
{
struct dsd_ls629_context *context = (struct dsd_ls629_context *)node->context;
context->out_type = (int)DSD_LS629__OUTTYPE;
- context->v_bias = range_to_bias(DSD_LS629__VRNG);
- context->v_cap = context->v_bias;
- context->v_threshold = range_to_threshold(DSD_LS629__VRNG);
- /* The voltage at the current charge pin after a state change */
- context->v_peak = context->v_bias * 2 - context->v_threshold;
context->flip_flop = 0;
- /* precalulate the voltage to current formula */
- context->k_vmod_to_i = 1.0 / 5 * LS624_FREQ_R_IN / (DSD_LS629__R_FREQ_IN + LS624_FREQ_R_IN) / LS624_R_EXT;
- context->k_vmod_to_i *= LS624_LOSS_FACTOR;
+ context->t_used = 0;
+ context->vmod_scale = RES_K(90) / (DSD_LS629__R_FREQ_IN + RES_K(90));
+ if (DSD_LS629__C_FREQ_IN > 0)
+ {
+ context->has_freq_in_cap = 1;
+ context->exponent = RC_CHARGE_EXP(RES_2_PARALLEL(DSD_LS629__R_FREQ_IN, RES_K(90)) * DSD_LS629__C_FREQ_IN);
+ context->v_cap_freq_in = 0;
+ }
+ else
+ context->has_freq_in_cap = 0;
+
node->output[0] = 0;
}
diff --git a/src/emu/sound/discrete.h b/src/emu/sound/discrete.h
index c16ee450785..2a8bc3d8b41 100644
--- a/src/emu/sound/discrete.h
+++ b/src/emu/sound/discrete.h
@@ -4526,7 +4526,7 @@ enum
#define DISCRETE_555_VCO1_CV(NODE,RESET,VIN,CTRLV,OPTIONS) { NODE, DSD_555_VCO1 , 3, { RESET,VIN,CTRLV }, { RESET,VIN,CTRLV }, OPTIONS, "DISCRETE_555_VCO1_CV" },
#define DISCRETE_566(NODE,VMOD,R,C,VPOS,VNEG,VCHARGE,OPTIONS) { NODE, DSD_566 , 7, { VMOD,R,C,NODE_NC,NODE_NC,VCHARGE,NODE_NC }, { VMOD,R,C,VPOS,VNEG,VCHARGE,OPTIONS }, NULL, "DISCRETE_566" },
#define DISCRETE_74LS624(NODE,VMOD,VRNG,C,OUTTYPE) { NODE, DSD_LS624 , 4, { VMOD,NODE_NC,NODE_NC,NODE_NC }, { VMOD,VRNG,C,OUTTYPE }, NULL, "DISCRETE_74LS624" },
-#define DISCRETE_74LS629(NODE,ENAB,VMOD,VRNG,C,R_FREQ_IN,OUTTYPE) { NODE, DSD_LS629 , 6, { ENAB,VMOD,NODE_NC,NODE_NC,NODE_NC,NODE_NC }, { ENAB,VMOD,VRNG,C,R_FREQ_IN,OUTTYPE }, NULL, "DISCRETE_74LS629" },
+#define DISCRETE_74LS629(NODE,ENAB,VMOD,VRNG,C,R_FREQ_IN,C_FREQ_IN,OUTTYPE) { NODE, DSD_LS629 , 7, { ENAB,VMOD,NODE_NC,NODE_NC,NODE_NC,NODE_NC,NODE_NC }, { ENAB,VMOD,VRNG,C,R_FREQ_IN,C_FREQ_IN,OUTTYPE }, NULL, "DISCRETE_74LS629" },
/* NOP */
#define DISCRETE_NOP(NODE) { NODE, DSS_NOP , 0, { 0 }, { 0 }, NULL, "DISCRETE_NOP" },
diff --git a/src/mame/audio/dkong.c b/src/mame/audio/dkong.c
index 7f5c799d526..cf85113ebb6 100644
--- a/src/mame/audio/dkong.c
+++ b/src/mame/audio/dkong.c
@@ -21,7 +21,7 @@
/* Set to 1 to use faster custom mixer */
#define DK_USE_CUSTOM (1)
-#define USE_LS629 (0) /* set to use new LS624 code */
+#define USE_LS629 (1) /* set to use new LS624 code */
/* Issue surrounded by this define need to be analyzed and
* reviewed at a later time.
@@ -893,7 +893,7 @@ static DISCRETE_SOUND_START(dkongjr)
DISCRETE_TASK_START(1)
DISCRETE_LOGIC_INVERT(DS_SOUND7,DS_SOUND7_INV)
- DISCRETE_COUNTER(NODE_100, 1, 0, NODE_118, 0, 0xFFFF, DISC_COUNT_UP, 0, DISC_CLK_BY_COUNT)
+ DISCRETE_COUNTER(NODE_100, 1, 0, NODE_118, 0, 0x3FFF, DISC_COUNT_UP, 0, DISC_CLK_BY_COUNT)
DISCRETE_BIT_DECODE(NODE_101, NODE_100, 6, 1) /*LS157 2A */
DISCRETE_BIT_DECODE(NODE_102, NODE_100, 3, 1) /*LS157 2B */
@@ -901,7 +901,7 @@ DISCRETE_TASK_START(1)
DISCRETE_BIT_DECODE(NODE_104, NODE_100, 11, 1) /*LS157 3B */
/* LS157 Switches */
- DISCRETE_SWITCH(NODE_105, 1, DS_SOUND7_INV, GND, NODE_113) /* Switch 1 from LS624 */
+// DISCRETE_SWITCH(NODE_105, 1, DS_SOUND7_INV, GND, NODE_113) /* Switch 1 from LS624 */
DISCRETE_SWITCH(NODE_106, 1, DS_SOUND7_INV, NODE_101, NODE_102) /* Switch 2 */
DISCRETE_SWITCH(NODE_107, 1, DS_SOUND7_INV, NODE_103, NODE_104) /* Switch 3 */
@@ -909,7 +909,6 @@ DISCRETE_TASK_START(1)
DISCRETE_SWITCH(NODE_111, /* invert voltage */
1, NODE_110, /* ENAB, SWITCH */
TTL_HIGH, 0) /* INP0, INP1 */
- DISCRETE_RCFILTER(NODE_112, NODE_111, JR_R10, JR_C17)
/* Breadboarded measurements IC 5K, pin 7
D.R. Oct 2010
@@ -928,19 +927,20 @@ DISCRETE_TASK_START(1)
#if (USE_LS629)
DISCRETE_74LS629(NODE_113, /* IC 5K, pin 7 */
1, /* ENAB */
- NODE_112, DK_SUP_V, /* VMOD, VRNG */
- JR_C18, JR_R10, /* C, R_FREQ_IN */
+ NODE_111, DK_SUP_V, /* VMOD, VRNG */
+ JR_C18, JR_R10, JR_C17, /* C, R_FREQ_IN, C_FREQ_IN */
DISC_LS624_OUT_ENERGY)
#else
+ DISCRETE_RCFILTER(NODE_112, NODE_111, JR_R10, JR_C17)
DISCRETE_74LS624(NODE_113, NODE_112, DK_SUP_V, JR_C18, DISC_LS624_OUT_ENERGY)
#endif
+ DISCRETE_SWITCH(NODE_105, 1, DS_SOUND7_INV, GND, NODE_113) /* Switch 1 from LS624 */
DISCRETE_LOGIC_XOR(NODE_115, NODE_105, NODE_106)
DISCRETE_SWITCH(NODE_116, /* invert with TTL voltage */
1, NODE_107, /* ENAB, SWITCH */
TTL_HIGH, 0) /* INP0, INP1 */
- DISCRETE_RCFILTER(NODE_117, NODE_116, JR_R11, JR_C16)
/* Breadboarded measurements IC 5K, pin 10
D.R. Oct 2010
@@ -956,13 +956,14 @@ DISCRETE_TASK_START(1)
4.15 59400
*/
-#if (0 && USE_LS629)
+#if (USE_LS629)
DISCRETE_74LS629(NODE_118, /* IC 5K, pin 10 */
1, /* ENAB */
- NODE_117, DK_SUP_V, /* VMOD, VRNG */
- JR_C19, JR_R11, /* C, R_FREQ_IN */
+ NODE_116, DK_SUP_V, /* VMOD, VRNG */
+ JR_C19, JR_R11, JR_C16, /* C, R_FREQ_IN, C_FREQ_IN */
DISC_LS624_OUT_COUNT_F)
#else
+ DISCRETE_RCFILTER(NODE_117, NODE_116, JR_R11, JR_C16)
DISCRETE_74LS624(NODE_118, NODE_117, DK_SUP_V, JR_C19, DISC_LS624_OUT_COUNT_F)
#endif
@@ -1001,7 +1002,8 @@ DISCRETE_TASK_START(2)
DISCRETE_74LS629(NODE_14, /* IC 8L, pin 10 */
1, /* ENAB */
NODE_13, DK_SUP_V, /* VMOD, VRNG */
- JR_C22, RES_2_PARALLEL(JR_R12, JR_R13), /* C, R_FREQ_IN */
+ /* C_FREQ_IN is taken care of by the NODE_13 mixer */
+ JR_C22, RES_2_PARALLEL(JR_R13, JR_R12), 0, /* C, R_FREQ_IN, C_FREQ_IN */
DISC_LS624_OUT_ENERGY)
#else
DISCRETE_74LS624( NODE_14, NODE_13, 0.98*DK_SUP_V, JR_C22, DISC_LS624_OUT_ENERGY)
@@ -1055,11 +1057,10 @@ DISCRETE_TASK_START(1)
*/
#if (USE_LS629)
- DISCRETE_RCFILTER(NODE_90, DS_SOUND9_INV, JR_R14, JR_C26)
DISCRETE_74LS629(NODE_91, /* IC 7P, pin 7 */
1, /* ENAB */
- NODE_90, DK_SUP_V, /* VMOD, VRNG */
- JR_C37, JR_R14, /* C, R_FREQ_IN */
+ DS_SOUND9_INV, DK_SUP_V, /* VMOD, VRNG */
+ JR_C37, JR_R14, JR_C26, /* C, R_FREQ_IN, C_FREQ_IN */
DISC_LS624_OUT_ENERGY)
DISCRETE_SWITCH(DS_OUT_SOUND9, 1, DS_SOUND9_INV, NODE_91, 0)
#else
@@ -1104,7 +1105,11 @@ DISCRETE_TASK_START(3)
* Just a 1:n amplifier without filters - just the output filter
*/
DISCRETE_CRFILTER(NODE_295,NODE_288, 1000, JR_C13)
+#if (USE_LS629)
+ DISCRETE_OUTPUT(NODE_295, 32767.0/5.0 * 5)
+#else
DISCRETE_OUTPUT(NODE_295, 32767.0/5.0 * 10)
+#endif
DISCRETE_TASK_END()
DISCRETE_SOUND_END