summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author Aaron Giles <aaron@aarongiles.com>2020-09-17 13:45:13 -0700
committer Aaron Giles <aaron@aarongiles.com>2020-09-17 13:45:13 -0700
commitaba8c220e89e5563c21aac3548a810adcdbfb71b (patch)
treee8d8408fbfe3fa93ca24642ab689fb2f3ea2cd88
parentec742d3eda78e2fefd01b69a9f10ae1939422d16 (diff)
sound: Some optimizations for common cases
* Reuse resamplers if routing the same output to multiple targets at the same rate * Avoid copying when there's only one stream going through a mixer
-rw-r--r--src/emu/disound.cpp7
-rw-r--r--src/emu/sound.cpp70
-rw-r--r--src/emu/sound.h8
3 files changed, 54 insertions, 31 deletions
diff --git a/src/emu/disound.cpp b/src/emu/disound.cpp
index 29d8b4e13b5..d2c063ff205 100644
--- a/src/emu/disound.cpp
+++ b/src/emu/disound.cpp
@@ -497,6 +497,13 @@ void device_mixer_interface::interface_post_load()
void device_mixer_interface::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
+ // special case: single input, single output, same rate
+ if (inputs.size() == 1 && outputs.size() == 1 && inputs[0].sample_rate() == outputs[0].sample_rate())
+ {
+ outputs[0] = inputs[0];
+ return;
+ }
+
// reset the clear flags
std::fill(std::begin(m_output_clear), std::end(m_output_clear), false);
diff --git a/src/emu/sound.cpp b/src/emu/sound.cpp
index a00546f7af3..6b54797de36 100644
--- a/src/emu/sound.cpp
+++ b/src/emu/sound.cpp
@@ -415,6 +415,29 @@ std::string sound_stream_output::name() const
}
+//-------------------------------------------------
+// optimize_resampler - optimize resamplers by
+// either returning the native rate or another
+// input's resampler if they can be reused
+//-------------------------------------------------
+
+sound_stream_output &sound_stream_output::optimize_resampler(sound_stream_output *input_resampler)
+{
+ // if no resampler, or if the resampler rate matches our rate, return ourself
+ if (input_resampler == nullptr || buffer_sample_rate() == input_resampler->buffer_sample_rate())
+ return *this;
+
+ // scan our list of resamplers to see if there's another match
+ for (auto &resampler : m_resampler_list)
+ if (resampler->buffer_sample_rate() == input_resampler->buffer_sample_rate())
+ return *resampler;
+
+ // add the input to our list and return the one we were given back
+ m_resampler_list.push_back(input_resampler);
+ return *input_resampler;
+}
+
+
//**************************************************************************
// SOUND STREAM INPUT
@@ -494,22 +517,15 @@ read_stream_view sound_stream_input::update(attotime start, attotime end)
// shouldn't get here unless valid
sound_assert(valid());
- // determine if we need to use the resampler
- bool resampled = false;
- if (m_resampler_source != nullptr)
- {
- // if sample rates differ, then yes
- if (m_owner->sample_rate() != m_native_source->buffer_sample_rate())
- resampled = true;
+ // pick an optimized resampler
+ sound_stream_output &source = m_native_source->optimize_resampler(m_resampler_source);
- // if not, keep the resampler's end time up to date
- else
- m_resampler_source->set_end_time(end);
- }
+ // if not using our own resampler, keep it up to date in case we need to invoke it later
+ if (m_resampler_source != nullptr && &source != m_resampler_source)
+ m_resampler_source->set_end_time(end);
// update the source, returning a view of the needed output over the start and end times
- sound_stream_output &source = resampled ? *m_resampler_source : *m_native_source;
- return source.stream().update_view(start, end, source.index()).set_gain(m_gain * m_user_gain * m_native_source->gain());
+ return source.stream().update_view(start, end, source.index()).apply_gain(m_gain * m_user_gain * m_native_source->gain());
}
@@ -763,7 +779,7 @@ read_stream_view sound_stream::update_view(attotime start, attotime end, u32 out
g_profiler.stop();
// return the requested view
- return read_stream_view(m_output[outputnum].view(start, end));
+ return read_stream_view(m_output_view[outputnum], start);
}
@@ -822,16 +838,16 @@ void sound_stream::apply_sample_rate_changes(u32 updatenum, u32 downstream_rate)
//-------------------------------------------------
#if (SOUND_DEBUG)
-void sound_stream::print_graph_recursive(int indent)
+void sound_stream::print_graph_recursive(int indent, int index)
{
- osd_printf_info("%c %*s%s @ %d\n", m_callback.isnull() ? ' ' : '!', indent, "", name().c_str(), sample_rate());
+ osd_printf_info("%c %*s%s Ch.%d @ %d\n", m_callback.isnull() ? ' ' : '!', indent, "", name().c_str(), index + m_output_base, sample_rate());
for (int index = 0; index < m_input.size(); index++)
if (m_input[index].valid())
{
if (m_input[index].m_resampler_source != nullptr)
- m_input[index].m_resampler_source->stream().print_graph_recursive(indent + 2);
+ m_input[index].m_resampler_source->stream().print_graph_recursive(indent + 2, m_input[index].m_resampler_source->index());
else
- m_input[index].m_native_source->stream().print_graph_recursive(indent + 2);
+ m_input[index].m_native_source->stream().print_graph_recursive(indent + 2, m_input[index].m_native_source->index());
}
}
#endif
@@ -1011,13 +1027,8 @@ void default_resampler_stream::resampler_sound_update(sound_stream &stream, std:
return;
}
- // if we have equal sample rates, we just need to copy
- auto numsamples = output.samples();
- if (input.sample_rate() == output.sample_rate())
- {
- output.copy(input);
- return;
- }
+ // optimize_resampler ensures we should not have equal sample rates
+ sound_assert(input.sample_rate() != output.sample_rate());
// compute the stepping value and the inverse
stream_buffer::sample_t step = stream_buffer::sample_t(input.sample_rate()) / stream_buffer::sample_t(output.sample_rate());
@@ -1036,6 +1047,7 @@ void default_resampler_stream::resampler_sound_update(sound_stream &stream, std:
// clamp the latency to the start (only relevant at the beginning)
s32 dstindex = 0;
attotime output_start = output.start_time();
+ auto numsamples = output.samples();
while (latency > output_start && dstindex < numsamples)
{
output.put(dstindex++, 0);
@@ -1383,10 +1395,10 @@ void sound_manager::reset()
// dump the sound graph when we start up
for (speaker_device &speaker : speaker_device_iterator(machine().root_device()))
{
- int dummy;
- sound_stream *output = speaker.output_to_stream_output(0, dummy);
- if (output)
- output->print_graph_recursive(0);
+ int index;
+ sound_stream *output = speaker.output_to_stream_output(0, index);
+ if (output != nullptr)
+ output->print_graph_recursive(0, index);
}
// dump the orphan list as well
diff --git a/src/emu/sound.h b/src/emu/sound.h
index 5ccc78c015b..c3027b28ba6 100644
--- a/src/emu/sound.h
+++ b/src/emu/sound.h
@@ -359,7 +359,7 @@ public:
}
// constructor that converts from a read_stream_view
- write_stream_view(read_stream_view &src) :
+ write_stream_view(read_stream_view const &src) :
read_stream_view(src)
{
}
@@ -472,12 +472,16 @@ public:
// resync the buffer to the given end time
void set_end_time(attotime end) { m_buffer.set_end_time(end); }
+ // attempt to optimize resamplers by reusing them where possible
+ sound_stream_output &optimize_resampler(sound_stream_output *input_resampler);
+
private:
// internal state
sound_stream *m_stream; // owning stream
stream_buffer m_buffer; // output buffer
u32 m_index; // output index within the stream
stream_buffer::sample_t m_gain; // gain to apply to the output
+ std::vector<sound_stream_output *> m_resampler_list; // list of resamplers we're connected to
};
@@ -616,7 +620,7 @@ public:
#if (SOUND_DEBUG)
// print one level of the sound graph and recursively tell our inputs to do the same
- void print_graph_recursive(int indent);
+ void print_graph_recursive(int indent, int index);
#endif
protected: