[Newer] Put Sonic 3K's Tempo Algorithm to Sonic 1

Discussion in 'Tutorials' started by Dark Shamil Khan, Apr 26, 2024.

  1. Dark Shamil Khan

    Dark Shamil Khan TASer lol Member

    Joined:
    Nov 7, 2021
    Messages:
    92
    Location:
    Pakistan
    Now, firstly I know what you're thinking. "Didn't Natsumi/Aurora Fields did that tutorial several years ago?" To which my fellow friend, my answer is yes. However, to me that Tutorial was a bit awkward and didn't made much sense. So in this tutorial, I'm going to show you step-by-step on how to port the tempo algorithm to Sonic 1. And explaining what it's doing in the comments. Because no one these days write comments that much.
    Let me just tell you about the Tempo Algorithm in Sonic 1 before the tutorial starts. Sonic 1 (alongside a few other sound drivers) use a very limited and basic tempo algorithm where you can't port some fast paced songs which are relied on the Tempo, to Sonic 1 sound driver. Just port Sonic 3D Blast's Invincibility to Sonic 1 or Megaman Wily Wars music to Sonic 1, you'll get what I mean. Anyhow, it's very limited and you can't really do much besides do it in a different tempo then increase or decrease the tempo how you want. But with Sonic 3K's (alongside other sound drivers which uses the same or similar tempo algorithm), rather than using a time out, instead it uses an accumulator to find when another delay needs to be added. And you end up having a variety of tempo values, and aren't very limited.

    So, open your Sonic 1 main assembly file sonic1.asm for Hivebrain 2005 disassembly. For Github users it's s1.sounddriver.asm. And you have to go to the loc_71B82 (.driverinput for Github). You'll something like this.
    Hivebrain 2005:
    Code:
            lea    ($FFF000).l,a6
            clr.b    $E(a6)
            tst.b    3(a6)        ; is music paused?
            bne.w    loc_71E50    ; if yes, branch
            subq.b    #1,1(a6)
            bne.s    loc_71B9E
            jsr    sub_7260C(pc)
    
    loc_71B9E:
    For Github:
    Code:
            lea    (v_snddriver_ram&$FFFFFF).l,a6
            clr.b    f_voice_selector(a6)
            tst.b    f_pausemusic(a6)        ; is music paused?
            bne.w    PauseMusic            ; if yes, branch
            subq.b    #1,v_main_tempo_timeout(a6)    ; Has main tempo timer expired?
            bne.s    .skipdelay
            jsr    TempoWait(pc)
    ; loc_71B9E:
    .skipdelay:
    Now what you want to do is comment both the subq command the command underneath, being bne.s. As well as the label it's going to.

    Now that both of them are commented out, we can now go to the meat of the tutorial. The tempo section. Now search up sub_7260C (TempoWait for Github). And you'll see something like this:
    Hivebrain 2005:
    Code:
    sub_7260C:
             move.b    2(a6),1(a6)
             lea    $4E(a6),a0
             moveq    #$30,d0
             moveq    #9,d1
    
    loc_7261A:
             addq.b    #1,(a0)
             adda.w    d0,a0
             dbf    d1,loc_7261A
    
             rts  
    ; End of function sub_7260C
    Github:
    Code:
    ; sub_7260C:
    TempoWait:
            move.b    v_main_tempo(a6),v_main_tempo_timeout(a6)    ; Reset main tempo timeout
            lea    v_music_track_ram+TrackDurationTimeout(a6),a0    ; note timeout
            moveq    #TrackSz,d0
            moveq    #((v_music_track_ram_end-v_music_track_ram)/TrackSz)-1,d1        ; 1 DAC + 6 FM + 3 PSG tracks
    ; loc_7261A:
    .tempoloop:
            addq.b    #1,(a0)    ; Delay note by 1 frame
            adda.w    d0,a0    ; Advance to next track
            dbf    d1,.tempoloop
    
            rts  
    ; End of function TempoWait

    Now what you wanna do is comment all of that out or delete it except the label at the top of course. And replace it with this:
    Hivebrain 2005:
    Code:
            tst.b    2(a6)         ; Check to see if song's tempo exists.
            beq.s    loc_7261A    ; If yes, then skip, otherwise branch.
            move.b    2(a6),d0    ; get Tempo Increment
            add.b    d0,1(a6)    ; add to current Tempo Counter
            bhs.s    loc_7261A
            lea    $40(a6),a0        ; Load Music RAM to a0
            moveq    #$30,d0        ; Quickly move Track Size (?)
            moveq    #9,d1        ; 1 DAC + 6 FM + 3 PSG channels
    
    @loop:
            tst.b    (a0)        ; Test to see if music is active.
            beq.s    @delay        ; if that is false. Delay.
            tst.b    (a0)        ; Test to see if music is active.
            bpl.s    @skip        ; if that is true. then skip.
    @delay:      
            addq.b    #1,$E(a0)    ; Delay note by 1 frame
    
    @skip:
            adda.w    d0,a0        ; Advance to next track
            dbf    d1,@loop        ; Loop 10 times!
    
    loc_7261A:
            rts
    Github:
    Code:
            tst.b    v_main_tempo(a6)         ; Check to see if song's tempo exists.
            beq.s    .return    ; If yes, then skip, otherwise branch.
            move.b    v_main_tempo(a6),d0    ; get Tempo Increment
            add.b    d0,v_main_tempo_timeout(a6)    ; add to current Tempo Counter
            bhs.s    .return
            lea    v_music_track_ram(a6),a0        ; Load Music RAM to a0
            moveq    #TrackSz,d0        ; Quickly move Track Size (?)
            moveq    #((v_music_track_ram_end-v_music_track_ram)/TrackSz)-1,d1        ; 1 DAC + 6 FM + 3 PSG channels
    
    .loop:
            tst.b    TrackPlaybackControl(a0)        ; Test to see if music is active.
            beq.s    .delay        ; if that is false. Delay.
            tst.b    TrackPlaybackControl(a0)        ; Test to see if music is active.
            bpl.s    .skip        ; if that is true. then skip.
    .delay:      
            addq.b    #1,TrackDurationTimeout(a0)    ; Delay note by 1 frame
    
    .skip:
            adda.w    d0,a0        ; Advance to next track
            dbf    d1,.loop        ; Loop 10 times!
    
    .return:
            rts

    Now that's ported, you can now finish and save it. However, you will notice that music plays faster or slower than usual. Except the credits jingle, but it might play a bit faster or slower at different songs. But anyhow, now what you are going to do is open your smps tracks in a hex editor (or ASM if using SMPS2ASM). And you need to find these 2 values.
    smps2asm version.PNG
    hex edit.PNG
    You will see that the highlighted values, that if you haven't guessed. is the tempo value. The first number represents the Tempo Divider and the second value represents the Tempo Modulator (or Modulation). Now you have variety of choices to pick a tempo that seems right for the song you have and just change it or modify to your own choice! Keep in mind, if you're using vgm2smps smps or asm files, this won't affect them and will play it normally how they were intially playing but if they do somehow play faster or slower, you know what to do then.
    Oh! One last thing, change the values for the speed shoes tempo in byte_71A94 (that being SpeedUpIndex in Github). And... that's about it I believe. If you have any problems or issues with porting this. Let me know, I'll fix it and edit it give my confirmation.
    Credits:
    Brain: Shoutout to my brain y'all, it finally decided to be get up and work!!
    Valley Bell: The man, the myth, the legend himself. For making SMPS Research pack and the drivers disassembly. Without it, I would have never made these sound driver tutorials.
     
    Last edited: Apr 26, 2024
  2. JGamer2151

    JGamer2151 Well-Known Member/Lurker Member

    Joined:
    Dec 1, 2020
    Messages:
    96
    Now this guide is more along the lines of how S3K, Ristar, and many other SMPS/Sound-Source drivers with "Tempo on Overflow" algorithms actually do it. The previous one by AURORA☆FIELDS was a bit hackish and didn’t modify the tempo subroutine to the S3K equivalent, but this one in particular is exactly how it should have been done in the first place, the way official SMPS/Sound-Source drivers do it. Neat stuff! Congrats on getting this one out there!

    I’ve been using the AURORA☆FIELDS method for years now, but after reading this guide, I have decided that I might try this one out for myself and see how it goes.

    Now if you excuse me, I’m going to replace the old method that I’ve used for years with this new one in my own hacks…

    P.S. As for fixing songs from Tempo Timeout to Overflow, I personally used AURORA☆FIELDS' automated tool to convert songs from Tempo Timeout to Overflow for binary files. This is the exact tool from that old guide I’ve mentioned above. I also used the tempo conversion calculator in the documentation for the AMPS sound driver to give me an approximation of the correct tempo algorithms for songs. These things should work for me IMO.
     
    Last edited: Apr 28, 2024
    Dark Shamil Khan likes this.