SCHG How-to

Expand the Sonic 1 sound index

From Sonic Retro

Revision as of 09:34, 6 November 2021 by Alex Field (talk | contribs) (Added one last fix)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

In Sonic 1, the sound index is limited from $81 to $E4, allowing for $63 possible slots; this is unlike Sonic 2, which allows slots from $81 to $FF, and Sonic 3 & Knuckles, which is $01 to $FF. Naturally, some people would like to extend this range.

Fortunately, this isn't very hard to do; in fact, the prototype does allow for more IDs, so why not apply this to the final? Note that this is designed for the Github disassembly, although Hivebrain users (2005 and 2021) shouldn't have a hard time making it work with their disassembly.

Part 1: $81-$9F

This first part will Firstly, in Constants.asm, change bgm__First to $01.

Secondly, in s1.sounddriver.asm, find this piece of code, and then delete it:

		cmpi.b	#$80,v_sound_id(a6)	; is song queue set for silence (empty)?
		beq.s	@nonewsound		; If yes, branch
		jsr	PlaySoundID(pc)
; loc_71BC8:

Then, at CycleSoundQueue, you should see this batch of code:

		cmpi.b	#$80,v_sound_id(a6)	; Is v_sound_id a $80 (silence/empty)?
		beq.s	@havesound		; If yes, branch
		move.b	d1,v_soundqueue0(a6)	; Put sound into v_soundqueue0
		bra.s	@nextinput
; ===========================================================================
; loc_71F2C:

Delete it too, since it prevents $01-$80 from being played. Just below it, you'll see a return command; delete it and its label, alongside replacing the branch above to PlaySoundID. Finally at PlaySoundID, delete the third and fourth lines.

We're already done, but we might as well perform a bit of optimization; replace PlaySoundID with this:

		moveq	#0,d7
		move.b	v_sound_id(a6),d7
		move.b	#$80,v_sound_id(a6)	; reset	music flag

		; Music
		cmpi.b	#bgm__Last,d7		; Is this music?
		bls.w	Sound_PlayBGM		; Branch if yes
		cmpi.b	#sfx__First,d7		; Is this after music but before sfx?
		blo.w	@locret			; Return if yes

		; SFX
		cmpi.b	#sfx__Last,d7		; Is this sfx?
		bls.w	Sound_PlaySFX		; Branch if yes
		cmpi.b	#spec__First,d7		; Is this after sfx but before special sfx?
		blo.w	@locret			; Return if yes

		; Special SFX
		cmpi.b	#spec__Last,d7		; Is this special sfx?
		bls.w	Sound_PlaySpecial	; Branch if yes
		cmpi.b	#flg__First,d7		; Is this after special sfx but before the commands?
		blo.w	@locret			; Return if yes

		; Sound Commands
		cmpi.b	#flg__Last,d7		; Is this sound commands?
		bls.s	Sound_E0toE4		; Branch if yes

What this does is fully prevent crashes if invalid IDs (i.e. ones that haven't been defined) are played; this also removes the need for this check at LevSel_NoCheat:

		; This is a workaround for a bug; see PlaySoundID for more.
		; Once you've fixed the bugs there, comment these four instructions out.
		cmpi.w	#bgm__Last+1,d0	; is sound $80-$93 being played?
		blo.s	LevSel_PlaySnd	; if yes, branch
		cmpi.w	#sfx__First,d0	; is sound $94-$9F being played?
		blo.s	LevelSelect	; if yes, branch


We'll be coming back to the level select later to expand the sound test range, but for now we'll move on to...

Part 2: $E5-$FF

This one, unlike the previous part, is stupidly simple; change flg__First in Constants.asm to $FB. The game's maximum sound range is already $FF, although this does raise the question of why they didn't do this, considering it would've saved more sound IDs for use.

Part 3: Extending the Level Select

Although the sound ID range has already been extended, the level select's sound test range hasn't, so let's fix that.

In sonic.asm, at LevelSelect, remove the 'addi.w #$80,d0'; then, at LevSel_SndTest, remove these two bits of code:

		bhs.s	LevSel_Right
		moveq	#$4F,d0		; if sound test	moves below 0, set to $4F
		cmpi.w	#$50,d0
		blo.s	LevSel_Refresh2
		moveq	#0,d0		; if sound test	moves above $4F, set to	0

There's another 'addi.w #$80,d0' at LevSel_DrawSnd; delete that as well.

Part 4: Crash Fix

There's one last fix before we leave, and that's to fix crashes when playing a sound with an ID that is above >$3F; at Sound_notA7 and Sound_PlaySpecial, add this before 'move.b (a1)+,d7':

		moveq	#0,d7

The crash is due to its starting ID being zero based by the sound driver, so $DF = $3F, and $E0 = $40; this is multiplied by 4 (since each pointer is long-word in length), so $3F becomes $FC, and $40 becomes... $100, which is beyond the sound index range, so the line below the one we just inserted blanks the register. This is actually how Ristar handles the fix.

Part 5: Sound Priorities

You might notice that certain sounds have higher priorities than they did originally; this is because Sonic 1 (and, by extension, most SMPS sound drivers) have a 'sound priority' system that determines which sounds should be played over others, and since we have extended the sound index, it is now reading garbage data.

To fix this, replace SoundPriorities with this:

		dc.b     $90,$90,$90,$90,$90,$90,$90,$90,$90,$90,$90,$90,$90,$90,$90	; $01
		dc.b $90,$90,$90,$90,$90,$90,$90,$90,$90,$90,$90,$90,$90,$90,$90,$90	; $10
		dc.b $90,$90,$90,$90,$90,$90,$90,$90,$90,$90,$90,$90,$90,$90,$90,$90	; $20
		dc.b $90,$90,$90,$90,$90,$90,$90,$90,$90,$90,$90,$90,$90,$90,$90,$90	; $30
		dc.b $90,$90,$90,$90,$90,$90,$90,$90,$90,$90,$90,$90,$90,$90,$90,$90	; $40
		dc.b $90,$90,$90,$90,$90,$90,$90,$90,$90,$90,$90,$90,$90,$90,$90,$90	; $50
		dc.b $90,$90,$90,$90,$90,$90,$90,$90,$90,$90,$90,$90,$90,$90,$90,$90	; $60
		dc.b $90,$90,$90,$90,$90,$90,$90,$90,$90,$90,$90,$90,$90,$90,$90,$90	; $70
		dc.b $90,$90,$90,$90,$90,$90,$90,$90,$90,$90,$90,$90,$90,$90,$90,$90	; $80
		dc.b $90,$90,$90,$90,$90,$90,$90,$90,$90,$90,$90,$90,$90,$90,$90,$90	; $90
		dc.b $80,$70,$70,$70,$70,$70,$70,$70,$70,$70,$68,$70,$70,$70,$60,$70	; $A0
		dc.b $70,$60,$70,$60,$70,$70,$70,$70,$70,$70,$70,$70,$70,$70,$70,$7F	; $B0
		dc.b $60,$70,$70,$70,$70,$70,$70,$70,$70,$70,$70,$70,$70,$70,$70,$70	; $C0
		dc.b $80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80	; $D0
		dc.b $90,$90,$90,$90,$90,$90,$90,$90,$90,$90,$90,$90,$90,$90,$90,$90	; $E0
		dc.b $90,$90,$90,$90,$90,$90,$90,$90,$90,$90,$90,$90,$90,$90,$90	; $F0

This properly expands the index to include all $FF entries.

SCHG How-To Guide: Sonic the Hedgehog (16-bit)
Fixing Bugs
Fix Demo Playback | Fix a Race Condition with Pattern Load Cues | Fix the SEGA Sound | Display the Press Start Button Text | Fix the Level Select Menu | Fix the Hidden Points Bug | Fix Accidental Deletion of Scattered Rings | Fix Ring Timers | Fix the Walk-Jump Bug | Correct Drowning Bugs | Fix the Death Boundary Bug | Fix the Camera Follow Bug | Fix Song Restoration Bugs | Fix the HUD Blinking | Fix the Level Select Graphics Bug | Fix a remember sprite related bug
Changing Design Choices
Change Spike Behavior | Collide with Water After Being Hurt | Fix Special Stage Jumping Physics | Improve the Fade In\Fade Out Progression Routines | Fix Scattered Rings' Underwater Physics | Remove the Speed Cap | Port the REV01 Background Effects | Port Sonic 2's Level Art Loader | Retain Rings Between Acts | Add Sonic 2 (Simon Wai Prototype) Level Select | Improve ObjectMove Subroutines | Port Sonic 2 Level Select
Adding Features
Add Spin Dash ( Part 1 / Part 2 / Part 3 / Part 4 ) | Add Eggman Monitor | Add Super Sonic | Add the Air Roll
Sound Features
Expand the Sound Index | Play Different Songs Per Act | Port Sonic 2 Final Sound Driver | Port Sonic 3's Sound Driver | Port Flamewing's Sonic 3 & Knuckles Sound Driver | Change The SEGA Sound
Extending the Game
Load Chunks From ROM | Add Extra Characters | Make an Alternative Title Screen | Use Dynamic Tilesets | Make GHZ Load Alternate Art | Add a New Zone | Set Up the Goggle Monitor | Add New Moves | Add a Dynamic Collision System | Dynamic Special Stage Walls System | Extend Sprite Mappings and Art Limit | Enigma Credits | Use Dynamic Palettes
Convert the Hivebrain 2005 Disassembly to ASM68K
Split Disassembly Guides
Set Up a Split Disassembly | Basic Level Editing | Basic Art Editing | Basic ASM Editing (Spin Dash)