;------------------------------------------------------------
;'Demolition Party' - Abrißparty by Kuemmel for Function 2023
;------------------------------------------------------------
org 100h
use16

;---screen init
sub al,-(0x13+0x80)   ;no screen clearing but doesn't matter and provides address
mov fs,word[si]       ;backbuffer (results in 0x6d2c which is okay as an address)
int 10h

;---palette
grey_red_loop:
   mov dx,0x3c8
   mov al,cl
   out dx,al
   inc dx
   out dx,al
   out dx,al
   cmp al,63
   jbe skip_red_col
      salc
   skip_red_col:
   out dx,al
loop grey_red_loop

;---screen address init
push 0a000h-70        ;center screen horizontally
pop es

;---init address
add si,si             ;si is 0x100+0x100

;---sound irq init
mov byte[si+bp],bl    ;init top counter to zero
mov dx,irq            ;new handler address
mov al,108            ;PIT counter divisor => 108 equals 11025 Hz
out 40h,al
mov al,0
out 40h,al
mov ax,2508h
int 21h

;---main intro loop
main:
mov dl,byte[si+bp]      ;get top counter
shl dl,7
salc
mov word[si+4],63       ;fixed resize
jz skip_vertical_movement_and_scatter
   mov al,byte[si-(end_of_data-irq.sample)-1]
   shr al,3
   sub word[si+4],ax    ;scatter rays by resize...or not
skip_vertical_movement_and_scatter:
mov byte[si+2],al       ;vertical movement........or not
mov byte[si+3],dl       ;colour adjust............or not
mov cx,word[si]         ;basic bass drum movement for both effects
shr cx,2

screen_loop:
   mov ax,0xcccd
   mul di
   sub dh,99
   add dh,byte[si+2]
   pusha
   fild word[bx-8]  ;x
   fild word[bx-9]  ;y
   fpatan           ;arc(y/x)
   fimul word[bx-6] ;cx sound effect
   fsin
   fimul word[si+4] ;resize effect
   fistp word[bx-4] ;store in ax
   popa
   cmp al,63
   jbe skip_clamp_to_zero
      salc
   skip_clamp_to_zero:
   add al,byte[si+3]
   mov byte[fs:di],al
   inc di
jnz screen_loop

;---vsync for flicker reduce
mov dx,03dah
vsync:
  in al,dx
  test al,8
jz vsync

;---copy buffer to screen
;needs di=0,cx=0
xor cx,cx
copy_buffer_loop:
    mov al,byte[fs:di]
    stosb
loop copy_buffer_loop

;---key check and exit
in al,60h
dec al      ;check later for ax if ah is zero
jnz main
;mov al,3    ;skip if needed
;int 10h     ;skip if needed
ret

;---bytebeat interrupt subroutine
;---a=(t*"..."[t>>10&63]>>1)&128, 
;---b=(sqrt(t&4095)<<6)&64, or (sqrt(t&4095)<<7)&128,
;---a+b
irq:
pusha
mov dx,0378h  ;LPT1 parallel port address
mov al,0      ;al=sample => self modifying code, play after calc => better sound quality
.sample:
out dx,al
mov ax,0      ;ax: timer => self modifying code, inc'ed after each irq call
.counter:
;---melody
mov bx,ax
shr bx,11                                 ;check with jnc later (64 notes, but >>11 as 32 notes at same address)
mov bl,byte[si-(end_of_data-melody)+bx]   ;get byte from 4 Bit table
jnc note_even                             ;even or uneven note count ?
   shr bl,4                               ;mask upper half
note_even:
and bl,00001111b                          ;mask lower nibble and clear bh
imul bx,ax                                ;t * "0...9" note
shr bx,1
and bl,128
;---bass drum
and ax,4095
mov word[si],ax
fild word[si]
fsqrt
fistp word[si]
mov al,byte[si]   ;used also for visualisation 
shl al,6
and al,64
;---variant choice
mov cl,byte[si+bp]   ;get toggle byte as shift
shl al,cl
;---combine melody and bass drum 
add al,bl
;---
mov byte[si-(end_of_data-irq.sample)-1],al   ;store sample for playback next interrupt
inc word[si-(end_of_data-irq.counter)-2]     ;inc timer each interrupt call within code
jnz skip_adjust_top_counter
   xor byte[si+bp],1
skip_adjust_top_counter:
mov al,20h
out 20h,al   ;end of irq
popa
iret
melody: 
    ;0464046404640464
    ;8040804080408040
    ;0464046404640464
    ;9876897690807060
    db 0+4*16,6+4*16,0+4*16,6+4*16,0+4*16,6+4*16,0+4*16,6+4*16
    db 8+0*16,4+0*16,8+0*16,4+0*16,8+0*16,4+0*16,8+0*16,4+0*16
    db 0+4*16,6+4*16,0+4*16,6+4*16,0+4*16,6+4*16,0+4*16,6+4*16
    db 9+8*16,7+6*16,8+9*16,7+6*16,9+0*16,8+0*16,7+0*16,6+0*16
end_of_data: