summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/sound/hc55516.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/sound/hc55516.cpp')
-rw-r--r--src/devices/sound/hc55516.cpp213
1 files changed, 99 insertions, 114 deletions
diff --git a/src/devices/sound/hc55516.cpp b/src/devices/sound/hc55516.cpp
index 90d9a38d2a6..0bd36ae381f 100644
--- a/src/devices/sound/hc55516.cpp
+++ b/src/devices/sound/hc55516.cpp
@@ -15,14 +15,19 @@
and removal of the encoder offset compensation DAC?)
- /src/mame/exidy/exidy440_a.cpp has its own internal implementation of the
MC3417 and MC3418, it should be using this file instead
+ - MC3417 interpolation slope being determined by the number of samples in
+ the current stream slice doesn't make sense
+
+ BTANB:
+ - outputs a low-volume but very high-pitched background tone when /FZ is
+ active and the hardware doesn't have a low-pass filter
*****************************************************************************/
#include "emu.h"
#include "hc55516.h"
-
-/* fixed samplerate of 192khz */
+// fixed samplerate of 192khz
#define SAMPLE_RATE (48000 * 4)
#define INTEGRATOR_LEAK_TC 0.001
@@ -47,8 +52,6 @@ cvsd_device_base::cvsd_device_base(const machine_config &mconfig, device_type ty
, m_last_clock_state(false)
, m_buffered_bit(false)
, m_shiftreg(0)
- , m_curr_sample(0)
- , m_next_sample(0)
, m_samples_generated(0)
{
}
@@ -59,14 +62,12 @@ cvsd_device_base::cvsd_device_base(const machine_config &mconfig, device_type ty
void cvsd_device_base::device_start()
{
- /* create the stream */
+ // create the stream
m_stream = stream_alloc(0, 1, SAMPLE_RATE);
save_item(NAME(m_last_clock_state));
save_item(NAME(m_buffered_bit));
save_item(NAME(m_shiftreg));
- save_item(NAME(m_curr_sample));
- save_item(NAME(m_next_sample));
save_item(NAME(m_samples_generated));
}
@@ -92,7 +93,7 @@ int cvsd_device_base::clock_r()
{
// prevent debugger from changing the internal state
if (!machine().side_effects_disabled())
- m_stream->update(); /* bring up to date first */
+ m_stream->update(); // bring up to date first
return clock_state_r();
}
@@ -131,14 +132,12 @@ inline bool cvsd_device_base::is_external_oscillator()
inline bool cvsd_device_base::is_clock_changed(bool clock_state)
{
- return ((!m_last_clock_state && clock_state) ||
- (m_last_clock_state && !clock_state));
+ return ((!m_last_clock_state && clock_state) || (m_last_clock_state && !clock_state));
}
inline bool cvsd_device_base::is_active_clock_transition(bool clock_state)
{
- return ((clock_state != m_last_clock_state) &&
- (clock_state == m_active_clock_edge));
+ return ((clock_state != m_last_clock_state) && (clock_state == m_active_clock_edge));
}
inline bool cvsd_device_base::current_clock_state()
@@ -146,42 +145,42 @@ inline bool cvsd_device_base::current_clock_state()
// keep track of the clock state given its previous state and the number of samples produced
// i.e. if we generated m_samples_generated samples, at a sample rate of SAMPLE_RATE, then are we on a
// positive or negative level of a squarewave at clock() hz? SAMPLE_RATE may not be an integer multiple of clock()
- //uint64_t fractions_of_second = (((uint64_t)m_samples_generated)<<32) / SAMPLE_RATE; // 32.32 bits of seconds passed so far
- //uint32_t clock_edges_passed = (fractions_of_second * clock() * 2)>>32
- //return (((((uint64_t)m_samples_generated<<32) * clock() * 2 / SAMPLE_RATE)>>32) & 0x1)?true:false;
- return (((uint64_t)m_samples_generated * clock() * 2 / SAMPLE_RATE) & 0x01)?true:false;
+ //uint64_t fractions_of_second = (((uint64_t)m_samples_generated) << 32) / SAMPLE_RATE; // 32.32 bits of seconds passed so far
+ //uint32_t clock_edges_passed = (fractions_of_second * clock() * 2) >> 32
+ //return bool(((((uint64_t)m_samples_generated << 32) * clock() * 2 / SAMPLE_RATE) >> 32) & 0x1);
+ return bool(((uint64_t)m_samples_generated * clock() * 2 / SAMPLE_RATE) & 0x01);
}
void cvsd_device_base::digit_w(int digit)
{
m_stream->update();
- m_buffered_bit = digit ? true : false;
+ m_buffered_bit = bool(digit);
}
void cvsd_device_base::clock_w(int state)
{
- /* update the output buffer first */
+ // update the output buffer first
m_stream->update();
- bool clock_state = state ? true : false;
+ bool clock_state = bool(state);
- /* only makes sense for setups with a software driven clock */
+ // only makes sense for setups with a software driven clock
assert(!is_external_oscillator());
- /* speech clock changing? */
+ // speech clock changing?
if (is_clock_changed(clock_state))
{
- /* clear the update count */
+ // clear the update count
m_samples_generated = 0;
process_bit(m_buffered_bit, clock_state);
}
- /* update the clock */
+ // update the clock
m_last_clock_state = clock_state;
}
int cvsd_device_base::clock_state_r()
{
- /* only makes sense for setups with an external oscillator */
+ // only makes sense for setups with an external oscillator
assert(is_external_oscillator());
m_stream->update();
@@ -198,15 +197,12 @@ void cvsd_device_base::process_bit(bool bit, bool clock_state)
// sound_stream_update - handle a stream update
//-------------------------------------------------
-void cvsd_device_base::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
+void cvsd_device_base::sound_stream_update(sound_stream &stream)
{
// Stub, just return silence
- auto &buffer = outputs[0];
-
- m_samples_generated += buffer.samples();
+ m_samples_generated += stream.samples();
if (m_samples_generated >= SAMPLE_RATE)
m_samples_generated -= SAMPLE_RATE;
- buffer.fill(0);
}
@@ -231,6 +227,7 @@ hc55516_device::hc55516_device(const machine_config &mconfig, device_type type,
, m_intshift(intshift)
, m_sylfilter(0)
, m_intfilter(0)
+ , m_next_sample(0)
, m_agc(true)
, m_buffered_fzq(true)
{
@@ -246,6 +243,7 @@ void hc55516_device::device_start()
save_item(NAME(m_sylfilter));
save_item(NAME(m_intfilter));
+ save_item(NAME(m_next_sample));
save_item(NAME(m_agc));
save_item(NAME(m_buffered_fzq));
}
@@ -257,6 +255,7 @@ void hc55516_device::device_start()
void hc55516_device::device_reset()
{
cvsd_device_base::device_reset();
+
// simulate /FZ having been held for a while
m_sylfilter = 0x3f;
m_intfilter = 0;
@@ -275,16 +274,15 @@ int hc55516_device::agc_r()
{
// prevent debugger from changing the internal state
if (!machine().side_effects_disabled())
- m_stream->update(); /* bring up to date first */
+ m_stream->update(); // bring up to date first
return m_agc;
}
void hc55516_device::process_bit(bool bit, bool clock_state)
{
- bool frozen = ( ( (m_intfilter >= 0x180) && (!bit) ) ||
- ( (m_intfilter <= -0x180) && (bit) ) );
-
+ const bool frozen = (((m_intfilter >= 0x180) && !bit) || ((m_intfilter <= -0x180) && bit));
int32_t sum;
+
if (is_active_clock_transition(clock_state))
{
// grab the /FZ state; if the callback is present, use that, otherwise use the buffered state
@@ -294,15 +292,15 @@ void hc55516_device::process_bit(bool bit, bool clock_state)
else
fzq_state = m_buffered_fzq;
- if (!fzq_state) // /FZ is active low, if it is active, the input bit is ignored and the inverse of the previous bit in the shifter is used instead
- bit = !(m_shiftreg&1);
+ // if /FZ is active, the input bit is ignored and the inverse of the previous bit in the shifter is used instead
+ if (!fzq_state)
+ bit = !(m_shiftreg & 1);
- /* shift the new bit into the shift register */
- m_shiftreg = (m_shiftreg << 1) | (bit?1:0);
+ // shift the new bit into the shift register
+ m_shiftreg = (m_shiftreg << 1) | (bit ? 1 : 0);
- /* if we got all 0's or all 1's in the last n bits... */
- if (((m_shiftreg & m_shiftreg_mask) == 0) ||
- ((m_shiftreg & m_shiftreg_mask) == m_shiftreg_mask))
+ // if we got all 0's or all 1's in the last n bits...
+ if (((m_shiftreg & m_shiftreg_mask) == 0) || ((m_shiftreg & m_shiftreg_mask) == m_shiftreg_mask))
{
// coincidence is true
if (!frozen) m_sylfilter += (((~m_sylfilter) & m_sylmask) >> m_sylshift);
@@ -314,28 +312,24 @@ void hc55516_device::process_bit(bool bit, bool clock_state)
}
m_sylfilter &= 0xfff;
- sum = ( ((~m_intfilter) >> m_intshift) + 1 ) & 0x3ff;
+ sum = util::sext(((~m_intfilter) >> m_intshift) + 1, 10);
}
- else // inactive clock transition
+ else
{
- if (m_shiftreg&1)
+ // inactive clock transition
+ if (m_shiftreg & 1)
{
- sum = ( ( ~std::max(2, m_sylfilter >> 6) ) + 1 ) & 0x3ff;
+ sum = util::sext((~std::max(2, m_sylfilter >> 6)) + 1, 10);
}
else
{
- sum = std::max(2, m_sylfilter >> 6) & 0x3ff;
+ sum = util::sext(std::max(2, m_sylfilter >> 6), 10);
}
}
- if (sum & 0x200)
- sum |= ~0x3ff; // sign extend
-
if (!frozen)
{
- m_intfilter += sum;
- m_intfilter &= 0x3ff;
- if (m_intfilter & 0x200) m_intfilter |= ~0x3ff; // sign extend
+ m_intfilter = util::sext(m_intfilter + sum, 10);
}
/* scale the result (-512 to 511) to -32768 thru 32767 */
@@ -343,10 +337,10 @@ void hc55516_device::process_bit(bool bit, bool clock_state)
F E D C B A 9 8 7 6 5 4 3 2 1 0
9 8 7 6 5 4 3 2 1 0/9 8 7 6 5 4
*/
- m_next_sample = ( (m_intfilter << 6) | ( ((m_intfilter & 0x3ff) ^ 0x200 ) >> 4 ) );
+ m_next_sample = ((m_intfilter << 6) | (((m_intfilter & 0x3ff) ^ 0x200) >> 4));
// update agc state
- if ( (m_intfilter >= 0x100) || (m_intfilter <= -0x100) )
+ if ((m_intfilter >= 0x100) || (m_intfilter <= -0x100))
m_agc = false;
else
m_agc = true;
@@ -359,35 +353,20 @@ void hc55516_device::process_bit(bool bit, bool clock_state)
// sound_stream_update_legacy - handle a stream update
//-------------------------------------------------
-void hc55516_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
+void hc55516_device::sound_stream_update(sound_stream &stream)
{
- auto &buffer = outputs[0];
-
-/*
- if (!is_external_oscillator())
- {
- // track how many samples we've updated without a clock; if it's been more than 1/32 of a second, output silence
- m_samples_generated += buffer.samples();
- if (m_samples_generated > SAMPLE_RATE / 32)
- {
- m_samples_generated = SAMPLE_RATE;
- m_next_sample = 0;
- }
- }
-*/
-
if (is_external_oscillator())
{
- /* external oscillator */
- for (int i = 0; i < buffer.samples(); i++)
+ // external oscillator
+ for (int i = 0; i < stream.samples(); i++)
{
- buffer.put_int(i, m_next_sample, 32768);
+ stream.put_int(0, i, m_next_sample, 32768);
m_samples_generated++;
uint8_t clock_state = current_clock_state();
- /* pull in next digit on the appropriate edge of the clock */
+ // pull in next digit on the appropriate edge of the clock
if (is_clock_changed(clock_state))
{
process_bit(m_buffered_bit, clock_state);
@@ -397,10 +376,12 @@ void hc55516_device::sound_stream_update(sound_stream &stream, std::vector<read_
}
}
- /* software driven clock */
+ // software driven clock
else
- for (int i = 0; i < buffer.samples(); i++)
- buffer.put_int(i, m_next_sample, 32768);
+ {
+ for (int i = 0; i < stream.samples(); i++)
+ stream.put_int(0, i, m_next_sample, 32768);
+ }
}
@@ -422,6 +403,7 @@ hc55532_device::hc55532_device(const machine_config &mconfig, const char *tag, d
void hc55532_device::device_reset()
{
cvsd_device_base::device_reset();
+
// simulate /FZ having been held for a while
m_sylfilter = 0x7f;
m_intfilter = 0;
@@ -447,8 +429,10 @@ mc3417_device::mc3417_device(const machine_config &mconfig, device_type type, co
, m_charge(pow(exp(-1.0), 1.0 / (FILTER_CHARGE_TC * 16000.0)))
, m_decay(pow(exp(-1.0), 1.0 / (FILTER_DECAY_TC * 16000.0)))
, m_leak(pow(exp(-1.0), 1.0 / (INTEGRATOR_LEAK_TC * 16000.0)))
- , m_sylfilter_d(0.0)
- , m_intfilter_d(0.0)
+ , m_sylfilter(0.0)
+ , m_intfilter(0.0)
+ , m_curr_sample(0.0)
+ , m_next_sample(0.0)
{
}
@@ -459,58 +443,57 @@ mc3417_device::mc3417_device(const machine_config &mconfig, device_type type, co
void mc3417_device::device_start()
{
cvsd_device_base::device_start();
- save_item(NAME(m_sylfilter_d));
- save_item(NAME(m_intfilter_d));
+
+ save_item(NAME(m_sylfilter));
+ save_item(NAME(m_intfilter));
+ save_item(NAME(m_curr_sample));
+ save_item(NAME(m_next_sample));
}
void mc3417_device::process_bit(bool bit, bool clock_state)
{
if (is_active_clock_transition(clock_state))
{
+ // shift the new bit into the shift register
+ m_shiftreg = (m_shiftreg << 1) | (bit ? 1 : 0);
- /* shift the new bit into the shift register */
- m_shiftreg = (m_shiftreg << 1) | (bit?1:0);
-
- /* move the estimator up or down a step based on the bit */
+ // move the estimator up or down a step based on the bit
if (!bit)
- m_intfilter_d += m_sylfilter_d;
+ m_intfilter += m_sylfilter;
else
- m_intfilter_d -= m_sylfilter_d;
+ m_intfilter -= m_sylfilter;
- /* simulate leakage */
- m_intfilter_d *= m_leak;
+ // simulate leakage
+ m_intfilter *= m_leak;
- /* if we got all 0's or all 1's in the last n bits, bump the step up */
- if (((m_shiftreg & m_shiftreg_mask) == 0) ||
- ((m_shiftreg & m_shiftreg_mask) == m_shiftreg_mask))
+ // if we got all 0's or all 1's in the last n bits, bump the step up
+ if (((m_shiftreg & m_shiftreg_mask) == 0) || ((m_shiftreg & m_shiftreg_mask) == m_shiftreg_mask))
{
// coincidence is true
- m_sylfilter_d = FILTER_MAX - ((FILTER_MAX - m_sylfilter_d) * m_charge);
+ m_sylfilter = FILTER_MAX - ((FILTER_MAX - m_sylfilter) * m_charge);
- if (m_sylfilter_d > FILTER_MAX)
- m_sylfilter_d = FILTER_MAX;
+ if (m_sylfilter > FILTER_MAX)
+ m_sylfilter = FILTER_MAX;
}
else
{
- m_sylfilter_d *= m_decay;
+ m_sylfilter *= m_decay;
- if (m_sylfilter_d < FILTER_MIN)
- m_sylfilter_d = FILTER_MIN;
+ if (m_sylfilter < FILTER_MIN)
+ m_sylfilter = FILTER_MIN;
}
- /* compute the sample as a 32-bit word */
- m_next_sample = m_intfilter_d * SAMPLE_GAIN;
+ // compute the sample as a 32-bit word
+ m_next_sample = m_intfilter * SAMPLE_GAIN;
}
}
-void mc3417_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
+void mc3417_device::sound_stream_update(sound_stream &stream)
{
- auto &buffer = outputs[0];
-
if (!is_external_oscillator())
{
- /* track how many samples we've updated without a clock; if it's been more than 1/32 of a second, output silence */
- m_samples_generated += buffer.samples();
+ // track how many samples we've updated without a clock; if it's been more than 1/32 of a second, output silence
+ m_samples_generated += stream.samples();
if (m_samples_generated > SAMPLE_RATE / 32)
{
m_samples_generated = SAMPLE_RATE;
@@ -518,23 +501,23 @@ void mc3417_device::sound_stream_update(sound_stream &stream, std::vector<read_s
}
}
- /* compute the interpolation slope */
- stream_buffer::sample_t sample = m_curr_sample;
- stream_buffer::sample_t slope = (m_next_sample - sample) / buffer.samples();
+ // compute the interpolation slope
+ sound_stream::sample_t sample = m_curr_sample;
+ sound_stream::sample_t slope = (m_next_sample - sample) / stream.samples();
m_curr_sample = m_next_sample;
if (is_external_oscillator())
{
- /* external oscillator */
- for (int i = 0; i < buffer.samples(); i++, sample += slope)
+ // external oscillator
+ for (int i = 0; i < stream.samples(); i++, sample += slope)
{
- buffer.put(i, sample);
+ stream.put(0, i, sample);
m_samples_generated++;
uint8_t clock_state = current_clock_state();
- /* pull in next digit on the appropriate edge of the clock */
+ // pull in next digit on the appropriate edge of the clock
if (is_clock_changed(clock_state))
{
process_bit(m_buffered_bit, clock_state);
@@ -544,10 +527,12 @@ void mc3417_device::sound_stream_update(sound_stream &stream, std::vector<read_s
}
}
- /* software driven clock */
+ // software driven clock
else
- for (int i = 0; i < buffer.samples(); i++, sample += slope)
- buffer.put(i, sample);
+ {
+ for (int i = 0; i < stream.samples(); i++, sample += slope)
+ stream.put(0, i, sample);
+ }
}