Wired all APU access to emulation layer. No sound yet :(

This commit is contained in:
Lucas Scharenbroich 2023-06-10 21:05:11 -05:00
parent ef581ab97b
commit 4f2c2aac0b
4 changed files with 758 additions and 97 deletions

View File

@ -81,6 +81,11 @@ FTblTmp equ 228
adc #$1FF ; Stack starts at the top of the page
sta ROMStk
; Initialize the sound hardware for APU emulation
jsr APUStartUp
; Start up GTE to drive the graphics
; brl :debug
lda #ENGINE_MODE_USER_TOOL ; Engine in Fast Mode as a User Tool
@ -192,15 +197,15 @@ EvtLoop
stz nmiCount
; sep #$20
; lda #1
; lda #7
; stal ROMBase+$075f
; stal ROMBase+$0766
; lda #2
; lda #3
; stal ROMBase+$0763
; stal ROMBase+$075c
; lda #$2
; lda #3
; stal ROMBase+$0767
; stal ROMBase+$0760
; rep #$30
@ -283,6 +288,7 @@ EvtLoop
Exit
_GTEShutDown
jsr APUShutDown
Quit
_QuitGS qtRec
qtRec adrl $0000
@ -1599,4 +1605,5 @@ Area3Palette dw $0F, $00, $30, $10, $00, $16, $17, $27, $1C, $36, $1D, $00,
WaterPalette dw $22, $00, $15, $12, $25, $3A, $1A, $0F, $30, $12, $27, $10, $16, $00, $16, $18
; Palette remapping
put pal_w11.s
put pal_w11.s
put apu.s

544
demos/smb/apu.s Normal file
View File

@ -0,0 +1,544 @@
; Init
sound_control = $3c ;really at $e1c03c
sound_data = $3d ;really at $e1c03d
sound_address = $3e ;really at $e1c03e
sound_interrupt_ptr = $e1002c
irq_volume = $e100ca
osc_interrupt = $e100cc
mx %10
access_doc_registers = *
ldal irq_volume
sta sound_control
rts
access_doc_ram = *
ldal irq_volume
ora #%0110_0000
sta sound_control
rts
access_doc_ram_no_inc = *
ldal irq_volume
ora #%0100_0000
sta sound_control
rts
mx %00
APUStartUp
sei
phd
pea $c000
pld
jsr copy_instruments_to_doc
; jsr setup_doc_registers
jsr setup_interrupt
pld
cli
rts
APUShutDown = *
sei
phd
lda #$c000
tcd
jsr stop_playing
lda backup_interrupt_ptr ; restore old interrupt ptr
stal sound_interrupt_ptr
lda backup_interrupt_ptr+2
stal sound_interrupt_ptr+2
cli
pld
clc
rts
stop_playing = *
ldy #7 ; Number of oscillators
sep #$20
mx %10
jsr access_doc_registers
lda #$a0 ; stop all oscillators in use
sta sound_address
lda #%11
]loop sta sound_data
inc sound_address
dey
bne ]loop
lda #$a0+interrupt_oscillator ; stop interrupt oscillator
sta sound_address
lda #3
sta sound_data
rep #$20
mx %00
rts
; Copy in 4 different square wave duty cycles and a triangle wave
copy_instruments_to_doc
jsr setup_docram
lda #$0100
jsr make_eigth_pulse
lda #$0200
jsr make_quarter_pulse
lda #$0300
jsr make_half_pulse
lda #$0400
jsr make_inv_quarter_pulse
lda #$0500
jsr copy_triangle
rts
;--------------------------
setup_docram
sep #$20
mx %10
jsr access_doc_ram
stz sound_address
lda #$80
ldx #256 ;make sure that page 00 has nonzero data for interrupt
:loop sta sound_data
dex
bne :loop
rep #$20
mx %00
rts
;--------------------------
make_eigth_pulse
ldy #32
jmp make_pulse
make_quarter_pulse
ldy #64
jmp make_pulse
make_half_pulse
ldy #128
jmp make_pulse
make_inv_quarter_pulse
ldy #192
jmp make_pulse
make_pulse
sep #$30
mx %11
stz sound_address
xba
sta sound_address+1
ldx #0
:loop1
lda #$01
sta sound_data
inx
dey
bne :loop1
:loop2
lda #$FF
sta sound_data
inx
bne :loop2
rep #$30
mx %00
rts
copy_triangle
sep #$30
mx %11
stz sound_address
xba
sta sound_address+1
ldx #0
:loop
lda triangle_wave,x
sta sound_data
inx
bne :loop
rep #$30
mx %00
rts
;--------------------------
triangle_wave
hex 80828486888a8c8e90929496989a9c9e
hex a0a2a4a6a8aaacaeb0b2b4b6b8babcbe
hex c0c1c3c5c7c9cbcdcfd1d3d5d7d9dbdd
hex dfe1e3e5e7e9ebedeff1f3f5f7f9fbfd
hex fffdfbf9f7f5f3f1efedebe9e7e5e3e1
hex dfdddbd9d7d5d3d1cfcdcbc9c7c5c3c1
hex c0bebcbab8b6b4b2b0aeacaaa8a6a4a2
hex a09e9c9a98969492908e8c8a88868482
hex 807e7c7a78767472706e6c6a68666462
hex 605e5c5a58565452504e4c4a48464442
hex 413f3d3b39373533312f2d2b29272523
hex 211f1d1b19171513110f0d0b09070503
hex 01030507090b0d0f11131517191b1d1f
hex 21232527292b2d2f31333537393b3d3f
hex 41424446484a4c4e50525456585a5c5e
hex 60626466686a6c6e70727476787a7c7e
;--------------------------
setup_doc_registers
sep #$20
mx %10
jsr access_doc_registers
rep #$20
mx %00
rts
;--------------------------
setup_interrupt = *
ldal sound_interrupt_ptr
sta backup_interrupt_ptr
ldal sound_interrupt_ptr+2
sta backup_interrupt_ptr+2
lda #$5c
stal sound_interrupt_ptr
phk
phk
pla
stal sound_interrupt_ptr+2
lda #interrupt_handler
stal sound_interrupt_ptr+1
sep #$20
mx %10
jsr access_doc_registers
ldy #0
]loop lda timer_sound_settings,y ; Set DOC registers for the interrupt oscillator
sta sound_address
iny
lda timer_sound_settings,y
sta sound_data
iny
cpy #7*2
bne ]loop
rep #$20
mx %00
rts
interrupt_oscillator = 31
reference_freq = 1195 ; interrupt frequence (240Hz)
timer_sound_settings = * ; set up oscillator 30 for interrupts
dfb $00+interrupt_oscillator,reference_freq ; frequency low register
dfb $20+interrupt_oscillator,reference_freq/256 ; frequency high register
dfb $40+interrupt_oscillator,0 ; volume register, volume = 0
dfb $80+interrupt_oscillator,0 ; wavetable pointer register, point to 0
dfb $c0+interrupt_oscillator,0 ; wavetable size register, 256 byte length
dfb $e1,$3e ; oscillator enable register
dfb $a0+interrupt_oscillator,$08 ; mode register, set to free run
pulse1_oscillator = 0
pulse2_oscillator = 2
triangle_oscillator = 4
default_freq = 16384
pulse1_sound_settings = *
dfb $00+pulse1_oscillator,default_freq ; frequency low register
dfb $20+pulse1_oscillator,default_freq/256 ; frequency high register
dfb $40+pulse1_oscillator,0 ; volume register, volume = 0
dfb $80+pulse1_oscillator,3 ; wavetable pointer register, point to $0300 by default (50% duty cycle)
dfb $c0+pulse1_oscillator,0 ; wavetable size register, 256 byte length
dfb $a0+pulse1_oscillator,0 ; mode register, set to free run
pulse2_sound_settings = *
dfb $00+pulse2_oscillator,default_freq ; frequency low register
dfb $20+pulse2_oscillator,default_freq/256 ; frequency high register
dfb $40+pulse2_oscillator,0 ; volume register, volume = 0
dfb $80+pulse2_oscillator,3 ; wavetable pointer register, point to $0300 by default (50% duty cycle)
dfb $c0+pulse2_oscillator,0 ; wavetable size register, 256 byte length
dfb $a0+pulse2_oscillator,0 ; mode register, set to free run
triangle_sound_settings = *
dfb $00+triangle_oscillator,default_freq ; frequency low register
dfb $20+triangle_oscillator,default_freq/256 ; frequency high register
dfb $40+triangle_oscillator,0 ; volume register, volume = 0
dfb $80+triangle_oscillator,5 ; wavetable pointer register, point to $0500
dfb $c0+triangle_oscillator,0 ; wavetable size register, 256 byte length
dfb $a0+triangle_oscillator,0 ; mode register, set to free run
backup_interrupt_ptr ds 4
;-----------------------------------------------------------------------------------------
; interupt handler
;-----------------------------------------------------------------------------------------
interrupt_handler = *
phb
phd
phk
plb
clc
xce
rep #$30
mx %00
lda #$c000
tcd
sep #$20
mx %10
jsr access_doc_registers
ldal osc_interrupt ; which oscillator generated the interrupt?
interrupt_handler_loop
and #%00111110
lsr
cmp #interrupt_oscillator
bne :not_timer ; Only service timer interrupts
; Set the parameters for the first square wave channel
lda APU_PULSE1_REG1 ; Get the cycle duty bits
rol
rol
rol
and #$03
tax
lda #$80+pulse1_oscillator
sta sound_address
lda duty_cycle_page,x
sta sound_data
lda APU_PULSE1_REG1 ; Get the volume
and #$0F
asl
asl
asl
asl
tax
lda #$40+pulse1_oscillator
sta sound_address
txa
sta sound_data
rep #$30
mx %00
lda APU_PULSE1_REG3
and #$07FF ; Load the timer value (11-bits); freq = 1.79MHz / (16 * (t - 1)) = 111860Hz / (t-1)
dec
lsr ; Divide top and bottom by 2 -- 55930 / ((t - 1)/2)
sta divisor
lda #55930
sta dividend
lda #0
ldx #10 ; 10 bits of division
asl dividend
:dl1 rol
cmp divisor
bcc :dl2
sbc divisor
:dl2 rol dividend
dex
bne :dl1
lda dividend
and #$3FF ; This is the NES APU frequence in hertz
sta dividend
asl
asl
adc dividend ; multiple by 5 to get the approx DOC value (0.2Hz per)
sta dividend
sep #$20
mx %10
lda #$00+pulse1_oscillator
sta sound_address
lda dividend
sta sound_data
lda #$20+pulse1_oscillator
sta sound_address
lda dividend+1
sta sound_data
; lda border_color
; inc
; and #$03
; sta border_color
; jsr setborder
:not_timer
sep #$30
pld
plb
clc
rtl
duty_cycle_page dfb $01,$02,$03,$04 ; Page of DOC RAM that holds the different duty cycle wavforms
border_color dw 0
dividend dw 0
divisor dw 0
; 8-bit mode
; A = register number
; X = register value
mx %00
SetDOCReg
stal $E0C03E
txa
stal $E0C03D
rts
_SetDOCReg mac
lda ]1 ; Select the oscillator enable registers
ldx ]2
jsr SetDOCReg
<<<
; Pulse Channel 1
APU_PULSE1
APU_PULSE1_REG1 ds 1 ; DDLC NNNN - Duty, loop envelope/disable length counter, constant volume, envelope period/volume
APU_PULSE1_REG2 ds 1 ; EPPP NSSS - Sweep unit: enabled, period, negative, shift count
APU_PULSE1_REG3 ds 1 ; LLLL LLLL - Timer Low
APU_PULSE1_REG4 ds 1 ; llll lHHH - Length counter load, timer high (also resets duty and starts envelope)
APU_PULSE2
APU_PULSE2_REG1 ds 1 ; DDLC NNNN - Duty, loop envelope/disable length counter, constant volume, envelope period/volume
APU_PULSE2_REG2 ds 1 ; EPPP NSSS - Sweep unit: enabled, period, negative, shift count
APU_PULSE2_REG3 ds 1 ; LLLL LLLL - Timer Low
APU_PULSE2_REG4 ds 1 ; llll lHHH - Length counter load, timer high (also resets duty and starts envelope)
APU_TRIANGLE
APU_TRIANGLE_REG1 ds 1 ; DDLC NNNN - Duty, loop envelope/disable length counter, constant volume, envelope period/volume
APU_TRIANGLE_REG2 ds 1 ; EPPP NSSS - Sweep unit: enabled, period, negative, shift count
APU_TRIANGLE_REG3 ds 1 ; LLLL LLLL - Timer Low
APU_TRIANGLE_REG4 ds 1 ; llll lHHH - Length counter load, timer high (also resets duty and starts envelope)
APU_STATUS ds 1
mx %11
APU_PULSE1_REG1_WRITE ENT
stal APU_PULSE1_REG1
rtl
APU_PULSE1_REG2_WRITE ENT
stal APU_PULSE1_REG2
rtl
APU_PULSE1_REG3_WRITE ENT
stal APU_PULSE1_REG3
rtl
APU_PULSE1_REG4_WRITE ENT
stal APU_PULSE1_REG4
rtl
APU_PULSE2_REG1_WRITE ENT
stal APU_PULSE2_REG1
rtl
APU_PULSE2_REG2_WRITE ENT
stal APU_PULSE2_REG2
rtl
APU_PULSE2_REG3_WRITE ENT
stal APU_PULSE2_REG3
rtl
APU_PULSE2_REG4_WRITE ENT
stal APU_PULSE2_REG4
rtl
APU_TRIANGLE_REG1_WRITE ENT
stal APU_TRIANGLE_REG1
rtl
APU_TRIANGLE_REG2_WRITE ENT
stal APU_TRIANGLE_REG2
rtl
APU_TRIANGLE_REG3_WRITE ENT
stal APU_TRIANGLE_REG3
rtl
APU_TRIANGLE_REG4_WRITE ENT
stal APU_TRIANGLE_REG4
rtl
APU_STATUS_WRITE ENT
stal APU_STATUS
pha
; Pulse 1 is OSC 0
bit #$01
beq :pulse1_off
_SetDOCReg #$40+pulse1_oscillator;#128
bra :pulse1_end
:pulse1_off
_SetDOCReg #$40+pulse1_oscillator;#0
:pulse1_end
; Pulse 2 is OSC 2
bit #$02
beq :pulse2_off
_SetDOCReg #$40+pulse2_oscillator;#128
bra :pulse2_end
:pulse2_off
_SetDOCReg #$40+pulse2_oscillator;#0
:pulse2_end
; Triangle is OSC 4
bit #$03
beq :triangle_off
_SetDOCReg #$40+triangle_oscillator;#128
bra :triangle_end
:triangle_off
_SetDOCReg #$40+triangle_oscillator;#0
:triangle_end
pla
rtl

View File

@ -606,6 +606,7 @@ y_offset_rows equ 2
y_height_rows equ 25
y_offset equ {y_offset_rows*8}
y_height equ {y_height_rows*8}
max_nes_y equ {y_height+y_offset-8}
x_offset equ 16
@ -628,7 +629,7 @@ scanOAMSprites
:loop
lda PPU_OAM,x ; Y-coordinate
cmp #y_height+y_offset-9
cmp #max_nes_y+1 ; Skip anything that is beyond this lint
bcs :skip
cmp #y_offset
bcc :skip
@ -648,38 +649,7 @@ scanOAMSprites
sta OAM_COPY+2,y
sep #$20
* ; Debug OAM values
* phy
* phx
* rep #$30
* ldx Tmp5
* cpx #{160*190}
* bcs :nodraw
* lda OAM_COPY+2,y
* pha
* lda OAM_COPY,y
* ldy #$FFFF
* jsr DrawWord
* lda Tmp5
* clc
* adc #128+16
* tax
* ldy #$FFFF
* pla
* jsr DrawWord
* lda Tmp5
* clc
* adc #8*160
* sta Tmp5
* :nodraw
* sep #$30
* plx
* ply
jsr debug_values
iny
iny
@ -697,6 +667,54 @@ scanOAMSprites
rep #$30
rts
debug_values
; Debug APU values
phy
phx
rep #$30
ldx #0
ldy #$FFFF
lda APU_STATUS
and #$00FF
jsr DrawWord
ldx #8*160
ldy #$FFFF
lda APU_PULSE1_REG1
jsr DrawWord
ldx #16*160
ldy #$FFFF
lda APU_PULSE1_REG3
jsr DrawWord
ldx #24*160
ldy #$FFFF
lda APU_PULSE2_REG1
jsr DrawWord
ldx #32*160
ldy #$FFFF
lda APU_PULSE2_REG3
jsr DrawWord
ldx #40*160
ldy #$FFFF
lda APU_TRIANGLE_REG1
jsr DrawWord
ldx #48*160
ldy #$FFFF
lda APU_TRIANGLE_REG3
jsr DrawWord
sep #$30
plx
ply
rts
; Screen is 200 lines tall. It's worth it be exact when building the list because one extra
; draw + shadow sequence takes at least 1,000 cycles.
shadowBitmap ds 32 ; Provide enough space for the full ppu range (240 lines) + 16 since the y coordinate can be off-screen
@ -728,7 +746,8 @@ buildShadowBitmap
; ldy PPU_OAM,x
ldy OAM_COPY,x
iny ; This is the y-coordinate of the top of the sprite
cpy #max_nes_y ; Don't increment something right on the edge (allows )
; iny ; This is the y-coordinate of the top of the sprite
ldx y2idx,y ; Get the index into the shadowBitmap array for this y coordinate (y -> blk_y)
lda y2low,y ; Get the bit pattern for the first byte
@ -1124,7 +1143,7 @@ oam_loop
phx ; Save x
lda OAM_COPY,x ; Y-coordinate
inc ; Compensate for PPU delayed scanline
; inc ; Compensate for PPU delayed scanline
rep #$30
and #$00FF

