Improve ZSM support by optimizing seek logic and using fractional CPU clocks. Also remove ZsmBackend::add_clocks, as it was no longer used, and caused issues when used.

This commit is contained in:
Zachary Hall 2024-10-16 09:05:41 -07:00
parent d5d9ca8ce5
commit b793fa949f
2 changed files with 26 additions and 43 deletions

View file

@ -109,7 +109,9 @@ void ZsmBackend::cleanup() {
void ZsmBackend::tick(bool step) {
delayTicks -= 1;
const double ClocksPerTick = ((double)HZ) / ((double)tick_rate);
ssize_t ticks_remaining = ClocksPerTick;
double prevCpuClocks = cpuClocks;
double nextCpuClocks = cpuClocks + ClocksPerTick;
double ticks_remaining = ClocksPerTick;
while (delayTicks <= 0) {
ZsmCommand cmd = get_command();
switch (cmd.id) {
@ -132,7 +134,7 @@ void ZsmBackend::tick(bool step) {
ticks_remaining -= clocksToAddForYm;
if (ticks_remaining < 0) {
delayTicks -= 1;
cpuClocks += ClocksPerTick;
nextCpuClocks += ClocksPerTick;
ticks_remaining += ClocksPerTick;
}
audio_step(clocksToAddForYm);
@ -205,38 +207,11 @@ void ZsmBackend::tick(bool step) {
} break;
}
}
audio_step(ticks_remaining);
cpuClocks += ClocksPerTick;
}
void ZsmBackend::add_clocks(double amount, bool step) {
const double ClocksPerTick = ((double)HZ) / ((double)tick_rate);
cpuClocks = std::fmod(cpuClocks, ClocksPerTick);
double prevCpuClocks = cpuClocks;
size_t prevIntCpuClocks = prevCpuClocks;
double tickDelta = amount / ClocksPerTick;
double prevTicks = ticks;
ticks += tickDelta;
size_t prevIntTicks = prevTicks;
size_t intTicks = ticks;
size_t intTicksDelta = intTicks - prevIntTicks;
cpuClocks += intTicks * ClocksPerTick;
double remainder = amount - (intTicksDelta * ClocksPerTick);
size_t intCpuClocks = cpuClocks;
size_t intCpuClockDelta = intCpuClocks - prevIntCpuClocks;
double initialTicks = prevCpuClocks / ClocksPerTick;
for (size_t i = 0; i < intTicksDelta; i++) {
double preTickCpuClocks = cpuClocks;
delayTicks--;
tick(step);
double neededCpuClocks = preTickCpuClocks + ClocksPerTick;
if (cpuClocks < neededCpuClocks) {
cpuClocks = neededCpuClocks;
}
}
if (remainder >= 0) {
cpuClocks += remainder;
audio_step(remainder);
}
size_t nextCpuClocksInt = std::floor(nextCpuClocks);
size_t prevCpuClocksInt = std::floor(prevCpuClocks);
size_t cpuClocksIntDelta = nextCpuClocksInt - prevCpuClocksInt;
audio_step(cpuClocksIntDelta);
cpuClocks = std::fmod(nextCpuClocks, ClocksPerTick);
}
size_t ZsmBackend::render(void *buf, size_t maxlen) {
size_t sample_type_len = 2;
@ -352,12 +327,20 @@ ZsmCommand::~ZsmCommand() {
}
}
void ZsmBackend::seek_internal(double position, bool loop) {
switch_stream(0);
file->seek(music_data_start, SeekType::SET);
this->cpuClocks = 0.0;
this->delayTicks = 0;
this->ticks = 0.0;
this->position = 0.0;
this->position = std::floor(this->position * PSG_FREQ) / PSG_FREQ;
position = std::floor(position * PSG_FREQ) / PSG_FREQ;
if (this->position > position) {
file->seek(music_data_start, SeekType::SET);
this->cpuClocks = 0.0;
this->delayTicks = 0;
this->ticks = 0.0;
this->position = 0.0;
} else if (this->position == position) {
audio_buf.clear();
return;
} else {
switch_stream(0);
}
while (this->position < position) {
audio_buf.clear();
try {
@ -369,6 +352,7 @@ void ZsmBackend::seek_internal(double position, bool loop) {
this->delayTicks = 0;
this->ticks = 0.0;
this->position = 0.0;
audio_buf.clear();
return;
}
}
@ -376,7 +360,7 @@ void ZsmBackend::seek_internal(double position, bool loop) {
while (samples--) {
audio_buf.pop();
}
this->position = std::floor(position * PSG_FREQ) / PSG_FREQ;
this->position = position;
}
void ZsmBackend::seek(double position) {
seek_internal(position, false);

View file

@ -155,8 +155,7 @@ class ZsmBackend : public PlaybackBackend {
inline double get_delay_per_frame() {
return 1.0;
}
void tick(bool step = true);
void add_clocks(double amount, bool step = true);
void tick(bool step = true);\
void seek_internal(double position, bool loop = true);
ZsmCommand get_command();
public: