; Sotplayer V1.1 for WLA-DX GBZ80
; CC furrtek 2012 - Use and redistribute as is
; Furrtek.org

setupmusic:
  ldi    a,(hl)
  ld     e,a
  ld     d,(hl)
  inc    hl
  push   hl
  push   de
  pop    hl
  call   getdelta
  push   hl
  ld     hl,Delta_1
  call   storeDEHL
  pop    de
  ld     hl,STEPPTR_T1
  ld     (hl),d
  inc    hl
  ld     (hl),e
  pop    hl
  
  ldi    a,(hl)
  ld     e,a
  ld     d,(hl)
  inc    hl
  push   hl
  push   de
  pop    hl
  call   getdelta
  push   hl
  ld     hl,Delta_2
  call   storeDEHL
  pop    de
  ld     hl,STEPPTR_T2
  ld     (hl),d
  inc    hl
  ld     (hl),e
  pop    hl
  
  ldi    a,(hl)
  ld     e,a
  ld     d,(hl)
  inc    hl
  push   hl
  push   de
  pop    hl
  call   getdelta
  push   hl
  ld     hl,Delta_3
  call   storeDEHL
  pop    de
  ld     hl,STEPPTR_T3
  ld     (hl),d
  inc    hl
  ld     (hl),e
  pop    hl

  ldi    a,(hl)
  ld     e,a
  ld     d,(hl)
  inc    hl
  push   hl
  push   de
  pop    hl
  call   getdelta
  push   hl
  ld     hl,Delta_4
  call   storeDEHL
  pop    de
  ld     hl,STEPPTR_T4
  ld     (hl),d
  inc    hl
  ld     (hl),e
  pop    hl
  
  ld     a,%01110111            ; No Vin, Left and Right at max volume
  ldh    ($24),a
  ld     a,$DE
  ldh    ($25),a                ; All channels to Left and Right
  ld     a,%10000000
  ldh    ($26),a                ; Sound on

  ret
  
storeDEHL:
  ld     a,d
  ldi    (hl),a
  ld     (hl),e
  ret
  
getdelta:
  ld     d,0                    ; Get new delta in DE from HL
  ldi    a,(hl)
  bit    7,a
  jr     z,+
  and    $7F
  ld     d,a
  ldi    a,(hl)
+:
  ld     e,a
  ret


stepmusic:
  ld     hl,VBLC
  inc    (hl)
  ld     a,(hl)
  cp     SPEED
  jr     nz,+
  xor    a
  ld     (hl),a

  ld     b,0
  call   Do_T
  ld     b,1
  call   Do_T
  ld     b,2
  call   Do_T
  ld     b,3
  call   Do_T
+:
  ret


Do_T:
  ld     hl,Delta_1             ; Get Delta counter
  call   makeptr
  ldi    a,(hl)                 ; =0? 16bits
  or     (hl)
  jr     nz,+++                 ; Skip if Delta > 0

  ld     hl,VU1                 ; Get VU-meter address for channel
  ld     d,0
  ld     e,b
  add    hl,de
  ld     (hl),$70

  ld     hl,STEPPTR_T1          ; Make step pointer address
  call   makeptr
  
  push   hl                     ; DE=HL
  pop    de

  push   de                     ; Save track pointer address

  ld     a,(de)                 ; HL=(DE) Get step pointer
  inc    de
  ld     h,a
  ld     a,(de)
  ld     l,a

  ldi    a,(hl)                 ; First byte

  bit    7,a                    ; Instrument change or note ?
  jr     z,+
  and    $7F                    ; Instrument change, nuke 7th bit
  push   hl
  or     a
  jr     z,silence
  dec    a
  call   LoadInstrument
  jr     doneli
silence:
  call   SilenceChannel
doneli:
  pop    hl
  ldi    a,(hl)                 ; Note follows
+:
  and    $7F                    ; Note

  push   hl                     ; Save track data ptr
  push   af                     ; Save note number

  ld     hl,Instru_1            ; Get channel number of last instrument played
  ld     d,0
  ld     e,b
  add    hl,de
  ld     a,(hl)

  cp     3
  jr     nz,+
  pop    af                     ; Pop note number
  call   SetCH4                 ; Special case for CH4
  jr     ++
+:
  ld     c,a                    ; C = channel number
  pop    af                     ; Pop note number
  call   SetFreq                ; Use LUT to set frequency of CH1~3
