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

View file

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