633 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			633 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
SECTION "Audio Interface", ROM0
 | 
						|
SoundSetup:
 | 
						|
  ld a, BANK(AudioEngineInit)
 | 
						|
  ld [rROMB0], a 
 | 
						|
  
 | 
						|
  ;ld de, gb_tarot_theme
 | 
						|
  call AudioEngineInit ; Play song
 | 
						|
 
 | 
						|
  ld a, [cvCardBank]
 | 
						|
  ld [rROMB0], a 
 | 
						|
  ret
 | 
						|
  
 | 
						|
SoundUpdate:
 | 
						|
  ld a, BANK(AudioEngineUpdate)
 | 
						|
  ld [rROMB0], a 
 | 
						|
  
 | 
						|
  ;call AudioEngineUpdate
 | 
						|
  
 | 
						|
  ld a, [cvCardBank]
 | 
						|
  ld [rROMB0], a 
 | 
						|
  ret
 | 
						|
 | 
						|
SECTION "Audio Variables", WRAM0[AUDIO_VARS_START]  
 | 
						|
ordersBank: db
 | 
						|
orders: dw
 | 
						|
 | 
						|
speed: db
 | 
						|
 | 
						|
readHead: dw
 | 
						|
 | 
						|
tick: db
 | 
						|
println "ticks are at ", tick
 | 
						|
row: db
 | 
						|
println "rows are at ", row
 | 
						|
order: db
 | 
						|
println "order index at ", order
 | 
						|
 | 
						|
; i've chosen to pack the variables for each instrument sequentially in memory
 | 
						|
; so all of channel 1's vars, then all of channel 2's vars, etc.
 | 
						|
; gbt-player instead packs all four notes together, then all four volumes,
 | 
						|
; then all four instruments. having thought about it more, gbt-player's approach
 | 
						|
; may be better - it makes indexing to a channel's value simpler. but i've
 | 
						|
; already written GetChannelAttributeAddress so it's neither here nor there
 | 
						|
; at this point.
 | 
						|
macro channel_vars
 | 
						|
  channel_\1:
 | 
						|
  ; inherents
 | 
						|
  channel_\1_note: db
 | 
						|
  channel_\1_volume: db
 | 
						|
  channel_\1_instrument: db
 | 
						|
  channel_\1_pan: db
 | 
						|
  ; special features!
 | 
						|
  channel_\1_arpeggio: db
 | 
						|
  channel_\1_vibrato: db
 | 
						|
  channel_\1_volume_slide: db
 | 
						|
  channel_\1_note_cut: db
 | 
						|
  
 | 
						|
  channel_\1_trigger: db
 | 
						|
endm
 | 
						|
 | 
						|
channel_vars 1
 | 
						|
channel_vars 2
 | 
						|
channel_vars 3
 | 
						|
channel_3_loaded_instrument: db
 | 
						|
channel_vars 4
 | 
						|
 | 
						|
SECTION "Audio Engine", ROMX
 | 
						|
 | 
						|
Periods:
 | 
						|
  DW    44,  156,  262,  363,  457,  547,  631,  710,  786,  854,  923,  986
 | 
						|
  DW  1046, 1102, 1155, 1205, 1253, 1297, 1339, 1379, 1417, 1452, 1486, 1517
 | 
						|
  DW  1546, 1575, 1602, 1627, 1650, 1673, 1694, 1714, 1732, 1750, 1767, 1783
 | 
						|
  DW  1798, 1812, 1825, 1837, 1849, 1860, 1871, 1881, 1890, 1899, 1907, 1915
 | 
						|
  DW  1923, 1930, 1936, 1943, 1949, 1954, 1959, 1964, 1969, 1974, 1978, 1982
 | 
						|
  DW  1985, 1988, 1992, 1995, 1998, 2001, 2004, 2006, 2009, 2011, 2013, 2015
 | 
						|
WaveSamples: ; 8 sounds, pilfered from gbt like so many things
 | 
						|
  DB $A5,$D7,$C9,$E1,$BC,$9A,$76,$31,$0C,$BA,$DE,$60,$1B,$CA,$03,$93 ; random
 | 
						|
  DB $F0,$E1,$D2,$C3,$B4,$A5,$96,$87,$78,$69,$5A,$4B,$3C,$2D,$1E,$0F
 | 
						|
  DB $FD,$EC,$DB,$CA,$B9,$A8,$97,$86,$79,$68,$57,$46,$35,$24,$13,$02 ; up-downs
 | 
						|
  DB $DE,$FE,$DC,$BA,$9A,$A9,$87,$77,$88,$87,$65,$56,$54,$32,$10,$12
 | 
						|
  DB $AB,$CD,$EF,$ED,$CB,$A0,$12,$3E,$DC,$BA,$BC,$DE,$FE,$DC,$32,$10 ; tri. broken
 | 
						|
  DB $FF,$EE,$DD,$CC,$BB,$AA,$99,$88,$77,$66,$55,$44,$33,$22,$11,$00 ; triangular
 | 
						|
  DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$00,$00,$00,$00,$00,$00,$00,$00 ; square
 | 
						|
  DB $79,$BC,$DE,$EF,$FF,$EE,$DC,$B9,$75,$43,$21,$10,$00,$11,$23,$45 ; sine
 | 
						|
NoiseOptions: ; 16 different ways to configure NR43 for different sounds
 | 
						|
; once again this method is from gbt. if you use the gbt sample# as an index into
 | 
						|
; this, it will match the gbt s3m template.
 | 
						|
    DB  $5F,$5B,$4B,$2F,$3B,$58,$1F,$0F ; 7 bit
 | 
						|
    DB  $90,$80,$70,$50,$00 ; 15 bit
 | 
						|
    DB  $67,$63,$53
 | 
						|
AudioEngineInit:
 | 
						|
  ld a, c
 | 
						|
  ld [ordersBank], a 
 | 
						|
  
 | 
						|
  ld a, e 
 | 
						|
  ld [orders], a
 | 
						|
  ld a, d 
 | 
						|
  ld [orders+1], a 
 | 
						|
  
 | 
						|
  ld a, 6
 | 
						|
  ld [speed], a
 | 
						|
  
 | 
						|
  ld a, $ff
 | 
						|
  ld [tick], a 
 | 
						|
  ld [row], a 
 | 
						|
  ld [order], a
 | 
						|
  
 | 
						|
  ld a, AUDENA_ON
 | 
						|
  ld [rNR52], a ; master audio enable
 | 
						|
  ld a, $ff
 | 
						|
  ld [rNR51], a ; panning
 | 
						|
  ld a, $ff
 | 
						|
  ld [rNR50], a ; stereo volume
 | 
						|
  
 | 
						|
  ld a, $ff
 | 
						|
  ld [channel_1_note_cut], a 
 | 
						|
  ld [channel_2_note_cut], a 
 | 
						|
  ld [channel_3_note_cut], a 
 | 
						|
  ld [channel_4_note_cut], a 
 | 
						|
  ld [channel_3_loaded_instrument], a 
 | 
						|
  ret
 | 
						|
 | 
						|
AudioEngineUpdate:
 | 
						|
  ld a, [ordersBank]
 | 
						|
  ;ld [rROMB0], a 
 | 
						|
  
 | 
						|
  call IncrementTick
 | 
						|
  ld a, [tick]
 | 
						|
  cp a, 0 
 | 
						|
  jp nz, .updateRegisters
 | 
						|
  call z, IncrementRow
 | 
						|
  
 | 
						|
  ld a, [row]
 | 
						|
  cp a, 0
 | 
						|
  call z, IncrementOrder
 | 
						|
  
 | 
						|
  ld a, [row]
 | 
						|
  cp a, 0
 | 
						|
  call z, hitit
 | 
						|
  
 | 
						|
  ld a, [row]
 | 
						|
  cp a, 0 
 | 
						|
  call z, FreshOrder
 | 
						|
 | 
						|
  call FreshRow
 | 
						|
.updateRegisters 
 | 
						|
  
 | 
						|
  call UpdateRegisters1
 | 
						|
  call UpdateRegisters2
 | 
						|
  call UpdateRegisters3
 | 
						|
  call UpdateRegisters4
 | 
						|
 | 
						|
  nop ; just throwiing this in here so i can break on it for timing
 | 
						|
  
 | 
						|
  ret
 | 
						|
hitit:
 | 
						|
  ret
 | 
						|
IncrementTick:
 | 
						|
  ld a, [speed]
 | 
						|
  ld b, a 
 | 
						|
  ld a, [tick]
 | 
						|
  inc a 
 | 
						|
  call ArrayClampLoopingB
 | 
						|
  ld [tick], a 
 | 
						|
  ret
 | 
						|
IncrementRow:
 | 
						|
  ld b, 64
 | 
						|
  ld a, [row]
 | 
						|
  inc a 
 | 
						|
  call ArrayClampLoopingB
 | 
						|
  ld [row], a 
 | 
						|
  ret
 | 
						|
IncrementOrder:
 | 
						|
  ld a, [orders]
 | 
						|
  ld l, a 
 | 
						|
  ld a, [orders+1]
 | 
						|
  ld h, a 
 | 
						|
  ld a, [order]
 | 
						|
  inc a 
 | 
						|
  call ArrayClampLooping
 | 
						|
  ld [order], a 
 | 
						|
  ret
 | 
						|
  
 | 
						|
FreshOrder:
 | 
						|
  ld a, [orders]
 | 
						|
  ld l, a 
 | 
						|
  ld a, [orders+1]
 | 
						|
  ld h, a 
 | 
						|
  inc hl
 | 
						|
  ld a, [order]
 | 
						|
  ld c, a 
 | 
						|
  ld b, 0 
 | 
						|
  
 | 
						|
  add hl, bc
 | 
						|
  add hl, bc 
 | 
						|
  ld b, h
 | 
						|
  ld c, l 
 | 
						|
  
 | 
						|
  ld a, [bc]
 | 
						|
  ld [readHead], a 
 | 
						|
  inc bc 
 | 
						|
  ld a, [bc]
 | 
						|
  ld [readHead+1], a 
 | 
						|
  
 | 
						|
  ret
 | 
						|
  
 | 
						|
FreshRow:
 | 
						|
  ld a, [readHead]
 | 
						|
  ld l, a 
 | 
						|
  ld a, [readHead+1]
 | 
						|
  ld h, a 
 | 
						|
  
 | 
						|
  ld a, [hl]
 | 
						|
  and a, $F0
 | 
						|
  cp a, 0 
 | 
						|
  ; this should always be zero.
 | 
						|
  
 | 
						|
  inc hl 
 | 
						|
  ld a, [row]
 | 
						|
  cp a, [hl]
 | 
						|
  
 | 
						|
  ret nz ; not ready for a fresh row until the current row matches the upcoming row
 | 
						|
  inc hl 
 | 
						|
  
 | 
						|
  ld e, l
 | 
						|
  ld a, l
 | 
						|
  ld [readHead], a
 | 
						|
  ld d, h
 | 
						|
  ld a, h
 | 
						|
  ld [readHead+1], a 
 | 
						|
  
 | 
						|
.examinePacket
 | 
						|
  ; de is our read head for the time being so we don't have to write
 | 
						|
  ; so many loads in and out of memory
 | 
						|
  ld a, [de]
 | 
						|
  and a, $F0
 | 
						|
  swap a 
 | 
						|
  ld hl, .packetJumpTable ; this all jumps based on what the top nibble is
 | 
						|
  ld c, a 
 | 
						|
  ld b, 0 
 | 
						|
  add hl, bc
 | 
						|
  add hl, bc 
 | 
						|
  ld c, [hl]
 | 
						|
  inc hl 
 | 
						|
  ld b, [hl]
 | 
						|
  ld l, c 
 | 
						|
  ld h, b
 | 
						|
  
 | 
						|
  jp hl
 | 
						|
