Sonic 2 Clone Driver v2

Discussion in 'Engineering & Reverse Engineering' started by Clownacy, Mar 31, 2014.

  1. Clownacy

    Clownacy

    Tech Member
    901
    193
    43
    Oh yeah, thanks for reminding me! The fully working feature is buried in an old prototype somewhere. If my understanding of it is correct, I might be able to replace the S1 Special SFX (looping GHZ waterfall sound) system with S3K's Continuous SFX system, and save that $60 bytes of RAM that the former uses.
     
  2. Caverns 4

    Caverns 4

    Member
    346
    0
    16
    Sonic: Retold
    So, before I even think about updating, to the latest version, some of the optimizations do look appealing, but I have to ask.

    How easy/hard is it to convert proper ASM songs to the format for this version?
     
  3. AkumaYin

    AkumaYin

    Member
    286
    6
    18
    You don't have to convert them; Clownacy didn't switch to an entirely different format or anything. The only modification to anything smps2asm-related was fixing a bug where it plays a missing coordination flag. It's still the same song format.
     
  4. Caverns 4

    Caverns 4

    Member
    346
    0
    16
    Sonic: Retold
    What I mean is SMPS2ASM music. Last I remember (it's been a while), it came out with some weird tempo issues or something, and I wanted to know what the status is on stuff like that.
     
  5. Clownacy

    Clownacy

    Tech Member
    901
    193
    43
    Whatever you experienced was a bug on your end. IIRC, it was probably your _smps2asm_inc.asm being outdated. S3 tempo-related stuff is handled during the build process, with no input from the user needed.
     
  6. Caverns 4

    Caverns 4

    Member
    346
    0
    16
    Sonic: Retold
    Oh, okay then. I must have made a mistake or something before then.
    I'll give it a go again later.

    EDIT: Also, an idea I've had: What about moving SoundPriorites and such to the external file where sounds are included as well?
     
  7. Clownacy

    Clownacy

    Tech Member
    901
    193
    43
    I suppose. I guess I'll have an s1.code.asm and s1.otherstuff.asm thing going on, just to keep the number of seperate files down while keeping everything update-friendly.
     
  8. Clownacy

    Clownacy

    Tech Member
    901
    193
    43
    Now to fix something that's been bugging me for a while.

    v2.2.3
    • Added S3K's additional PSG frequencies
    • Added S3K's continuous SFX system
    • Split sound priorities and speedup tempos from main asm into s1.sounddriver.other.asm

    Many months ago, a user asked about a problem he'd experienced with the driver: S3's credits theme was seemingly missing a channel. It was that faint noise channel you'd hear a few seconds into the song. It seems that it relied on S3K's additional frequencies to work, so, adding them has fixed it. Thanks to Flamewing for this one, his addition to the Port Knuckles guide brought attention to one SFX's reliance on a unique frequency, without that this problem will probably have gone unfixed. This may have fixed some other audio quirks with S3K songs, but I haven't tested my S3K+Clone v2 disasm in ages.

    Updating:
    You must overwrite _smps2asm_inc.asm with the new one. It contains a new feature.

    Also. note the presence of a new file, s1.soundriver.other.asm. It, like sound and music.asm are not to be overwritten when updates are applied. It contains the sound priorities and speedup tempos, so they can be retained between updates.

    Find VintRet and replace the jsr to UpdateMusic with this:

    Code (ASM):
    1.     jsr (UpdateMusic).l         ; update Sonic 2 Clone Driver
    2.  
    3. VintRet_NoMusic:


    Then go to loc_748 and replace the rts with this:

    Code (ASM):
    1.     addq.l  #4,sp
    2.     bra.w   VintRet_NoMusic


    And go to loc_1072 and, after this...

    Code (ASM):
    1.     bsr.w   Do_Updates


    ...add this:

    Code (ASM):
    1.     jsr (UpdateMusic).l
     
  9. ValleyBell

    ValleyBell

    Tech Member
    243
    14
    18
    researching PC-98/X68000 sound drivers
    Fixed.

    Sorry, but you can't always just port things and expect them to work correctly with everything. (That also is true for FM frequencies and the modulation algorithm.)
    90% of the PSG frequencies in S1 and S3K (or SMPS 68k and Z80 in general) are compatible, but the white noise is an exception.
    I'd recommend to make the table end with $11, 0, $10, 0. This way you still have all PSG frequencies from S3K, but S1/S2 songs will still work.

    btw: The next-to-last PSG frequency in S3K doesn't seem to be used by any song (they all use the last 0 in the table) and I think frequency $10 isn't used anywhere either.
     
  10. Clownacy

    Clownacy

    Tech Member
    901
    193
    43
    Right, thanks for that. Looking back at Flamewing's work, 10h is absent. Didn't think that 0 was used by anything in S1/S2, looked like an unequated 'even'.
     
  11. Caverns 4

    Caverns 4

    Member
    346
    0
    16
    Sonic: Retold
    Okay, so I've got a question, and I think it's a very good one:

    I was just implementing this into a fresh disassembly of Sonic 2, and I didn't bother to free up any RAM, because I was feeling lazy, so I just went here:

    Code (Text):
    1.                 ds.b    $500    ; $FFFFF100-$FFFFF5FF ; unused, leftover from the Sonic 1 sound driver (and used by it when you port it to Sonic 2)
    and put the "Clone_Driver_RAM" label before that.When testing, I had literally no issues, and just to be safe, I put the underwater palette tables after that $500 bytes so I could observe it in Regen's VDP viewer. Doing so, I noticed that at no point did the water's palette colours get corrupted, nor did the music or audio act up.

    Now, later on in your guide, you say this:
    That would be the $500 bytes I gave the Clone Driver RAM, $80 bytes for the first underwater palette table, and another $20 for the first line of the second underwater table, so in theory, Sonic's underwater palette would bug out at the very least, but it doesn't seem to.

    So, finally, I went into the Sound Driver Constants file, and looked at your equates. The highest active one is $340, and the highest inactive one is $3A0.
    I think you know what I'm asking at this point, but I'll say it anyway:
    Am I correct in surmising that $600 or $5A0 is an oversight? Do we even need $400 bytes?
     
  12. Clownacy

    Clownacy

    Tech Member
    901
    193
    43
    Get an extra life. Then it'll bug out.

    Somehow you overlooked that the RAM at the end is a (massive) save state of the currently playing song. When the extra life jingle is set to play, the currently playing song is backed up, the jingle plays, and the song is restored, then faded in.
     
  13. Caverns 4

    Caverns 4

    Member
    346
    0
    16
    Sonic: Retold
    Ah, yes. You're right. That is one thing I never checked.
     
  14. Clownacy

    Clownacy

    Tech Member
    901
    193
    43
    So, turns out the Extra Life system really doesn't like FM6. We know about this bug (and fix), right? Well, turns out there's a second half.

    Ever get a 1UP in an S1 special stage? Or, at least, whenever an FM6-using song is playing? FM6 doesn't fade back in. The fix? Make Resume_NoDAC enable FM6. You see, MJ's code checks for if DAC is playing, and if it isn't, it branches to an rts. It's safe to assume that if the DAC isn't playing, then FM6 must be.

    So, taking a little code from the header reader, specifically the part that handles whether to enable FM6 or DAC (above PBGM_SilenceFM6), and adding it to MJ's code should fix it. Here's my version:

    Code (ASM):
    1. FadeIn_FadedDone:   ; Modified version of MJ's original DAC fade-in fix
    2.     bclr    #2,v_dac_playback_control(a6)   ; Clear SFX overriding bit
    3.     bclr    #f_fadein_flag,misc_flags(a6)   ; Stop fadein   ; Clownacy | Changed to use a bit instead of a byte
    4.     tst.b   v_dac_playback_control(a6)  ; is the DAC channel running?
    5.     bpl.s   FadeIn_FM6          ; if not, branch
    6. ; FadeIn_DAC:
    7.     move.b  #$B6,d0     ; AMS/FMS/panning of FM6
    8.     move.b  v_dac_amsfmspan(a6),d1 ; MJ: load DAC channel's L/R/AMS/FMS value
    9.     bra.w   WriteFMII   ; MJ: write to FM 6
    10.  
    11. FadeIn_FM6:
    12.     moveq   #$2B,d0         ; DAC enable/disable register
    13.     moveq   #0,d1           ; Disable DAC
    14.     bra.w   WriteFMI
    15. ; End of function DoFadeIn
    I'd added the rest of the DAC initialisation/FM6 shut up-er just in case, but you get the idea.

    Next up, cfFadeToPrevious. You might know this in SMPS2ASM lingo as smpsFade. What if you wanted an FM6 extra life jingle? This flag will make you regret it. You see, the flag is designed for use on DAC tracks only. This is evident through the stack meddling, which lines up with UpdateDAC only, and not the FM/PSG equivalent. The problem is that you need to use the flag on a DAC track that you likely don't have. Fixing this is simple: Add a check for f_updating_dac, and adjust the stack pointer accordingly. Here's my version:

    At the end of cfFadeInToPrevious, near cfFadePrev_NextPSG, remove the addq.w #8,sp. Then, at the beginning of cfFadeInToPrevious, add this:

    Code (ASM):
    1.     addq.w  #8,sp               ; Tamper return value so we don't return to caller?
    2.     btst    #f_updating_dac,misc_flags(a6)  ; Clownacy | Is this running on the DAC channel
    3.     bne.s   .dactrack           ; If so, branch
    4.     addq.w  #4,sp               ; Tamper return value so we don't return to caller ; Clownacy | FM/PSG requires three addresses be stripped off
    5. .dactrack:
     
  15. RetroKoH

    RetroKoH

    Member
    1,661
    17
    18
    Project Sonic 8x16
    So forgive my ignorance... is this something I could apply to my non-Clone Driver S1? Or is it something that requires your driver, or a similar one to it as a pre-requisite?
     
  16. Clownacy

    Clownacy

    Tech Member
    901
    193
    43
    No, I get why you'd be confused. I was so preoccupied with confirming the fix that I didn't appropriate it for other versions of the driver. Yes, it's something you can apply to the stock S1 driver. The labels will just be different.
     
  17. Clownacy

    Clownacy

    Tech Member
    901
    193
    43
    Anyone who followed the earlier post, please undo that. I've found a better (read: real) fix:

    For those who've followed the guide before, remove (cut) the added 3 instructions. They're in the wrong place. Their current location means that FM6 will only resume AFTER the song has fully faded back in. That's bad, we want it restoring with the rest of the channels!

    Go to cfFadeInToPrevious, and after this line:
    Code (ASM):
    1.     movea.l a3,a5
    Add your three additional lines, along with a check, giving you this:
    Code (ASM):
    1.     movea.l a3,a5
    2.     tst.b   v_dac_playback_control(a6)  ; is the DAC channel running?
    3.     bmi.s   .DAC                ; if it is, branch
    4.     moveq   #$2B,d0             ; DAC enable/disable register
    5.     moveq   #0,d1               ; Disable DAC
    6.     bsr.w   WriteFMI
    7. .DAC
    8.     bset    #f_fadein_flag,misc_flags(a6)   ; Trigger fade-in   ; Clownacy | Changed to use a bit instead of a byte
    9.     move.b  #$28,v_fadein_counter(a6)   ; Fade-in delay
    10.     clr.b   f_1up_playing(a6)
    11.     addq.w  #8,sp               ; Tamper return value so we don't return to caller
    12.     rts
    And, yes, you guys that followed the guide earlier can move the addq.w #8 from the top to the bottom of the code. I don't know why I moved it in the first place.
     
  18. Clownacy

    Clownacy

    Tech Member
    901
    193
    43
    So, who remembers this thing? Looking at it, it needed all the cycles it could get, but not all chances were taken, so the code is pretty unoptimised because of it.

    Here's the old version currently in the Clone Driver v2 with cycles-used added:

    Code (ASM):
    1. PlaySega:
    2.     stopZ80
    3.     lea (SegaPCM).l,a2          ; 12(3/0)
    4.     move.l  #(SegaPCM_End-SegaPCM),d3   ; 12(3/0)
    5.     move.b  #$2A,(ym2612_a0).l      ; 20(4/1)
    6. .loop:   
    7.     move.b  (a2)+,(ym2612_d0).l     ; 20(4/1)
    8.     moveq   #$13,d0             ; 4(1/0)
    9. .idle:
    10.     dbf d0,.idle            ; 10(2/0) (loop), 14(3/0) (not looped)
    11.     subq.l  #1,d3               ; 8(1/0)
    12.     beq.s   .endloop            ; 10(2/0) (taken), 8(1/0) (not taken)
    13.     lea (Ctrl_1).w,a0           ; 8(2/0)
    14.     lea (HW_Port_1_Data).l,a1       ; 12(3/0)
    15.     jsr (Joypad_Read).w         ; 18(2/2)
    16.     btst    #7,(Ctrl_1).w           ; 4(1/0) + 8(2/0)/8(2/0) + 8(2/0) (?)
    17.     beq.s   .loop               ; 10(2/0) (taken), 8(1/0) (not taken)
    18.     startZ80
    19. .endloop:
    20.     addq.w  #4,sp
    21.     rts
    And here's an optimised version I cooked up.

    Code (ASM):
    1. PlaySega:
    2.     stopZ80
    3.     lea (SegaPCM).l,a2          ; 12(3/0)
    4.     lea (ym2612_d0).l,a3        ; 12(3/0)
    5.     lea (Ctrl_1).w,a4           ; 8(2/0)
    6.     lea (HW_Port_1_Data).l,a5       ; 12(3/0)
    7.     move.l  #(SegaPCM_End-SegaPCM)-1,d3 ; 12(3/0)
    8.     move.b  #$2A,(ym2612_a0).l      ; 20(4/1)
    9. .loop:   
    10.     move.b  (a2)+,(a3)          ; 12(2/1)
    11.     moveq   #$18,d0             ; 4(1/0)
    12. .idle:
    13.     dbf d0,.idle            ; 10(2/0) (loop), 14(3/0) (not looped)
    14.     movea.l a4,a0               ; 4(1/0)
    15.     movea.l a5,a1               ; 4(1/0)
    16.     jsr (Joypad_Read).w         ; 18(2/2)
    17.     btst    #7,(a4)             ; 4(1/0) + 4(1/0)/8(2/0) + 4(1/0) (?)
    18.     bne.s   .endloop            ; 10(2/0) (taken), 8(1/0) (not taken)
    19.     dbf d3,.loop            ; 10(2/0) (loop), 14(3/0) (not looped)
    20. .endloop:
    21.     startZ80
    22.     addq.w  #4,sp
    23.     rts
    Joypad_Read can be tweaked a little too. Replace the 'move.b #0' with a 'clr.b', and the 'lsl.b #2,d0' with a pair of 'add.b d0,d0's.
     
  19. MarkeyJester

    MarkeyJester

    A D V A N C E Resident Jester
    2,101
    230
    43
    Japan
    Ahh, optimising the old fix routines, very nice! I'm glad someone's actually taking the time to do this...

    A few things to note though, are;

    Code (ASM):
    1.         move.l  #(SegaPCM_End-SegaPCM)-1,d3
    This could be made into a word instead, since the sample is small enough.

    Code (ASM):
    1.     move.b  #$2A,(ym2612_a0).l
    2. .loop:   
    3.     move.b  (a2)+,(a3)
    You may need a delay between these two instructions as the YM2612 might not be quick enough on hardware (Not to say one missed byte will make a noticeable difference mind), perhaps move one or two of the above instructions down in-between them...

    Code (ASM):
    1.     movea.l a4,a0
    You'd only need to perform a word move since it's sign extended (Though I wouldn't imagine that'd be any quicker, so it could probably be disregarded).

    Code (ASM):
    1.     btst    #7,(a4)
    2.     bne.s   .endloop
    Try using tst with a bmi instead. Since it's only the start button you want checking.
     
  20. flamewing

    flamewing

    Emerald Hunter Tech Member
    1,161
    62
    28
    France
    Sonic Classic Heroes; Sonic 2 Special Stage Editor; Sonic 3&K Heroes (on hold)
    You are right, it isn't any faster: moving between registers always takes the same time because the 68k's internal bus is 32-bits in size. It is only when data enters or leaves the 68k which word vs long makes a difference.