From c1bd56f0d318c71faac757d89c910c2682af6651 Mon Sep 17 00:00:00 2001 From: Aaron Giles Date: Sun, 13 Sep 2020 10:18:44 -0700 Subject: Significant internal changes to sound streams (#7169) Significant internal changes to sound streams: Abstracted buffers of sound data into an internal stream_buffer class, with helper classes read_stream_view and write_stream_view which offer readable/writable "views" into the buffers Internal sound calculations are all done using stream_buffer::sample_t, which is a 32-bit float; existing callbacks are supported through an adapter that converts to/from signed 32-bit integers Improved behavior of dynamic stream sample rate changes to resample a short runway of data to preserve continuity across transitions Created a new stream update callback which passes a std::vector of read_stream_views for inputs, and a std::vector of write_stream_views for outputs Updated core mixer and speaker devices to the new stream update callback Updated the following sound cores to the new stream update callback: ay8910, dac, k054539, msm5205, namco, netlist, okim6295, pokey, samples, sn76496, sp0250, tms5220, tms57002, upd7759, vgm_visualizer, volt_reg Changed existing stream update callback to make inputs explicitly const and the output pointers const as well, since they are re-used across calls; fixed several engines that violated this rule Sound_manager::stream_alloc can no longer automatically connect to a device's sound_stream_update callback; instead, the stream_alloc() on the sound_device_interface should be called; updated many violators of this rule Streams can be created with SAMPLE_RATE_OUTPUT_ADAPTIVE, which dynamically tracks the sample rate of its first downstream output, or with SAMPLE_RATE_INPUT_ADAPTIVE, which tracks the sample rate of its first input Changed resampling to be a separate sound_stream that is invoked as needed, opening the path for selectable resampling implementations Added a flags parameter to the new stream allocation method that allows you to specify a that input streams should not be resampled Exposed stream_input and stream_output classes directly, simplifying access to user gains and stream names Added a simple dynamic compressor to sound_manager to provide nicer results when overdriven sound happens; compression does not affect speaker_report results Improved verbose speaker_report to print a graph of peaks over time More aggressive debugging enabled for now even in release builds (should be disabled prior to next release) via SOUND_DEBUG define in sound.h; report any assertions for fixing --- src/devices/sound/upd7759.cpp | 77 ++++++++++++++++++++++++++----------------- 1 file changed, 47 insertions(+), 30 deletions(-) (limited to 'src/devices/sound/upd7759.cpp') diff --git a/src/devices/sound/upd7759.cpp b/src/devices/sound/upd7759.cpp index 35a66d0b736..fc07c0f95ab 100644 --- a/src/devices/sound/upd7759.cpp +++ b/src/devices/sound/upd7759.cpp @@ -210,7 +210,7 @@ upd7756_device::upd7756_device(const machine_config &mconfig, device_type type, void upd775x_device::device_start() { // allocate a stream channel - m_channel = machine().sound().stream_alloc(*this, 0, 1, clock()/4); + m_channel = stream_alloc(0, 1, clock()/4); // compute the stepping rate based on the chip's clock speed m_step = 4 * FRAC_ONE; @@ -264,7 +264,7 @@ void upd7759_device::device_start() // chip configuration m_sample_offset_shift = 1; - m_timer = timer_alloc(TIMER_SLAVE_UPDATE); + m_timer = timer_alloc(TID_SLAVE_UPDATE); m_drqcallback.resolve_safe(); @@ -599,24 +599,35 @@ void upd7759_device::device_timer(emu_timer &timer, device_timer_id id, int para switch (id) { - case TIMER_SLAVE_UPDATE: + case TID_PORT_WRITE: + m_fifo_in = param; + break; + + case TID_RESET_WRITE: + internal_reset_w(param); + break; + + case TID_START_WRITE: + internal_start_w(param); + break; - /* update the stream */ - m_channel->update(); + case TID_SLAVE_UPDATE: + /* update the stream */ + m_channel->update(); - /* advance the state */ - advance_state(); + /* advance the state */ + advance_state(); - /* if the DRQ changed, update it */ - if (DEBUG_STATES) - logerror("upd7759_slave_update: DRQ %d->%d\n", olddrq, m_drq); - if (olddrq != m_drq) - m_drqcallback(m_drq); + /* if the DRQ changed, update it */ + if (DEBUG_STATES) + logerror("upd7759_slave_update: DRQ %d->%d\n", olddrq, m_drq); + if (olddrq != m_drq) + m_drqcallback(m_drq); - /* set a timer to go off when that is done */ - if (m_state != STATE_IDLE) - m_timer->adjust(m_clock_period * m_clocks_left); - break; + /* set a timer to go off when that is done */ + if (m_state != STATE_IDLE) + m_timer->adjust(m_clock_period * m_clocks_left); + break; default: throw emu_fatalerror("Unknown id in upd7759_device::device_timer"); @@ -630,6 +641,11 @@ void upd7759_device::device_timer(emu_timer &timer, device_timer_id id, int para *************************************************************/ WRITE_LINE_MEMBER( upd775x_device::reset_w ) +{ + synchronize(TID_RESET_WRITE, state); +} + +void upd775x_device::internal_reset_w(int state) { /* update the reset value */ uint8_t oldreset = m_reset; @@ -643,12 +659,12 @@ WRITE_LINE_MEMBER( upd775x_device::reset_w ) device_reset(); } -WRITE_LINE_MEMBER(upd7759_device::md_w) +WRITE_LINE_MEMBER( upd775x_device::start_w ) { - m_md = state; + synchronize(TID_START_WRITE, state); } -WRITE_LINE_MEMBER( upd7759_device::start_w ) +void upd7759_device::internal_start_w(int state) { /* update the start value */ uint8_t oldstart = m_start; @@ -671,8 +687,9 @@ WRITE_LINE_MEMBER( upd7759_device::start_w ) } } -WRITE_LINE_MEMBER( upd7756_device::start_w ) +void upd7756_device::internal_start_w(int state) { + /* update the start value */ uint8_t oldstart = m_start; m_start = (state != 0); @@ -694,7 +711,7 @@ WRITE_LINE_MEMBER( upd7756_device::start_w ) void upd775x_device::port_w(u8 data) { /* update the FIFO value */ - m_fifo_in = data; + synchronize(TID_PORT_WRITE, data); } @@ -712,21 +729,21 @@ READ_LINE_MEMBER( upd775x_device::busy_r ) // sound_stream_update - handle a stream update //------------------------------------------------- -void upd775x_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +void upd775x_device::sound_stream_update(sound_stream &stream, std::vector const &inputs, std::vector &outputs) { + constexpr stream_buffer::sample_t sample_scale = 128.0 / 32768.0; + stream_buffer::sample_t sample = stream_buffer::sample_t(m_sample) * sample_scale; int32_t clocks_left = m_clocks_left; - int16_t sample = m_sample; uint32_t step = m_step; uint32_t pos = m_pos; - stream_sample_t *buffer = outputs[0]; /* loop until done */ + u32 index = 0; if (m_state != STATE_IDLE) - while (samples != 0) + for ( ; index < outputs[0].samples(); index++) { /* store the current sample */ - *buffer++ = sample << 7; - samples--; + outputs[0].put(index, sample); /* advance by the number of clocks/output sample */ pos += step; @@ -752,14 +769,14 @@ void upd775x_device::sound_stream_update(sound_stream &stream, stream_sample_t * /* reimport the variables that we cached */ clocks_left = m_clocks_left; - sample = m_sample; + sample = stream_buffer::sample_t(m_sample) * sample_scale; } } } /* if we got out early, just zap the rest of the buffer */ - if (samples != 0) - memset(buffer, 0, samples * sizeof(*buffer)); + for (; index < outputs[0].samples(); index++) + outputs[0].put(index, 0); /* flush the state back */ m_clocks_left = clocks_left; -- cgit v1.2.3-70-g09d2