.packetJumpTable
 | 
						|
  dw .newRow        ;$0x
 | 
						|
  dw .setNote       ;$1x
 | 
						|
  dw .setVolume     ;$2x
 | 
						|
  dw .setInstrument ;$3x
 | 
						|
  dw .setPan        ;$4x
 | 
						|
  dw .setArpeggio   ;$5x
 | 
						|
  dw .setVibrato    ;$6x
 | 
						|
  dw .setVolumeSlide;$7x
 | 
						|
  dw .setNoteCut    ;$8x
 | 
						|
  dw .jumpOrder     ;$90
 | 
						|
  dw .breakAndSetRow;$A0
 | 
						|
  dw .setSpeed      ;$B0
 | 
						|
  dw .callbackEvent ;$C0
 | 
						|
.newRow
 | 
						|
  ; if we find a new row, set the read head to that value and return
 | 
						|
  ld a, e 
 | 
						|
  ld [readHead], a 
 | 
						|
  ld a, d
 | 
						|
  ld [readHead+1], a 
 | 
						|
  ret 
 | 
						|
.setNote
 | 
						|
  call TriggerIt ; always trigger on notes
 | 
						|
  ld hl, channel_1_note - channel_1
 | 
						|
  jp .WriteAttributeButDoNotTrigger
 | 
						|
.setVolume
 | 
						|
  ld hl, channel_1_volume - channel_1
 | 
						|
  jp .WriteAttributeAndTriggerIfDifferent
 | 
						|
.setInstrument
 | 
						|
  ld hl, channel_1_instrument - channel_1
 | 
						|
  jp .WriteAttributeAndTriggerIfDifferent
 | 
						|
.setPan
 | 
						|
  ld hl, channel_1_pan - channel_1
 | 
						|
  jp .WriteAttributeButDoNotTrigger
 | 
						|
.setArpeggio
 | 
						|
  ld hl, channel_1_arpeggio - channel_1
 | 
						|
  jp .WriteAttributeAndTriggerIfDifferent
 | 
						|
.setVibrato
 | 
						|
  ld hl, channel_1_vibrato - channel_1
 | 
						|
  jp .WriteAttributeAndTriggerIfDifferent
 | 
						|
.setVolumeSlide
 | 
						|
  ld hl, channel_1_volume_slide - channel_1
 | 
						|
  jp .WriteAttributeAndTriggerIfDifferent
 | 
						|
.setNoteCut
 | 
						|
  ld hl, channel_1_note_cut - channel_1
 | 
						|
  jp .WriteAttributeButDoNotTrigger
 | 
						|
.jumpOrder
 | 
						|
  inc de
 | 
						|
  ld a, [de]
 | 
						|
  ld [order], a 
 | 
						|
  
 | 
						|
  ld a, 0
 | 
						|
  ld [row], a 
 | 
						|
  ld [tick], a 
 | 
						|
  
 | 
						|
  call FreshOrder
 | 
						|
  call FreshRow
 | 
						|
  ret
 | 
						|
.breakAndSetRow
 | 
						|
  inc de
 | 
						|
  
 | 
						|
  call IncrementOrder
 | 
						|
 | 
						|
  call FreshOrder
 | 
						|
  call FreshRow
 | 
						|
  ret
 | 
						|
.setSpeed
 | 
						|
  inc de
 | 
						|
  ld a, [de]
 | 
						|
  ld [speed], a 
 | 
						|
  inc de
 | 
						|
  jp .examinePacket
 | 
						|
.callbackEvent
 | 
						|
  ; todo, fall through
 | 
						|
.skipIt
 | 
						|
  inc de
 | 
						|
  inc de
 | 
						|
  jp .examinePacket
 | 
						|
  
 | 
						|
.WriteAttributeAndTriggerIfDifferent:
 | 
						|
  ; de points to a packet
 | 
						|
  ; hl holds an offset to an attribute (e.g. channel_1_volume - channel_1)
 | 
						|
  ld a, [de]
 | 
						|
  and a, $0F
 | 
						|
  call GetChannelAttributeAddress
 | 
						|
  push hl
 | 
						|
  
 | 
						|
  inc de
 | 
						|
  ld a, [de]
 | 
						|
  cp a, [hl]
 | 
						|
  call nz, TriggerBack
 | 
						|
  ld a, [de]
 | 
						|
  pop hl
 | 
						|
  ld [hl], a 
 | 
						|
  
 | 
						|
  inc de
 | 
						|
  jp .examinePacket
 | 
						|
 | 
						|
