virtualc64
virtualc64 copied to clipboard
Electronic Speech System
After V4.5 Ghostbusters and Impossible Mission have a distorted Electronic Speech System output. I've tried many different settings but none of them worked for me. Is there something I'm missing in the machine configuration settings or is it a bug?
Did you select the 6581 SID? The newer 8580 does not so well at speach synthesis. Commodore removed a bug in the newer SID which was exploited for speach synthesis.
Confirmed. Something is broken.
Yup, bug. SID 6581 doesn't make any difference.
Seems to work in v4.6. First broken release is v4.7b1
Next step: Determine the faulty commit
Tried V4.6 and the speech synthesis works.
Did a binary search on the repo: Culprit is commit 55aadf4.
Culprit is the CIA sleep logic. Here is the relevant part with an additional if-statement added for debugging:
// Sleep if threshold is reached
if (tiredness > 8 && !CIA_ON_STEROIDS) {
sleep();
scheduleWakeUp();
// EXPERIMENTAL TO HUNT DOWN #785
if (wakeUpCycle <= sleepCycle) {
printf("Alert: %lld %lld\n", wakeUpCycle, sleepCycle);
wakeUp();
}
} else {
scheduleNextExecution();
}
During speech synthesis, the following output is produced:
Alert: 60326377 60326377
Alert: 60331070 60331070
Alert: 60338006 60338006
...
The CIA puts itself to sleep with a wake-up cycle that matches the current clock. In the old code, events were processed after each half-cycle which woke the CIA in the same cycle it fell asleep. In the optimized code (with events only processed once per cycle), the wakeup comes one CPU cycle too late, resulting in a stuttered sound.
Clean fix: Alter the sleep logic such the CIA is only put to rest if it sleeps for at least 'n' cycles (with a suitable 'n').
Here is a small speed-improvement idea. Current code:
void
CIA::serviceEvent(EventID id)
{
switch(id) {
case CIA_EXECUTE:
executeOneCycle();
break;
case CIA_WAKEUP:
wakeUp();
break;
default:
fatalError;
}
}
Idea: Since CIA_WAKEUP
is a rare event, emulation can be sped up by adding a separate CIA_WAKEUP_SLOT
in the secondary event table. By doing so, the CIA_EVENT
slot would only be responsible for CIA execution. The dispatch function above could be eliminated, and executeOneCycle()
could be called directly whenever a CIA event fires.
I'm impressed.
Any news about V4.8?
I'm currently working on v5.0, which will feature run-ahead. It'll still take some time because I've refactored large parts of the code (which broke various stuff), and I am also busy with other projects.
Fixed in v5.0b1