View File

@ -682,10 +682,20 @@ PPUDATA_READ EXT
PPUDATA_WRITE EXT
PPUDMA_WRITE EXT
APU_PUSLE1_REG1_WRITE EXT
APU_PUSLE1_REG2_WRITE EXT
APU_PUSLE1_REG3_WRITE EXT
APU_PUSLE1_REG4_WRITE EXT
APU_PULSE1_REG1_WRITE EXT
APU_PULSE1_REG2_WRITE EXT
APU_PULSE1_REG3_WRITE EXT
APU_PULSE1_REG4_WRITE EXT
APU_PULSE2_REG1_WRITE EXT
APU_PULSE2_REG2_WRITE EXT
APU_PULSE2_REG3_WRITE EXT
APU_PULSE2_REG4_WRITE EXT
APU_TRIANGLE_REG1_WRITE EXT
APU_TRIANGLE_REG2_WRITE EXT
APU_TRIANGLE_REG3_WRITE EXT
APU_TRIANGLE_REG4_WRITE EXT
APU_STATUS_WRITE EXT
ROMBase ENT
ds $7A00
@ -720,36 +730,80 @@ APU_IND_X_REG4_W
dw APU_TRIANGLE_REG4_W,APU_TRIANGLE_REG4_W
APU_PULSE1_REG1_W
; jsl APU_PULSE1_REG1_WRITE
jsl APU_PULSE1_REG1_WRITE
rts
APU_PULSE1_REG1_WX
; jsl APU_PULSE1_REG1_WRITE
pha
txa
jsl APU_PULSE1_REG1_WRITE
pla
rts
APU_PULSE1_REG2_W
; jsl APU_PULSE1_REG2_WRITE
jsl APU_PULSE1_REG2_WRITE
rts
APU_PULSE1_REG2_WY
; jsl APU_PULSE1_REG2_WRITE
pha
tya
jsl APU_PULSE1_REG2_WRITE
pla
rts
APU_PULSE1_REG3_W
; jsl APU_PULSE1_REG3_WRITE
jsl APU_PULSE1_REG3_WRITE
rts
APU_PULSE1_REG4_W
; jsl APU_PULSE1_REG4_WRITE
jsl APU_PULSE1_REG4_WRITE
rts
APU_PULSE2_REG1_W
jsl APU_PULSE2_REG1_WRITE
rts
APU_PULSE2_REG1_WX
pha
txa
jsl APU_PULSE2_REG1_WRITE
pla
rts
APU_PULSE2_REG2_W
jsl APU_PULSE2_REG2_WRITE
rts
APU_PULSE2_REG2_WY
pha
tya
jsl APU_PULSE2_REG2_WRITE
pla
rts
APU_PULSE2_REG2_WX
pha
txa
jsl APU_PULSE2_REG2_WRITE
pla
rts
APU_PULSE2_REG3_W
; jsl APU_PUSLE2_REG3_WRITE
jsl APU_PULSE2_REG3_WRITE
rts
APU_PULSE2_REG4_W
; jsl APU_PULSE2_REG4_WRITE
jsl APU_PULSE2_REG4_WRITE
rts
APU_TRIANGLE_REG1_W
jsl APU_TRIANGLE_REG1_WRITE
rts
APU_TRIANGLE_REG2_W
jsl APU_TRIANGLE_REG2_WRITE
rts
APU_TRIANGLE_REG3_W
; jsl APU_TRIANGLE_REG3_WRITE
jsl APU_TRIANGLE_REG3_WRITE
rts
APU_TRIANGLE_REG4_W
; jsl APU_TRIANGLE_REG4_WRITE
jsl APU_TRIANGLE_REG4_WRITE
rts
APU_STATUS_W
jsl APU_STATUS_WRITE
rts
APU_STATUS_WX
phx
jsl APU_STATUS_WRITE
plx
rts
; Hooks to call back to the GTE harness for PPU memory-mapped accesses
mx %11
@ -827,7 +881,8 @@ ColdBoot jsr InitializeMemory ;clear memory using pointer in Y
sta WarmBootValidation
sta PseudoRandomBitReg ;set seed for pseudorandom register
lda #%00001111
sta SND_MASTERCTRL_REG ;enable all sound channels except dmc
; sta SND_MASTERCTRL_REG ;enable all sound channels except dmc
jsr APU_STATUS_W
lda #%00000110
jsr PPU_MASK_W ;turn off clipping for OAM and background
jsr MoveAllSpritesOffscreen
@ -875,7 +930,7 @@ NonMaskableInterrupt ENT
bne ScreenOff ;if set, used bits as-is
lda Mirror_PPU_CTRL_REG2 ;otherwise reenable bits and save them
ora #%00011110
ScreenOff sta Mirror_PPU_CTRL_REG2 ;save bits for later but not in register at the moment
ScreenOff sta Mirror_PPU_CTRL_REG2 ;save bits for later but not in register at the moment
and #%11100111 ;disable screen for now
jsr PPU_MASK_W
jsr PPU_STATUS_RX ;reset flip-flop and reset scroll registers to zero
@ -895,14 +950,14 @@ ScreenOff sta Mirror_PPU_CTRL_REG2 ;save bits for later but not in register
cpx #$06
bne InitBuffer
iny ;get offset based on usage
InitBuffer ldx VRAM_Buffer_Offset,y
InitBuffer ldx VRAM_Buffer_Offset,y
lda #$00 ;clear buffer header at last location
sta VRAM_Buffer1_Offset,x
sta VRAM_Buffer1,x
sta VRAM_Buffer_AddrCtrl ;reinit address control to $0301
lda Mirror_PPU_CTRL_REG2 ;copy mirror of $2001 to register
jsr PPU_MASK_W
; jsr SoundEngine ;play sound
jsr SoundEngine ;play sound
jsr ReadJoypads ;read joypads
jsr PauseRoutine ;handle pause
jsr UpdateTopScore
@ -15573,30 +15628,34 @@ SetHFAt ora $04 ;add other OAM attributes if necessary
SoundEngine
lda OperMode ;are we in title screen mode?
bne SndOn
sta SND_MASTERCTRL_REG ;if so, disable sound and leave
; sta SND_MASTERCTRL_REG ;if so, disable sound and leave
jsr APU_STATUS_W
rts
SndOn lda #$ff
SndOn lda #$ff
sta JOYPAD_PORT2 ;disable irqs and set frame counter mode???
lda #$0f
sta SND_MASTERCTRL_REG ;enable first four channels
; sta SND_MASTERCTRL_REG ;enable first four channels
jsr APU_STATUS_W
lda PauseModeFlag ;is sound already in pause mode?
bne InPause
lda PauseSoundQueue ;if not, check pause sfx queue
cmp #$01
bne RunSoundSubroutines ;if queue is empty, skip pause mode routine
InPause lda PauseSoundBuffer ;check pause sfx buffer
InPause lda PauseSoundBuffer ;check pause sfx buffer
bne ContPau
lda PauseSoundQueue ;check pause queue
beq SkipSoundSubroutines
sta PauseSoundBuffer ;if queue full, store in buffer and activate
sta PauseModeFlag ;pause mode to interrupt game sounds
lda #$00 ;disable sound and clear sfx buffers
sta SND_MASTERCTRL_REG
; sta SND_MASTERCTRL_REG
jsr APU_STATUS_W
sta Square1SoundBuffer
sta Square2SoundBuffer
sta NoiseSoundBuffer
lda #$0f
sta SND_MASTERCTRL_REG ;enable sound again
; sta SND_MASTERCTRL_REG ;enable sound again
jsr APU_STATUS_W
lda #$2a ;store length of sound in pause counter
sta Squ1_SfxLenCounter
PTone1F lda #$44 ;play first tone
@ -15615,7 +15674,8 @@ PTRegC ldx #$84
DecPauC dec Squ1_SfxLenCounter ;decrement pause sfx counter
bne SkipSoundSubroutines
lda #$00 ;disable sound if in pause mode and
sta SND_MASTERCTRL_REG ;not currently playing the pause sfx
; sta SND_MASTERCTRL_REG ;not currently playing the pause sfx
jsr APU_STATUS_W
lda PauseSoundBuffer ;if no longer playing pause sfx, check to see
cmp #$02 ;if we need to be playing sound again
bne SkipPIn
@ -15656,8 +15716,10 @@ StrWave sty SND_DELTA_REG+1 ;store into DMC load register (??)
;--------------------------------
Dump_Squ1_Regs
sty SND_SQUARE1_REG+1 ;dump the contents of X and Y into square 1's control regs
stx SND_SQUARE1_REG
; sty SND_SQUARE1_REG+1 ;dump the contents of X and Y into square 1's control regs
; stx SND_SQUARE1_REG
jsr APU_PULSE1_REG2_WY
jsr APU_PULSE1_REG1_WX
rts
PlaySqu1Sfx
@ -15670,15 +15732,19 @@ Dump_Freq_Regs
tay
lda FreqRegLookupTbl+1,y ;use previous contents of A for sound reg offset
beq NoTone ;if zero, then do not load
sta SND_REGISTER+2,x ;first byte goes into LSB of frequency divider
; sta SND_REGISTER+2,x ;first byte goes into LSB of frequency divider
jsr APU_IND_X_REG3_W
lda FreqRegLookupTbl,y ;second byte goes into 3 MSB plus extra bit for
ora #%00001000 ;length counter
sta SND_REGISTER+3,x
; sta SND_REGISTER+3,x
jsr APU_IND_X_REG4_W
NoTone rts
Dump_Sq2_Regs
stx SND_SQUARE2_REG ;dump the contents of X and Y into square 2's control regs
sty SND_SQUARE2_REG+1
; stx SND_SQUARE2_REG ;dump the contents of X and Y into square 2's control regs
; sty SND_SQUARE2_REG+1
jsr APU_PULSE2_REG1_WX
jsr APU_PULSE2_REG2_WY
rts
PlaySqu2Sfx
@ -15752,7 +15818,8 @@ ContinueBumpThrow
cmp #$06
bne DecJpFPS
lda #$bb ;load second part directly
sta SND_SQUARE1_REG+1
; sta SND_SQUARE1_REG+1
jsr APU_PULSE1_REG2_W
DecJpFPS bne BranchToDecLength1 ;unconditional branch
@ -15807,11 +15874,13 @@ PlaySwimStomp
ContinueSwimStomp
ldy Squ1_SfxLenCounter ;look up reg contents in data section based on
lda SwimStompEnvelopeData-1,y ;length of sound left, used to control sound's
sta SND_SQUARE1_REG ;envelope
; sta SND_SQUARE1_REG ;envelope
jsr APU_PULSE1_REG1_W
cpy #$06
bne BranchToDecLength1
lda #$9e ;when the length counts down to a certain point, put this
sta SND_SQUARE1_REG+2 ;directly into the LSB of square 1's frequency divider
; sta SND_SQUARE1_REG+2 ;directly into the LSB of square 1's frequency divider
jsr APU_PULSE1_REG3_W
BranchToDecLength1
bne DecrementSfx1Length ;unconditional branch (regardless of how we got here)
@ -15830,11 +15899,13 @@ ContinueSmackEnemy
cpy #$08
bne SmSpc
lda #$a0 ;if we're at the about-halfway point, make the second tone
sta SND_SQUARE1_REG+2 ;in the smack enemy sound
; sta SND_SQUARE1_REG+2 ;in the smack enemy sound
jsr APU_PULSE1_REG3_W
lda #$9f
bne SmTick
SmSpc lda #$90 ;this creates spaces in the sound, giving it its distinct noise
SmTick sta SND_SQUARE1_REG
SmSpc lda #$90 ;this creates spaces in the sound, giving it its distinct noise
;SmTick sta SND_SQUARE1_REG
SmTick jsr APU_PULSE1_REG1_W
DecrementSfx1Length
dec Squ1_SfxLenCounter ;decrement length of sfx
@ -15844,9 +15915,11 @@ StopSquare1Sfx
ldx #$00 ;if end of sfx reached, clear buffer
stx $f1 ;and stop making the sfx
ldx #$0e
stx SND_MASTERCTRL_REG
; stx SND_MASTERCTRL_REG
jsr APU_STATUS_WX
ldx #$0f
stx SND_MASTERCTRL_REG
; stx SND_MASTERCTRL_REG
jsr APU_STATUS_WX
ExSfx1 rts
PlayPipeDownInj
@ -15906,7 +15979,8 @@ ContinueCGrabTTick
cmp #$30 ;timer tick sound also executes this, not sure why
bne N2Tone
lda #$54 ;if so, load the tone directly into the reg
sta SND_SQUARE2_REG+2
; sta SND_SQUARE2_REG+2
jsr APU_PULSE2_REG3_W
N2Tone bne DecrementSfx2Length
PlayBlast
@ -15950,9 +16024,11 @@ EmptySfx2Buffer
StopSquare2Sfx
ldx #$0d ;stop playing the sfx
stx SND_MASTERCTRL_REG
; stx SND_MASTERCTRL_REG
jsr APU_STATUS_WX
ldx #$0f
stx SND_MASTERCTRL_REG
; stx SND_MASTERCTRL_REG
jsr APU_STATUS_WX
ExSfx2 rts
Square2SfxHandler
@ -16047,7 +16123,8 @@ PlayGrowVine
GrowItemRegs
sta Squ2_SfxLenCounter
lda #$7f ;load contents of reg for both sounds directly
sta SND_SQUARE2_REG+1
; sta SND_SQUARE2_REG+1
jsr APU_PULSE2_REG2_W
lda #$00 ;start secondary counter for both sounds
sta Sfx_SecondaryCounter
@ -16059,7 +16136,8 @@ ContinueGrowItems
cpy Squ2_SfxLenCounter ;have we reached the end yet?
beq StopGrowItems ;if so, branch to jump, and stop playing sounds
lda #$9d ;load contents of other reg directly
sta SND_SQUARE2_REG
; sta SND_SQUARE2_REG
jsr APU_PULSE2_REG1_W
lda PUp_VGrow_FreqData,y ;use secondary counter / 2 as offset for frequency regs
jsr SetFreq_Squ2
rts
@ -16216,9 +16294,11 @@ LoadHeader
sta MusicOffset_Square2
sta AltRegContentFlag ;initialize alternate control reg data used by square 1
lda #$0b ;disable triangle channel and reenable it
sta SND_MASTERCTRL_REG
; sta SND_MASTERCTRL_REG
jsr APU_STATUS_W
lda #$0f
sta SND_MASTERCTRL_REG
; sta SND_MASTERCTRL_REG
jsr APU_STATUS_W
HandleSquare2Music
dec Squ2_NoteLenCounter ;decrement square 2 note length
@ -16244,10 +16324,13 @@ NotTRO and #VictoryMusic ;check for victory music (the only secondary tha
lda #$00 ;clear primary and secondary buffers and initialize
sta AreaMusicBuffer ;control regs of square and triangle channels
sta EventMusicBuffer
sta SND_TRIANGLE_REG
; sta SND_TRIANGLE_REG
jsr APU_TRIANGLE_REG1_W
lda #$90
sta SND_SQUARE1_REG
sta SND_SQUARE2_REG
; sta SND_SQUARE1_REG
; sta SND_SQUARE2_REG
jsr APU_PULSE1_REG1_W
jsr APU_PULSE2_REG1_W
rts
MusicLoopBack
@ -16284,9 +16367,11 @@ MiscSqu2MusicTasks
beq NoDecEnv1
dec Squ2_EnvelopeDataCtrl ;decrement unless already zero
NoDecEnv1 jsr LoadEnvelopeData ;do a load of envelope data to replace default
sta SND_SQUARE2_REG ;based on offset set by first load unless playing
; sta SND_SQUARE2_REG ;based on offset set by first load unless playing
jsr APU_PULSE2_REG1_W
ldx #$7f ;death music or d4 set on secondary buffer
stx SND_SQUARE2_REG+1
; stx SND_SQUARE2_REG+1
jsr APU_PULSE2_REG2_WX
HandleSquare1Music
ldy MusicOffset_Square1 ;is there a nonzero offset here?
@ -16300,9 +16385,11 @@ FetchSqu1MusicData
lda (MusicData),y
bne Squ1NoteHandler ;if nonzero, then skip this part
lda #$83
sta SND_SQUARE1_REG ;store some data into control regs for square 1
; sta SND_SQUARE1_REG ;store some data into control regs for square 1
jsr APU_PULSE1_REG1_W
lda #$94 ;and fetch another byte of data, used to give
sta SND_SQUARE1_REG+1 ;death music its unique sound
; sta SND_SQUARE1_REG+1 ;death music its unique sound
jsr APU_PULSE1_REG2_W
sta AltRegContentFlag
bne FetchSqu1MusicData ;unconditional branch
@ -16329,11 +16416,13 @@ MiscSqu1MusicTasks
beq NoDecEnv2
dec Squ1_EnvelopeDataCtrl ;decrement unless already zero
NoDecEnv2 jsr LoadEnvelopeData ;do a load of envelope data
sta SND_SQUARE1_REG ;based on offset set by first load
; sta SND_SQUARE1_REG ;based on offset set by first load
jsr APU_PULSE1_REG1_W
DeathMAltReg lda AltRegContentFlag ;check for alternate control reg data
bne DoAltLoad
lda #$7f ;load this value if zero, the alternate value
DoAltLoad sta SND_SQUARE1_REG+1 ;if nonzero, and let's move on
;DoAltLoad sta SND_SQUARE1_REG+1 ;if nonzero, and let's move on
DoAltLoad jsr APU_PULSE1_REG2_W
HandleTriangleMusic
lda MusicOffset_Triangle
@ -16347,7 +16436,8 @@ HandleTriangleMusic
jsr ProcessLengthData ;otherwise, it is length data
sta Tri_NoteLenBuffer ;save contents of A
lda #$1f
sta SND_TRIANGLE_REG ;load some default data for triangle control reg
; sta SND_TRIANGLE_REG ;load some default data for triangle control reg
jsr APU_TRIANGLE_REG1_W
ldy MusicOffset_Triangle ;fetch another byte
inc MusicOffset_Triangle
lda (MusicData),y
@ -16375,8 +16465,9 @@ MediN lda #$1f ;secondary besides death and d4 except win cast
bne LoadTriCtrlReg ;a short note, and load value $ff if playing a long note on water, castle
LongN lda #$ff ;or any secondary (including win castle) except death and d4
LoadTriCtrlReg
sta SND_TRIANGLE_REG ;save final contents of A into control reg for triangle
LoadTriCtrlReg
; sta SND_TRIANGLE_REG ;save final contents of A into control reg for triangle
jsr APU_TRIANGLE_REG1_W
HandleNoiseMusic
lda AreaMusicBuffer ;check if playing underground or castle music