.WriteAttributeButDoNotTrigger:
 | 
						|
  ld a, [de]
 | 
						|
  and a, $0F
 | 
						|
  call GetChannelAttributeAddress
 | 
						|
  
 | 
						|
  inc de
 | 
						|
  ld a, [de]
 | 
						|
  ld [hl], a 
 | 
						|
  
 | 
						|
  inc de
 | 
						|
  jp .examinePacket
 | 
						|
 | 
						|
GetChannelAttributeAddress:
 | 
						|
  ; this is a weird one.
 | 
						|
  ; a should have the channel number (1, 2, 3, 4)
 | 
						|
  ; hl shoulld have an offset into a channel attribute (like channel_1_note - channel_1)
 | 
						|
  ; htis will fetch into hl that attribute's address on that channel.
 | 
						|
  push hl 
 | 
						|
  ld hl, .beginningsOfNoteData
 | 
						|
  ld b, 0 
 | 
						|
  ld c, a 
 | 
						|
  add hl, bc
 | 
						|
  add hl, bc
 | 
						|
  ld c, [hl]
 | 
						|
  inc hl 
 | 
						|
  ld b, [hl]
 | 
						|
  pop hl
 | 
						|
  add hl, bc
 | 
						|
  ret
 | 
						|
 
 | 
						|
.beginningsOfNoteData
 | 
						|
  dw 0
 | 
						|
  dw channel_1
 | 
						|
  dw channel_2
 | 
						|
  dw channel_3
 | 
						|
  dw channel_4
 | 
						|
  
 | 
						|
TriggerBack:
 | 
						|
  ; de points to an address. get the low nibble one address previous, 
 | 
						|
  ; take as a channel number, and write 1 to the corresponding channel_1_trigger
 | 
						|
  ; address
 | 
						|
  dec de
 | 
						|
  call TriggerIt
 | 
						|
  inc de
 | 
						|
  ret
 | 
						|
  
 | 
						|
TriggerIt:
 | 
						|
  ld a, [de]
 | 
						|
  and a, $0F
 | 
						|
  ld hl, channel_1_trigger - channel_1
 | 
						|
  call GetChannelAttributeAddress
 | 
						|
  ld [hl], 1 
 | 
						|
  ret
 | 
						|
 | 
						|
UpdateRegisters1:
 | 
						|
  ld a, [tick]
 | 
						|
  ld b, a 
 | 
						|
  ld a, [channel_1_note_cut]
 | 
						|
  cp a, b
 | 
						|
  jp nz, :+
 | 
						|
  ld a, 0 
 | 
						|
  ld [channel_1_volume], a
 | 
						|
  
 | 
						|
  cpl 
 | 
						|
  ld [channel_1_trigger], a 
 | 
						|
  
 | 
						|
  ld a, $ff
 | 
						|
  ld [channel_1_note_cut], a
 | 
						|
:
 | 
						|
  ld a, [channel_1_trigger]
 | 
						|
  cp a, 0
 | 
						|
  ret z
 | 
						|
  
 | 
						|
  ld a, 0 
 | 
						|
  ld [rNR10], a 
 | 
						|
  
 | 
						|
  
 | 
						|
  ld a, [channel_1_instrument]
 | 
						|
  ld [rNR11], a 
 | 
						|
  
 | 
						|
  
 | 
						|
  ld a, [channel_1_volume]
 | 
						|
  swap a
 | 
						|
  and a, $70
 | 
						|
  ld [rNR12], a 
 | 
						|
 | 
						|
  ld a, [channel_1_note]
 | 
						|
  ld b, 0 
 | 
						|
  ld c, a 
 | 
						|
  ld hl, Periods
 | 
						|
  add hl, bc
 | 
						|
  add hl, bc
 | 
						|
  ld a, [hl+]
 | 
						|
  ld [rNR13], a
 | 
						|
  
 | 
						|
  ld a, [hl]
 | 
						|
  or a, AUDHIGH_RESTART
 | 
						|
  ld [rNR14], a 
 | 
						|
  
 | 
						|
  ld a, 0 
 | 
						|
  ld [channel_1_trigger], a
 | 
						|
  ret
 | 
						|
