Dual PCM

Discussion in 'Utilities' started by MarkeyJester, Nov 27, 2016.

  1. MarkeyJester

    MarkeyJester !%#@ Member

    Joined:
    Jun 27, 2009
    Messages:
    2,660
    IF YOU WANT TO GET THE MOST OUT OF THE DRIVER I AM ABOUT TO RELEASE HERE, THEN PLEASE READ THIS ENTIRE POST BEFORE USING/RESPONDING. ANYONE WHO RESPONDS BECAUSE THEY DIDN'T READ, I SHALL NOT RESPOND TO.

    [​IMG]

    What is it?

    Dual PCM is a Z80 sound driver for the SEGA Mega Drive, it can play any two PCM samples, of any size, at any single time, through the DAC channel. It comes complete with Jester Stream Technology™ allowing it to play the samples at the least damaging quality possible.

    Here is a test ROM of Sonic 1, with Dual PCM, Download.

    This one has a few edits to the original songs, Green Hill Zone has a set of piano chords during the chorus, as does Labyrinth Zone, Scrap Brain Zone has it's Timpani drums seperated onto the second channel, and Spring Yard Zone and Invincible have a PCM bass guitar now. This is just an example of what you can do with this driver.

    Requirements:

    Dual PCM simply requires the 68k (Main CPU) to give it the sample information in order for it to play the sample(s), Dual PCM also requires the 68k to tell it when it's about to request VDP DMA transfers, and when it's finished.

    If you intend on playing FM/PSG sounds, this MUST be handled by the 68k, so if you have a sound driver that plays back tracker data (for example SMPS), then it must be a 68k variant, Dual PCM operates on its own and requires all of the Z80's resources. It is a puppet, and the 68k is the puppeteer.

    Installation

    Please use this as a "guide" and nothing more, it doesn't have to be used with 68k SMPS, it can be used with any 68k code that can operate it properly.

    This guide below will simply assume you're using Sonic 1 and its 68k SMPS variant, I'll be using the 2005 Hivebrain disassembly (known as "Sonic 1 (Split and Text by Hivebrain) (ASM68K)" on this page), nothing against other disassembly variants, I just know this one best.

    You must handle the splitting and normal setup of the disassembly yourself, however, I will place a download link to a disassembly of the changes below made already, for your conveniece.

    Step 01 - Replacing the Z80 driver

    Sonic 1 has a Z80 DPCM playback driver, we must first rip this out, and then replace it with the new driver.

    >> 1. Inside the "sound" folder, you'll have "z80_1.bin" and "z80_2.bin", you won't need these, so delete them.
    >> 2. Next, open up "sonic1.asm", and find this:
    Code:
    Kos_Z80:	incbin	sound\z80_1.bin
    		dc.w ((SegaPCM&$FF)<<8)+((SegaPCM&$FF00)>>8)
    		dc.b $21
    		dc.w (((EndOfRom-SegaPCM)&$FF)<<8)+(((EndOfRom-SegaPCM)&$FF00)>>8)
    		incbin	sound\z80_2.bin
    		even
    Replace it with:
    Code:
    Z80ROM:		incbin	"Dual PCM\Z80.bin"
    Z80ROM_End:	even
    >> 3. Find this:
    Code:
    SoundDriverLoad:			; XREF: GameClrRAM; TitleScreen
    		nop	
    		move.w	#$100,($A11100).l ; stop the Z80
    		move.w	#$100,($A11200).l ; reset the Z80
    		lea	(Kos_Z80).l,a0	; load sound driver
    		lea	($A00000).l,a1
    		bsr.w	KosDec		; decompress
    		move.w	#0,($A11200).l
    		nop	
    		nop	
    		nop	
    		nop	
    		move.w	#$100,($A11200).l ; reset the Z80
    		move.w	#0,($A11100).l	; start	the Z80
    		rts	
    ; End of function SoundDriverLoad
    Replace it with:
    Code:
    SoundDriverLoad:
    		lea	(Z80ROM).l,a0				; load Z80 ROM data
    		lea	($A00000).l,a1				; load Z80 RAM space address
    		move.w	#(Z80ROM_End-Z80ROM)-$01,d1		; set repeat times
    		move.w	#$0100,($A11100).l			; request Z80 stop (ON)
    		move.w	#$0100,($A11200).l			; request Z80 reset (OFF)
    		btst.b	#$00,($A11100).l			; has the Z80 stopped yet?
    		bne.s	*-$08					; if not, branch
    
    SM_LoadZ80:
    		move.b	(a0)+,(a1)+				; dump Z80 data to Z80 space
    		dbf	d1,SM_LoadZ80				; repeat til done
    		lea	(StopSample).l,a0			; load stop/mute sample address
    		lea	($A00000+MuteSample).l,a1		; load Z80 RAM space where the pointer is to be stored
    		move.b	(a0)+,(a1)+				; copy pointer over into Z80
    		move.b	(a0)+,(a1)+				; ''
    		move.b	(a0)+,(a1)+				; ''
    		move.w	#$0000,($A11200).l			; request Z80 reset (ON)
    		moveq	#$7F,d1					; set repeat times
    		dbf	d1,*					; there's no way of checking for reset, so a manual delay is necessary
    		move.w	#$0000,($A11100).l			; request Z80 stop (OFF)
    		move.w	#$0100,($A11200).l			; request Z80 reset (OFF)
    		rts						; return
    >> 4. Make a new folder at the root of your disassembly, and name it "Dual PCM":

    [​IMG]

    >> 5. Download this new Z80 sound driver source code, and place it in the "Dual PCM" folder.

    Step 02 - Replacing the assembly tools

    We need an assembler for the Z80, as well as some tools to help assemble/convert the new driver

    >> 1. Delete "build.bat", "ASM68K.EXE", "fixheadr.exe", and "rompad.exe".

    >> 2. Download this folder of tools and extract it at the root of your disassembly:

    Download (32-Bit)
    Download (64-Bit)

    [​IMG]

    >> 3. Download this new batch file and place it at the root of your disassembly:

    [​IMG]

    Step 03 - Editing the 68k Sound Driver

    The sound driver is still handling the old Z80 driver, as well as only handling one DAC channel, and a few unoptimal things (this one is quite lengthy...)

    >> 1. Find:
    Code:
    sub_71B4C:				; XREF: loc_B10; PalToCRAM
    		move.w	#$100,($A11100).l ; stop the Z80
    		nop	
    		nop	
    		nop	
    
    loc_71B5A:
    		btst	#0,($A11100).l
    		bne.s	loc_71B5A
    
    		btst	#7,($A01FFD).l
    		beq.s	loc_71B82
    		move.w	#0,($A11100).l	; start	the Z80
    		nop	
    		nop	
    		nop	
    		nop	
    		nop	
    		bra.s	sub_71B4C
    ; ===========================================================================
    
    loc_71B82:
    		lea	($FFF000).l,a6
    And replace with:
    Code:
    YM_Access_WaitRead:
    		StartZ80					; EXT: request Z80 stop off (allow it to continue)
    		rept	$10					; EXT: delay for a long enough time to allow the...
    		nop						; EXT: '' ...68k pointer to be saved correctly.
    		endr						; EXT: ''
    
    sub_71B4C:	
    		lea	($FFF000).l,a6
    
    		lea	($A00000+YM_Access).l,a0		; EXT: load access address in Z80
    		move.l	#$A00000,d0				; EXT: prepare Z80 RAM address in d0 (i.e. start of Cue list address)
    		StopZ80						; EXT: request Z80 stop on
    		tst.b	(a0)+					; EXT: is the Z80 accessing the 68k pointer?
    		bne.s	YM_Access_WaitRead			; EXT: if so, branch and wait for it to finish...
    		move.b	(a0)+,d1				; EXT: load lower byte of pointer
    		move.b	(a0)+,d0				; EXT: load upper byte of pointer
    		StartZ80					; EXT: request Z80 stop off
    		lsl.w	#$08,d0					; EXT: shift upper byte up
    		move.b	d1,d0					; EXT: put lower byte with it
    		move.l	d0,$10(a6)				; EXT: store the cue address
    >> 2. Find:
    Code:
    loc_71BC8:
    		lea	$40(a6),a5
    		tst.b	(a5)
    		bpl.s	loc_71BD4
    		jsr	sub_71C4E(pc)
    
    loc_71BD4:
    And replace with:
    Code:
    loc_71BC8:
    		lea	$40-$30(a6),a5			; MJ: making correction for flow below
    		moveq	#2-1,d7				; MJ: set number of PCM channels to run
    		move.b	#$80-1,$08(a6)			; MJ: reset as PCM channel
    
    SD_NextPCM:
    		addq.b	#$01,$08(a6)			; MJ: advance PCM channel ID
    		lea	$30(a5),a5			; MJ: advance to next channel
    		tst.b	(a5)
    		bpl.s	loc_71BD4
    		jsr	sub_71C4E(pc)
    
    loc_71BD4:
    		dbf	d7,SD_NextPCM			; MJ: repeat for number of PCM channels available
    >> 3. Goto "loc_71C44:" and replace this:
    Code:
    		move.w	#0,($A11100).l	; start	the Z80
    With this:
    Code:
    		bra.s	YM_Access_TestWrite			; EXT: jump into the access loop
    
    YM_Access_WaitWrite:
    		StartZ80					; EXT: request Z80 stop off (allow it to continue)
    		rept	$10					; EXT: delay for a long enough time to let the Z80...
    		nop						; EXT: '' ...finish writing the 68k pointer, so it doesn't...
    		endr						; EXT: '' ...clash with 68k's pointer writing.
    
    YM_Access_TestWrite:
    		lea	($A00000+YM_Access).l,a0		; EXT: load access address in Z80
    		lea	$13(a6),a1				; EXT: load the 68k's pointer finish location
    		StopZ80						; EXT: request Z80 stop on
    		tst.b	(a0)+					; EXT: is the Z80 accessing the 68k pointer?
    		bne.s	YM_Access_WaitWrite			; EXT: if so, branch and wait for it to finish...
    		move.b	(a1),(a0)+				; EXT: save lower byte of pointer
    		move.b	-(a1),(a0)				; EXT: save upper byte of pointer
    		StartZ80					; EXT: request Z80 stop off
    >> 4. Goto "sub_71C4E:" and replace this:
    Code:
    sub_71C4E:				; XREF: sub_71B4C
    		subq.b	#1,$E(a5)
    		bne.s	locret_71CAA
    		move.b	#$80,8(a6)
    		movea.l	4(a5),a4
    With this:
    Code:
    sub_71C4E:				; XREF: sub_71B4C
    		subq.b	#1,$E(a5)
    		bne.w	locret_71CAA
    		movea.l	4(a5),a4
    (Note the branch size change)

    >> 5. Find this:
    Code:
    loc_71C88:
    		move.l	a4,4(a5)
    		btst	#2,(a5)
    		bne.s	locret_71CAA
    		moveq	#0,d0
    		move.b	$10(a5),d0
    		cmpi.b	#$80,d0
    		beq.s	locret_71CAA
    		btst	#3,d0
    		bne.s	loc_71CAC
    		move.b	d0,($A01FFF).l
    
    locret_71CAA:
    		rts	
    ; ===========================================================================
    
    loc_71CAC:
    		subi.b	#$88,d0
    		move.b	byte_71CC4(pc,d0.w),d0
    		move.b	d0,($A000EA).l
    		move.b	#$83,($A01FFF).l
    		rts	
    ; End of function sub_71C4E
    
    ; ===========================================================================
    byte_71CC4:	dc.b $12, $15, $1C, $1D, $FF, $FF
    
    ; ||||||||||||||| S U B	R O U T	I N E |||||||||||||||||||||||||||||||||||||||
    
    And replace with:
    Code:
    loc_71C88:
    		move.l	a4,4(a5)
    		btst	#2,(a5)
    		bne.s	locret_71CAA
    		moveq	#0,d0
    		move.b	$10(a5),d0
    		subi.b	#$80,d0					; MJ: minus 80
    		add.w	d0,d0					; MJ: multiply by 4 (long-word size)
    		add.w	d0,d0					; MJ: ''
    		movem.l	a0/a1,-(sp)				; MJ: store register data
    		lea	(SampleList).l,a0			; MJ: load sample list
    		move.l	(a0,d0.w),a0				; MJ: load correct sample z80 pointer address
    
    		cmpi.b	#$80,$08(a6)				; MJ: is this PCM 1?
    		bne.s	WritePCM2				; MJ: if not, branch for PCM 2 writing
    
    	; --- Writing to PCM 1 ---
    
    		StopZ80
    		lea	($A00000+PCM1_Sample).l,a1			; MJ: load PCM 1 slot address
    		move.b	(a0)+,(a1)+					; MJ: set address of sample
    		move.b	(a0)+,(a1)+					; MJ: ''
    		move.b	(a0)+,(a1)+					; MJ: ''
    		move.b	#(CUPCM1_NewSample&$FF),($A00000+CU_Stack).l	; MJ: set routine to run
    		move.b	#(CUPCM1_NewSample>>$08),($A00000+CU_Stack+1).l	; MJ: ''
    		move.b	#%11001001,($A00000+CUPCM1_RET).l		; MJ: change "NOP" to "RET"
    		StartZ80
    
    		movem.l	(sp)+,a0/a1				; MJ: restore register data
    
    locret_71CAA:
    		rts						; MJ: return
    
    	; --- Writing to PCM 2 ---
    
    WritePCM2:
    		StopZ80
    		lea	($A00000+PCM2_Sample).l,a1			; MJ: load PCM 2 slot address
    		move.b	(a0)+,(a1)+					; MJ: ''
    		move.b	(a0)+,(a1)+					; MJ: ''
    		move.b	(a0)+,(a1)+					; MJ: ''
    		move.b	#%00101000,($A00000+CUPCM2_RET).l		; change "JR NZ" to "JR Z"
    		StartZ80
    
    		movem.l	(sp)+,a0/a1				; MJ: restore register data
    		rts						; MJ: return
    
    ; ===========================================================================
    >> 6. Find this:
    Code:
    loc_71E94:				; XREF: loc_71E50
    		clr.b	3(a6)
    		moveq	#$30,d3
    		lea	$40(a6),a5
    		moveq	#6,d4
    
    loc_71EA0:
    		btst	#7,(a5)
    		beq.s	loc_71EB8
    		btst	#2,(a5)
    		bne.s	loc_71EB8
    		move.b	#-$4C,d0
    		move.b	$A(a5),d1
    		jsr	sub_72722(pc)
    
    loc_71EB8:
    		adda.w	d3,a5
    		dbf	d4,loc_71EA0
    
    		lea	$220(a6),a5
    		moveq	#2,d4
    
    loc_71EC4:
    		btst	#7,(a5)
    		beq.s	loc_71EDC
    		btst	#2,(a5)
    		bne.s	loc_71EDC
    		move.b	#-$4C,d0
    		move.b	$A(a5),d1
    		jsr	sub_72722(pc)
    
    loc_71EDC:
    		adda.w	d3,a5
    		dbf	d4,loc_71EC4
    
    		lea	$340(a6),a5
    		btst	#7,(a5)
    		beq.s	loc_71EFE
    		btst	#2,(a5)
    		bne.s	loc_71EFE
    		move.b	#-$4C,d0
    		move.b	$A(a5),d1
    		jsr	sub_72722(pc)
    
    loc_71EFE:
    		bra.w	loc_71C44
    And replace with:
    Code:
    loc_71E94:				; XREF: loc_71E50
    		clr.b	3(a6)
    		moveq	#$30,d3
    		lea	$40(a6),a5
    		moveq	#7,d4					; MJ: number of YM2612 based channels
    
    loc_71EA0:
    		btst	#7,(a5)
    		beq.s	loc_71EB8
    		btst	#2,(a5)
    		bne.s	loc_71EB8
    		move.b	#-$4C,d0
    		move.b	$A(a5),d1
    		jsr	sub_72722(pc)
    
    loc_71EB8:
    		adda.w	d3,a5
    		dbf	d4,loc_71EA0
    
    		lea	$250(a6),a5				; MJ: new SFX location
    		moveq	#2,d4
    
    loc_71EC4:
    		btst	#7,(a5)
    		beq.s	loc_71EDC
    		btst	#2,(a5)
    		bne.s	loc_71EDC
    		move.b	#-$4C,d0
    		move.b	$A(a5),d1
    		jsr	sub_72722(pc)
    
    loc_71EDC:
    		adda.w	d3,a5
    		dbf	d4,loc_71EC4
    
    		lea	$370(a6),a5				; MJ: new SFX location
    		btst	#7,(a5)
    		beq.s	loc_71EFE
    		btst	#2,(a5)
    		bne.s	loc_71EFE
    		move.b	#-$4C,d0
    		move.b	$A(a5),d1
    		jsr	sub_72722(pc)
    
    loc_71EFE:
    		bra.w	loc_71C44
    >> 7. Find this:
    Code:
    ; ===========================================================================
    ; ---------------------------------------------------------------------------
    ; Play "Say-gaa" PCM sound
    ; ---------------------------------------------------------------------------
    
    Sound_E1:				; XREF: Sound_ExIndex
    		move.b	#$88,($A01FFF).l
    		move.w	#0,($A11100).l	; start	the Z80
    		move.w	#$11,d1
    
    loc_71FC0:
    		move.w	#-1,d0
    
    loc_71FC4:
    		nop	
    		dbf	d0,loc_71FC4
    
    		dbf	d1,loc_71FC0
    
    		addq.w	#4,sp
    		rts	
    ; ===========================================================================
    And replace with::
    Code:
    ; ===========================================================================
    ; ---------------------------------------------------------------------------
    ; Play "Say-gaa" PCM sound
    ; ---------------------------------------------------------------------------
    
    Sound_E1:
    		StopZ80						; MJ: request Z80 stop "ON"
    		lea	(SegaPCM).l,a2				; MJ: load sample address
    		lea	($A04000).l,a3				; MJ: load YM2612 port
    		move.b	#$2A,(a3)+				; MJ: set YM2612 address to the PCM data port
    		move.l	#(SegaPCM_End-SegaPCM)-$01,d4		; MJ: prepare size
    		move.w	d4,d3					; MJ: get lower word size
    		swap	d4					; MJ: get upper word size
    
    PlayPCM_Loop:
    		move.b	(a2)+,(a3)				; MJ: save sample data to port
    		moveq	#$2B,d0					; MJ: set delay time
    		dbf	d0,*					; MJ: delay...
    		dbf	d3,PlayPCM_Loop				; MJ: repeat til done
    		dbf	d4,PlayPCM_Loop				; MJ: ''
    		move.b	#$80,(a3)				; MJ: save mute data to port
    		addq.w	#$04,sp					; MJ: skip return address
    		subq.w	#$01,a3					; MJ: move back to address port
    		tst.b	(a3)					; MJ: is the YM2612 busy?
    		bmi.s	*-$02					; MJ: if so, branch and recheck
    		move.b	#$2A,(a3)				; MJ: write address (set it back to DAC port for the Z80)
    		StartZ80					; MJ: request Z80 stop "OFF"
    		rts						; MJ: return
    
    ; ===========================================================================
    >> 8. Find all of this:
    Code:
    ; ===========================================================================
    ; ---------------------------------------------------------------------------
    ; Play music track $81-$9F
    ; ---------------------------------------------------------------------------
    
    Sound_81to9F:				; XREF: Sound_ChkValue
    		cmpi.b	#$88,d7		; is "extra life" music	played?
    		bne.s	loc_72024	; if not, branch
    		tst.b	$27(a6)
    		bne.w	loc_721B6
    		lea	$40(a6),a5
    		moveq	#9,d0
    
    loc_71FE6:
    		bclr	#2,(a5)
    		adda.w	#$30,a5
    		dbf	d0,loc_71FE6
    
    		lea	$220(a6),a5
    		moveq	#5,d0
    
    loc_71FF8:
    		bclr	#7,(a5)
    		adda.w	#$30,a5
    		dbf	d0,loc_71FF8
    		clr.b	0(a6)
    		movea.l	a6,a0
    		lea	$3A0(a6),a1
    		move.w	#$87,d0
    
    loc_72012:
    		move.l	(a0)+,(a1)+
    		dbf	d0,loc_72012
    
    		move.b	#$80,$27(a6)
    		clr.b	0(a6)
    		bra.s	loc_7202C
    ; ===========================================================================
    
    loc_72024:
    		clr.b	$27(a6)
    		clr.b	$26(a6)
    
    loc_7202C:
    		jsr	sub_725CA(pc)
    		movea.l	(off_719A0).l,a4
    		subi.b	#$81,d7
    		move.b	(a4,d7.w),$29(a6)
    		movea.l	(Go_MusicIndex).l,a4
    		lsl.w	#2,d7
    		movea.l	(a4,d7.w),a4
    		moveq	#0,d0
    		move.w	(a4),d0
    		add.l	a4,d0
    		move.l	d0,$18(a6)
    		move.b	5(a4),d0
    		move.b	d0,$28(a6)
    		tst.b	$2A(a6)
    		beq.s	loc_72068
    		move.b	$29(a6),d0
    
    loc_72068:
    		move.b	d0,2(a6)
    		move.b	d0,1(a6)
    		moveq	#0,d1
    		movea.l	a4,a3
    		addq.w	#6,a4
    		moveq	#0,d7
    		move.b	2(a3),d7
    		beq.w	loc_72114
    		subq.b	#1,d7
    		move.b	#-$40,d1
    		move.b	4(a3),d4
    		moveq	#$30,d6
    		move.b	#1,d5
    		lea	$40(a6),a1
    		lea	byte_721BA(pc),a2
    
    loc_72098:
    		bset	#7,(a1)
    		move.b	(a2)+,1(a1)
    		move.b	d4,2(a1)
    		move.b	d6,$D(a1)
    		move.b	d1,$A(a1)
    		move.b	d5,$E(a1)
    		moveq	#0,d0
    		move.w	(a4)+,d0
    		add.l	a3,d0
    		move.l	d0,4(a1)
    		move.w	(a4)+,8(a1)
    		adda.w	d6,a1
    		dbf	d7,loc_72098
    		cmpi.b	#7,2(a3)
    		bne.s	loc_720D8
    		moveq	#$2B,d0
    		moveq	#0,d1
    		jsr	sub_7272E(pc)
    		bra.w	loc_72114
    ; ===========================================================================
    
    loc_720D8:
    		moveq	#$28,d0
    		moveq	#6,d1
    		jsr	sub_7272E(pc)
    		move.b	#$42,d0
    		moveq	#$7F,d1
    		jsr	sub_72764(pc)
    		move.b	#$4A,d0
    		moveq	#$7F,d1
    		jsr	sub_72764(pc)
    		move.b	#$46,d0
    		moveq	#$7F,d1
    		jsr	sub_72764(pc)
    		move.b	#$4E,d0
    		moveq	#$7F,d1
    		jsr	sub_72764(pc)
    		move.b	#-$4A,d0
    		move.b	#-$40,d1
    		jsr	sub_72764(pc)
    
    loc_72114:
    		moveq	#0,d7
    		move.b	3(a3),d7
    		beq.s	loc_72154
    		subq.b	#1,d7
    		lea	$190(a6),a1
    		lea	byte_721C2(pc),a2
    
    loc_72126:
    		bset	#7,(a1)
    		move.b	(a2)+,1(a1)
    		move.b	d4,2(a1)
    		move.b	d6,$D(a1)
    		move.b	d5,$E(a1)
    		moveq	#0,d0
    		move.w	(a4)+,d0
    		add.l	a3,d0
    		move.l	d0,4(a1)
    		move.w	(a4)+,8(a1)
    		move.b	(a4)+,d0
    		move.b	(a4)+,$B(a1)
    		adda.w	d6,a1
    		dbf	d7,loc_72126
    
    loc_72154:
    		lea	$220(a6),a1
    		moveq	#5,d7
    
    loc_7215A:
    		tst.b	(a1)
    		bpl.w	loc_7217C
    		moveq	#0,d0
    		move.b	1(a1),d0
    		bmi.s	loc_7216E
    		subq.b	#2,d0
    		lsl.b	#2,d0
    		bra.s	loc_72170
    ; ===========================================================================
    
    loc_7216E:
    		lsr.b	#3,d0
    
    loc_72170:
    		lea	dword_722CC(pc),a0
    		movea.l	(a0,d0.w),a0
    		bset	#2,(a0)
    
    loc_7217C:
    		adda.w	d6,a1
    		dbf	d7,loc_7215A
    
    		tst.w	$340(a6)
    		bpl.s	loc_7218E
    		bset	#2,$100(a6)
    
    loc_7218E:
    		tst.w	$370(a6)
    		bpl.s	loc_7219A
    		bset	#2,$1F0(a6)
    
    loc_7219A:
    		lea	$70(a6),a5
    		moveq	#5,d4
    
    loc_721A0:
    		jsr	sub_726FE(pc)
    		adda.w	d6,a5
    		dbf	d4,loc_721A0
    		moveq	#2,d4
    
    loc_721AC:
    		jsr	sub_729A0(pc)
    		adda.w	d6,a5
    		dbf	d4,loc_721AC
    
    loc_721B6:
    		addq.w	#4,sp
    		rts	
    ; ===========================================================================
    byte_721BA:	dc.b 6,	0, 1, 2, 4, 5, 6, 0
    		even
    byte_721C2:	dc.b $80, $A0, $C0, 0
    		even
    ; ===========================================================================
    ; ---------------------------------------------------------------------------
    ; Play normal sound effect
    ; ---------------------------------------------------------------------------
    
    Sound_A0toCF:				; XREF: Sound_ChkValue
    		tst.b	$27(a6)
    		bne.w	loc_722C6
    		tst.b	4(a6)
    		bne.w	loc_722C6
    		tst.b	$24(a6)
    		bne.w	loc_722C6
    		cmpi.b	#$B5,d7		; is ring sound	effect played?
    		bne.s	Sound_notB5	; if not, branch
    		tst.b	$2B(a6)
    		bne.s	loc_721EE
    		move.b	#$CE,d7		; play ring sound in left speaker
    
    loc_721EE:
    		bchg	#0,$2B(a6)	; change speaker
    
    Sound_notB5:
    		cmpi.b	#$A7,d7		; is "pushing" sound played?
    		bne.s	Sound_notA7	; if not, branch
    		tst.b	$2C(a6)
    		bne.w	locret_722C4
    		move.b	#$80,$2C(a6)
    
    Sound_notA7:
    		movea.l	(Go_SoundIndex).l,a0
    		subi.b	#$A0,d7
    		lsl.w	#2,d7
    		movea.l	(a0,d7.w),a3
    		movea.l	a3,a1
    		moveq	#0,d1
    		move.w	(a1)+,d1
    		add.l	a3,d1
    		move.b	(a1)+,d5
    		move.b	(a1)+,d7
    		subq.b	#1,d7
    		moveq	#$30,d6
    
    loc_72228:
    		moveq	#0,d3
    		move.b	1(a1),d3
    		move.b	d3,d4
    		bmi.s	loc_72244
    		subq.w	#2,d3
    		lsl.w	#2,d3
    		lea	dword_722CC(pc),a5
    		movea.l	(a5,d3.w),a5
    		bset	#2,(a5)
    		bra.s	loc_7226E
    ; ===========================================================================
    
    loc_72244:
    		lsr.w	#3,d3
    		lea	dword_722CC(pc),a5
    		movea.l	(a5,d3.w),a5
    		bset	#2,(a5)
    		cmpi.b	#$C0,d4
    		bne.s	loc_7226E
    		move.b	d4,d0
    		ori.b	#$1F,d0
    		move.b	d0,($C00011).l
    		bchg	#5,d0
    		move.b	d0,($C00011).l
    
    loc_7226E:
    		movea.l	dword_722EC(pc,d3.w),a5
    		movea.l	a5,a2
    		moveq	#$B,d0
    
    loc_72276:
    		clr.l	(a2)+
    		dbf	d0,loc_72276
    
    		move.w	(a1)+,(a5)
    		move.b	d5,2(a5)
    		moveq	#0,d0
    		move.w	(a1)+,d0
    		add.l	a3,d0
    		move.l	d0,4(a5)
    		move.w	(a1)+,8(a5)
    		move.b	#1,$E(a5)
    		move.b	d6,$D(a5)
    		tst.b	d4
    		bmi.s	loc_722A8
    		move.b	#$C0,$A(a5)
    		move.l	d1,$20(a5)
    
    loc_722A8:
    		dbf	d7,loc_72228
    
    		tst.b	$250(a6)
    		bpl.s	loc_722B8
    		bset	#2,$340(a6)
    
    loc_722B8:
    		tst.b	$310(a6)
    		bpl.s	locret_722C4
    		bset	#2,$370(a6)
    
    locret_722C4:
    		rts	
    ; ===========================================================================
    
    loc_722C6:
    		clr.b	0(a6)
    		rts	
    ; ===========================================================================
    dword_722CC:	dc.l $FFF0D0
    		dc.l 0
    		dc.l $FFF100
    		dc.l $FFF130
    		dc.l $FFF190
    		dc.l $FFF1C0
    		dc.l $FFF1F0
    		dc.l $FFF1F0
    dword_722EC:	dc.l $FFF220
    		dc.l 0
    		dc.l $FFF250
    		dc.l $FFF280
    		dc.l $FFF2B0
    		dc.l $FFF2E0
    		dc.l $FFF310
    		dc.l $FFF310
    ; ===========================================================================
    ; ---------------------------------------------------------------------------
    ; Play GHZ waterfall sound
    ; ---------------------------------------------------------------------------
    
    Sound_D0toDF:				; XREF: Sound_ChkValue
    		tst.b	$27(a6)
    		bne.w	locret_723C6
    		tst.b	4(a6)
    		bne.w	locret_723C6
    		tst.b	$24(a6)
    		bne.w	locret_723C6
    		movea.l	(Go_SoundD0).l,a0
    		subi.b	#$D0,d7
    		lsl.w	#2,d7
    		movea.l	(a0,d7.w),a3
    		movea.l	a3,a1
    		moveq	#0,d0
    		move.w	(a1)+,d0
    		add.l	a3,d0
    		move.l	d0,$20(a6)
    		move.b	(a1)+,d5
    		move.b	(a1)+,d7
    		subq.b	#1,d7
    		moveq	#$30,d6
    
    loc_72348:
    		move.b	1(a1),d4
    		bmi.s	loc_7235A
    		bset	#2,$100(a6)
    		lea	$340(a6),a5
    		bra.s	loc_72364
    ; ===========================================================================
    
    loc_7235A:
    		bset	#2,$1F0(a6)
    		lea	$370(a6),a5
    
    loc_72364:
    		movea.l	a5,a2
    		moveq	#$B,d0
    
    loc_72368:
    		clr.l	(a2)+
    		dbf	d0,loc_72368
    
    		move.w	(a1)+,(a5)
    		move.b	d5,2(a5)
    		moveq	#0,d0
    		move.w	(a1)+,d0
    		add.l	a3,d0
    		move.l	d0,4(a5)
    		move.w	(a1)+,8(a5)
    		move.b	#1,$E(a5)
    		move.b	d6,$D(a5)
    		tst.b	d4
    		bmi.s	loc_72396
    		move.b	#$C0,$A(a5)
    
    loc_72396:
    		dbf	d7,loc_72348
    
    		tst.b	$250(a6)
    		bpl.s	loc_723A6
    		bset	#2,$340(a6)
    
    loc_723A6:
    		tst.b	$310(a6)
    		bpl.s	locret_723C6
    		bset	#2,$370(a6)
    		ori.b	#$1F,d4
    		move.b	d4,($C00011).l
    		bchg	#5,d4
    		move.b	d4,($C00011).l
    
    locret_723C6:
    		rts	
    ; End of function Sound_ChkValue
    
    ; ===========================================================================
    		dc.l $FFF100
    		dc.l $FFF1F0
    		dc.l $FFF250
    		dc.l $FFF310
    		dc.l $FFF340
    		dc.l $FFF370
    
    ; ||||||||||||||| S U B	R O U T	I N E |||||||||||||||||||||||||||||||||||||||
    
    
    Snd_FadeOut1:				; XREF: Sound_E0
    		clr.b	0(a6)
    		lea	$220(a6),a5
    		moveq	#5,d7
    
    loc_723EA:
    		tst.b	(a5)
    		bpl.w	loc_72472
    		bclr	#7,(a5)
    		moveq	#0,d3
    		move.b	1(a5),d3
    		bmi.s	loc_7243C
    		jsr	sub_726FE(pc)
    		cmpi.b	#4,d3
    		bne.s	loc_72416
    		tst.b	$340(a6)
    		bpl.s	loc_72416
    		lea	$340(a6),a5
    		movea.l	$20(a6),a1
    		bra.s	loc_72428
    ; ===========================================================================
    
    loc_72416:
    		subq.b	#2,d3
    		lsl.b	#2,d3
    		lea	dword_722CC(pc),a0
    		movea.l	a5,a3
    		movea.l	(a0,d3.w),a5
    		movea.l	$18(a6),a1
    
    loc_72428:
    		bclr	#2,(a5)
    		bset	#1,(a5)
    		move.b	$B(a5),d0
    		jsr	sub_72C4E(pc)
    		movea.l	a3,a5
    		bra.s	loc_72472
    ; ===========================================================================
    
    loc_7243C:
    		jsr	sub_729A0(pc)
    		lea	$370(a6),a0
    		cmpi.b	#$E0,d3
    		beq.s	loc_7245A
    		cmpi.b	#$C0,d3
    		beq.s	loc_7245A
    		lsr.b	#3,d3
    		lea	dword_722CC(pc),a0
    		movea.l	(a0,d3.w),a0
    
    loc_7245A:
    		bclr	#2,(a0)
    		bset	#1,(a0)
    		cmpi.b	#$E0,1(a0)
    		bne.s	loc_72472
    		move.b	$1F(a0),($C00011).l
    
    loc_72472:
    		adda.w	#$30,a5
    		dbf	d7,loc_723EA
    
    		rts	
    ; End of function Snd_FadeOut1
    
    
    ; ||||||||||||||| S U B	R O U T	I N E |||||||||||||||||||||||||||||||||||||||
    
    
    Snd_FadeOut2:				; XREF: Sound_E0
    		lea	$340(a6),a5
    		tst.b	(a5)
    		bpl.s	loc_724AE
    		bclr	#7,(a5)
    		btst	#2,(a5)
    		bne.s	loc_724AE
    		jsr	loc_7270A(pc)
    		lea	$100(a6),a5
    		bclr	#2,(a5)
    		bset	#1,(a5)
    		tst.b	(a5)
    		bpl.s	loc_724AE
    		movea.l	$18(a6),a1
    		move.b	$B(a5),d0
    		jsr	sub_72C4E(pc)
    
    loc_724AE:
    		lea	$370(a6),a5
    		tst.b	(a5)
    		bpl.s	locret_724E4
    		bclr	#7,(a5)
    		btst	#2,(a5)
    		bne.s	locret_724E4
    		jsr	loc_729A6(pc)
    		lea	$1F0(a6),a5
    		bclr	#2,(a5)
    		bset	#1,(a5)
    		tst.b	(a5)
    		bpl.s	locret_724E4
    		cmpi.b	#-$20,1(a5)
    		bne.s	locret_724E4
    		move.b	$1F(a5),($C00011).l
    
    locret_724E4:
    		rts	
    ; End of function Snd_FadeOut2
    
    ; ===========================================================================
    ; ---------------------------------------------------------------------------
    ; Fade out music
    ; ---------------------------------------------------------------------------
    
    Sound_E0:				; XREF: Sound_ExIndex
    		jsr	Snd_FadeOut1(pc)
    		jsr	Snd_FadeOut2(pc)
    		move.b	#3,6(a6)
    		move.b	#$28,4(a6)
    		clr.b	$40(a6)
    		clr.b	$2A(a6)
    		rts	
    
    ; ||||||||||||||| S U B	R O U T	I N E |||||||||||||||||||||||||||||||||||||||
    
    
    sub_72504:				; XREF: sub_71B4C
    		move.b	6(a6),d0
    		beq.s	loc_72510
    		subq.b	#1,6(a6)
    		rts	
    ; ===========================================================================
    
    loc_72510:
    		subq.b	#1,4(a6)
    		beq.w	Sound_E4
    		move.b	#3,6(a6)
    		lea	$70(a6),a5
    		moveq	#5,d7
    
    loc_72524:
    		tst.b	(a5)
    		bpl.s	loc_72538
    		addq.b	#1,9(a5)
    		bpl.s	loc_72534
    		bclr	#7,(a5)
    		bra.s	loc_72538
    ; ===========================================================================
    
    loc_72534:
    		jsr	sub_72CB4(pc)
    
    loc_72538:
    		adda.w	#$30,a5
    		dbf	d7,loc_72524
    
    		moveq	#2,d7
    
    loc_72542:
    		tst.b	(a5)
    		bpl.s	loc_72560
    		addq.b	#1,9(a5)
    		cmpi.b	#$10,9(a5)
    		bcs.s	loc_72558
    		bclr	#7,(a5)
    		bra.s	loc_72560
    ; ===========================================================================
    
    loc_72558:
    		move.b	9(a5),d6
    		jsr	sub_7296A(pc)
    
    loc_72560:
    		adda.w	#$30,a5
    		dbf	d7,loc_72542
    
    		rts	
    ; End of function sub_72504
    
    
    ; ||||||||||||||| S U B	R O U T	I N E |||||||||||||||||||||||||||||||||||||||
    
    
    sub_7256A:				; XREF: Sound_E4; sub_725CA
    		moveq	#2,d3
    		moveq	#$28,d0
    
    loc_7256E:
    		move.b	d3,d1
    		jsr	sub_7272E(pc)
    		addq.b	#4,d1
    		jsr	sub_7272E(pc)
    		dbf	d3,loc_7256E
    
    		moveq	#$40,d0
    		moveq	#$7F,d1
    		moveq	#2,d4
    
    loc_72584:
    		moveq	#3,d3
    
    loc_72586:
    		jsr	sub_7272E(pc)
    		jsr	sub_72764(pc)
    		addq.w	#4,d0
    		dbf	d3,loc_72586
    
    		subi.b	#$F,d0
    		dbf	d4,loc_72584
    
    		rts	
    ; End of function sub_7256A
    
    ; ===========================================================================
    ; ---------------------------------------------------------------------------
    ; Stop music
    ; ---------------------------------------------------------------------------
    
    Sound_E4:				; XREF: Sound_ChkValue; Sound_ExIndex; sub_72504
    		moveq	#$2B,d0
    		move.b	#$80,d1
    		jsr	sub_7272E(pc)
    		moveq	#$27,d0
    		moveq	#0,d1
    		jsr	sub_7272E(pc)
    		movea.l	a6,a0
    		move.w	#$E3,d0
    
    loc_725B6:
    		clr.l	(a0)+
    		dbf	d0,loc_725B6
    
    		move.b	#$80,9(a6)	; set music to $80 (silence)
    		jsr	sub_7256A(pc)
    		bra.w	sub_729B6
    
    ; ||||||||||||||| S U B	R O U T	I N E |||||||||||||||||||||||||||||||||||||||
    
    
    sub_725CA:				; XREF: Sound_ChkValue
    		movea.l	a6,a0
    		move.b	0(a6),d1
    		move.b	$27(a6),d2
    		move.b	$2A(a6),d3
    		move.b	$26(a6),d4
    		move.w	$A(a6),d5
    		move.w	#$87,d0
    
    loc_725E4:
    		clr.l	(a0)+
    		dbf	d0,loc_725E4
    
    		move.b	d1,0(a6)
    		move.b	d2,$27(a6)
    		move.b	d3,$2A(a6)
    		move.b	d4,$26(a6)
    		move.w	d5,$A(a6)
    		move.b	#$80,9(a6)
    		jsr	sub_7256A(pc)
    		bra.w	sub_729B6
    ; End of function sub_725CA
    
    
    ; ||||||||||||||| S U B	R O U T	I N E |||||||||||||||||||||||||||||||||||||||
    
    
    sub_7260C:				; XREF: sub_71B4C
    		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
    
    ; ===========================================================================
    ; ---------------------------------------------------------------------------
    ; Speed	up music
    ; ---------------------------------------------------------------------------
    
    Sound_E2:				; XREF: Sound_ExIndex
    		tst.b	$27(a6)
    		bne.s	loc_7263E
    		move.b	$29(a6),2(a6)
    		move.b	$29(a6),1(a6)
    		move.b	#$80,$2A(a6)
    		rts	
    ; ===========================================================================
    
    loc_7263E:
    		move.b	$3C9(a6),$3A2(a6)
    		move.b	$3C9(a6),$3A1(a6)
    		move.b	#$80,$3CA(a6)
    		rts	
    ; ===========================================================================
    ; ---------------------------------------------------------------------------
    ; Change music back to normal speed
    ; ---------------------------------------------------------------------------
    
    Sound_E3:				; XREF: Sound_ExIndex
    		tst.b	$27(a6)
    		bne.s	loc_7266A
    		move.b	$28(a6),2(a6)
    		move.b	$28(a6),1(a6)
    		clr.b	$2A(a6)
    		rts	
    ; ===========================================================================
    
    loc_7266A:
    		move.b	$3C8(a6),$3A2(a6)
    		move.b	$3C8(a6),$3A1(a6)
    		clr.b	$3CA(a6)
    		rts	
    
    ; ||||||||||||||| S U B	R O U T	I N E |||||||||||||||||||||||||||||||||||||||
    
    
    sub_7267C:				; XREF: sub_71B4C
    		tst.b	$25(a6)
    		beq.s	loc_72688
    		subq.b	#1,$25(a6)
    		rts	
    ; ===========================================================================
    
    loc_72688:
    		tst.b	$26(a6)
    		beq.s	loc_726D6
    		subq.b	#1,$26(a6)
    		move.b	#2,$25(a6)
    		lea	$70(a6),a5
    		moveq	#5,d7
    
    loc_7269E:
    		tst.b	(a5)
    		bpl.s	loc_726AA
    		subq.b	#1,9(a5)
    		jsr	sub_72CB4(pc)
    
    loc_726AA:
    		adda.w	#$30,a5
    		dbf	d7,loc_7269E
    		moveq	#2,d7
    
    loc_726B4:
    		tst.b	(a5)
    		bpl.s	loc_726CC
    		subq.b	#1,9(a5)
    		move.b	9(a5),d6
    		cmpi.b	#$10,d6
    		bcs.s	loc_726C8
    		moveq	#$F,d6
    
    loc_726C8:
    		jsr	sub_7296A(pc)
    
    loc_726CC:
    		adda.w	#$30,a5
    		dbf	d7,loc_726B4
    		rts	
    ; ===========================================================================
    
    loc_726D6:
    		bclr	#2,$40(a6)
    		clr.b	$24(a6)
    		rts	
    ; End of function sub_7267C
    
    ; ===========================================================================
    
    loc_726E2:				; XREF: sub_71CCA
    		btst	#1,(a5)
    		bne.s	locret_726FC
    		btst	#2,(a5)
    		bne.s	locret_726FC
    		moveq	#$28,d0
    		move.b	1(a5),d1
    		ori.b	#-$10,d1
    		bra.w	sub_7272E
    ; ===========================================================================
    
    locret_726FC:
    		rts	
    
    ; ||||||||||||||| S U B	R O U T	I N E |||||||||||||||||||||||||||||||||||||||
    
    
    sub_726FE:				; XREF: sub_71CEC; sub_71D9E; Sound_ChkValue; Snd_FadeOut1
    		btst	#4,(a5)
    		bne.s	locret_72714
    		btst	#2,(a5)
    		bne.s	locret_72714
    
    loc_7270A:				; XREF: Snd_FadeOut2
    		moveq	#$28,d0
    		move.b	1(a5),d1
    		bra.w	sub_7272E
    ; ===========================================================================
    
    locret_72714:
    		rts	
    ; End of function sub_726FE
    
    ; ===========================================================================
    
    loc_72716:				; XREF: sub_72A5A
    		btst	#2,(a5)
    		bne.s	locret_72720
    		bra.w	sub_72722
    ; ===========================================================================
    
    locret_72720:
    		rts	
    And replace it all with:
    Code:
    ; ===========================================================================
    ; ---------------------------------------------------------------------------
    ; Play music track $81-$9F
    ; ---------------------------------------------------------------------------
    
    Sound_81to9F:				; XREF: Sound_ChkValue
    
    
    		StopZ80
    		lea	(StopSample).l,a0				; MJ: load stop sample address
    		lea	($A00000+PCM1_Sample).l,a1			; MJ: load PCM 1 slot address
    		move.b	(a0)+,(a1)+					; MJ: set address of sample
    		move.b	(a0)+,(a1)+					; MJ: ''
    		move.b	(a0)+,(a1)+					; MJ: ''
    		move.b	#(CUPCM1_NewSample&$FF),($A00000+CU_Stack).l	; MJ: set routine to run
    		move.b	#(CUPCM1_NewSample>>$08),($A00000+CU_Stack+1).l	; MJ: ''
    		move.b	#%11001001,($A00000+CUPCM1_RET).l		; MJ: change "NOP" to "RET"
    		lea	(StopSample).l,a0				; MJ: load stop sample address
    		lea	($A00000+PCM2_Sample).l,a1			; MJ: load PCM 2 slot address
    		move.b	(a0)+,(a1)+					; MJ: ''
    		move.b	(a0)+,(a1)+					; MJ: ''
    		move.b	(a0)+,(a1)+					; MJ: ''
    		move.b	#%00101000,($A00000+CUPCM2_RET).l		; MJ: change "JR NZ" to "JR Z"
    		StartZ80
    
    
    
    		cmpi.b	#$88,d7		; is "extra life" music	played?
    		bne.s	loc_72024	; if not, branch
    		tst.b	$27(a6)
    		bne.w	loc_721B6
    		lea	$40(a6),a5
    		moveq	#10,d0					; MJ: number of channels in total
    
    loc_71FE6:
    		bclr	#2,(a5)
    		adda.w	#$30,a5
    		dbf	d0,loc_71FE6
    
    		lea	$250(a6),a5				; MJ: new SFX location
    		moveq	#5,d0
    
    loc_71FF8:
    		bclr	#7,(a5)
    		adda.w	#$30,a5
    		dbf	d0,loc_71FF8
    		clr.b	0(a6)
    		movea.l	a6,a0
    		lea	$3D0(a6),a1				; MJ: new SFX location
    		move.w	#$87,d0
    
    loc_72012:
    		move.l	(a0)+,(a1)+
    		dbf	d0,loc_72012
    
    		move.b	#$80,$27(a6)
    		clr.b	0(a6)
    		bra.s	loc_7202C
    ; ===========================================================================
    
    loc_72024:
    		clr.b	$27(a6)
    		clr.b	$26(a6)
    
    loc_7202C:
    		jsr	sub_725CA(pc)
    		movea.l	(off_719A0).l,a4
    		subi.b	#$81,d7
    		move.b	(a4,d7.w),$29(a6)
    		movea.l	(Go_MusicIndex).l,a4
    		lsl.w	#2,d7
    		movea.l	(a4,d7.w),a4
    		moveq	#0,d0
    		move.w	(a4),d0
    		add.l	a4,d0
    		move.l	d0,$18(a6)
    		move.b	5(a4),d0
    		move.b	d0,$28(a6)
    		tst.b	$2A(a6)
    		beq.s	loc_72068
    		move.b	$29(a6),d0
    
    loc_72068:
    		move.b	d0,2(a6)
    		move.b	d0,1(a6)
    		moveq	#0,d1
    		movea.l	a4,a3
    		addq.w	#6,a4
    		moveq	#0,d7
    		move.b	2(a3),d7
    		beq.w	loc_72114
    		subq.b	#1,d7
    		move.b	#-$40,d1
    		move.b	4(a3),d4
    		moveq	#$30,d6
    		move.b	#1,d5
    		lea	$40(a6),a1
    		lea	byte_721BA(pc),a2
    
    loc_72098:
    		bset	#7,(a1)
    		move.b	(a2)+,1(a1)
    		move.b	d4,2(a1)
    		move.b	d6,$D(a1)
    		move.b	d1,$A(a1)
    		move.b	d5,$E(a1)
    		moveq	#0,d0
    		move.w	d0,$10(a1)				; MJ: clear FM's frequency (ensures no frequency writing)
    		move.w	(a4)+,d0
    		add.l	a3,d0
    		move.l	d0,4(a1)
    		move.w	(a4)+,8(a1)
    		adda.w	d6,a1
    		dbf	d7,loc_72098
    		moveq	#$2B,d0					; MJ: set YM2612 address to DAC/FM6 switch
    		move.b	#%10000000,d1				; MJ: set to turn DAC on
    		cmpi.b	#8,2(a3)				; MJ: changed to 8 (8 = 6FM channels, no DAC)
    		bne.s	loc_720D8
    	;	moveq	#$2B,d0					; MJ: removed...
    		moveq	#0,d1
    		jsr	sub_7272E(pc)
    		bra.w	loc_72114
    ; ===========================================================================
    
    loc_720D8:
    		jsr	sub_7272E(pc)				; MJ: added... (turn DAC on)
    		moveq	#$28,d0
    		moveq	#6,d1
    		jsr	sub_7272E(pc)
    		move.b	#$42,d0
    		moveq	#$7F,d1
    		jsr	sub_72764(pc)
    		move.b	#$4A,d0
    		moveq	#$7F,d1
    		jsr	sub_72764(pc)
    		move.b	#$46,d0
    		moveq	#$7F,d1
    		jsr	sub_72764(pc)
    		move.b	#$4E,d0
    		moveq	#$7F,d1
    		jsr	sub_72764(pc)
    		move.b	#-$4A,d0
    		move.b	#-$40,d1
    		jsr	sub_72764(pc)
    
    loc_72114:
    		moveq	#$02,d5					; EXT: set PSG to delay for 1 extra frame (This is to match the PSG with the FM/DAC which is delayed a frame by the Z80)
    		moveq	#0,d7
    		move.b	3(a3),d7
    		beq.s	loc_72154
    		subq.b	#1,d7
    		lea	$1C0(a6),a1				; MJ: new BGM/SFX location
    		lea	byte_721C2(pc),a2
    
    loc_72126:
    		bset	#7,(a1)
    		move.b	(a2)+,1(a1)
    		move.b	d4,2(a1)
    		move.b	d6,$D(a1)
    		move.b	d5,$E(a1)
    		move.w	#$FFFF,$10(a1)				; MJ: clear PSG's frequency (ensures no frequency writing)
    		move.b	#$01,$12(a1)				; MJ: set key release rate to 1
    		moveq	#0,d0
    		move.w	(a4)+,d0
    		add.l	a3,d0
    		move.l	d0,4(a1)
    		move.w	(a4)+,8(a1)
    		move.b	(a4)+,d0
    		move.b	(a4)+,$B(a1)
    		adda.w	d6,a1
    		dbf	d7,loc_72126
    
    loc_72154:
    		lea	$250(a6),a1				; MJ: new SFX location
    		moveq	#5,d7
    
    loc_7215A:
    		tst.b	(a1)
    		bpl.w	loc_7217C
    		moveq	#0,d0
    		move.b	1(a1),d0
    		bmi.s	loc_7216E
    		subq.b	#2,d0
    		lsl.b	#2,d0
    		bra.s	loc_72170
    ; ===========================================================================
    
    loc_7216E:
    		lsr.b	#3,d0
    
    loc_72170:
    		lea	dword_722CC(pc),a0
    		movea.l	(a0,d0.w),a0
    		bset	#2,(a0)
    
    loc_7217C:
    		adda.w	d6,a1
    		dbf	d7,loc_7215A
    
    		tst.w	$370(a6)				; MJ: new SFX location
    		bpl.s	loc_7218E
    		bset	#2,$130(a6)				; MJ: new BGM location
    
    loc_7218E:
    		tst.w	$3A0(a6)				; MJ: new SFX location
    		bpl.s	loc_7219A
    		bset	#2,$220(a6)				; MJ: new BGM location
    
    
    loc_7219A:
    		lea	$A0(a6),a5				; MJ: new FM location
    		moveq	#5,d4
    
    loc_721A0:
    		jsr	sub_726FE(pc)
    		adda.w	d6,a5
    		dbf	d4,loc_721A0
    		moveq	#2,d4
    
    loc_721AC:
    		jsr	sub_729A0(pc)
    		adda.w	d6,a5
    		dbf	d4,loc_721AC
    
    loc_721B6:
    		addq.w	#4,sp
    		rts	
    ; ===========================================================================
    byte_721BA:	dc.b 6,	6, 0, 1, 2, 4, 5, 6, 0			; MJ: extra 6 (for PCM 2)
    		even
    byte_721C2:	dc.b $80, $A0, $C0, 0
    		even
    ; ===========================================================================
    ; ---------------------------------------------------------------------------
    ; Play normal sound effect
    ; ---------------------------------------------------------------------------
    
    Sound_A0toCF:				; XREF: Sound_ChkValue
    		tst.b	$27(a6)
    		bne.w	loc_722C6
    		tst.b	4(a6)
    		bne.w	loc_722C6
    		tst.b	$24(a6)
    		bne.w	loc_722C6
    		cmpi.b	#$B5,d7		; is ring sound	effect played?
    		bne.s	Sound_notB5	; if not, branch
    		tst.b	$2B(a6)
    		bne.s	loc_721EE
    		move.b	#$CE,d7		; play ring sound in left speaker
    
    loc_721EE:
    		bchg	#0,$2B(a6)	; change speaker
    
    Sound_notB5:
    		cmpi.b	#$A7,d7		; is "pushing" sound played?
    		bne.s	Sound_notA7	; if not, branch
    		tst.b	$2C(a6)
    		bne.w	locret_722C4
    		move.b	#$80,$2C(a6)
    
    Sound_notA7:
    		movea.l	(Go_SoundIndex).l,a0
    		subi.b	#$A0,d7
    		lsl.w	#2,d7
    		movea.l	(a0,d7.w),a3
    		movea.l	a3,a1
    		moveq	#0,d1
    		move.w	(a1)+,d1
    		add.l	a3,d1
    		move.b	(a1)+,d5
    		move.b	(a1)+,d7
    		subq.b	#1,d7
    		moveq	#$30,d6
    
    loc_72228:
    		moveq	#0,d3
    		move.b	1(a1),d3
    		moveq	#$02,d2					; EXT: set PSG to delay for 1 extra frame (This is to match the PSG with the FM/DAC which is delayed a frame by the Z80)
    		move.b	d3,d4
    		bmi.s	loc_72244
    		move.b	#$01,d2					; EXT: set DAC/FM to delay for 0 frames like normal (these have an auto delay of 1 frame in the Z80)
    		subq.w	#2,d3
    		lsl.w	#2,d3
    		lea	dword_722CC(pc),a5
    		movea.l	(a5,d3.w),a5
    		bset	#2,(a5)
    		bra.s	loc_7226E
    ; ===========================================================================
    
    loc_72244:
    		lsr.w	#3,d3
    		lea	dword_722CC(pc),a5
    		movea.l	(a5,d3.w),a5
    		bset	#2,(a5)
    		cmpi.b	#$C0,d4
    		bne.s	loc_7226E
    		move.b	d4,d0
    		ori.b	#$1F,d0
    		move.b	d0,($C00011).l
    		bchg	#5,d0
    		move.b	d0,($C00011).l
    
    loc_7226E:
    		movea.l	dword_722EC(pc,d3.w),a5
    		movea.l	a5,a2
    		moveq	#$B,d0
    
    loc_72276:
    		clr.l	(a2)+
    		dbf	d0,loc_72276
    
    		move.w	(a1)+,(a5)
    		move.b	d5,2(a5)
    		moveq	#0,d0
    		move.w	(a1)+,d0
    		add.l	a3,d0
    		move.l	d0,4(a5)
    		move.w	(a1)+,8(a5)
    		move.b	d2,$E(a5)				; EXT: moving d2 contents (1 for FM/4 for PSG)
    		move.b	d6,$D(a5)
    		tst.b	d4
    		bmi.s	loc_722A8
    		move.b	#$C0,$A(a5)
    		move.l	d1,$20(a5)
    
    loc_722A8:
    		dbf	d7,loc_72228
    
    		tst.b	$280(a6)				; MJ: new SFX location
    		bpl.s	loc_722B8
    		bset	#2,$370(a6)				; MJ: new SFX location
    
    loc_722B8:
    		tst.b	$340(a6)				; MJ: new SFX location
    		bpl.s	locret_722C4
    		bset	#2,$3A0(a6)				; MJ: new SFX location
    
    locret_722C4:
    		rts	
    ; ===========================================================================
    
    loc_722C6:
    		clr.b	0(a6)
    		rts	
    ; ===========================================================================
    dword_722CC:	dc.l $FFF0D0+$30				; MJ: new locations (see all +$30)
    		dc.l 0
    		dc.l $FFF100+$30
    		dc.l $FFF130+$30
    		dc.l $FFF190+$30
    		dc.l $FFF1C0+$30
    		dc.l $FFF1F0+$30
    		dc.l $FFF1F0+$30
    dword_722EC:	dc.l $FFF220+$30
    		dc.l 0
    		dc.l $FFF250+$30
    		dc.l $FFF280+$30
    		dc.l $FFF2B0+$30
    		dc.l $FFF2E0+$30
    		dc.l $FFF310+$30
    		dc.l $FFF310+$30
    ; ===========================================================================
    ; ---------------------------------------------------------------------------
    ; Play GHZ waterfall sound
    ; ---------------------------------------------------------------------------
    
    Sound_D0toDF:				; XREF: Sound_ChkValue
    		tst.b	$27(a6)
    		bne.w	locret_723C6
    		tst.b	4(a6)
    		bne.w	locret_723C6
    		tst.b	$24(a6)
    		bne.w	locret_723C6
    		movea.l	(Go_SoundD0).l,a0
    		subi.b	#$D0,d7
    		lsl.w	#2,d7
    		movea.l	(a0,d7.w),a3
    		movea.l	a3,a1
    		moveq	#0,d0
    		move.w	(a1)+,d0
    		add.l	a3,d0
    		move.l	d0,$20(a6)
    		move.b	(a1)+,d5
    		move.b	(a1)+,d7
    		subq.b	#1,d7
    		moveq	#$30,d6
    
    loc_72348:
    		move.b	1(a1),d4
    		bmi.s	loc_7235A
    		bset	#2,$130(a6)				; MJ: new BGM location
    		lea	$370(a6),a5				; MJ: new SFX location
    		bra.s	loc_72364
    ; ===========================================================================
    
    loc_7235A:
    		bset	#2,$220(a6)				; MJ: new BGM location
    		lea	$3A0(a6),a5				; MJ: new SFX location
    
    loc_72364:
    		movea.l	a5,a2
    		moveq	#$B,d0
    
    loc_72368:
    		clr.l	(a2)+
    		dbf	d0,loc_72368
    
    		move.w	(a1)+,(a5)
    		move.b	d5,2(a5)
    		moveq	#0,d0
    		move.w	(a1)+,d0
    		add.l	a3,d0
    		move.l	d0,4(a5)
    		move.w	(a1)+,8(a5)
    		move.b	#1,$E(a5)
    		move.b	d6,$D(a5)
    		tst.b	d4
    		bmi.s	loc_72396
    		move.b	#$C0,$A(a5)
    
    loc_72396:
    		dbf	d7,loc_72348
    
    		tst.b	$280(a6)				; MJ: new SFX location
    		bpl.s	loc_723A6
    		bset	#2,$370(a6)				; MJ: new SFX location
    
    loc_723A6:
    		tst.b	$340(a6)				; MJ: new SFX location
    		bpl.s	locret_723C6
    		bset	#2,$3A0(a6)				; MJ: new SFX location
    		ori.b	#$1F,d4
    		move.b	d4,($C00011).l
    		bchg	#5,d4
    		move.b	d4,($C00011).l
    
    locret_723C6:
    		rts	
    ; End of function Sound_ChkValue
    
    ; ===========================================================================
    		dc.l $FFF100+$30				; MJ: new channel locations (see +$30)
    		dc.l $FFF1F0+$30
    		dc.l $FFF250+$30
    		dc.l $FFF310+$30
    		dc.l $FFF340+$30
    		dc.l $FFF370+$30
    
    ; ||||||||||||||| S U B	R O U T	I N E |||||||||||||||||||||||||||||||||||||||
    
    
    Snd_FadeOut1:				; XREF: Sound_E0
    		clr.b	0(a6)
    		lea	$250(a6),a5				; MJ: new SFX location
    		moveq	#5,d7
    
    loc_723EA:
    		tst.b	(a5)
    		bpl.w	loc_72472
    		bclr	#7,(a5)
    		moveq	#0,d3
    		move.b	1(a5),d3
    		bmi.s	loc_7243C
    		jsr	sub_726FE(pc)
    		cmpi.b	#4,d3
    		bne.s	loc_72416
    		tst.b	$370(a6)				; MJ: new SFX location
    		bpl.s	loc_72416
    		lea	$370(a6),a5				; MJ: new SFX location
    		movea.l	$20(a6),a1
    		bra.s	loc_72428
    ; ===========================================================================
    
    loc_72416:
    		subq.b	#2,d3
    		lsl.b	#2,d3
    		lea	dword_722CC(pc),a0
    		movea.l	a5,a3
    		movea.l	(a0,d3.w),a5
    		movea.l	$18(a6),a1
    
    loc_72428:
    		bclr	#2,(a5)
    		bset	#1,(a5)
    		move.b	$B(a5),d0
    		jsr	sub_72C4E(pc)
    		movea.l	a3,a5
    		bra.s	loc_72472
    ; ===========================================================================
    
    loc_7243C:
    		jsr	sub_729A0(pc)
    		lea	$3A0(a6),a0				; MJ: new SFX location
    		cmpi.b	#$E0,d3
    		beq.s	loc_7245A
    		cmpi.b	#$C0,d3
    		beq.s	loc_7245A
    		lsr.b	#3,d3
    		lea	dword_722CC(pc),a0
    		movea.l	(a0,d3.w),a0
    
    loc_7245A:
    		bclr	#2,(a0)
    		bset	#1,(a0)
    		cmpi.b	#$E0,1(a0)
    		bne.s	loc_72472
    		move.b	$1F(a0),($C00011).l
    
    loc_72472:
    		adda.w	#$30,a5
    		dbf	d7,loc_723EA
    
    		rts	
    ; End of function Snd_FadeOut1
    
    
    ; ||||||||||||||| S U B	R O U T	I N E |||||||||||||||||||||||||||||||||||||||
    
    
    Snd_FadeOut2:				; XREF: Sound_E0
    		lea	$370(a6),a5				; MJ: new SFX location
    		tst.b	(a5)
    		bpl.s	loc_724AE
    		bclr	#7,(a5)
    		btst	#2,(a5)
    		bne.s	loc_724AE
    		jsr	loc_7270A(pc)
    		lea	$130(a6),a5				; MJ: new BGM location
    		bclr	#2,(a5)
    		bset	#1,(a5)
    		tst.b	(a5)
    		bpl.s	loc_724AE
    		movea.l	$18(a6),a1
    		move.b	$B(a5),d0
    		jsr	sub_72C4E(pc)
    
    loc_724AE:
    		lea	$3A0(a6),a5				; MJ: new SFX location
    		tst.b	(a5)
    		bpl.s	locret_724E4
    		bclr	#7,(a5)
    		btst	#2,(a5)
    		bne.s	locret_724E4
    		jsr	loc_729A6(pc)
    		lea	$220(a6),a5				; MJ: new BGM location
    		bclr	#2,(a5)
    		bset	#1,(a5)
    		tst.b	(a5)
    		bpl.s	locret_724E4
    		cmpi.b	#-$20,1(a5)
    		bne.s	locret_724E4
    		move.b	$1F(a5),($C00011).l
    
    locret_724E4:
    		rts	
    ; End of function Snd_FadeOut2
    
    ; ===========================================================================
    ; ---------------------------------------------------------------------------
    ; Fade out music
    ; ---------------------------------------------------------------------------
    
    Sound_E0:				; XREF: Sound_ExIndex
    		jsr	Snd_FadeOut1(pc)
    		jsr	Snd_FadeOut2(pc)
    		move.b	#3,6(a6)
    		move.b	#$28,4(a6)
    		clr.b	$40(a6)
    		clr.b	$70(a6)					; MJ: stop PCM 2 as well
    		clr.b	$2A(a6)
    		rts	
    
    ; ||||||||||||||| S U B	R O U T	I N E |||||||||||||||||||||||||||||||||||||||
    
    
    sub_72504:				; XREF: sub_71B4C
    		move.b	6(a6),d0
    		beq.s	loc_72510
    		subq.b	#1,6(a6)
    		rts	
    ; ===========================================================================
    
    loc_72510:
    		subq.b	#1,4(a6)
    		beq.w	Sound_E4
    		move.b	#3,6(a6)
    		lea	$A0(a6),a5				; MJ: new FM location
    		moveq	#5,d7
    
    loc_72524:
    		tst.b	(a5)
    		bpl.s	loc_72538
    		addq.b	#1,9(a5)
    		bpl.s	loc_72534
    		bclr	#7,(a5)
    		bra.s	loc_72538
    ; ===========================================================================
    
    loc_72534:
    		jsr	sub_72CB4(pc)
    
    loc_72538:
    		adda.w	#$30,a5
    		dbf	d7,loc_72524
    
    		moveq	#2,d7
    
    loc_72542:
    		tst.b	(a5)
    		bpl.s	loc_72560
    		addq.b	#1,9(a5)
    		cmpi.b	#$10,9(a5)
    		bcs.s	loc_72558
    		bclr	#7,(a5)
    		bra.s	loc_72560
    ; ===========================================================================
    
    loc_72558:
    		move.b	9(a5),d6
    		jsr	sub_7296A(pc)
    
    loc_72560:
    		adda.w	#$30,a5
    		dbf	d7,loc_72542
    
    		rts	
    ; End of function sub_72504
    
    
    ; ||||||||||||||| S U B	R O U T	I N E |||||||||||||||||||||||||||||||||||||||
    
    
    sub_7256A:				; XREF: Sound_E4; sub_725CA
    		moveq	#2,d3
    		moveq	#$28,d0
    
    loc_7256E:
    		move.b	d3,d1
    		jsr	sub_7272E(pc)
    		addq.b	#4,d1
    		jsr	sub_7272E(pc)
    		dbf	d3,loc_7256E
    
    		moveq	#$40,d0
    		moveq	#$7F,d1
    		moveq	#2,d4
    
    loc_72584:
    		moveq	#3,d3
    
    loc_72586:
    		jsr	sub_7272E(pc)
    		jsr	sub_72764(pc)
    		addq.w	#4,d0
    		dbf	d3,loc_72586
    
    		subi.b	#$F,d0
    		dbf	d4,loc_72584
    
    		rts	
    ; End of function sub_7256A
    
    ; ===========================================================================
    ; ---------------------------------------------------------------------------
    ; Stop music
    ; ---------------------------------------------------------------------------
    
    Sound_E4:
    		StopZ80
    		lea	(StopSample).l,a0				; EXT: load stop sample address
    		lea	($A00000+PCM1_Sample).l,a1			; EXT: load PCM 1 slot address
    		move.b	(a0)+,(a1)+					; EXT: set address of sample
    		move.b	(a0)+,(a1)+					; EXT: ''
    		move.b	(a0)+,(a1)+					; EXT: ''
    		move.b	#(CUPCM1_NewSample&$FF),($A00000+CU_Stack).l	; EXT: set routine to run
    		move.b	#(CUPCM1_NewSample>>$08),($A00000+CU_Stack+1).l	; EXT: ''
    		move.b	#%11001001,($A00000+CUPCM1_RET).l		; EXT: change "NOP" to "RET"
    		lea	(StopSample).l,a0				; EXT: load stop sample address
    		lea	($A00000+PCM2_Sample).l,a1			; EXT: load PCM 2 slot address
    		move.b	(a0)+,(a1)+					; EXT: ''
    		move.b	(a0)+,(a1)+					; EXT: ''
    		move.b	(a0)+,(a1)+					; EXT: ''
    		move.b	#%00101000,($A00000+CUPCM2_RET).l		; EXT: change "JR NZ" to "JR Z"
    		StartZ80
    
    		moveq	#$2B,d0
    		move.b	#$80,d1
    		jsr	sub_7272E(pc)
    		moveq	#$27,d0
    		moveq	#0,d1
    		jsr	sub_7272E(pc)
    		movea.l	a6,a0
    		move.l	$10(a6),d6					; EXT: store YM Cue list pointer
    		move.w	#$EF,d0						; MJ: new size of data to clear
    
    loc_725B6:
    		clr.l	(a0)+
    		dbf	d0,loc_725B6
    
    		move.l	d6,$10(a6)					; EXT: restore YM Cue list pointer
    		move.b	#$80,9(a6)	; set music to $80 (silence)
    		jsr	sub_7256A(pc)
    		bra.w	sub_729B6
    
    ; ||||||||||||||| S U B	R O U T	I N E |||||||||||||||||||||||||||||||||||||||
    
    
    sub_725CA:				; XREF: Sound_ChkValue
    		movea.l	a6,a0
    		move.b	0(a6),d1
    		move.b	$27(a6),d2
    		move.b	$2A(a6),d3
    		move.b	$26(a6),d4
    		move.w	$A(a6),d5
    		move.l	$10(a6),d6					; EXT: store YM Cue list pointer
    		move.w	#$93,d0						; MJ: new size
    
    loc_725E4:
    		clr.l	(a0)+
    		dbf	d0,loc_725E4
    
    		move.b	d1,0(a6)
    		move.b	d2,$27(a6)
    		move.b	d3,$2A(a6)
    		move.b	d4,$26(a6)
    		move.w	d5,$A(a6)
    		move.l	d6,$10(a6)					; EXT: restore YM Cue list pointer
    		move.b	#$80,9(a6)
    		jsr	sub_7256A(pc)
    		bra.w	sub_729B6
    ; End of function sub_725CA
    
    
    ; ||||||||||||||| S U B	R O U T	I N E |||||||||||||||||||||||||||||||||||||||
    
    
    sub_7260C:				; XREF: sub_71B4C
    		move.b	2(a6),1(a6)
    		lea	$4E(a6),a0
    		moveq	#$30,d0
    		moveq	#10,d1				; MJ: new number of channels
    
    loc_7261A:
    		addq.b	#1,(a0)
    		adda.w	d0,a0
    		dbf	d1,loc_7261A
    
    		rts	
    ; End of function sub_7260C
    
    ; ===========================================================================
    ; ---------------------------------------------------------------------------
    ; Speed	up music
    ; ---------------------------------------------------------------------------
    
    Sound_E2:				; XREF: Sound_ExIndex
    		tst.b	$27(a6)
    		bne.s	loc_7263E
    		move.b	$29(a6),2(a6)
    		move.b	$29(a6),1(a6)
    		move.b	#$80,$2A(a6)
    		rts	
    ; ===========================================================================
    
    loc_7263E:
    		move.b	$3F9(a6),$3D2(a6)			; MJ: new location
    		move.b	$3F9(a6),$3D1(a6)			; MJ: new location
    		move.b	#$80,$3FA(a6)
    		rts	
    ; ===========================================================================
    ; ---------------------------------------------------------------------------
    ; Change music back to normal speed
    ; ---------------------------------------------------------------------------
    
    Sound_E3:				; XREF: Sound_ExIndex
    		tst.b	$27(a6)
    		bne.s	loc_7266A
    		move.b	$28(a6),2(a6)
    		move.b	$28(a6),1(a6)
    		clr.b	$2A(a6)
    		rts	
    ; ===========================================================================
    
    loc_7266A:
    		move.b	$3F8(a6),$3D2(a6)
    		move.b	$3F8(a6),$3D1(a6)
    		clr.b	$3FA(a6)
    		rts	
    
    ; ||||||||||||||| S U B	R O U T	I N E |||||||||||||||||||||||||||||||||||||||
    
    
    sub_7267C:				; XREF: sub_71B4C
    		tst.b	$25(a6)
    		beq.s	loc_72688
    		subq.b	#1,$25(a6)
    		rts	
    ; ===========================================================================
    
    loc_72688:
    		tst.b	$26(a6)
    		beq.s	loc_726D6
    		subq.b	#1,$26(a6)
    		move.b	#2,$25(a6)
    		lea	$A0(a6),a5				; MJ: new SFX location
    		moveq	#5,d7
    
    loc_7269E:
    		tst.b	(a5)
    		bpl.s	loc_726AA
    		subq.b	#1,9(a5)
    		jsr	sub_72CB4(pc)
    
    loc_726AA:
    		adda.w	#$30,a5
    		dbf	d7,loc_7269E
    		moveq	#2,d7
    
    loc_726B4:
    		tst.b	(a5)
    		bpl.s	loc_726CC
    		subq.b	#1,9(a5)
    		move.b	9(a5),d6
    		cmpi.b	#$10,d6
    		bcs.s	loc_726C8
    		moveq	#$F,d6
    
    loc_726C8:
    		jsr	sub_7296A(pc)
    
    loc_726CC:
    		adda.w	#$30,a5
    		dbf	d7,loc_726B4
    		rts	
    ; ===========================================================================
    
    loc_726D6:
    		bclr	#2,$40(a6)
    		bclr	#2,$70(a6)				; MJ: do PCM 2 as well...
    		clr.b	$24(a6)
    		rts	
    ; End of function sub_7267C
    
    ; ===========================================================================
    
    loc_726E2:				; XREF: sub_71CCA
    		btst	#1,(a5)
    		bne.s	locret_726FC
    		btst	#2,(a5)
    		bne.s	locret_726FC
    		moveq	#$28,d0
    		move.b	1(a5),d1
    		ori.b	#-$10,d1
    		bra.w	sub_7272E
    ; ===========================================================================
    
    locret_726FC:
    		rts	
    
    ; ||||||||||||||| S U B	R O U T	I N E |||||||||||||||||||||||||||||||||||||||
    
    
    sub_726FE:				; XREF: sub_71CEC; sub_71D9E; Sound_ChkValue; Snd_FadeOut1
    		btst	#4,(a5)
    		bne.s	locret_72714
    		btst	#2,(a5)
    		bne.s	locret_72714
    
    loc_7270A:				; XREF: Snd_FadeOut2
    		moveq	#$28,d0
    		move.b	1(a5),d1
    		bra.w	sub_7272E
    ; ===========================================================================
    
    locret_72714:
    		rts	
    ; End of function sub_726FE
    
    ; ===========================================================================
    
    loc_72716:				; XREF: sub_72A5A
    		btst	#2,(a5)
    		bne.s	locret_72720
    		bra.w	sub_72722
    ; ===========================================================================
    
    locret_72720:
    		rts
    >> 9. Next the YM2612 writing subroutine, find this:
    Code:
    sub_72722:				; XREF: sub_71E18; sub_72C4E; sub_72CB4
    		btst	#2,1(a5)
    		bne.s	loc_7275A
    		add.b	1(a5),d0
    ; End of function sub_72722
    
    
    ; ||||||||||||||| S U B	R O U T	I N E |||||||||||||||||||||||||||||||||||||||
    
    
    sub_7272E:				; XREF: loc_71E6A
    		move.b	($A04000).l,d2
    		btst	#7,d2
    		bne.s	sub_7272E
    		move.b	d0,($A04000).l
    		nop	
    		nop	
    		nop	
    
    loc_72746:
    		move.b	($A04000).l,d2
    		btst	#7,d2
    		bne.s	loc_72746
    
    		move.b	d1,($A04001).l
    		rts	
    ; End of function sub_7272E
    
    ; ===========================================================================
    
    loc_7275A:				; XREF: sub_72722
    		move.b	1(a5),d2
    		bclr	#2,d2
    		add.b	d2,d0
    
    ; ||||||||||||||| S U B	R O U T	I N E |||||||||||||||||||||||||||||||||||||||
    
    
    sub_72764:				; XREF: loc_71E6A; Sound_ChkValue; sub_7256A; sub_72764
    		move.b	($A04000).l,d2
    		btst	#7,d2
    		bne.s	sub_72764
    		move.b	d0,($A04002).l
    		nop	
    		nop	
    		nop	
    
    loc_7277C:
    		move.b	($A04000).l,d2
    		btst	#7,d2
    		bne.s	loc_7277C
    
    		move.b	d1,($A04003).l
    		rts	
    ; End of function sub_72764
    And replace it with this newer version:
    Code:
    sub_72722:				; XREF: sub_71E18; sub_72C4E; sub_72CB4
    		btst	#2,1(a5)
    		bne.s	loc_7275A
    		add.b	1(a5),d0
    ; End of function sub_72722
    
    
    ; ||||||||||||||| S U B	R O U T	I N E |||||||||||||||||||||||||||||||||||||||
    
    sub_7272E:
    		movem.l	d2/a0,-(sp)				; EXT: store register data
    		movea.l	$10(a6),a0				; EXT: load Cue pointer
    		addq.w	#$01,a0					; EXT: skip $40
    		move.b	#$00,d2					; EXT: prepare d2 for YM2612 port address ($4000 - $4001)
    		StopZ80						; EXT: request Z80 stop "ON"
    		move.b	d2,(a0)+				; EXT: write YM2612 port address
    		move.b	d1,(a0)+				; EXT: write YM2612 data
    		move.b	d0,(a0)+				; EXT: write YM2612 address
    		StartZ80					; EXT: request Z80 stop "OFF"
    		move.w	a0,d2					; EXT: load Cue pointer
    		andi.w	#$0FFF,d2				; EXT: wrap it
    		ori.w	#$1000,d2				; EXT: ''
    		move.w	d2,$12(a6)				; EXT: update it
    		movem.l	(sp)+,d2/a0				; EXT: restore register data
    		rts						; EXT: return
    
    ; ===========================================================================
    
    loc_7275A:				; XREF: sub_72722
    		move.b	1(a5),d2
    		bclr	#2,d2
    		add.b	d2,d0
    
    ; ||||||||||||||| S U B	R O U T	I N E |||||||||||||||||||||||||||||||||||||||
    
    
    sub_72764:
    		movem.l	d2/a0,-(sp)				; EXT: store register data
    		movea.l	$10(a6),a0				; EXT: load Cue pointer
    		addq.w	#$01,a0					; EXT: skip $40
    		move.b	#$02,d2					; EXT: prepare d2 for YM2612 port address ($4002 - $4003)
    		StopZ80						; EXT: request Z80 stop "ON"
    		move.b	d2,(a0)+				; EXT: write YM2612 port address
    		move.b	d1,(a0)+				; EXT: write YM2612 data
    		move.b	d0,(a0)+				; EXT: write YM2612 address
    		StartZ80					; EXT: request Z80 stop "OFF"
    		move.w	a0,d2					; EXT: load Cue pointer
    		andi.w	#$0FFF,d2				; EXT: wrap it
    		ori.w	#$1000,d2				; EXT: ''
    		move.w	d2,$12(a6)				; EXT: update it
    		movem.l	(sp)+,d2/a0				; EXT: restore register data
    		rts						; EXT: return
    >> 10. Find this:
    Code:
    loc_72B14:				; XREF: loc_72A64
    		movea.l	a6,a0
    		lea	$3A0(a6),a1
    		move.w	#$87,d0
    
    loc_72B1E:
    		move.l	(a1)+,(a0)+
    		dbf	d0,loc_72B1E
    
    		bset	#2,$40(a6)
    		movea.l	a5,a3
    		move.b	#$28,d6
    		sub.b	$26(a6),d6
    		moveq	#5,d7
    		lea	$70(a6),a5
    And replace with:
    Code:
    loc_72B14:				; XREF: loc_72A64
    		movea.l	a6,a0
    		lea	$3D0(a6),a1				; MJ: new SFX location
    		move.w	#$93,d0					; MJ: new size to store
    
    loc_72B1E:
    		move.l	(a1)+,(a0)+
    		dbf	d0,loc_72B1E
    
    		bset	#2,$40(a6)
    		bset	#2,$70(a6)				; MJ: enable PCM 2
    		movea.l	a5,a3
    		move.b	#$28,d6
    		sub.b	$26(a6),d6
    		moveq	#5,d7
    		lea	$A0(a6),a5				; MJ: new FM location
    >> 11. Goto "loc_72B78:" and delete this line:
    Code:
    		move.w	#0,($A11100).l
    >> 12. Find this:
    Code:
    loc_72BD0:				; XREF: loc_72A64
    		lea	$40(a6),a0
    		move.b	(a4)+,d0
    		moveq	#$30,d1
    		moveq	#9,d2
    
    loc_72BDA:
    		move.b	d0,2(a0)
    		adda.w	d1,a0
    		dbf	d2,loc_72BDA
    
    		rts	
    ; ===========================================================================
    
    loc_72BE6:				; XREF: loc_72A64
    		move.b	(a4)+,d0
    		add.b	d0,9(a5)
    		rts	
    ; ===========================================================================
    
    loc_72BEE:				; XREF: loc_72A64
    		clr.b	$2C(a6)
    		rts	
    ; ===========================================================================
    
    loc_72BF4:				; XREF: loc_72A64
    		bclr	#7,(a5)
    		bclr	#4,(a5)
    		jsr	sub_726FE(pc)
    		tst.b	$250(a6)
    		bmi.s	loc_72C22
    		movea.l	a5,a3
    		lea	$100(a6),a5
    		movea.l	$18(a6),a1
    		bclr	#2,(a5)
    		bset	#1,(a5)
    		move.b	$B(a5),d0
    		jsr	sub_72C4E(pc)
    		movea.l	a3,a5
    
    loc_72C22:
    		addq.w	#8,sp
    		rts	
    And replace with:
    Code:
    loc_72BD0:				; XREF: loc_72A64
    		lea	$40(a6),a0
    		move.b	(a4)+,d0
    		moveq	#$30,d1
    		moveq	#10,d2				; MJ: extra channel
    
    loc_72BDA:
    		move.b	d0,2(a0)
    		adda.w	d1,a0
    		dbf	d2,loc_72BDA
    
    		rts	
    ; ===========================================================================
    
    loc_72BE6:				; XREF: loc_72A64
    		move.b	(a4)+,d0
    		add.b	d0,9(a5)
    		rts	
    ; ===========================================================================
    
    loc_72BEE:				; XREF: loc_72A64
    		clr.b	$2C(a6)
    		rts	
    ; ===========================================================================
    
    loc_72BF4:				; XREF: loc_72A64
    		bclr	#7,(a5)
    		bclr	#4,(a5)
    		jsr	sub_726FE(pc)
    		tst.b	$280(a6)				; MJ: new SFX location
    		bmi.s	loc_72C22
    		movea.l	a5,a3
    		lea	$130(a6),a5				; MJ: new BGM location
    		movea.l	$18(a6),a1
    		bclr	#2,(a5)
    		bset	#1,(a5)
    		move.b	$B(a5),d0
    		jsr	sub_72C4E(pc)
    		movea.l	a3,a5
    
    loc_72C22:
    		addq.w	#8,sp
    		rts	
    >> 13. Find this:
    Code:
    loc_72D78:
    		tst.b	$E(a6)
    		bpl.w	loc_72E02
    		clr.b	0(a6)
    		moveq	#0,d0
    		move.b	1(a5),d0
    		bmi.s	loc_72DCC
    		lea	dword_722CC(pc),a0
    		movea.l	a5,a3
    		cmpi.b	#4,d0
    		bne.s	loc_72DA8
    		tst.b	$340(a6)
    		bpl.s	loc_72DA8
    		lea	$340(a6),a5
    		movea.l	$20(a6),a1
    		bra.s	loc_72DB8
    ; ===========================================================================
    
    loc_72DA8:
    		subq.b	#2,d0
    		lsl.b	#2,d0
    		movea.l	(a0,d0.w),a5
    		tst.b	(a5)
    		bpl.s	loc_72DC8
    		movea.l	$18(a6),a1
    
    loc_72DB8:
    		bclr	#2,(a5)
    		bset	#1,(a5)
    		move.b	$B(a5),d0
    		jsr	sub_72C4E(pc)
    
    loc_72DC8:
    		movea.l	a3,a5
    		bra.s	loc_72E02
    ; ===========================================================================
    
    loc_72DCC:
    		lea	$370(a6),a0
    		tst.b	(a0)
    		bpl.s	loc_72DE0
    		cmpi.b	#$E0,d0
    		beq.s	loc_72DEA
    		cmpi.b	#$C0,d0
    		beq.s	loc_72DEA
    
    loc_72DE0:
    		lea	dword_722CC(pc),a0
    		lsr.b	#3,d0
    		movea.l	(a0,d0.w),a0
    
    loc_72DEA:
    		bclr	#2,(a0)
    		bset	#1,(a0)
    		cmpi.b	#$E0,1(a0)
    		bne.s	loc_72E02
    		move.b	$1F(a0),($C00011).l
    
    loc_72E02:
    		addq.w	#8,sp
    		rts	
    ; ===========================================================================
    
    loc_72E06:				; XREF: loc_72A64
    		move.b	#$E0,1(a5)
    		move.b	(a4)+,$1F(a5)
    		btst	#2,(a5)
    		bne.s	locret_72E1E
    		move.b	-1(a4),($C00011).l
    
    locret_72E1E:
    		rts	
    And replace with:
    Code:
    loc_72D78:
    		tst.b	$E(a6)
    		bpl.w	loc_72E02
    		clr.b	0(a6)
    		moveq	#0,d0
    		move.b	1(a5),d0
    		bmi.s	loc_72DCC
    		lea	dword_722CC(pc),a0
    		movea.l	a5,a3
    		cmpi.b	#4,d0
    		bne.s	loc_72DA8
    		tst.b	$370(a6)				; MJ: new SFX location
    		bpl.s	loc_72DA8
    		lea	$370(a6),a5				; MJ: new SFX location
    		movea.l	$20(a6),a1
    		bra.s	loc_72DB8
    ; ===========================================================================
    
    loc_72DA8:
    		subq.b	#2,d0
    		lsl.b	#2,d0
    		movea.l	(a0,d0.w),a5
    		tst.b	(a5)
    		bpl.s	loc_72DC8
    		movea.l	$18(a6),a1
    
    loc_72DB8:
    		bclr	#2,(a5)
    		bset	#1,(a5)
    		move.b	$B(a5),d0
    		jsr	sub_72C4E(pc)
    
    loc_72DC8:
    		movea.l	a3,a5
    		bra.s	loc_72E02
    ; ===========================================================================
    
    loc_72DCC:
    		lea	$3A0(a6),a0				; MJ: new SFX location
    		tst.b	(a0)
    		bpl.s	loc_72DE0
    		cmpi.b	#$E0,d0
    		beq.s	loc_72DEA
    		cmpi.b	#$C0,d0
    		beq.s	loc_72DEA
    
    loc_72DE0:
    		lea	dword_722CC(pc),a0
    		lsr.b	#3,d0
    		movea.l	(a0,d0.w),a0
    
    loc_72DEA:
    		bclr	#2,(a0)
    		bset	#1,(a0)
    		cmpi.b	#$E0,1(a0)
    		bne.s	loc_72E02
    		move.b	$1F(a0),($C00011).l
    
    loc_72E02:
    		addq.w	#4,sp					; MJ: changed to 4 (go back, but not out of sound driver)
    		tst.b	$08(a6)					; MJ: is this a PCM channel?
    		bne.s	FlagF2_NoWaitFrame			; MJ: if so, branch
    		addq.w	#4,sp					; MJ: go back outside the sound driver like normal
    
    FlagF2_NoWaitFrame:
    		rts	
    ; ===========================================================================
    
    loc_72E06:				; XREF: loc_72A64
    		move.b	#$E0,1(a5)
    		move.b	(a4)+,$1F(a5)
    		btst	#2,(a5)
    		bne.s	locret_72E1E 
    		move.b	-1(a4),d0				; MJ: reload F3 setting to d0
    		move.b	d0,($C00011).l				; MJ: save F3 setting (should be EX (PSG 4) related)
    		andi.b	#%00000011,d0				; MJ: get only frequency mode bits
    		cmpi.b	#%00000011,d0				; MJ: has it been set to use PSG 3's frequency?
    		bne.s	locret_72E1E				; MJ: if not, branch
    		move.b	#%11011111,($C00011).l			; MJ: mute PSG 3's volume
    
    locret_72E1E:
    		rts	
    >> 14. Find this:
    Code:
    SegaPCM:	incbin	sound\segapcm.bin
    		even
    And replace with:
    Code:
    SegaPCM:	incbin	sound\segapcm.wav,$3A
    SegaPCM_End:	even
    Step 04 - Some new files

    Some macro/Sample files to be added and included.

    >> 1. Open up "sonic1.asm", and replace:
    Code:
    align macro
    	cnop 0,\1
    	endm
    With this:
    Code:
    		include	"Equz80.asm"
    		include	"Macros.asm"
    >> 2. Download this file, and place at the root of the disassembly:

    [​IMG]

    >> 3. Download this SEGA wav file, and place it in the "sound" folder (and delete the old "segapcm.bin" while you're at it):

    [​IMG]

    >> 4. Inside the "Dual PCM" folder, create a new folder and name it "Samples":

    [​IMG]

    >> 5. Download and extract this into that new "Samples" folder:

    Download (32-bit)
    Download (64-bit)

    (For those who want the source for ConvPCM, download here).

    [​IMG]

    >> 6. Open up "sonic1.asm" and go to the very bottom where you'll find:
    Code:
    ; end of 'ROM'
    EndOfRom:
    
    
    		END
    Above this, place the following:
    Code:
    ; ===========================================================================
    ; ---------------------------------------------------------------------------
    ; Sample 68k PCM list
    ; ---------------------------------------------------------------------------
    
    SampleList:		dc.l	StopSample			; 80 (THIS IS A REST NOTE, DO NOT EDIT...)
    			dc.l	Sonic1Kick			; 81
    			dc.l	Sonic1Snare			; 82
    			dc.l	Sonic1TimpaniLow		; 83
    			dc.l	StopSample			; 84
    			dc.l	StopSample			; 85
    			dc.l	StopSample			; 86
    			dc.l	StopSample			; 87
    			dc.l	Sonic1TimpaniHigh		; 88
    			dc.l	Sonic1TimpaniMid		; 89
    			dc.l	Sonic1TimpaniLow		; 8A
    			dc.l	Sonic1TimpaniLower		; 8B
    
    ; ---------------------------------------------------------------------------
    ; Sample z80 pointers
    ; ---------------------------------------------------------------------------
    
    StopSample:		dcz80	SWF_StopSample
    Sonic1Kick:		dcz80	SWF_S1Kick
    Sonic1Snare:		dcz80	SWF_S1Snare
    Sonic1TimpaniHigh:	dcz80	SWF_S1TimpaniHigh
    Sonic1TimpaniMid:	dcz80	SWF_S1TimpaniMid
    Sonic1TimpaniLow:	dcz80	SWF_S1TimpaniLow
    Sonic1TimpaniLower:	dcz80	SWF_S1TimpaniLower
    
    ; ---------------------------------------------------------------------------
    ; Sample file includes
    ; ---------------------------------------------------------------------------
    			align	$20,$FF
    SWF_StopSample:		dcb.b	$7FFF,$00
    			dc.b	$80
    ; ---------------------------------------------------------------------------
    SWF_S1Kick:		incbin	"Dual PCM\Samples\incswf\Sonic 1 Kick.swf"
    SWF_S1Snare:		incbin	"Dual PCM\Samples\incswf\Sonic 1 Snare.swf"
    SWF_S1TimpaniHigh:	incbin	"Dual PCM\Samples\incswf\Sonic 1 Timpani High.swf"
    SWF_S1TimpaniMid:	incbin	"Dual PCM\Samples\incswf\Sonic 1 Timpani Mid.swf"
    SWF_S1TimpaniLow:	incbin	"Dual PCM\Samples\incswf\Sonic 1 Timpani Low.swf"
    SWF_S1TimpaniLower:	incbin	"Dual PCM\Samples\incswf\Sonic 1 Timpani Lower.swf"
    
    ; ===========================================================================
    Step 05 - Adjustments

    The new driver will make the current SMPS music files incompatible, and we need to make the new samples compatible also.

    >> 1. Drag and drop all of the "music" files from the "sound" folder, onto a program inside the "_Assembly Tools" folder named "AddDAC.exe", like so:

    [​IMG]

    YOU ONLY NEED TO DO THIS ONCE, DO NOT DO IT MORE THAN ONCE.

    This will give all of the music files an extra PCM channel, and point it to an F2 stop flag, this will simply make it compatible for the new driver, and won't actually change the song's result.

    >> 2. Inside the "Dual PCM\Samples" folder, you will need to drag and drop all of the ".wav" files onto that program named "ConvPCM.exe", like so:

    [​IMG]

    Let the program do its thing, and press enter when it's finished, this will create a folder named "incswf", it'll convert the ".wav" files into the correct format and rate, and save the converted files inside "incswf" as ".swf" files, and THOSE are the files that are included into the source, the program will NEVER tamper with the original ".wav" files, so you may keep the original files in their former format/quality without having to worry.

    Step 06 - DMA Stops

    There are a series of Z80 stops when DMA transfers are due to occur, we need to replace those with Z80 DMA requests.

    >> 1. Replace all of this:
    Code:
    loc_BBA:
    		move.w	#1,($FFFFF644).w
    		move.w	#$100,($A11100).l
    
    loc_BC8:
    		btst	#0,($A11100).l
    		bne.s	loc_BC8
    		tst.b	($FFFFF64E).w
    		bne.s	loc_BFE
    		lea	($C00004).l,a5
    		move.l	#$94009340,(a5)
    		move.l	#$96FD9580,(a5)
    		move.w	#$977F,(a5)
    		move.w	#$C000,(a5)
    		move.w	#$80,($FFFFF640).w
    		move.w	($FFFFF640).w,(a5)
    		bra.s	loc_C22
    ; ===========================================================================
    
    loc_BFE:				; XREF: loc_BC8
    		lea	($C00004).l,a5
    		move.l	#$94009340,(a5)
    		move.l	#$96FD9540,(a5)
    		move.w	#$977F,(a5)
    		move.w	#$C000,(a5)
    		move.w	#$80,($FFFFF640).w
    		move.w	($FFFFF640).w,(a5)
    
    loc_C22:				; XREF: loc_BC8
    		move.w	($FFFFF624).w,(a5)
    		move.w	#0,($A11100).l
    		bra.w	loc_B5E
    ; ===========================================================================
    
    loc_C32:				; XREF: off_B6E
    		bsr.w	sub_106E
    
    loc_C36:				; XREF: off_B6E
    		tst.w	($FFFFF614).w
    		beq.w	locret_C42
    		subq.w	#1,($FFFFF614).w
    
    locret_C42:
    		rts	
    ; ===========================================================================
    
    loc_C44:				; XREF: off_B6E
    		bsr.w	sub_106E
    		bsr.w	sub_6886
    		bsr.w	sub_1642
    		tst.w	($FFFFF614).w
    		beq.w	locret_C5C
    		subq.w	#1,($FFFFF614).w
    
    locret_C5C:
    		rts	
    ; ===========================================================================
    
    loc_C5E:				; XREF: off_B6E
    		bsr.w	sub_106E
    		rts	
    ; ===========================================================================
    
    loc_C64:				; XREF: off_B6E
    		cmpi.b	#$10,($FFFFF600).w ; is	game mode = $10	(special stage)	?
    		beq.w	loc_DA6		; if yes, branch
    
    loc_C6E:				; XREF: off_B6E
    		move.w	#$100,($A11100).l ; stop the Z80
    
    loc_C76:
    		btst	#0,($A11100).l	; has Z80 stopped?
    		bne.s	loc_C76		; if not, branch
    		bsr.w	ReadJoypads
    		tst.b	($FFFFF64E).w
    		bne.s	loc_CB0
    		lea	($C00004).l,a5
    		move.l	#$94009340,(a5)
    		move.l	#$96FD9580,(a5)
    		move.w	#$977F,(a5)
    		move.w	#$C000,(a5)
    		move.w	#$80,($FFFFF640).w
    		move.w	($FFFFF640).w,(a5)
    		bra.s	loc_CD4
    ; ===========================================================================
    
    loc_CB0:				; XREF: loc_C76
    		lea	($C00004).l,a5
    		move.l	#$94009340,(a5)
    		move.l	#$96FD9540,(a5)
    		move.w	#$977F,(a5)
    		move.w	#$C000,(a5)
    		move.w	#$80,($FFFFF640).w
    		move.w	($FFFFF640).w,(a5)
    
    loc_CD4:				; XREF: loc_C76
    		move.w	($FFFFF624).w,(a5)
    		lea	($C00004).l,a5
    		move.l	#$940193C0,(a5)
    		move.l	#$96E69500,(a5)
    		move.w	#$977F,(a5)
    		move.w	#$7C00,(a5)
    		move.w	#$83,($FFFFF640).w
    		move.w	($FFFFF640).w,(a5)
    		lea	($C00004).l,a5
    		move.l	#$94019340,(a5)
    		move.l	#$96FC9500,(a5)
    		move.w	#$977F,(a5)
    		move.w	#$7800,(a5)
    		move.w	#$83,($FFFFF640).w
    		move.w	($FFFFF640).w,(a5)
    		tst.b	($FFFFF767).w
    		beq.s	loc_D50
    		lea	($C00004).l,a5
    		move.l	#$94019370,(a5)
    		move.l	#$96E49500,(a5)
    		move.w	#$977F,(a5)
    		move.w	#$7000,(a5)
    		move.w	#$83,($FFFFF640).w
    		move.w	($FFFFF640).w,(a5)
    		move.b	#0,($FFFFF767).w
    
    loc_D50:
    		move.w	#0,($A11100).l
    		movem.l	($FFFFF700).w,d0-d7
    		movem.l	d0-d7,($FFFFFF10).w
    		movem.l	($FFFFF754).w,d0-d1
    		movem.l	d0-d1,($FFFFFF30).w
    		cmpi.b	#$60,($FFFFF625).w
    		bcc.s	Demo_Time
    		move.b	#1,($FFFFF64F).w
    		addq.l	#4,sp
    		bra.w	loc_B64
    
    ; ---------------------------------------------------------------------------
    ; Subroutine to	run a demo for an amount of time
    ; ---------------------------------------------------------------------------
    
    ; ||||||||||||||| S U B	R O U T	I N E |||||||||||||||||||||||||||||||||||||||
    
    
    Demo_Time:				; XREF: loc_D50; PalToCRAM
    		bsr.w	LoadTilesAsYouMove
    		jsr	AniArt_Load
    		jsr	HudUpdate
    		bsr.w	sub_165E
    		tst.w	($FFFFF614).w	; is there time	left on	the demo?
    		beq.w	Demo_TimeEnd	; if not, branch
    		subq.w	#1,($FFFFF614).w ; subtract 1 from time	left
    
    Demo_TimeEnd:
    		rts	
    ; End of function Demo_Time
    
    ; ===========================================================================
    
    loc_DA6:				; XREF: off_B6E
    		move.w	#$100,($A11100).l ; stop the Z80
    
    loc_DAE:
    		btst	#0,($A11100).l	; has Z80 stopped?
    		bne.s	loc_DAE		; if not, branch
    		bsr.w	ReadJoypads
    		lea	($C00004).l,a5
    		move.l	#$94009340,(a5)
    		move.l	#$96FD9580,(a5)
    		move.w	#$977F,(a5)
    		move.w	#$C000,(a5)
    		move.w	#$80,($FFFFF640).w
    		move.w	($FFFFF640).w,(a5)
    		lea	($C00004).l,a5
    		move.l	#$94019340,(a5)
    		move.l	#$96FC9500,(a5)
    		move.w	#$977F,(a5)
    		move.w	#$7800,(a5)
    		move.w	#$83,($FFFFF640).w
    		move.w	($FFFFF640).w,(a5)
    		lea	($C00004).l,a5
    		move.l	#$940193C0,(a5)
    		move.l	#$96E69500,(a5)
    		move.w	#$977F,(a5)
    		move.w	#$7C00,(a5)
    		move.w	#$83,($FFFFF640).w
    		move.w	($FFFFF640).w,(a5)
    		move.w	#0,($A11100).l
    		bsr.w	PalCycle_SS
    		tst.b	($FFFFF767).w
    		beq.s	loc_E64
    		lea	($C00004).l,a5
    		move.l	#$94019370,(a5)
    		move.l	#$96E49500,(a5)
    		move.w	#$977F,(a5)
    		move.w	#$7000,(a5)
    		move.w	#$83,($FFFFF640).w
    		move.w	($FFFFF640).w,(a5)
    		move.b	#0,($FFFFF767).w
    
    loc_E64:
    		tst.w	($FFFFF614).w
    		beq.w	locret_E70
    		subq.w	#1,($FFFFF614).w
    
    locret_E70:
    		rts	
    ; ===========================================================================
    
    loc_E72:				; XREF: off_B6E
    		move.w	#$100,($A11100).l ; stop the Z80
    
    loc_E7A:
    		btst	#0,($A11100).l	; has Z80 stopped?
    		bne.s	loc_E7A		; if not, branch
    		bsr.w	ReadJoypads
    		tst.b	($FFFFF64E).w
    		bne.s	loc_EB4
    		lea	($C00004).l,a5
    		move.l	#$94009340,(a5)
    		move.l	#$96FD9580,(a5)
    		move.w	#$977F,(a5)
    		move.w	#$C000,(a5)
    		move.w	#$80,($FFFFF640).w
    		move.w	($FFFFF640).w,(a5)
    		bra.s	loc_ED8
    ; ===========================================================================
    
    loc_EB4:				; XREF: loc_E7A
    		lea	($C00004).l,a5
    		move.l	#$94009340,(a5)
    		move.l	#$96FD9540,(a5)
    		move.w	#$977F,(a5)
    		move.w	#$C000,(a5)
    		move.w	#$80,($FFFFF640).w
    		move.w	($FFFFF640).w,(a5)
    
    loc_ED8:				; XREF: loc_E7A
    		move.w	($FFFFF624).w,(a5)
    		lea	($C00004).l,a5
    		move.l	#$940193C0,(a5)
    		move.l	#$96E69500,(a5)
    
    loc_EEE:
    		move.w	#$977F,(a5)
    		move.w	#$7C00,(a5)
    		move.w	#$83,($FFFFF640).w
    		move.w	($FFFFF640).w,(a5)
    		lea	($C00004).l,a5
    		move.l	#$94019340,(a5)
    		move.l	#$96FC9500,(a5)
    		move.w	#$977F,(a5)
    		move.w	#$7800,(a5)
    		move.w	#$83,($FFFFF640).w
    		move.w	($FFFFF640).w,(a5)
    		tst.b	($FFFFF767).w
    		beq.s	loc_F54
    		lea	($C00004).l,a5
    		move.l	#$94019370,(a5)
    		move.l	#$96E49500,(a5)
    		move.w	#$977F,(a5)
    		move.w	#$7000,(a5)
    		move.w	#$83,($FFFFF640).w
    		move.w	($FFFFF640).w,(a5)
    		move.b	#0,($FFFFF767).w
    
    loc_F54:
    		move.w	#0,($A11100).l	; start	the Z80
    		movem.l	($FFFFF700).w,d0-d7
    		movem.l	d0-d7,($FFFFFF10).w
    		movem.l	($FFFFF754).w,d0-d1
    		movem.l	d0-d1,($FFFFFF30).w
    		bsr.w	LoadTilesAsYouMove
    		jsr	AniArt_Load
    		jsr	HudUpdate
    		bsr.w	sub_1642
    		rts	
    ; ===========================================================================
    
    loc_F8A:				; XREF: off_B6E
    		bsr.w	sub_106E
    		addq.b	#1,($FFFFF628).w
    		move.b	#$E,($FFFFF62A).w
    		rts	
    ; ===========================================================================
    
    loc_F9A:				; XREF: off_B6E
    		bsr.w	sub_106E
    		move.w	($FFFFF624).w,(a5)
    		bra.w	sub_1642
    ; ===========================================================================
    
    loc_FA6:				; XREF: off_B6E
    		move.w	#$100,($A11100).l ; stop the Z80
    
    loc_FAE:
    		btst	#0,($A11100).l	; has Z80 stopped?
    		bne.s	loc_FAE		; if not, branch
    		bsr.w	ReadJoypads
    		lea	($C00004).l,a5
    		move.l	#$94009340,(a5)
    		move.l	#$96FD9580,(a5)
    		move.w	#$977F,(a5)
    		move.w	#$C000,(a5)
    		move.w	#$80,($FFFFF640).w
    		move.w	($FFFFF640).w,(a5)
    		lea	($C00004).l,a5
    		move.l	#$94019340,(a5)
    		move.l	#$96FC9500,(a5)
    		move.w	#$977F,(a5)
    		move.w	#$7800,(a5)
    		move.w	#$83,($FFFFF640).w
    		move.w	($FFFFF640).w,(a5)
    		lea	($C00004).l,a5
    		move.l	#$940193C0,(a5)
    		move.l	#$96E69500,(a5)
    		move.w	#$977F,(a5)
    		move.w	#$7C00,(a5)
    		move.w	#$83,($FFFFF640).w
    		move.w	($FFFFF640).w,(a5)
    		move.w	#0,($A11100).l	; start	the Z80
    		tst.b	($FFFFF767).w
    		beq.s	loc_1060
    		lea	($C00004).l,a5
    		move.l	#$94019370,(a5)
    		move.l	#$96E49500,(a5)
    		move.w	#$977F,(a5)
    		move.w	#$7000,(a5)
    		move.w	#$83,($FFFFF640).w
    		move.w	($FFFFF640).w,(a5)
    		move.b	#0,($FFFFF767).w
    
    loc_1060:
    		tst.w	($FFFFF614).w
    		beq.w	locret_106C
    		subq.w	#1,($FFFFF614).w
    
    locret_106C:
    		rts	
    
    ; ||||||||||||||| S U B	R O U T	I N E |||||||||||||||||||||||||||||||||||||||
    
    
    sub_106E:				; XREF: loc_C32; et al
    		move.w	#$100,($A11100).l ; stop the Z80
    
    loc_1076:
    		btst	#0,($A11100).l	; has Z80 stopped?
    		bne.s	loc_1076	; if not, branch
    		bsr.w	ReadJoypads
    		tst.b	($FFFFF64E).w
    		bne.s	loc_10B0
    		lea	($C00004).l,a5
    		move.l	#$94009340,(a5)
    		move.l	#$96FD9580,(a5)
    		move.w	#$977F,(a5)
    		move.w	#$C000,(a5)
    		move.w	#$80,($FFFFF640).w
    		move.w	($FFFFF640).w,(a5)
    		bra.s	loc_10D4
    ; ===========================================================================
    
    loc_10B0:				; XREF: sub_106E
    		lea	($C00004).l,a5
    		move.l	#$94009340,(a5)
    		move.l	#$96FD9540,(a5)
    		move.w	#$977F,(a5)
    		move.w	#$C000,(a5)
    		move.w	#$80,($FFFFF640).w
    		move.w	($FFFFF640).w,(a5)
    
    loc_10D4:				; XREF: sub_106E
    		lea	($C00004).l,a5
    		move.l	#$94019340,(a5)
    		move.l	#$96FC9500,(a5)
    		move.w	#$977F,(a5)
    		move.w	#$7800,(a5)
    		move.w	#$83,($FFFFF640).w
    		move.w	($FFFFF640).w,(a5)
    		lea	($C00004).l,a5
    		move.l	#$940193C0,(a5)
    		move.l	#$96E69500,(a5)
    		move.w	#$977F,(a5)
    		move.w	#$7C00,(a5)
    		move.w	#$83,($FFFFF640).w
    		move.w	($FFFFF640).w,(a5)
    		move.w	#0,($A11100).l	; start	the Z80
    		rts	
    ; End of function sub_106E
    With this:
    Code:
    loc_BBA:
    		move.w	#1,($FFFFF644).w
    	Z80DMA_ON
    		tst.b	($FFFFF64E).w
    		bne.s	loc_BFE
    		lea	($C00004).l,a5
    		move.l	#$94009340,(a5)
    		move.l	#$96FD9580,(a5)
    		move.w	#$977F,(a5)
    		move.w	#$C000,(a5)
    		move.w	#$80,($FFFFF640).w
    		move.w	($FFFFF640).w,(a5)
    		bra.s	loc_C22
    ; ===========================================================================
    
    loc_BFE:				; XREF: loc_BC8
    		lea	($C00004).l,a5
    		move.l	#$94009340,(a5)
    		move.l	#$96FD9540,(a5)
    		move.w	#$977F,(a5)
    		move.w	#$C000,(a5)
    		move.w	#$80,($FFFFF640).w
    		move.w	($FFFFF640).w,(a5)
    
    loc_C22:				; XREF: loc_BC8
    		move.w	($FFFFF624).w,(a5)
    	Z80DMA_OFF
    		bra.w	loc_B5E
    ; ===========================================================================
    
    loc_C32:				; XREF: off_B6E
    		bsr.w	sub_106E
    
    loc_C36:				; XREF: off_B6E
    		tst.w	($FFFFF614).w
    		beq.w	locret_C42
    		subq.w	#1,($FFFFF614).w
    
    locret_C42:
    		rts	
    ; ===========================================================================
    
    loc_C44:				; XREF: off_B6E
    		bsr.w	sub_106E
    		bsr.w	sub_6886
    		bsr.w	sub_1642
    		tst.w	($FFFFF614).w
    		beq.w	locret_C5C
    		subq.w	#1,($FFFFF614).w
    
    locret_C5C:
    		rts	
    ; ===========================================================================
    
    loc_C5E:				; XREF: off_B6E
    		bsr.w	sub_106E
    		rts
    
    Return:
    		bsr.w	ReadJoypads
    		rts	
    ; ===========================================================================
    
    loc_C64:				; XREF: off_B6E
    		cmpi.b	#$10,($FFFFF600).w ; is	game mode = $10	(special stage)	?
    		beq.w	loc_DA6		; if yes, branch
    
    loc_C6E:				; XREF: off_B6E
    	Z80DMA_ON
    		bsr.w	ReadJoypads
    		tst.b	($FFFFF64E).w
    		bne.s	loc_CB0
    		lea	($C00004).l,a5
    		move.l	#$94009340,(a5)
    		move.l	#$96FD9580,(a5)
    		move.w	#$977F,(a5)
    		move.w	#$C000,(a5)
    		move.w	#$80,($FFFFF640).w
    		move.w	($FFFFF640).w,(a5)
    		bra.s	loc_CD4
    ; ===========================================================================
    
    loc_CB0:				; XREF: loc_C76
    		lea	($C00004).l,a5
    		move.l	#$94009340,(a5)
    		move.l	#$96FD9540,(a5)
    		move.w	#$977F,(a5)
    		move.w	#$C000,(a5)
    		move.w	#$80,($FFFFF640).w
    		move.w	($FFFFF640).w,(a5)
    
    loc_CD4:				; XREF: loc_C76
    		move.w	($FFFFF624).w,(a5)
    		lea	($C00004).l,a5
    		move.l	#$940193C0,(a5)
    		move.l	#$96E69500,(a5)
    		move.w	#$977F,(a5)
    		move.w	#$7C00,(a5)
    		move.w	#$83,($FFFFF640).w
    		move.w	($FFFFF640).w,(a5)
    		lea	($C00004).l,a5
    		move.l	#$94019340,(a5)
    		move.l	#$96FC9500,(a5)
    		move.w	#$977F,(a5)
    		move.w	#$7800,(a5)
    		move.w	#$83,($FFFFF640).w
    		move.w	($FFFFF640).w,(a5)
    		tst.b	($FFFFF767).w
    		beq.s	loc_D50
    		lea	($C00004).l,a5
    		move.l	#$94019370,(a5)
    		move.l	#$96E49500,(a5)
    		move.w	#$977F,(a5)
    		move.w	#$7000,(a5)
    		move.w	#$83,($FFFFF640).w
    		move.w	($FFFFF640).w,(a5)
    		move.b	#0,($FFFFF767).w
    
    loc_D50:
    	Z80DMA_OFF
    		movem.l	($FFFFF700).w,d0-d7
    		movem.l	d0-d7,($FFFFFF10).w
    		movem.l	($FFFFF754).w,d0-d1
    		movem.l	d0-d1,($FFFFFF30).w
    		cmpi.b	#$60,($FFFFF625).w
    		bcc.s	Demo_Time
    		move.b	#1,($FFFFF64F).w
    		addq.l	#4,sp
    		bra.w	loc_B64
    
    ; ---------------------------------------------------------------------------
    ; Subroutine to	run a demo for an amount of time
    ; ---------------------------------------------------------------------------
    
    ; ||||||||||||||| S U B	R O U T	I N E |||||||||||||||||||||||||||||||||||||||
    
    
    Demo_Time:				; XREF: loc_D50; PalToCRAM
    		bsr.w	LoadTilesAsYouMove
    		jsr	AniArt_Load
    		jsr	HudUpdate
    		bsr.w	sub_165E
    		tst.w	($FFFFF614).w	; is there time	left on	the demo?
    		beq.w	Demo_TimeEnd	; if not, branch
    		subq.w	#1,($FFFFF614).w ; subtract 1 from time	left
    
    Demo_TimeEnd:
    		rts	
    ; End of function Demo_Time
    
    ; ===========================================================================
    
    loc_DA6:				; XREF: off_B6E
    		bsr.w	ReadJoypads
    	Z80DMA_ON
    		lea	($C00004).l,a5
    		move.l	#$94009340,(a5)
    		move.l	#$96FD9580,(a5)
    		move.w	#$977F,(a5)
    		move.w	#$C000,(a5)
    		move.w	#$80,($FFFFF640).w
    		move.w	($FFFFF640).w,(a5)
    		lea	($C00004).l,a5
    		move.l	#$94019340,(a5)
    		move.l	#$96FC9500,(a5)
    		move.w	#$977F,(a5)
    		move.w	#$7800,(a5)
    		move.w	#$83,($FFFFF640).w
    		move.w	($FFFFF640).w,(a5)
    		lea	($C00004).l,a5
    		move.l	#$940193C0,(a5)
    		move.l	#$96E69500,(a5)
    		move.w	#$977F,(a5)
    		move.w	#$7C00,(a5)
    		move.w	#$83,($FFFFF640).w
    		move.w	($FFFFF640).w,(a5)
    		bsr.w	PalCycle_SS
    		tst.b	($FFFFF767).w
    		beq.s	loc_E64
    		lea	($C00004).l,a5
    		move.l	#$94019370,(a5)
    		move.l	#$96E49500,(a5)
    		move.w	#$977F,(a5)
    		move.w	#$7000,(a5)
    		move.w	#$83,($FFFFF640).w
    		move.w	($FFFFF640).w,(a5)
    		move.b	#0,($FFFFF767).w
    
    loc_E64:
    	Z80DMA_OFF
    		tst.w	($FFFFF614).w
    		beq.w	locret_E70
    		subq.w	#1,($FFFFF614).w
    
    locret_E70:
    		rts	
    ; ===========================================================================
    
    loc_E72:				; XREF: off_B6E
    		bsr.w	ReadJoypads
    	Z80DMA_ON
    		tst.b	($FFFFF64E).w
    		bne.s	loc_EB4
    		lea	($C00004).l,a5
    		move.l	#$94009340,(a5)
    		move.l	#$96FD9580,(a5)
    		move.w	#$977F,(a5)
    		move.w	#$C000,(a5)
    		move.w	#$80,($FFFFF640).w
    		move.w	($FFFFF640).w,(a5)
    		bra.s	loc_ED8
    ; ===========================================================================
    
    loc_EB4:				; XREF: loc_E7A
    		lea	($C00004).l,a5
    		move.l	#$94009340,(a5)
    		move.l	#$96FD9540,(a5)
    		move.w	#$977F,(a5)
    		move.w	#$C000,(a5)
    		move.w	#$80,($FFFFF640).w
    		move.w	($FFFFF640).w,(a5)
    
    loc_ED8:				; XREF: loc_E7A
    		move.w	($FFFFF624).w,(a5)
    		lea	($C00004).l,a5
    		move.l	#$940193C0,(a5)
    		move.l	#$96E69500,(a5)
    
    loc_EEE:
    		move.w	#$977F,(a5)
    		move.w	#$7C00,(a5)
    		move.w	#$83,($FFFFF640).w
    		move.w	($FFFFF640).w,(a5)
    		lea	($C00004).l,a5
    		move.l	#$94019340,(a5)
    		move.l	#$96FC9500,(a5)
    		move.w	#$977F,(a5)
    		move.w	#$7800,(a5)
    		move.w	#$83,($FFFFF640).w
    		move.w	($FFFFF640).w,(a5)
    		tst.b	($FFFFF767).w
    		beq.s	loc_F54
    		lea	($C00004).l,a5
    		move.l	#$94019370,(a5)
    		move.l	#$96E49500,(a5)
    		move.w	#$977F,(a5)
    		move.w	#$7000,(a5)
    		move.w	#$83,($FFFFF640).w
    		move.w	($FFFFF640).w,(a5)
    		move.b	#0,($FFFFF767).w
    
    loc_F54:
    	Z80DMA_OFF
    		movem.l	($FFFFF700).w,d0-d7
    		movem.l	d0-d7,($FFFFFF10).w
    		movem.l	($FFFFF754).w,d0-d1
    		movem.l	d0-d1,($FFFFFF30).w
    		bsr.w	LoadTilesAsYouMove
    		jsr	AniArt_Load
    		jsr	HudUpdate
    		bsr.w	sub_1642
    		rts	
    ; ===========================================================================
    
    loc_F8A:				; XREF: off_B6E
    		bsr.w	sub_106E
    		addq.b	#1,($FFFFF628).w
    		move.b	#$E,($FFFFF62A).w
    		rts	
    ; ===========================================================================
    
    loc_F9A:				; XREF: off_B6E
    		bsr.w	sub_106E
    		move.w	($FFFFF624).w,(a5)
    		bra.w	sub_1642
    ; ===========================================================================
    
    loc_FA6:				; XREF: off_B6E
    		bsr.w	ReadJoypads
    	Z80DMA_ON
    		lea	($C00004).l,a5
    		move.l	#$94009340,(a5)
    		move.l	#$96FD9580,(a5)
    		move.w	#$977F,(a5)
    		move.w	#$C000,(a5)
    		move.w	#$80,($FFFFF640).w
    		move.w	($FFFFF640).w,(a5)
    		lea	($C00004).l,a5
    		move.l	#$94019340,(a5)
    		move.l	#$96FC9500,(a5)
    		move.w	#$977F,(a5)
    		move.w	#$7800,(a5)
    		move.w	#$83,($FFFFF640).w
    		move.w	($FFFFF640).w,(a5)
    		lea	($C00004).l,a5
    		move.l	#$940193C0,(a5)
    		move.l	#$96E69500,(a5)
    		move.w	#$977F,(a5)
    		move.w	#$7C00,(a5)
    		move.w	#$83,($FFFFF640).w
    		move.w	($FFFFF640).w,(a5)
    		tst.b	($FFFFF767).w
    		beq.s	loc_1060
    		lea	($C00004).l,a5
    		move.l	#$94019370,(a5)
    		move.l	#$96E49500,(a5)
    		move.w	#$977F,(a5)
    		move.w	#$7000,(a5)
    		move.w	#$83,($FFFFF640).w
    		move.w	($FFFFF640).w,(a5)
    		move.b	#0,($FFFFF767).w
    
    loc_1060:
    	Z80DMA_OFF
    		tst.w	($FFFFF614).w
    		beq.w	locret_106C
    		subq.w	#1,($FFFFF614).w
    
    locret_106C:
    		rts	
    
    ; ||||||||||||||| S U B	R O U T	I N E |||||||||||||||||||||||||||||||||||||||
    
    
    sub_106E:				; XREF: loc_C32; et al
    		bsr.w	ReadJoypads
    	Z80DMA_ON
    		tst.b	($FFFFF64E).w
    		bne.s	loc_10B0
    		lea	($C00004).l,a5
    		move.l	#$94009340,(a5)
    		move.l	#$96FD9580,(a5)
    		move.w	#$977F,(a5)
    		move.w	#$C000,(a5)
    		move.w	#$80,($FFFFF640).w
    		move.w	($FFFFF640).w,(a5)
    
    PAL1_LOAD:
    		bra.s	loc_10D4
    ; ===========================================================================
    
    loc_10B0:
    		lea	($C00004).l,a5
    		move.l	#$94009340,(a5)
    		move.l	#$96FD9540,(a5)
    		move.w	#$977F,(a5)
    		move.w	#$C000,(a5)
    		move.w	#$80,($FFFFF640).w
    		move.w	($FFFFF640).w,(a5)
    loc_10D4:
    		lea	($C00004).l,a5
    		move.l	#$94019340,(a5)
    		move.l	#$96FC9500,(a5)
    		move.w	#$977F,(a5)
    		move.w	#$7800,(a5)
    		move.w	#$83,($FFFFF640).w
    		move.w	($FFFFF640).w,(a5)
    		lea	($C00004).l,a5
    		move.l	#$940193C0,(a5)
    		move.l	#$96E69500,(a5)
    		move.w	#$977F,(a5)
    		move.w	#$7C00,(a5)
    		move.w	#$83,($FFFFF640).w
    		move.w	($FFFFF640).w,(a5)
    	Z80DMA_OFF
    		rts	
    ; End of function sub_106E
    Basically, all we've done is replaced all of these instances:
    Code:
    		move.w	#$100,($A11100).l ; stop the Z80
    
    location:
    		btst	#0,($A11100).l	; has Z80 stopped?
    		bne.s	location	; if not, branch
    With these:
    Code:
    	Z80DMA_ON
    And all of these instances:
    Code:
    		move.w	#0,($A11100).l	; start	the Z80
    With these:
    Code:
    	Z80DMA_OFF
    So now instead of stopping the Z80, it'll just send it a note saying that there's a DMA transfer to occur.

    Finished

    Your disassembly is now setup with the new Dual PCM driver, here is a download link to a Sonic 1 disassembly with the changes already applied.

    Download (32-bit)
    Download (64-bit)

    Adding in new samples

    Alright, so now that everything's pretty much setup, you'll no doubt want to put new samples in, or, replace the old ones, or whatever. Here, we look at putting in the sample, converting it, and including it properly.

    Step 01 - Adjusting the volume of your sample

    This driver fuses two samples together by "addition" before flushing out the final result, the problem is, when you add two samples together, you are in danger of overflowing the 8-bit limit. Getting Dual PCM to cap the limit if it overflows would take extra processing time, and this would cause the sample rate to drop really low.

    So, instead, the tool "ConvPCM" will automatically convert the sample to 7-bit, this ensures that the samples (when added/fused together) don't overflow, this creates a problem though, 7-bit samples playing in the lower of 8-bit will sound very quiet and low volume, there is no avoiding this. What I would advise you to do, is to raise the volume of your sample by twice as much before putting it into the game.

    Now you might say "won't this cause the sample to overflow", quite possibly, however, there is a phenomina known as the "Loudness Wars", long story short, sharp sounds (such as drums or waves that jitter very eratically) can be overflown to a degree without any notice-able damage to the quality. Because they're so sharp, the resulting overflow is also sharp, therefore there appears to be no difference in quality. You can use this to your advantage, many of your samples you will be able to get away with multiplying the volume to 200% (an extra 100%), this will help the volume of the sample sound normal in-game. There are plenty of tools out there you can use to edit the sample's volume (Audacity for example).

    The tool doesn't adjust the volume twice as loud to compensate for you, the reason is that you might want the sample a specific volume (that, and not all samples sound great at 200%, some may just need 150%), the Sonic 1 samples provided above have their volumes already raised to 200%, and if you listen, you'll find barely any difference in quality (in fact, it'll be higher quality because of the driver, which is irrelevant to the conversion anyway...).

    Step 02 - Putting your sample file in

    Put the ".wav" or ".bin" file Inside the "Dual PCM\Samples" folder, for example, we'll have a sample called "Scratch.wav" just as an example:

    [​IMG]

    If you open up "ConvPCM.txt" you'll find this:
    Code:
    Sample Rate:	20500
    Interpolation:	TRUE
    It is recommended that you keep the "Sample Rate" at 20500, this is just for any changes to the driver that'll cause a sample rate change, what might be of interest to you is the "Interpolation" setting, I've had it set to "TRUE" by default, this simply smooths out the samples when they change from say... 44,100Hz to 20,500Hz, this will make all sharp sounds that might sound horrible at 20,500Hz, soften up. If you do not like the result and want all of your samples to remain sharp, change this to "FALSE" (this will effect any samples you convert).

    Now, all that's left, is to drag and drop "Scratch.wav" onto "ConvPCM.exe":

    [​IMG]

    A "Scratch.swf" file shall now exist in the "incswf" folder, and we can now include it into the game. Open up "sonic1.asm" and go down to here:
    Code:
    ; ---------------------------------------------------------------------------
    ; Sample file includes
    ; ---------------------------------------------------------------------------
    			align	$20,$FF
    SWF_StopSample:		dcb.b	$7FFF,$00
    			dc.b	$80
    ; ---------------------------------------------------------------------------
    SWF_S1Kick:		incbin	"Dual PCM\Samples\incswf\Sonic 1 Kick.swf"
    SWF_S1Snare:		incbin	"Dual PCM\Samples\incswf\Sonic 1 Snare.swf"
    SWF_S1TimpaniHigh:	incbin	"Dual PCM\Samples\incswf\Sonic 1 Timpani High.swf"
    SWF_S1TimpaniMid:	incbin	"Dual PCM\Samples\incswf\Sonic 1 Timpani Mid.swf"
    SWF_S1TimpaniLow:	incbin	"Dual PCM\Samples\incswf\Sonic 1 Timpani Low.swf"
    SWF_S1TimpaniLower:	incbin	"Dual PCM\Samples\incswf\Sonic 1 Timpani Lower.swf"
    You can now insert your new incbin for "Scratch.swf" on the end:
    Code:
    SWF_Scratch:		incbin	"Dual PCM\Samples\incswf\Scratch.swf"
    Next thing to do, is to create a Z80 pointer for it here:
    Code:
    ; ---------------------------------------------------------------------------
    ; Sample z80 pointers
    ; ---------------------------------------------------------------------------
    
    StopSample:		dcz80	SWF_StopSample
    Sonic1Kick:		dcz80	SWF_S1Kick
    Sonic1Snare:		dcz80	SWF_S1Snare
    Sonic1TimpaniHigh:	dcz80	SWF_S1TimpaniHigh
    Sonic1TimpaniMid:	dcz80	SWF_S1TimpaniMid
    Sonic1TimpaniLow:	dcz80	SWF_S1TimpaniLow
    Sonic1TimpaniLower:	dcz80	SWF_S1TimpaniLower
    Add it onto the end of the list:
    Code:
    Scratch:		dcz80	SWF_Scratch
    Finally, you now need to place it in a slot somewhere, right here:
    Code:
    ; ---------------------------------------------------------------------------
    ; Sample 68k PCM list
    ; ---------------------------------------------------------------------------
    
    SampleList:		dc.l	StopSample			; 80 (THIS IS A REST NOTE, DO NOT EDIT...)
    			dc.l	Sonic1Kick			; 81
    			dc.l	Sonic1Snare			; 82
    			dc.l	Sonic1TimpaniLow		; 83
    			dc.l	StopSample			; 84
    			dc.l	StopSample			; 85
    			dc.l	StopSample			; 86
    			dc.l	StopSample			; 87
    			dc.l	Sonic1TimpaniHigh		; 88
    			dc.l	Sonic1TimpaniMid		; 89
    			dc.l	Sonic1TimpaniLow		; 8A
    			dc.l	Sonic1TimpaniLower		; 8B
    You can use any of the slots already taken so far, by replacing the name with "Scratch", for example, we could replace "Sonic1Snare" with "Scratch", and this will cause the DAC ID 82 to play the scratch sample instead of Sonic 1's snare sample. You could use slot 84, 85, 86 or 87 since they're unused, or, you can add in new slots onto the end like so:
    Code:
    SampleList:		dc.l	StopSample			; 80 (THIS IS A REST NOTE, DO NOT EDIT...)
    			dc.l	Sonic1Kick			; 81
    			dc.l	Sonic1Snare			; 82
    			dc.l	Sonic1TimpaniLow		; 83
    			dc.l	StopSample			; 84
    			dc.l	StopSample			; 85
    			dc.l	StopSample			; 86
    			dc.l	StopSample			; 87
    			dc.l	Sonic1TimpaniHigh		; 88
    			dc.l	Sonic1TimpaniMid		; 89
    			dc.l	Sonic1TimpaniLow		; 8A
    			dc.l	Sonic1TimpaniLower		; 8B
    			dc.l	Scratch				; 8C
    From now on, DAC ID "8C" will play the scratch sample.

    The SMPS format only allows you to play samples from 81 to DF, so that will be your limit, this is not a limit of Dual PCM, this is a limit of SMPS

    The scratch sample itself doesn't have to be any specific size, it can be a 1 minute sample if you really wanted it to, what you have to watch out for though, is your ROM limit, again, not a limit of Dual PCM, but rather a limit of the CPU's memory map.

    One important thing to note, I have used ".wav" files here, and the program converts them from any uncompressed "RIFF" format to the right format for Dual PCM, you can use ".bin" files if you want, but your files MUST be 8-bit, MUST be mono, MUST be unsigned, and MUST be 20,500Hz, the program will only convert the important related parts, it cannot know the what bit format, rate, channels, etc, so it simply "assumes" that all ".bin" files will be 8-bit, mono, unsigned, 20,500Hz samples, with NO extra headers/information, just RAW sample data.

    If you make a change to any of the sample files, you MUST redrag them onto the program to convert them once again to update the ".swf" files.

    SMPS Tracker Format

    The only difference to the SMPS files now, is that there's an extra pointer put in for the second PCM channel, and an F2 stop flag for it, and the number of FM/DAC channels has been increased by 1:

    [​IMG]

    After:

    [​IMG]

    And that's it, treat this new channel as you would a normal DAC channel, it is nothing more than having another DAC channel.

    Optimising SFX

    The more FM channels you have running, then the more the Z80 needs to be accessed by the 68k for passing on FM operator data.

    However, I do have something to combat this, a new set of optimised SFX tracks, you can download them here:

    Optimised Sound Pack

    Not all SFX have changed, only some of them (I forget which so I included all of them...).

    A lot of Sonic 1's SFX used multiple channels, even though they really didn't need to, there were also some stereo effects, and so on, and while they might have seem awesome at the time, they are often something that people don't really notice...

    ..and do you know how I know? Because I've used these optimised SFX files (and improved on them) ever since Sonic 1 Brother Trouble, I even used them in Sonic 1 The Next Level, and you know what? No-one even noticed.

    The only person who came close to noticing was one person who mentioned that a track on Brother Trouble seemed to use "extra channels", what they didn't realise was that it's because the SFX didn't mute the music much, they use less channels and sound almost the same. But its use here is more for prevention of quality loss in the PCM playback, the lack of channel stopping is a bonus, you can't say fairer than that~

    Final Stuff

    If you plan to perform DMA transfers, ALWAYS put in a "Z80DMA_ON" before, and a "Z80DMA_OFF" afterwards, to allow the Z80 to avoid getting stopped during a transfer. If you have multiple transfers, DO NOT turn DMA on and off and on and off between each transfer. Turn it on, do all of your transfers, then turn it off. This will reduce the amount of changes the Z80 needs to make to account for the transfers.

    If you plan to write something to the YM2612 from the 68k side, make sure that once you're finished, you write $2A to the YM2612 address port before starting the Z80 again. The Dual PCM driver will NOT set the YM2612 address, it simply "assumes" it already is at $2A, this is to save on Z80 processing time.

    All samples MUST be aligned to a $20th position in the ROM, and the sample MUST end with $80 on the $1Fth position. I have already set this up for you, the program that converts the ".wav" files into ".swf" files will automatically pad to the next $20, and place an $80 on the last byte. And the alignment is already done in the source here:
    Code:
    ; ---------------------------------------------------------------------------
    ; Sample file includes
    ; ---------------------------------------------------------------------------
    			align	$20,$FF
    As long as you place all includes here, you will be fine.

    A thank you to "Ralakimus" for providing 32-bit builds of my programs, and to "Egor The Cat" for his helpful guide, and for reminding me of extra details I forgot to add.

    I will be doing some clean up and some quality improvements as time goes on, but I am hoping that some other Z80 programmers out there will contribute to improve the driver, we need as many improvements as we can get if we want Pitch/Volume support. Adding those may cause a major drop in sample rate, and so, we need to be careful how we go about this.

    If any of you have any ideas, or wish to contribute in some way, by all means post away, I'll be happy to at least "attempt" to implement or allow the implementation of ideas into the product as it grows (if it grows).

    I need to stop typing more stuff now as the site's editor is lagging from the amount of text and code put in this tiny dialogue box, have fun~
     
    Last edited: Dec 13, 2016
  2. Mr. Cat

    Mr. Cat The Holy Cat Jr. Member

    Joined:
    May 31, 2014
    Messages:
    377
    you really trademarked jst?

    I really like this, not because of any technical aspects or whatever, but by how user friendly it is. I think i will try installing it into my hack.

    The only issue so far is that there's not a macro to play a sample anywhere in the code like there was in Mega PCM, it was really useful, and i thought there would be a lot of possibilites given the extra channel. Too bad I guess.
     
  3. MarkeyJester

    MarkeyJester !%#@ Member

    Joined:
    Jun 27, 2009
    Messages:
    2,660
    If you wish to access the Dual PCM directly, you can do so by:
    Code:
    		lea	(Scratch).l,a0
    		StopZ80
    		lea	($A00000+PCM1_Sample).l,a1			; MJ: load PCM 1 slot address
    		move.b	(a0)+,(a1)+					; MJ: set address of sample
    		move.b	(a0)+,(a1)+					; MJ: ''
    		move.b	(a0)+,(a1)+					; MJ: ''
    		move.b	#(CUPCM1_NewSample&$FF),($A00000+CU_Stack).l	; MJ: set routine to run
    		move.b	#(CUPCM1_NewSample>>$08),($A00000+CU_Stack+1).l	; MJ: ''
    		move.b	#%11001001,($A00000+CUPCM1_RET).l		; MJ: change "NOP" to "RET"
    		StartZ80
    For PCM 1, or:
    Code:
    		lea	(Scratch).l,a0
    		StopZ80
    		lea	($A00000+PCM2_Sample).l,a1			; MJ: load PCM 2 slot address
    		move.b	(a0)+,(a1)+					; MJ: ''
    		move.b	(a0)+,(a1)+					; MJ: ''
    		move.b	(a0)+,(a1)+					; MJ: ''
    		move.b	#%00101000,($A00000+CUPCM2_RET).l		; change "JR NZ" to "JR Z"
    		StartZ80
    For PCM 2, where "Scratch" is the address of the Z80 pointer. You can make this into a set of macros if you wish.

    Like I said above, the guide is nothing but a guide, it's just stock code allowing SMPS to control it. It's up to you to write your own 68k code for anything specific that you desire.
     
    FATA-, Bluestreak, Pacca and 4 others like this.
  4. Novedicus

    Novedicus Well-Known Member Member

    Joined:
    Aug 26, 2013
    Messages:
    855
    Unfortunately, I'm using a 32 bit version of Windows 7 (yeah, go ahead and shoot me for not having a 64 bit version). However, since you provided the sources to the assembly tools you provided, I was able to recompile them as 32 bit versions with ease. However, I cannot use ConvPCM since that's for 64 bit systems and the source for it is not provided, so I cannot recompile it.
     
    Last edited: Nov 27, 2016
    Bluestreak and MarkeyJester like this.
  5. FохConED

    FохConED Join to Digital Resistance! Member

    Joined:
    Dec 13, 2014
    Messages:
    179
    Location:
    Konakovo
    I very much liked your work, everything is realized top-level! I would like to enclose also the efforts in this project.
    I found weaknesses of the converter in the format supported in this driver.
    And so, one of weaknesses of this converter that it doesn't want to accept RAW samples correctly as it has no header, actually he can't read sampling rate of this file.
    I want to offer that it was possible to enter sample rate of the file into a program configuration, and also regulation of pitch in output sample.

    Also I want to share knowledge and some resources which I made.

    How to use 2 DAC channels in S1SMPS2ASM?
    It can be done very simply, for example music from the GHZ level, so.
    Step 1:
    Convert GHZ music in S1SMPS2ASM for receiving asm of the file
    Step 2:
    Now we need to force the second PCM channel to work,
    For this purpose we need to change header.

    As we see how the original the header looks:
    Code:
    GHZ_Header:
        smpsHeaderVoice    GHZ_Voices
        smpsHeaderChan    $06,    $03
        smpsHeaderTempo    $01,    $03
    
        smpsHeaderDAC    GHZ_DAC
        smpsHeaderFM    GHZ_FM1,    smpsPitch01lo,    $12
        smpsHeaderFM    GHZ_FM2,    smpsPitch00,    $0B
        smpsHeaderFM    GHZ_FM3,    smpsPitch01lo,    $14
        smpsHeaderFM    GHZ_FM4,    smpsPitch01lo,    $08
        smpsHeaderFM    GHZ_FM5,    smpsPitch01lo,    $20
        smpsHeaderPSG    GHZ_PSG1,    smpsPitch04lo,    $01,    $03
        smpsHeaderPSG    GHZ_PSG2,    smpsPitch04lo,    $03,    $06
        smpsHeaderPSG    GHZ_PSG3,    smpsPitch00,    $05,    $04
    We need to change byte of current number of FM/DAC of channels to one more, and also to add one more DAC channel to the list, it will look:
    Code:
    GHZ_Header:
        smpsHeaderVoice    GHZ_Voices
        smpsHeaderChan    $07,    $03
        smpsHeaderTempo    $01,    $03
    
        smpsHeaderDAC    GHZ_DAC
        smpsHeaderDAC    GHZ_DAC2
        smpsHeaderFM    GHZ_FM1,    smpsPitch01lo,    $12
        smpsHeaderFM    GHZ_FM2,    smpsPitch00,    $0B
        smpsHeaderFM    GHZ_FM3,    smpsPitch01lo,    $14
        smpsHeaderFM    GHZ_FM4,    smpsPitch01lo,    $08
        smpsHeaderFM    GHZ_FM5,    smpsPitch01lo,    $20
        smpsHeaderPSG    GHZ_PSG1,    smpsPitch04lo,    $01,    $03
        smpsHeaderPSG    GHZ_PSG2,    smpsPitch04lo,    $03,    $06
        smpsHeaderPSG    GHZ_PSG3,    smpsPitch00,    $05,    $04
    Step 3:
    And now we need to add the DAC channel with percussions and we designate. I, for example use hats sample on the second DAC channel:
    Code:
    GHZ_DAC2:
        dc.b        $8C,    $10,    $10,    $10
    GHZ_DAC2_Jump06:
        dc.b        $08
        smpsJump    GHZ_DAC2_Jump06
    $8C - New hat sample
    Also I will throw off the ASM file and build with changed SMPS in GHZ and new samples (As I spoke, I used 2 DAC channel for Hats and I used PSG3 channel for PSG1 channel echo)
    ASM File
    And...
    Build
     
    HackGame, Ozaleto and MarkeyJester like this.
  6. MarkeyJester

    MarkeyJester !%#@ Member

    Joined:
    Jun 27, 2009
    Messages:
    2,660
    My apologies~

    Here is the source code to ConvPCM, in my tired stuper I forgot all about it.

    If you could provide for me a copy of 32-Bit builds, I'll rehost them and edit the first post to have 32-bit/64-bit builds downloadable.

    What did I say? WHAT DID I SAY?

    Someone didn't READ THE FIRST POST!

    Fantastic work, thank you very much for your support, that is very kind of you~ *Gives rep point*
     
    Bluestreak and FохConED like this.
  7. Novedicus

    Novedicus Well-Known Member Member

    Joined:
    Aug 26, 2013
    Messages:
    855
    Bluestreak likes this.
  8. FохConED

    FохConED Join to Digital Resistance! Member

    Joined:
    Dec 13, 2014
    Messages:
    179
    Location:
    Konakovo
    I meant, what would be more comfortable, if parameters of which aren't present in RAW it would be possible to specify in a config,
    also I know a problem that in case of conversion of pcm files become MUCH more silent in volume.
     
  9. MarkeyJester

    MarkeyJester !%#@ Member

    Joined:
    Jun 27, 2009
    Messages:
    2,660
    Ah right, what we could do, is have it such that you have a config file for each raw/binary file, and you drag that config file onto the program, and it takes the information from there. I would need a copy of a few of your config files to know the format.

    Also, the volume issue...

    Fusing two samples is done by adding the samples together, this causes the volume to rise, which means that two 8-bit samples fused together would become a 9-bit sample (in other words, it'll end up capping the limit). In order to save on Z80 CPU time, no cap checks are perform, instead, the samples are converted to 7-bit, this ensures that the samples remain in the 8-bit limit without CPU time wastes on checking for overflow.

    However, there is a thing know as the "Volume Wars" (which I intended to mention in the first post, but forgot). Basically, sharp wave forms that cap the limit will often sound the same as those that don't, this is because of the sudden change in the wave. You can use this to your advantage, since most samples will be drum based, you may be able to raise the volume of your samples by an extra 100% to keep its volume. This is what I did with the Sonic 1 samples, if you open it with a wave editor of some sort, you'll see that the wave for Sonic 1's drums cap the limit, yet they still sound the same "within reason".

    I'll update the first post later tonight with the details of this phenomena.
     
  10. Crash

    Crash Well-Known Member Member

    Joined:
    Jul 15, 2010
    Messages:
    299
    Location:
    Australia
    https://www.dropbox.com/s/eask3rn8lgy4osb/apotos dual pcm.vgz?dl=0

    made a quick and dirty little test song with this, the samples came out sounding better than i expected!

    (also the vgm format doesn't work so well with songs with this kind of sample use, the uncompressed vgm was 14mb :p )

    e: also by the way this uses 34 samples and they take up 460kb so it's probably not feasible to do a full soundtrack of songs like this
     
    Last edited: Apr 30, 2017
  11. amphobius

    amphobius spreader of the pink text Member

    Joined:
    Feb 24, 2008
    Messages:
    971
    Location:
    United Kingdom
    Tried to make a conversion of Gradius 3's Final Shot with this. Still got a few things I need to figure out that I'm sure I'll be able to work around, but once I got it working I'm happy with the results. Definitely going to see much use from me.
     
    Crash, jubbalub and FохConED like this.
  12. MarkeyJester

    MarkeyJester !%#@ Member

    Joined:
    Jun 27, 2009
    Messages:
    2,660
    Are majority of those samples just different pitch variations? If so, then I'm working on a solution for that.

    I'm attempting some pitch control, but I'm looking at it from a glance, and in theory it's really going to detriment the quality. How far would you all be willing to go? What's the boarder-line sample rate you'd be willing to accept?
     
  13. Natsumi

    Natsumi Markey's Member

    Joined:
    Oct 7, 2011
    Messages:
    647
    Location:
    Otter's lap
    I think anything below 12kHz is not any good for many use-cases, but many games have gone off with 8kHz, so maybe it can be an optional thing?
     
  14. Crash

    Crash Well-Known Member Member

    Joined:
    Jul 15, 2010
    Messages:
    299
    Location:
    Australia
    It wouldn't help a real lot for that song, because most samples were fairly different chords/volume/levels of muting/whatever. But for stuff like the basslines in your examples yeah, it'd be a nice feature. If I had to choose between having pitch control and keeping the quality as it is though, I'd probably go for the latter.
     
  15. MarkeyJester

    MarkeyJester !%#@ Member

    Joined:
    Jun 27, 2009
    Messages:
    2,660
    Update...

    Some changes that will improve the quality slightly...

    Open up "sonic1.asm" source, find this:
    Code:
    Z80ROM:		incbin	"Dual PCM\Z80.bin"
    Z80ROM_End:	even
    Change it to this:
    Code:
    Z80ROM:		incbin	"Dual PCM\Z80.bin"
    		dcz80	SWF_StopSample
    Z80ROM_End:	even
    Then find this:
    Code:
    SWF_StopSample:	dcb.b	$1F,$00
    		dc.b	$80
    Change it to this:
    Code:
    SWF_StopSample:	dcb.b	$7FFF,$00
    		dc.b	$80
    Download this new Z80.asm file, and replace the old one.

    And finally, open up "ConvPCM.txt" and change "19500" to "20500", and of course, drag and drop your samples again.

    ------------------------------------------------------------------------------------

    Basically, the sample flushing is staggered, but it wasn't 100% smooth/consistent. I analysed the output waveform and found difference in times between each byte flush, I've changed the order slightly, and now it's considerably smoother, this'll remove the "crinkly" sound you here a little bit.

    In addition, some emulators (like KEGA) as well as hardware had samples playing at a slightly higher pitch when one of the channels were resting, I'm not too sure though I suspect the Z80 accessing the window is slightly slower. And so, the null/mute sample that the channels will play when resting, will now be on the 68k side and accessed through the window instead. This will cost you $8000 bytes of ROM space. But it'll mean the pitch will also remain consistent now.

    I'll update the first post to include this update in a moment.
     
    FохConED likes this.
  16. EMK-20218

    EMK-20218 They call me as 'Eduardo Knuckles' Member

    Joined:
    Aug 8, 2008
    Messages:
    953
    Location:
    SEGA Land
    Well... I followed the guide instead of to download the source code with the stuff already applied and everything seems to work well. I just notice the amazing thing of the 07xx pointer I didn't expect to see when I opened it (of course... As you said, you added a extra channel instead of using a unused/etc channel and stuff for the extra DAC). I'm really impressed with what I see. But there's a little question I have. Will my MID2SMPS-based songs work with the converter you made which converted the original songs adding the extra DAC channel to them? I'm really having some interesting ideas of how to use the power of this new feature, but I'm in doubt of this.
     
  17. MarkeyJester

    MarkeyJester !%#@ Member

    Joined:
    Jun 27, 2009
    Messages:
    2,660
    The program will only "add" a second DAC channel, and create a null pointer for it, that's all. If your track is for example, a 5-FM 1-DAC 3-PSG track, it'll simply give it another DAC channel, and it'll make that second DAC channel point to F2 (stop).

    If you want to use that second DAC channel, you'll have to either, do it by hand in a hex editor, or, find a tool that'll make the track 2-DAC. The tool is only design to make "normal" single DAC tracks compatible with the sound driver, that's all. I cannot help you with MID2SMPS. I've never used it, nor am I the creator, and I don't have access to its source code, sorry. You will have to hunt down the respective creators of the tools you use.

    Ending on a more positive note though; I may have a way of avoiding quality loss caused by the FM channels writing YM2612 data, which means the BGM's FM channels as well as SFX using FM channels will no longer cause that irritating chopping in the sample quality. This'll take probably a few days to put together, but I'm confident it'll work, so we may end up with virtually 100% crystal clear playback, with SFX and the like playing simultaneously!
     
  18. EMK-20218

    EMK-20218 They call me as 'Eduardo Knuckles' Member

    Joined:
    Aug 8, 2008
    Messages:
    953
    Location:
    SEGA Land
    Alright. This info was all I needed for me to make my first test with it.

    And there it is. I did a little addition to the Marble Zone level song using this new feature of the driver. And frankly, I liked the result and everything seems to work pretty well. As for the people who want to use it, I have a suggestion I'll post here soon which can ease even more the life of the people who want to use it. Currently, there's the progress of my tests with the driver. I'm really impressed, man!


    The same thing in the VGM format
     
    Last edited: Dec 2, 2016
  19. MarkeyJester

    MarkeyJester !%#@ Member

    Joined:
    Jun 27, 2009
    Messages:
    2,660
    Right, I want you all to download THIS NEW ROM, and give it a whirl.

    This one attempts to avoid quality loss caused by the 68k needing to stop the Z80 for YM2612 FM operator writes, what it basically means is, even with the music's FM channels playing, and even with FM SFX playing, the DAC quality should remain clear, this was an issue that's present on emulation as well as hardware, so emulator users can test this for me too.

    There is one catch, but, I'm not going to tell you what it is yet, I want to see if any of you will even notice it. Because if you don't notice it, then it won't be a problem. So give it a play-through, and listen while you're playing, and give me your feedback on this. I still have something to fix on hardware, but since this can be tested by you guys on emulation, it shouldn't matter.

    This test is important.
     
    FохConED likes this.
  20. DevEd

    DevEd A lol who occasionally doge nothing Member

    Joined:
    Oct 12, 2012
    Messages:
    268
    Location:
    Somewhere...?
    In some cases, it seems like either the FM is lagging behind or the PCM is. I can't really tell which is the case.

    I'm also assuming the modification to the special stage music was intentional. If it wasn't, though...

    (Tested in Kega Fusion 3.64)