Fix setting sample rate back to zero & crash for synchronous streams when rate is zero. This fixes all reported bugs. (nw)

This commit is contained in:
smf- 2018-07-29 13:32:24 +01:00
parent 64afd77e7c
commit 3a732c9b1c
2 changed files with 71 additions and 41 deletions

View File

@ -452,7 +452,12 @@ void device_scheduler::timeslice()
{
// only process if this CPU is executing or truly halted (not yielding)
// and if our target is later than the CPU's current time (coarse check)
if (EXPECTED((exec->m_suspend == 0 || exec->m_eatcycles) && target.seconds() >= exec->m_localtime.seconds()))
if (exec->m_suspend != 0)
{
if (exec->m_eatcycles)
exec->m_localtime = target;
}
else if (target.seconds() >= exec->m_localtime.seconds())
{
// compute how many attoseconds to execute this CPU
attoseconds_t delta = target.attoseconds() - exec->m_localtime.attoseconds();
@ -467,33 +472,29 @@ void device_scheduler::timeslice()
int ran = exec->m_cycles_running = divu_64x32(u64(delta) >> exec->m_divshift, exec->m_divisor);
LOG((" cpu '%s': %d (%d cycles)\n", exec->device().tag(), delta, exec->m_cycles_running));
// if we're not suspended, actually execute
if (exec->m_suspend == 0)
g_profiler.start(exec->m_profiler);
// note that this global variable cycles_stolen can be modified
// via the call to cpu_execute
exec->m_cycles_stolen = 0;
m_executing_device = exec;
*exec->m_icountptr = exec->m_cycles_running;
if (!call_debugger)
exec->run();
else
{
g_profiler.start(exec->m_profiler);
// note that this global variable cycles_stolen can be modified
// via the call to cpu_execute
exec->m_cycles_stolen = 0;
m_executing_device = exec;
*exec->m_icountptr = exec->m_cycles_running;
if (!call_debugger)
exec->run();
else
{
exec->debugger_start_cpu_hook(target);
exec->run();
exec->debugger_stop_cpu_hook();
}
// adjust for any cycles we took back
assert(ran >= *exec->m_icountptr);
ran -= *exec->m_icountptr;
assert(ran >= exec->m_cycles_stolen);
ran -= exec->m_cycles_stolen;
g_profiler.stop();
exec->debugger_start_cpu_hook(target);
exec->run();
exec->debugger_stop_cpu_hook();
}
// adjust for any cycles we took back
assert(ran >= *exec->m_icountptr);
ran -= *exec->m_icountptr;
assert(ran >= exec->m_cycles_stolen);
ran -= exec->m_cycles_stolen;
g_profiler.stop();
// account for these cycles
exec->m_totalcycles += ran;

View File

@ -53,7 +53,7 @@ sound_stream::sound_stream(device_t &device, int inputs, int outputs, int sample
: m_device(device),
m_next(nullptr),
m_sample_rate(sample_rate),
m_new_sample_rate(0),
m_new_sample_rate(0xffffffff),
m_attoseconds_per_sample(0),
m_max_samples_per_update(0),
m_input(inputs),
@ -264,6 +264,9 @@ void sound_stream::set_input(int index, sound_stream *input_stream, int output_i
void sound_stream::update()
{
if (!m_attoseconds_per_sample)
return;
// determine the number of samples since the start of this second
attotime time = m_device.machine().time();
s32 update_sampindex = s32(time.attoseconds() / m_attoseconds_per_sample);
@ -427,25 +430,35 @@ void sound_stream::update_with_accounting(bool second_tick)
void sound_stream::apply_sample_rate_changes()
{
// skip if nothing to do
if (m_new_sample_rate == 0)
if (m_new_sample_rate == 0xffffffff)
return;
// update to the new rate and remember the old rate
u32 old_rate = m_sample_rate;
m_sample_rate = m_new_sample_rate;
m_new_sample_rate = 0;
m_new_sample_rate = 0xffffffff;
// recompute all the data
recompute_sample_rate_data();
// reset our sample indexes to the current time
m_output_sampindex = s64(m_output_sampindex) * s64(m_sample_rate) / old_rate;
m_output_update_sampindex = s64(m_output_update_sampindex) * s64(m_sample_rate) / old_rate;
if (old_rate)
{
m_output_sampindex = s64(m_output_sampindex) * s64(m_sample_rate) / old_rate;
m_output_update_sampindex = s64(m_output_update_sampindex) * s64(m_sample_rate) / old_rate;
}
else
{
m_output_sampindex = m_attoseconds_per_sample ? m_device.machine().sound().last_update().attoseconds() / m_attoseconds_per_sample : 0;
m_output_update_sampindex = m_output_sampindex;
}
m_output_base_sampindex = m_output_sampindex - m_max_samples_per_update;
// clear out the buffer
for (auto & elem : m_output)
memset(&elem.m_buffer[0], 0, m_max_samples_per_update * sizeof(elem.m_buffer[0]));
if (m_max_samples_per_update)
for (auto & elem : m_output)
memset(&elem.m_buffer[0], 0, m_max_samples_per_update * sizeof(elem.m_buffer[0]));
}
@ -471,15 +484,22 @@ void sound_stream::recompute_sample_rate_data()
throw emu_fatalerror("Incompatible sample rates as input of a synchronous stream: %d and %d\n", m_sample_rate, input.m_source->m_stream->m_sample_rate);
}
}
if (!m_sample_rate)
m_sample_rate = 1000;
}
// recompute the timing parameters
attoseconds_t update_attoseconds = m_device.machine().sound().update_attoseconds();
m_attoseconds_per_sample = ATTOSECONDS_PER_SECOND / m_sample_rate;
m_max_samples_per_update = (update_attoseconds + m_attoseconds_per_sample - 1) / m_attoseconds_per_sample;
if (m_sample_rate)
{
m_attoseconds_per_sample = ATTOSECONDS_PER_SECOND / m_sample_rate;
m_max_samples_per_update = (update_attoseconds + m_attoseconds_per_sample - 1) / m_attoseconds_per_sample;
}
else
{
m_attoseconds_per_sample = 0;
m_max_samples_per_update = 0;
}
// update resample and output buffer sizes
allocate_resample_buffers();
@ -490,7 +510,7 @@ void sound_stream::recompute_sample_rate_data()
{
// if we have a source, see if its sample rate changed
if (input.m_source != nullptr)
if (input.m_source != nullptr && input.m_source->m_stream->m_sample_rate)
{
// okay, we have a new sample rate; recompute the latency to be the maximum
// sample period between us and our input
@ -511,14 +531,23 @@ void sound_stream::recompute_sample_rate_data()
input.m_latency_attoseconds = std::max(input.m_latency_attoseconds, latency);
assert(input.m_latency_attoseconds < update_attoseconds);
}
else
{
input.m_latency_attoseconds = 0;
}
}
// If synchronous, prime the timer
if (m_synchronous)
{
attotime time = m_device.machine().time();
attoseconds_t next_edge = m_attoseconds_per_sample - (time.attoseconds() % m_attoseconds_per_sample);
m_sync_timer->adjust(attotime(0, next_edge));
if (m_attoseconds_per_sample)
{
attoseconds_t next_edge = m_attoseconds_per_sample - (time.attoseconds() % m_attoseconds_per_sample);
m_sync_timer->adjust(attotime(0, next_edge));
}
else
m_sync_timer->adjust(attotime::never);
}
}
@ -587,7 +616,7 @@ void sound_stream::postload()
memset(&elem.m_buffer[0], 0, m_output_bufalloc * sizeof(elem.m_buffer[0]));
// recompute the sample indexes to make sense
m_output_sampindex = m_device.machine().sound().last_update().attoseconds() / m_attoseconds_per_sample;
m_output_sampindex = m_attoseconds_per_sample ? m_device.machine().sound().last_update().attoseconds() / m_attoseconds_per_sample : 0;
m_output_update_sampindex = m_output_sampindex;
m_output_base_sampindex = m_output_sampindex - m_max_samples_per_update;
}
@ -653,7 +682,7 @@ stream_sample_t *sound_stream::generate_resampled_data(stream_input &input, u32
{
// if we don't have an output to pull data from, generate silence
stream_sample_t *dest = &input.m_resample[0];
if (input.m_source == nullptr)
if (input.m_source == nullptr || input.m_source->m_stream->m_attoseconds_per_sample == 0)
{
memset(dest, 0, numsamples * sizeof(*dest));
return &input.m_resample[0];