diff --git a/src/devices/sound/cem3394.cpp b/src/devices/sound/cem3394.cpp index 477384eb1c7a8..7798720e8478b 100644 --- a/src/devices/sound/cem3394.cpp +++ b/src/devices/sound/cem3394.cpp @@ -45,6 +45,9 @@ static constexpr double TRIANGLE_VOLUME = SAWTOOTH_VOLUME * 1.27f; // external input is unknown but let's make it the same as the pulse static constexpr double EXTERNAL_VOLUME = PULSE_VOLUME; +// filter volume when self-oscillating unknown, using PULSE_VOLUME arbitrarily +static constexpr double FILTER_OSC_VOLUME = PULSE_VOLUME; + // waveform generation parameters #define ENABLE_PULSE 1 @@ -156,6 +159,7 @@ cem3394_device::cem3394_device(const machine_config &mconfig, const char *tag, d m_filter_frequency(1300), m_filter_modulation(0), m_filter_resonance(0), + m_filter_osc_position(0), m_filter_in{0}, m_filter_out{0}, m_pulse_width(0), @@ -420,10 +424,31 @@ void cem3394_device::sound_stream_update(sound_stream &stream) if (ENABLE_EXTERNAL && BIT(input_mask, AUDIO_INPUT)) result += EXTERNAL_VOLUME * m_mixer_external * stream.get(AUDIO_INPUT, sampindex); - // compute the modulated filter frequency and apply the filter - // modulation tracks the VCO triangle - double filter_freq = m_filter_frequency * (1 + m_filter_modulation * triangle); - result = filter(result, filter_freq); + if (FILTER_TYPE) + { + // compute the modulated filter frequency and apply the filter + // modulation tracks the VCO triangle + const double filter_freq = m_filter_frequency * (1 + m_filter_modulation * triangle); + // need to call filter() and advance the filter's state, even if we don't use the result + const double filter_result = filter(result, filter_freq); + + // advance the position of the oscillator used when the filter is self-oscillating + m_filter_osc_position += filter_freq * m_inv_sample_rate; + if (m_filter_osc_position >= 1.0) + m_filter_osc_position -= floor(m_filter_osc_position); + + if (!m_wave_select && m_filter_resonance >= 1.0) + { + // when no waveform is selected and the filter is configured to self-oscilate, + // use a sine wave oscillator. + const double angle = 2 * M_PI * m_filter_osc_position - M_PI; + result = FILTER_OSC_VOLUME * sin(angle); + } + else + { + result = filter_result; + } + } // apply AC coupling if (ENABLE_AC_COUPLING) @@ -460,6 +485,7 @@ void cem3394_device::device_start() save_item(NAME(m_filter_frequency)); save_item(NAME(m_filter_modulation)); save_item(NAME(m_filter_resonance)); + save_item(NAME(m_filter_osc_position)); save_item(NAME(m_filter_in)); save_item(NAME(m_filter_out)); @@ -578,7 +604,7 @@ void cem3394_device::set_voltage_internal(int input, double voltage) } else if (voltage > 2.0) { - m_pulse_width = 100; + m_pulse_width = 1; m_wave_select &= ~WAVE_PULSE; } else diff --git a/src/devices/sound/cem3394.h b/src/devices/sound/cem3394.h index fd6d147cdbb21..111495eaf4327 100644 --- a/src/devices/sound/cem3394.h +++ b/src/devices/sound/cem3394.h @@ -97,6 +97,7 @@ class cem3394_device : public device_t, public device_sound_interface double m_filter_frequency; // baseline filter frequency double m_filter_modulation; // depth of modulation (up to 1.0) double m_filter_resonance; // depth of modulation (up to 1.0) + double m_filter_osc_position; // current filter self-oscillation position (always < 1.0) double m_filter_in[4]; // filter input history double m_filter_out[4]; // filter output history