mirror of
https://github.com/holub/mame
synced 2025-07-03 00:56:03 +03:00
spkrdev: fix regression with filtering
This commit is contained in:
parent
5a63d0e738
commit
17c64fa372
@ -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: */
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user