After messing around with some YM code on my own, enough to satisfy my curiosity (ugh, passing values to the YM is slow) I checked out AT2 and yeah, it's all there isn't it. So I got all my music and sound effects done in a weekend. Ok, that was really easy.
I just have one thing I need to do for it to be perfect. I need to be able to stop a subsong, play another subsong, and then resume the first subsong from where it left off (rather than start again from the beginning). Presumably it's just a matter of storing some values.
Indeed that will require a function which is freezing the current state, so that you can restore it later. I thought about the same already.
My plan is to go through the init routine were tons of variables are reset, and use this as a reference what has to be saved.
Not sure if I have time for this during next two days, please tell me if you are already faster :)
There are ways, but not built-in indeed.
- Storing the various pointers isn't quite easy but there is probably no need to be very thorough. You could only save the main ones (where you are in the linker, the pointers at each track, the one on each instrument, plus the PSG registers).
- A simple brute-force trick I used in Orion Prime is to count how many frames of each song has passed (don't forget to reset it when the song loops!). Then when wanting to resume, bypass the PSG output code, and play the song X times :). Raw but actually works pretty fine, and costs only a few bytes!
- The ROM player is a bit slower, but as it doesn't automodify itself, all the data is in a single buffer of 250-ish bytes. You could save it and restore it at will.
Thanks for the quick response; very much appreciated.
Because this happens during gameplay I'm looking for the fastest solution, although calling the player until it reaches the right spot does sound nice and simple, ideally I'd like to get there with the least amount of CPU time.
So I was hoping to force-feed in the minimum number of pointers that it would need to straighten itself out (option 1). The subsong I'm jumping out of will have already finished so the player will be in a known state when I start. Resuming from the start of the chunk would also be fine.
I was just hacking this in:
PLY_AKG_MUSICSTATE_TAB
dw PLY_AKG_ARPEGGIOSTABLE+1: db 2
dw PLY_AKG_PITCHESTABLE+1: db 2
dw PLY_AKG_INSTRUMENTSTABLE+1: db 2
dw PLY_AKG_CHANNEL_READEFFECTS_EFFECTBLOCKS1+1: db 2
dw PLY_AKG_CHANNEL_READEFFECTS_EFFECTBLOCKS2+1: db 2
dw PLY_AKG_CHANNEL3_READCELLEND+1: db 1
dw PLY_AKG_CHANNEL1_NOTE+1: db 1
dw PLY_AKG_READLINKER+1: db 2
dw PLY_AKG_PSGREG13_OLDVALUE+1: db 1
dw PLY_AKG_ENDWITHOUTLOOP+1: db 2
dw PLY_AKG_CHANNEL1_PTINSTRUMENT+1: db 2
dw PLY_AKG_CHANNEL2_PTINSTRUMENT+1: db 2
dw PLY_AKG_CHANNEL3_PTINSTRUMENT+1: db 2
dw PLY_AKG_CHANNEL1_SOUNDEFFECTDATA: db 2
dw PLY_AKG_CHANNEL2_SOUNDEFFECTDATA: db 2
dw PLY_AKG_CHANNEL3_SOUNDEFFECTDATA: db 2
PLY_AKG_MUSICSTATE_TAB_END
;### Saves the current (sub)song state
;### Input DE=state memory (83 bytes)
PLY_AKG_STATE_SAVE
ld ix,PLY_AKG_MUSICSTATE_TAB
ld iyl,16 ;(PLY_AKG_MUSICSTATE_TAB_END-PLY_AKG_MUSICSTATE_TAB)/3
ld b,0
PLY_AKG_STATE_SAVE_LOOP1
ld l,(ix+0)
ld h,(ix+1)
ld c,(iy+2)
ldir
ld c,3
add ix,bc
dec iyl
jr nz,PLY_AKG_STATE_SAVE_LOOP1
ld ix,PLY_AKG_INITTABLE0
ld iyl,27 ;(PLY_AKG_INITTABLEORA_END-PLY_AKG_INITTABLE0)/2
PLY_AKG_STATE_SAVE_LOOP2
ld l,(ix+0)
ld h,(ix+1)
ld c,4
ldi
ldi
add ix,bc
dec iyl
jr nz,PLY_AKG_STATE_SAVE_LOOP2
ret
;### Loads a (sub)song state
;### Input HL=state memory (83 bytes)
PLY_AKG_STATE_LOAD
ld ix,PLY_AKG_MUSICSTATE_TAB
ld iyl,16 ;(PLY_AKG_MUSICSTATE_TAB_END-PLY_AKG_MUSICSTATE_TAB)/3
ld b,0
PLY_AKG_STATE_LOAD_LOOP1
ld e,(ix+0)
ld d,(ix+1)
ld c,(iy+2)
ldir
ld c,3
add ix,bc
dec iyl
jr nz,PLY_AKG_STATE_LOAD_LOOP1
ld ix,PLY_AKG_INITTABLE0
ld iyl,27 ;(PLY_AKG_INITTABLEORA_END-PLY_AKG_INITTABLE0)/2
PLY_AKG_STATE_LOAD_LOOP2
ld e,(ix+0)
ld d,(ix+1)
ld c,4
ldi
ldi
add ix,bc
dec iyl
jr nz,PLY_AKG_STATE_LOAD_LOOP2
ret
I didn't test it yet, so no idea if this will work.
But you should get the idea, all these are the vars, which are set in the PLY_AKG_INIT routine.
Storing/restoring the PSG registers is not included yet.
sorry...
ld c,(iy+2)
should be...
ld c,(ix+2)
however still not tested...
I'll have to shuffle some memory before I can try this on the game as the memory bank the music lives in is very snug right now. I'll get stuck in sometime over the next couple of weekends, cheers.