From 17c64fa3727e728bf0c3ebb3cc9722e70601a1e1 Mon Sep 17 00:00:00 2001 From: hap Date: Sun, 4 Apr 2021 21:38:26 +0200 Subject: spkrdev: fix regression with filtering --- src/devices/sound/spkrdev.cpp | 64 ++++++++++++++++++------------------------- src/devices/sound/spkrdev.h | 2 +- 2 files changed, 28 insertions(+), 38 deletions(-) diff --git a/src/devices/sound/spkrdev.cpp b/src/devices/sound/spkrdev.cpp index b33e4ee5520..03694c84b3e 100644 --- a/src/devices/sound/spkrdev.cpp +++ b/src/devices/sound/spkrdev.cpp @@ -53,11 +53,11 @@ * Virtual stream 2: Intermediate representation. * Sample rate = RATE_MULTIPLIER * stream 3 sample rate. * If effective rate of stream 1 exceeds rate of stream 2, - * some aliasing distorsion is introduced in this step because the average filtering is a compromise. - * The distorsion is however mostly in the higher frequencies. + * some aliasing distortion is introduced in this step because the average filtering is a compromise. + * The distortion is however mostly in the higher frequencies. * -> low-pass anti-alias filtering with kernel ampl[] -> * -> down-sampling -> - * Actual stream 3: channel output generated by speaker_sound_update(). + * Actual stream 3: channel output generated by sound_stream_update(). * Sample rate = device sample rate = configured "-samplerate". * * In the speaker_state data structure, @@ -77,7 +77,7 @@ static constexpr double default_levels[2] = {0.0, 1.0}; -// Internal oversampling factor (interm. samples vs stream samples) +// Internal oversampling factor (intermediate samples vs stream samples) static constexpr int RATE_MULTIPLIER = 4; @@ -109,16 +109,17 @@ void speaker_sound_device::device_start() m_composed_volume[i] = 0; m_composed_sample_index = 0; + m_interm_sample_index = 0; + m_prevx = m_prevy = 0.0; + m_last_update_time = machine().time(); m_channel_sample_period = HZ_TO_ATTOSECONDS(machine().sample_rate()); m_channel_sample_period_secfrac = ATTOSECONDS_TO_DOUBLE(m_channel_sample_period); m_interm_sample_period = m_channel_sample_period / RATE_MULTIPLIER; m_interm_sample_period_secfrac = ATTOSECONDS_TO_DOUBLE(m_interm_sample_period); - m_channel_last_sample_time = m_channel->sample_time(); + m_channel_last_sample_time = m_last_update_time; m_channel_next_sample_time = m_channel_last_sample_time + attotime(0, m_channel_sample_period); m_next_interm_sample_time = m_channel_last_sample_time + attotime(0, m_interm_sample_period); - m_interm_sample_index = 0; - m_prevx = m_prevy = 0.0; /* Note: To avoid time drift due to floating point inaccuracies, * it is good if the speaker time synchronizes itself with the stream timing regularly. @@ -172,23 +173,7 @@ void speaker_sound_device::device_start() void speaker_sound_device::device_reset() { - int i; - m_level = 0; - for (i = 0; i < FILTER_LENGTH; i++) - m_composed_volume[i] = 0; - - m_composed_sample_index = 0; - m_last_update_time = machine().time(); - m_channel_sample_period = HZ_TO_ATTOSECONDS(machine().sample_rate()); - m_channel_sample_period_secfrac = ATTOSECONDS_TO_DOUBLE(m_channel_sample_period); - m_interm_sample_period = m_channel_sample_period / RATE_MULTIPLIER; - m_interm_sample_period_secfrac = ATTOSECONDS_TO_DOUBLE(m_interm_sample_period); - m_channel_last_sample_time = m_channel->sample_time(); - m_channel_next_sample_time = m_channel_last_sample_time + attotime(0, m_channel_sample_period); - m_next_interm_sample_time = m_channel_last_sample_time + attotime(0, m_interm_sample_period); - m_interm_sample_index = 0; - m_prevx = m_prevy = 0.0; } void speaker_sound_device::device_post_load() @@ -224,7 +209,7 @@ void speaker_sound_device::sound_stream_update(sound_stream &stream, std::vector for (int sampindex = 0; sampindex < buffer.samples(); ) { - /* Note that first interm. sample may be composed... */ + /* Note that first intermediate sample may be composed... */ filtered_volume = update_interm_samples_get_filtered_volume(volume); /* Composite volume is now quantized to the stream resolution */ @@ -249,7 +234,7 @@ void speaker_sound_device::sound_stream_update(sound_stream &stream, std::vector void speaker_sound_device::level_w(int new_level) { - int volume; + double volume; attotime time; if (new_level == m_level) @@ -266,7 +251,7 @@ void speaker_sound_device::level_w(int new_level) if (time < m_channel_next_sample_time) { - /* Stream sample is yet unfinished, but we may have one or more interm. samples */ + /* Stream sample is yet unfinished, but we may have one or more intermediate samples */ update_interm_samples(time, volume); /* Do not forget to update speaker state before returning! */ @@ -275,23 +260,28 @@ void speaker_sound_device::level_w(int new_level) } /* Reaching here means such time has passed since last stream update * that we can add at least one complete sample to the stream. - * The details have to be handled by speaker_sound_update() + * The details have to be handled by sound_stream_update() */ - /* Force streams.c to update sound until this point in time now */ + /* Force stream to update sound until this point in time now */ m_channel->update(); - /* This is redundant because time update has to be done within speaker_sound_update() anyway, + /* This is redundant because time update has to be done within sound_stream_update() anyway, * however this ensures synchronization between the speaker and stream timing: */ m_channel_last_sample_time = m_channel->sample_time(); + + /* sample_time() may be ahead of us */ + if (m_channel_last_sample_time > time) + m_channel_last_sample_time -= attotime(0, m_channel_sample_period); + m_channel_next_sample_time = m_channel_last_sample_time + attotime(0, m_channel_sample_period); m_next_interm_sample_time = m_channel_last_sample_time + attotime(0, m_interm_sample_period); m_last_update_time = m_channel_last_sample_time; /* Assertion: time - last_update_time < channel_sample_period, i.e. time < channel_next_sample_time */ - /* The overshooting fraction of time will make zero, one or more interm. samples: */ + /* The overshooting fraction of time will make zero, one or more intermediate samples: */ update_interm_samples(time, volume); /* Finally update speaker state before returning */ @@ -299,14 +289,14 @@ void speaker_sound_device::level_w(int new_level) } -void speaker_sound_device::update_interm_samples(const attotime &time, int volume) +void speaker_sound_device::update_interm_samples(const attotime &time, double volume) { double fraction; - /* We may have completed zero, one or more interm. samples: */ + /* We may have completed zero, one or more intermediate samples: */ while (time >= m_next_interm_sample_time) { - /* First interm. sample may be composed, subsequent samples will be homogeneous. */ + /* First intermediate sample may be composed, subsequent samples will be homogeneous. */ /* Treat all the same general way. */ finalize_interm_sample(volume); init_next_interm_sample(); @@ -325,20 +315,20 @@ double speaker_sound_device::update_interm_samples_get_filtered_volume(double vo { double filtered_volume, tempx; - /* We may have one or more interm. samples to go */ + /* We may have one or more intermediate samples to go */ if (m_interm_sample_index < RATE_MULTIPLIER) { - /* First interm. sample may be composed. */ + /* First intermediate sample may be composed. */ finalize_interm_sample(volume); - /* Subsequent interm. samples will be homogeneous. */ + /* Subsequent intermediate samples will be homogeneous. */ while (m_interm_sample_index + 1 < RATE_MULTIPLIER) { init_next_interm_sample(); m_composed_volume[m_composed_sample_index] = volume; } } - /* Important: next interm. sample not initialised yet, so that no data is destroyed before filtering... */ + /* Important: next intermediate sample not initialised yet, so that no data is destroyed before filtering... */ filtered_volume = get_filtered_volume(); init_next_interm_sample(); /* Reset counter to next stream sample: */ diff --git a/src/devices/sound/spkrdev.h b/src/devices/sound/spkrdev.h index 49b8eae2756..98289857f07 100644 --- a/src/devices/sound/spkrdev.h +++ b/src/devices/sound/spkrdev.h @@ -44,7 +44,7 @@ private: // internal state // Updates the composed volume array according to time - void update_interm_samples(const attotime &time, int volume); + void update_interm_samples(const attotime &time, double volume); // Updates the composed volume array and returns final filtered volume of next stream sample double update_interm_samples_get_filtered_volume(double volume); -- cgit v1.2.3