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: Spoiler: Old code with the tempo 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: Spoiler: New Code for the tempo 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. Spoiler: smps2asm Spoiler: Binary 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.
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.
*cough* Oh hey! Uhh yeah basically I was going to rename this thread to Put the Overflow Tempo Algorithm to Sonic 1. But some of the newbies wouldn't understand what that means... So.. I decided to keep it like this. A little information on how Overflow Tempo Algorithm works: Basically this tempo works as.. divisions of the 60Hz Clock. And everytime the internal music clock doesn't overflow, it'll update it. So, in theory, a tempo of $80 will update 30 times a second! Anyhow... What I showed there is how Overflow Tempo Algorithm is handled, and some other drivers (I believe Golden Axe II) has Overflow+Timeout Algorithm combined. Albeit it uses a check to see if tempo goes up to 7F, it's timeout and 80-FF is overflow. However, I recently just converted the Sonic 3 and Knuckles' Overflow Tempo Algorithm from Z80 to 68k! And oh boy, it looks much more cleaner than what I have or got! Now, you don't actually have to do anything different here. If you want to replace the one that I have with this, go to sub_7260C, and then replace it with this (don't remove the label btw): Code: move.b 2(a6),d0 ; Get Main Tempo add.b d0,1(a6) ; then add to Tempo Counter bvc.s loc_7261A ; return if it overflows! lea $40(a6),a0 ; Load Music Ram to a0 moveq #$30,d1 ; Get Track size to d1 moveq #9,d0 ; Number of channels in the music track @loop: addi.b #1,$E(a0) ; Delay the note by 1 frame adda.l d1,a0 ; Advance to next track dbra d0,@loop ; Loop it 10 times! loc_7261A: rts Now.. one optimization could be made if you change the addi to addq, and yeah.. I believe that's it. Oh and also, yeah, you can use the Tool by Aurora Fields/Natsumi, if you really want to! But yeah, I hope this helps! Let me know if you find even better one than this! But for now, I'll see you all in a bit!
If someone want the new method with the original tempo. heres a small tutorial. Change these 3 lines Code: move.b 2(a6),d0 ; Get Main Tempo ; add.b d0,1(a6) ; then add to Tempo Counter bvc.s loc_7261A ; return if it overflows! ;code... To this Code: subq.b #1,1(a6) ; Has main tempo timer expired? bne.s loc_7261A ; if yes, return! move.b 2(a6),1(a6) ; Move the song's tempo to timeout tempo. ;code...