diff options
Diffstat (limited to 'src/emu/disound.cpp')
-rw-r--r-- | src/emu/disound.cpp | 458 |
1 files changed, 155 insertions, 303 deletions
diff --git a/src/emu/disound.cpp b/src/emu/disound.cpp index 83d2c2bf084..57fd6a9c030 100644 --- a/src/emu/disound.cpp +++ b/src/emu/disound.cpp @@ -23,9 +23,11 @@ device_sound_interface::device_sound_interface(const machine_config &mconfig, device_t &device) : device_interface(device, "sound"), - m_outputs(0), - m_auto_allocated_inputs(0), - m_specified_inputs_mask(0) + m_sound_requested_inputs_mask(0), + m_sound_requested_outputs_mask(0), + m_sound_requested_inputs(0), + m_sound_requested_outputs(0), + m_sound_hook(false) { } @@ -43,25 +45,20 @@ device_sound_interface::~device_sound_interface() // add_route - send sound output to a consumer //------------------------------------------------- -device_sound_interface &device_sound_interface::add_route(u32 output, const char *target, double gain, u32 input, u32 mixoutput) +device_sound_interface &device_sound_interface::add_route(u32 output, const char *target, double gain, u32 channel) { - return add_route(output, device().mconfig().current_device(), target, gain, input, mixoutput); + return add_route(output, device().mconfig().current_device(), target, gain, channel); } -device_sound_interface &device_sound_interface::add_route(u32 output, device_sound_interface &target, double gain, u32 input, u32 mixoutput) +device_sound_interface &device_sound_interface::add_route(u32 output, device_sound_interface &target, double gain, u32 channel) { - return add_route(output, target.device(), DEVICE_SELF, gain, input, mixoutput); + return add_route(output, target.device(), DEVICE_SELF, gain, channel); } -device_sound_interface &device_sound_interface::add_route(u32 output, speaker_device &target, double gain, u32 input, u32 mixoutput) -{ - return add_route(output, target, DEVICE_SELF, gain, input, mixoutput); -} - -device_sound_interface &device_sound_interface::add_route(u32 output, device_t &base, const char *target, double gain, u32 input, u32 mixoutput) +device_sound_interface &device_sound_interface::add_route(u32 output, device_t &base, const char *target, double gain, u32 channel) { assert(!device().started()); - m_route_list.emplace_back(sound_route{ output, input, mixoutput, float(gain), base, target }); + m_route_list.emplace_back(sound_route{ output, channel, float(gain), base, target, nullptr }); return *this; } @@ -71,45 +68,41 @@ device_sound_interface &device_sound_interface::add_route(u32 output, device_t & // associated with this device //------------------------------------------------- -sound_stream *device_sound_interface::stream_alloc(int inputs, int outputs, int sample_rate) -{ - return device().machine().sound().stream_alloc(*this, inputs, outputs, sample_rate, stream_update_delegate(&device_sound_interface::sound_stream_update, this), STREAM_DEFAULT_FLAGS); -} - sound_stream *device_sound_interface::stream_alloc(int inputs, int outputs, int sample_rate, sound_stream_flags flags) { - return device().machine().sound().stream_alloc(*this, inputs, outputs, sample_rate, stream_update_delegate(&device_sound_interface::sound_stream_update, this), flags); + sound_stream *stream = device().machine().sound().stream_alloc(*this, inputs, outputs, sample_rate, stream_update_delegate(&device_sound_interface::sound_stream_update, this), flags); + m_sound_streams.push_back(stream); + return stream; } + //------------------------------------------------- // inputs - return the total number of inputs -// for the given device +// forthe given device //------------------------------------------------- int device_sound_interface::inputs() const { // scan the list counting streams we own and summing their inputs int inputs = 0; - for (auto &stream : device().machine().sound().streams()) - if (&stream->device() == &device()) - inputs += stream->input_count(); + for(sound_stream *stream : m_sound_streams) + inputs += stream->input_count(); return inputs; } //------------------------------------------------- // outputs - return the total number of outputs -// for the given device +// forthe given device //------------------------------------------------- int device_sound_interface::outputs() const { // scan the list counting streams we own and summing their outputs int outputs = 0; - for (auto &stream : device().machine().sound().streams()) - if (&stream->device() == &device()) - outputs += stream->output_count(); + for(auto *stream : m_sound_streams) + outputs += stream->output_count(); return outputs; } @@ -120,24 +113,19 @@ int device_sound_interface::outputs() const // on that stream //------------------------------------------------- -sound_stream *device_sound_interface::input_to_stream_input(int inputnum, int &stream_inputnum) const +std::pair<sound_stream *, int> device_sound_interface::input_to_stream_input(int inputnum) const { assert(inputnum >= 0); + int orig_inputnum = inputnum; - // scan the list looking for streams owned by this device - for (auto &stream : device().machine().sound().streams()) - if (&stream->device() == &device()) - { - if (inputnum < stream->input_count()) - { - stream_inputnum = inputnum; - return stream.get(); - } - inputnum -= stream->input_count(); - } + // scan the list looking forstreams owned by this device + for(auto *stream : m_sound_streams) { + if(inputnum < stream->input_count()) + return std::make_pair(stream, inputnum); + inputnum -= stream->input_count(); + } - // not found - return nullptr; + fatalerror("Requested input %d on sound device %s which only has %d.", orig_inputnum, device().tag(), inputs()); } @@ -147,24 +135,19 @@ sound_stream *device_sound_interface::input_to_stream_input(int inputnum, int &s // on that stream //------------------------------------------------- -sound_stream *device_sound_interface::output_to_stream_output(int outputnum, int &stream_outputnum) const +std::pair<sound_stream *, int> device_sound_interface::output_to_stream_output(int outputnum) const { assert(outputnum >= 0); + int orig_outputnum = outputnum; - // scan the list looking for streams owned by this device - for (auto &stream : device().machine().sound().streams()) - if (&stream->device() == &device()) - { - if (outputnum < stream->output_count()) - { - stream_outputnum = outputnum; - return stream.get(); - } - outputnum -= stream->output_count(); - } + // scan the list looking forstreams owned by this device + for(auto *stream : m_sound_streams) { + if(outputnum < stream->output_count()) + return std::make_pair(stream, outputnum); + outputnum -= stream->output_count(); + } - // not found - return nullptr; + fatalerror("Requested output %d on sound device %s which only has %d.", orig_outputnum, device().tag(), outputs()); } @@ -175,9 +158,8 @@ sound_stream *device_sound_interface::output_to_stream_output(int outputnum, int float device_sound_interface::input_gain(int inputnum) const { - int stream_inputnum; - sound_stream *stream = input_to_stream_input(inputnum, stream_inputnum); - return (stream != nullptr) ? stream->input(stream_inputnum).gain() : 0.0f; + auto [stream, input] = input_to_stream_input(inputnum); + return stream->input_gain(input); } @@ -188,9 +170,32 @@ float device_sound_interface::input_gain(int inputnum) const float device_sound_interface::output_gain(int outputnum) const { - int stream_outputnum; - sound_stream *stream = output_to_stream_output(outputnum, stream_outputnum); - return (stream != nullptr) ? stream->output(stream_outputnum).gain() : 0.0f; + auto [stream, output] = output_to_stream_output(outputnum); + return stream->output_gain(output); +} + + +//------------------------------------------------- +// user_output_gain - return the user gain for the device +//------------------------------------------------- + +float device_sound_interface::user_output_gain() const +{ + if(!outputs()) + fatalerror("Requested user output gain on sound device %s which has no outputs.", device().tag()); + return m_sound_streams.front()->user_output_gain(); +} + + +//------------------------------------------------- +// user_output_gain - return the user gain on the given +// output index of the device +//------------------------------------------------- + +float device_sound_interface::user_output_gain(int outputnum) const +{ + auto [stream, output] = output_to_stream_output(outputnum); + return stream->user_output_gain(output); } @@ -201,10 +206,8 @@ float device_sound_interface::output_gain(int outputnum) const void device_sound_interface::set_input_gain(int inputnum, float gain) { - int stream_inputnum; - sound_stream *stream = input_to_stream_input(inputnum, stream_inputnum); - if (stream != nullptr) - stream->input(stream_inputnum).set_gain(gain); + auto [stream, input] = input_to_stream_input(inputnum); + stream->set_input_gain(input, gain); } @@ -216,45 +219,66 @@ void device_sound_interface::set_input_gain(int inputnum, float gain) void device_sound_interface::set_output_gain(int outputnum, float gain) { // handle ALL_OUTPUTS as a special case - if (outputnum == ALL_OUTPUTS) + if(outputnum == ALL_OUTPUTS) { - for (auto &stream : device().machine().sound().streams()) - if (&stream->device() == &device()) - for (int num = 0; num < stream->output_count(); num++) - stream->output(num).set_gain(gain); + if(!outputs()) + fatalerror("Requested setting output gain on sound device %s which has no outputs.", device().tag()); + for(auto *stream : m_sound_streams) + for(int num = 0; num < stream->output_count(); num++) + stream->set_output_gain(num, gain); } // look up the stream and stream output index else { - int stream_outputnum; - sound_stream *stream = output_to_stream_output(outputnum, stream_outputnum); - if (stream != nullptr) - stream->output(stream_outputnum).set_gain(gain); + auto [stream, output] = output_to_stream_output(outputnum); + stream->set_output_gain(output, gain); } } +//------------------------------------------------- +// user_set_output_gain - set the user gain on the device +//------------------------------------------------- + +void device_sound_interface::set_user_output_gain(float gain) +{ + if(!outputs()) + fatalerror("Requested setting user output gain on sound device %s which has no outputs.", device().tag()); + for(auto *stream : m_sound_streams) + stream->set_user_output_gain(gain); +} + + + +//------------------------------------------------- +// set_user_output_gain - set the user gain on the given +// output index of the device +//------------------------------------------------- + +void device_sound_interface::set_user_output_gain(int outputnum, float gain) +{ + auto [stream, output] = output_to_stream_output(outputnum); + stream->set_user_output_gain(output, gain); +} + //------------------------------------------------- -// inputnum_from_device - return the input number -// that is connected to the given device's output +// set_route_gain - set the gain on a route //------------------------------------------------- -int device_sound_interface::inputnum_from_device(device_t &source_device, int outputnum) const +void device_sound_interface::set_route_gain(int source_channel, device_sound_interface *target, int target_channel, float gain) { - int overall = 0; - for (auto &stream : device().machine().sound().streams()) - if (&stream->device() == &device()) - for (int inputnum = 0; inputnum < stream->input_count(); inputnum++, overall++) - { - auto &input = stream->input(inputnum); - if (input.valid() && &input.source().stream().device() == &source_device && input.source().index() == outputnum) - return overall; - } - return -1; + auto [sstream, schan] = output_to_stream_output(source_channel); + auto [tstream, tchan] = target->input_to_stream_input(target_channel); + tstream->update(); + if(tstream->set_route_gain(sstream, schan, tchan, gain)) + return; + + fatalerror("Trying to change the gain on a non-existant route between %s channel %d and %s channel %d\n", device().tag(), source_channel, target->device().tag(), target_channel); } + //------------------------------------------------- // interface_validity_check - validation for a // device after the configuration has been @@ -264,16 +288,16 @@ int device_sound_interface::inputnum_from_device(device_t &source_device, int ou void device_sound_interface::interface_validity_check(validity_checker &valid) const { // loop over all the routes - for (sound_route const &route : routes()) + for(sound_route const &route : routes()) { // find a device with the requested tag device_t const *const target = route.m_base.get().subdevice(route.m_target); - if (!target) + if(!target) osd_printf_error("Attempting to route sound to non-existent device '%s'\n", route.m_base.get().subtag(route.m_target)); - // if it's not a speaker or a sound device, error + // ifit's not a speaker or a sound device, error device_sound_interface const *sound; - if (target && (target->type() != SPEAKER) && !target->interface(sound)) + if(target && !target->interface(sound)) osd_printf_error("Attempting to route sound to a non-sound device '%s' (%s)\n", target->tag(), target->name()); } } @@ -284,240 +308,68 @@ void device_sound_interface::interface_validity_check(validity_checker &valid) c // devices are started //------------------------------------------------- -void device_sound_interface::interface_pre_start() +void device_sound_interface::sound_before_devices_init() { - // scan all the sound devices - sound_interface_enumerator iter(device().machine().root_device()); - for (device_sound_interface const &sound : iter) - { - // scan each route on the device - for (sound_route const &route : sound.routes()) - { - device_t *const target_device = route.m_base.get().subdevice(route.m_target); - if (target_device == &device()) - { - // see if we are the target of this route; if we are, make sure the source device is started - if (!sound.device().started()) - throw device_missing_dependencies(); - if (route.m_input != AUTO_ALLOC_INPUT) - m_specified_inputs_mask |= 1 << route.m_input; - } - } - } - - // now iterate through devices again and assign any auto-allocated inputs - m_auto_allocated_inputs = 0; - for (device_sound_interface &sound : iter) - { - // scan each route on the device - for (sound_route &route : sound.routes()) - { - // see if we are the target of this route - device_t *const target_device = route.m_base.get().subdevice(route.m_target); - if (target_device == &device() && route.m_input == AUTO_ALLOC_INPUT) - { - route.m_input = m_auto_allocated_inputs; - m_auto_allocated_inputs += (route.m_output == ALL_OUTPUTS) ? sound.outputs() : 1; - } + for(sound_route &route : routes()) { + device_t *dev = route.m_base.get().subdevice(route.m_target); + dev->interface(route.m_interface); + if(route.m_output != ALL_OUTPUTS && m_sound_requested_outputs <= route.m_output) { + m_sound_requested_outputs_mask |= u64(1) << route.m_output; + m_sound_requested_outputs = route.m_output + 1; } + route.m_interface->sound_request_input(route.m_input); } } - -//------------------------------------------------- -// interface_post_start - verify that state was -// properly set up -//------------------------------------------------- - -void device_sound_interface::interface_post_start() +void device_sound_interface::sound_after_devices_init() { - // iterate over all the sound devices - for (device_sound_interface &sound : sound_interface_enumerator(device().machine().root_device())) - { - // scan each route on the device - for (sound_route const &route : sound.routes()) - { - // if we are the target of this route, hook it up - device_t *const target_device = route.m_base.get().subdevice(route.m_target); - if (target_device == &device()) - { - // iterate over all outputs, matching any that apply - int inputnum = route.m_input; - int const numoutputs = sound.outputs(); - for (int outputnum = 0; outputnum < numoutputs; outputnum++) - if (route.m_output == outputnum || route.m_output == ALL_OUTPUTS) - { - // find the output stream to connect from - int streamoutputnum; - sound_stream *const outputstream = sound.output_to_stream_output(outputnum, streamoutputnum); - if (!outputstream) - fatalerror("Sound device '%s' specifies route for nonexistent output #%d\n", sound.device().tag(), outputnum); - - // find the input stream to connect to - int streaminputnum; - sound_stream *const inputstream = input_to_stream_input(inputnum++, streaminputnum); - if (!inputstream) - fatalerror("Sound device '%s' targeted output #%d to nonexistent device '%s' input %d\n", sound.device().tag(), outputnum, device().tag(), inputnum - 1); - - // set the input - inputstream->set_input(streaminputnum, outputstream, streamoutputnum, route.m_gain); - } - } + for(sound_route &route : routes()) { + auto [si, ii] = route.m_interface->input_to_stream_input(route.m_input); + if(!si) + fatalerror("Requesting sound route to device %s input %d which doesn't exist\n", route.m_interface->device().tag(), route.m_input); + if(route.m_output != ALL_OUTPUTS) { + auto [so, io] = output_to_stream_output(route.m_output); + if(!so) + fatalerror("Requesting sound route from device %s output %d which doesn't exist\n", device().tag(), route.m_output); + si->add_bw_route(so, io, ii, route.m_gain); + so->add_fw_route(si, ii, io); + + } else { + for(sound_stream *so : m_sound_streams) + for(int io = 0; io != so->output_count(); io ++) { + si->add_bw_route(so, io, ii, route.m_gain); + so->add_fw_route(si, ii, io); + } } } } - -//------------------------------------------------- -// interface_pre_reset - called prior to -// resetting the device -//------------------------------------------------- - -void device_sound_interface::interface_pre_reset() -{ - // update all streams on this device prior to reset - for (auto &stream : device().machine().sound().streams()) - if (&stream->device() == &device()) - stream->update(); -} - - -//------------------------------------------------- -// sound_stream_update - default implementation -// that should be overridden -//------------------------------------------------- - -void device_sound_interface::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) +void device_sound_interface::sound_request_input(u32 input) { - throw emu_fatalerror("sound_stream_update called but not overridden by owning class"); + m_sound_requested_inputs_mask |= u64(1) << input; + if(m_sound_requested_inputs <= input) + m_sound_requested_inputs = input + 1; } - - -//************************************************************************** -// SIMPLE DERIVED MIXER INTERFACE -//************************************************************************** - -//------------------------------------------------- -// device_mixer_interface - constructor -//------------------------------------------------- - -device_mixer_interface::device_mixer_interface(const machine_config &mconfig, device_t &device, int outputs) - : device_sound_interface(mconfig, device), - m_outputs(outputs), - m_mixer_stream(nullptr) +device_mixer_interface::device_mixer_interface(const machine_config &mconfig, device_t &device) : + device_sound_interface(mconfig, device) { } - -//------------------------------------------------- -// ~device_mixer_interface - destructor -//------------------------------------------------- - device_mixer_interface::~device_mixer_interface() { } - -//------------------------------------------------- -// interface_pre_start - perform startup prior -// to the device startup -//------------------------------------------------- - void device_mixer_interface::interface_pre_start() { - // call our parent - device_sound_interface::interface_pre_start(); - - // no inputs? that's weird - if (m_auto_allocated_inputs == 0) - { - device().logerror("Warning: mixer \"%s\" has no inputs\n", device().tag()); - return; - } - - // generate the output map - m_outputmap.resize(m_auto_allocated_inputs); - - // iterate through all routes that point to us and note their mixer output - for (device_sound_interface const &sound : sound_interface_enumerator(device().machine().root_device())) - { - for (sound_route const &route : sound.routes()) - { - // see if we are the target of this route - device_t *const target_device = route.m_base.get().subdevice(route.m_target); - if (target_device == &device() && route.m_input < m_auto_allocated_inputs) - { - int const count = (route.m_output == ALL_OUTPUTS) ? sound.outputs() : 1; - for (int output = 0; output < count; output++) - m_outputmap[route.m_input + output] = route.m_mixoutput; - } - } - } - - // keep a small buffer handy for tracking cleared buffers - m_output_clear.resize(m_outputs); - - // allocate the mixer stream - m_mixer_stream = stream_alloc(m_auto_allocated_inputs, m_outputs, device().machine().sample_rate(), STREAM_DEFAULT_FLAGS); -} - - -//------------------------------------------------- -// interface_post_load - after we load a save -// state be sure to update the mixer stream's -// output sample rate -//------------------------------------------------- - -void device_mixer_interface::interface_post_load() -{ - // mixer stream could be null if no inputs were specified - if (m_mixer_stream != nullptr) - m_mixer_stream->set_sample_rate(device().machine().sample_rate()); - - // call our parent - device_sound_interface::interface_post_load(); + u32 ni = get_sound_requested_inputs(); + u32 no = get_sound_requested_outputs(); + u32 nc = ni > no ? ni : no; + for(u32 i = 0; i != nc; i++) + stream_alloc(1, 1, SAMPLE_RATE_ADAPTIVE); } - -//------------------------------------------------- -// sound_stream_update - mix all inputs to one -// output -//------------------------------------------------- - -void device_mixer_interface::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) +void device_mixer_interface::sound_stream_update(sound_stream &stream) { - // 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); - - // loop over inputs - for (int inputnum = 0; inputnum < m_auto_allocated_inputs; inputnum++) - { - // skip if the gain is 0 - auto &input = inputs[inputnum]; - if (input.gain() == 0) - continue; - - // either store or accumulate - int outputnum = m_outputmap[inputnum]; - auto &output = outputs[outputnum]; - if (!m_output_clear[outputnum]) - output.copy(input); - else - output.add(input); - - m_output_clear[outputnum] = true; - } - - // clear anything unused - for (int outputnum = 0; outputnum < m_outputs; outputnum++) - if (!m_output_clear[outputnum]) - outputs[outputnum].fill(0); + stream.copy(0, 0); } |