Input Playback Sync

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
Input Playback Sync
by on (#125481)
Hello all;

I'm working on an emulator based on codeproject.com/Articles/38348/My-Nes-Nes-Emulator

My current project is adding record and playback functionality, which I've partly accomplished by saving/loading the state at the start of record/playback and intercepting 4016:
Code:
case (0x4016):
    if ((this.JoyStrobe == 1) && ((data & 1) == 0))
    {
        _inputManager.Update();
        this.JoyData1 = _joypad1.GetJoyData() | 0x100;
        this.JoyData2 = _joypad2.GetJoyData() | 0x200;
        myVcr.Intercept(ref JoyData1, ref JoyData2); // <- Used to record or replay by capturing or replacing pad state
    }
    this.JoyStrobe = (byte)(data & 1);
    break;

This works okay for recording, but when I play the data back it gets out of sync after a minute or so. This is a multithreaded application, so I suspect that just polling the input isn't deterministic enough.

How is this accomplished in other emulators? Is there another counter I could synchronize off of?

Thanks!
Re: Input Playback Sync
by on (#125489)
The proper place to synchronize input is probably not during writes to $4016 but rather at a specific point during each frame (e.g. at the start of VBlank).

If you are implementing DPCM/controller conflicts, then failing to make the timing 100% consistent could result in conflicts happening at different points of time (or not at all) and causing the desynchronization you are observing.
Re: Input Playback Sync
by on (#125490)
Thanks. I'll try syncing on vblank and see it that gets it close.