UpdateRegisters2:
 | 
						|
  ld a, [tick]
 | 
						|
  ld b, a 
 | 
						|
  ld a, [channel_2_note_cut]
 | 
						|
  cp a, b
 | 
						|
  jp nz, :+
 | 
						|
  ld a, 0 
 | 
						|
  ld [channel_2_volume], a
 | 
						|
  
 | 
						|
  cpl 
 | 
						|
  ld [channel_2_trigger], a 
 | 
						|
  
 | 
						|
  ld a, $ff
 | 
						|
  ld [channel_2_note_cut], a
 | 
						|
:
 | 
						|
  ld a, [channel_2_trigger]
 | 
						|
  cp a, 0
 | 
						|
  ret z
 | 
						|
  
 | 
						|
  ld a, [channel_2_instrument]
 | 
						|
  ld [rNR21], a 
 | 
						|
  
 | 
						|
  
 | 
						|
  ld a, [channel_2_volume]
 | 
						|
  swap a
 | 
						|
  and a, $f0
 | 
						|
  ld [rNR22], a 
 | 
						|
 | 
						|
  ld a, [channel_2_note]
 | 
						|
  ld b, 0 
 | 
						|
  ld c, a 
 | 
						|
  ld hl, Periods
 | 
						|
  add hl, bc
 | 
						|
  add hl, bc
 | 
						|
  ld a, [hl+]
 | 
						|
  ld [rNR23], a
 | 
						|
  
 | 
						|
  ld a, [hl]
 | 
						|
  or a, AUDHIGH_RESTART
 | 
						|
  ld [rNR24], a 
 | 
						|
  
 | 
						|
  ld a, 0 
 | 
						|
  ld [channel_2_trigger], a
 | 
						|
  ret
 | 
						|
UpdateRegisters3:
 | 
						|
  ld a, [tick]
 | 
						|
  ld b, a 
 | 
						|
  ld a, [channel_3_note_cut]
 | 
						|
  cp a, b
 | 
						|
  jp nz, :+
 | 
						|
  ld a, 0
 | 
						|
  ld [rNR30], a ; turn off channel 3 if we hit a note cut.
 | 
						|
  
 | 
						|
  ld a, 0 
 | 
						|
  ld [channel_3_volume], a
 | 
						|
  
 | 
						|
  ; we don't need to retrigger because we already turned off the dac.
 | 
						|
  ;ld a, 1
 | 
						|
  ;ld [channel_3_trigger], a 
 | 
						|
  
 | 
						|
  ; we do want to reset the note cut tho.
 | 
						|
  ld a, $ff
 | 
						|
  ld [channel_3_note_cut], a
 | 
						|
:
 | 
						|
  ld a, [channel_3_trigger] 
 | 
						|
  cp a, 0
 | 
						|
  ret z ; if we don't have a trigger, then don't do anything else.
 | 
						|
  
 | 
						|
  ; instrument has a special meaning for channel 3; it refers to an index into
 | 
						|
  ; an array of 16 (could be more!) samples, defined at the top of this file.
 | 
						|
  ; (each "sample" is a 16-byte sequence of 4-bit values blah blah read the
 | 
						|
  ; pandoc for that)
 | 
						|
  ld a, [channel_3_instrument]
 | 
						|
  ld hl, channel_3_loaded_instrument
 | 
						|
  cp a, [hl]
 | 
						|
  call nz, ChangeLoadedWave
 | 
						|
  
 | 
						|
  ld a, 0 ; length should always be zero
 | 
						|
  ld [rNR31], a
 | 
						|
  
 | 
						|
  
 | 
						|
  ; volumes are pre-processed by the export script.
 | 
						|
  ld a, [channel_3_volume]
 | 
						|
  swap a
 | 
						|
  and a, $f0
 | 
						|
  ld [rNR32], a 
 | 
						|
  cp a, 0
 | 
						|
  call nz, .turnOnDAC
 | 
						|
  ld a, [channel_3_trigger]
 | 
						|
  cp a, 0
 | 
						|
  call nz, .turnOnDAC
 | 
						|
 | 
						|
 | 
						|
  ; periods don't seem to be different for channel 3, so leave it as is
 | 
						|
  ld a, [channel_3_note]
 | 
						|
  ld b, 0 
 | 
						|
  ld c, a 
 | 
						|
  ld hl, Periods
 | 
						|
  add hl, bc
 | 
						|
  add hl, bc
 | 
						|
  ld a, [hl+]
 | 
						|
  ld [rNR33], a
 | 
						|
  
 | 
						|
  ld a, [hl]
 | 
						|
  or a, AUDHIGH_RESTART
 | 
						|
  ld [rNR34], a 
 | 
						|
  
 | 
						|
  ld a, 0 
 | 
						|
  ld [channel_3_trigger], a
 | 
						|
  ret
 | 
						|