++:

  pop    hl                     ; Pop track data ptr
  call   getdelta

  push   hl                     ; Save track data ptr
  push   de                     ; Save new Delta

  ld     hl,Delta_1
  call   makeptr
  
  pop    de                     ; Pop new Delta
  call   storeDEHL              ; Set new Delta

  pop    hl                     ; Pop track data ptr

  pop    de                     ; Pop track pointer address
  ld     a,h                    ; (DE)=HL save new track pointer
  ld     (de),a
  inc    de
  ld     a,l
  ld     (de),a

+++:
  ld     hl,Delta_1             ; Dec delta counter
  call   makeptr
  ld     d,(hl)                 ; (HL)-- 16bits
  inc    hl
  ld     e,(hl)
  dec    de
  dec    hl
  ld     (hl),d
  inc    hl
  ld     (hl),e
  ret
  

makeptr:
  ld     d,0                    ; HL+=A*2
  ld     a,b
  add    a
  ld     e,a
  add    hl,de
  ret
  

SilenceChannel:                 ; B=Track #
  push   hl

  ld     hl,Instru_1            ; Get channel number of last instrument played
  ld     d,0
  ld     e,b
  add    hl,de
  ld     a,(hl)
  
  ld     hl,SilenceRegs         ; Volume registers
  ld     d,0
  ld     e,a
  add    hl,de
  ld     l,(hl)
  ld     h,$FF

  xor    a
  ld     (hl),a

  pop    hl
  
  ret

SilenceRegs:
  .db    $12
  .db    $17
  .db    $1A
  .db    $21

  
SetFreq:                        ; C=CH #   A=Note #
  push   hl
  push   bc
  
  ld     hl,notelut             ; Get address of note value in LUT (mettre plus bas ?)
  ld     d,0
  add    a
  ld     e,a
  add    hl,de

  push   hl                     ; Save note LUT pointer

  ld     hl,freqregs            ; Get first frequency register number
  ld     d,0
  ld     e,c
  add    hl,de
  ld     c,(hl)
  ld     b,$FF                  ; BC = first register for frequency

  pop    hl                     ; Pop note LUT pointer

  ldi    a,(hl)
  ld     (bc),a                 ; LSB frequency
  inc    bc                     ; next register
  ld     a,(hl)
  or     $B0                    ; Set start sound bits
  ld     (bc),a                 ; MSB frequency
  
  pop    bc
  pop    hl

  ret
  
SetCH4:
  ld     a,$B0                  ; Just start sound, no frequency change
  ldh    ($23),a
  ret


LoadInstrument:                 ; A=instrument #
  ld     hl,instruments
  ld     d,0
  add    a
  ld     e,a
  add    hl,de         ; HL=(instruments+A*2)
  ldi    a,(hl)
  ld     h,(hl)
  ld     l,a           ; HL=(HL)
  or     h
  ret    z             ; Don't load if pointer = 0

  ldi    a,(hl)        ; Get channel number of instrument
  push   hl
  ld     hl,Instru_1   ; Save channel number in RAM (used for note update)
  ld     d,0
  ld     e,b
  add    hl,de
  ld     (hl),a        ; (Instru_1+B)=A

  ld     hl,LoadIJT    ; Jump table for instrument parameters loading routines
  ld     d,0
  add    a
  ld     e,a
  add    hl,de
  ldi    a,(hl)
  ld     h,(hl)
  ld     l,a

  jp     hl            ; JP (LoadIJT+A*2)

LoadIJT:
  .dw    loadCH1
  .dw    loadCH2
  .dw    loadCH3
  .dw    loadCH4
  
loadCH1:
  pop    hl
  ldi    a,(hl)
  ldh    ($10),a
  ldi    a,(hl)
  ldh    ($11),a
  ldi    a,(hl)
  ldh    ($12),a
  ld     a,(hl)
  ldh    ($14),a
  ret

loadCH2:
  pop    hl
  ldi    a,(hl)
  ldh    ($16),a
  ldi    a,(hl)
  ldh    ($17),a
  ld     a,(hl)
  ldh    ($19),a
  ret

loadCH3:
  pop    hl
  push   de
  ldi    a,(hl)
  ldh    ($1A),a
  ldi    a,(hl)
  ldh    ($1B),a
  ldi    a,(hl)
  ldh    ($1C),a
  ldi    a,(hl)
  ldh    ($1E),a
  ld     c,$10
  ld     de,$FF30                        ; Load wave RAM
-:
  ldi    a,(hl)
  ld     (de),a
  inc    de
  dec    c
  jr     nz,-
  pop    de
  ret

loadCH4:
  pop    hl
  ldi    a,(hl)
  ldh    ($20),a
  ldi    a,(hl)
  ldh    ($21),a
  ldi    a,(hl)
  ldh    ($22),a
  ld     a,(hl)
  ldh    ($23),a
  ret
  
freqregs:
  .db $13,$18,$1D
