Save and restore score cursor position (ArduboyPlaytune)

Hi! This question is probably for @MLXXXp: Is there is a way to save and restore the cursor position? I guess it is not as simple of exposing the variables used by the step() function

Maybe it is not possible because some params are not atomic and they have to be interpreted to advance in the score?

1 Like

There currently isn’t any code to save/restore the current score position.

It’s not impossible to add but could be a bit tricky. There’s a variable called score_cursor but you wouldn’t be able to just blindly read or write it because the system is dependent on the current state of what’s playing, which would also have to be saved and restored.

It would likely be easier to implement pause and resume functions. Would this be sufficient? The difference between this and save/restore is that you wouldn’t be able to “restore” randomly to any previously saved position in the score. You’d only be able to resume from where you last paused.

1 Like

Thanks for the answer. Well it might help but I want to have 3 songs (my game is like a dashboard with 3 subgames that you need to switch because everything is in realtime).

I can shorten the songs and make them simpler so it is not that annoying to hear them from the beginning. How hard would be to include the cursor position? maybe I can create and call “stepMute” (another function that is muted) to skip parts of the song?

1 Like

The problem with starting anywhere within a score is knowing what was happening previously to that point.

The score essentially consists of “start note”, “stop note” and “wait before processing the next command” commands. If a note was previously playing, you wouldn’t hear it upon resuming unless you either scanned backwards or saved this info as part of a save function. (If notes on both tone generators change frequently, the brief missing notes might not be noticeable before the next one starts, but that wouldn’t be very universal.)

Another problem is you can’t just start on any byte in the score. Delay and start note commands are 2 bytes long and starting on the second byte wouldn’t be properly interpreted.

I think a save() function would involve setting a flag that the interrupt service routine (ISR), that’s actually playing the score in the background, picks up on. The ISR would save everything needed to resume, in global variables, and then clear the flag. The save() function would wait for the flag to be cleared and then return the values of the global variables to the sketch for it to save and pass back to a restore() function.

A restore() function would require similar operations to reverse the procedure.

To implement this, the ISR may have to continuously maintain additional state information (possibly just what notes are currently playing) in order to provide the proper save data.

Since much of this code would be in the ISR, it would increase the size of the library even if the save() and restore() functions weren’t used by a sketch.

You could consider breaking a score into small sections, with each section now being a stand alone score. Each section would end with an end score command, not repeat score. In your main loop you would call the playing() function to know when the section had finished and start the next section (or start the first section after the last for continuous play).

By keeping track of the current section you were playing for each subgame, you could resume on a section basis granularity, either by restarting the section that was previously playing or skipping to the next section.

2 Likes

Yeah that sounds like a solution :smiley:

(Lazy question: do I need to split the midi?)

Probably, unless you want to manually decode the outputted score and split it by hand.