.turnOnDAC:
 | 
						|
  ld a, $80
 | 
						|
  ld [rNR30], a
 | 
						|
  ret
 | 
						|
ChangeLoadedWave:
 | 
						|
  ; a has the nidex of the wave in the wave table at the top of the file
 | 
						|
  ld b, a 
 | 
						|
  ld a, [rNR30]
 | 
						|
  push af ; save thsi for later so we can restore it.
 | 
						|
  ld a, 0
 | 
						|
  ld [rNR30], a ; turn off the DAC for channel 3
 | 
						|
  ld a, b 
 | 
						|
  ld [channel_3_loaded_instrument], a ; mark that we've switched to it
 | 
						|
  
 | 
						|
  and a, $0F
 | 
						|
  swap a ; fast multiply by 16
 | 
						|
  
 | 
						|
  ld hl, WaveSamples
 | 
						|
  ld b, 0
 | 
						|
  ld c, a 
 | 
						|
  add hl, bc ; hl shoulld now ponit to the appropriate wave 
 | 
						|
  ld de, _AUD3WAVERAM
 | 
						|
  ld bc, 16 
 | 
						|
  call CopyRangeBy8s
 | 
						|
  
 | 
						|
  pop af 
 | 
						|
  ld [rNR30], a 
 | 
						|
  ret
 | 
						|
  
 | 
						|
UpdateRegisters4:
 | 
						|
  ld a, [tick]
 | 
						|
  ld b, a 
 | 
						|
  ld a, [channel_4_note_cut]
 | 
						|
  cp a, b
 | 
						|
  jp nz, :+
 | 
						|
  ld a, 0 
 | 
						|
  ld [channel_4_volume], a
 | 
						|
  
 | 
						|
  cpl 
 | 
						|
  ld [channel_4_trigger], a 
 | 
						|
  
 | 
						|
  ld a, $ff
 | 
						|
  ld [channel_4_note_cut], a
 | 
						|
:
 | 
						|
  ld a, [channel_4_trigger]
 | 
						|
  cp a, 0
 | 
						|
  ret z
 | 
						|
  
 | 
						|
  ld a, 0; [channel_2_instrument]
 | 
						|
  ld [rNR41], a 
 | 
						|
  
 | 
						|
  
 | 
						|
  ld a, [channel_4_volume]
 | 
						|
  swap a
 | 
						|
  and a, $f0
 | 
						|
  ld [rNR42], a 
 | 
						|
 | 
						|
  ld a, [channel_4_instrument]
 | 
						|
  ld b, 0 
 | 
						|
  ld c, a 
 | 
						|
  ld hl, NoiseOptions
 | 
						|
  add hl, bc
 | 
						|
  ld a, [hl]
 | 
						|
  ld [rNR43], a
 | 
						|
  
 | 
						|
  ld a, AUDHIGH_RESTART
 | 
						|
  ld [rNR44], a 
 | 
						|
  
 | 
						|
  ld a, 0 
 | 
						|
  ld [channel_4_trigger], a
 | 
						|
  ret
 | 
						|
 | 
						|
;INCLUDE "theme.inc"
 |