; Program: Simple Note Player #2 by MATRIX

;octave 0:
C=262 ; DO
CIS=277
D=294 ; RE
DIS=311
E=330 ; MI
F=349 ; FA
FIS=370
G=392 ; SO
GIS=415
A=440 ; LA
AIS=466
H=494 ; TI

org 256
call setup_pit_timer

mov si,msg_startnote
call Print

mov bx,startnote
call Play

mov si,msg_somenotes
call Print

mov cx,15
call pit_tick_delay

mov bx,tonedata
call Play

mov si,msg_exiting
call Print

call reset_pit_timer
int 20h

;************************************************************
; Procedure print
; prints a zero terminated string pointed to by si
;************************************************************

Print:
push ax
mov ah,14; BIOS code for screen display
cld
print_loop:lodsb; moving the character to be displayed to al
or al, al; checking if the char is NULL
jz printdone
int 10h; Calling BIOS routine
JMP print_loop
printdone:pop ax

bendline: ; ends the line ( adds y loc = 1 x loc = 0 )
push ax bx ; returns:  AX = 0xE0A ; BX = 7
mov bx,7
mov ax,$E0D
int 10h
mov al,$A
int 10h
pop bx ax
;ret

ret
; End of print procedure...

;************************************************************
; Procedure Play
; plays a sick and demented melody
;************************************************************
Play:
pusha	       ;save regs
localloop:
mov ax,[bx]    ;load sound data
add bx,2
or ax,ax
jz finished
jns notdelay
delay:
push bx
neg ax
mov cx,ax
and cx,1111b ; max wait is now 31
call pit_tick_delay
pop bx
jmp localloop
notdelay: ; not delay, its a note
push bx
call sound  ;play it
pop bx
jmp localloop
finished:
call nosound
popa
ret
;end Play

nosound: ; Silences the speaker.
in al,0x61
and al,0xFC
out 0x61,al
ret

sound: ; AX = frequency Starts the speaker emiting a sound of a given frequency
mov bx,ax ; RETURNS:  AX,BX,DX = undefined
mov dx,0x12
mov ax,0x34DD ; ;mov ax,0x34DC ; which is more accurate?
div bx
mov bl,al
mov al,0xB6
out 0x43,al
mov al,bl
out 0x42,al
mov al,ah
out 0x42,al
in al,0x61
or al,3
out 0x61,al
ret

pit_tick_delay:  ; waits cx ticks, destroys: ax bx
;cli ;if you need accurate timing uncomment this
  call	  read_pit_value
 mov	 bx,ax
.below:
  call	  read_pit_value
 cmp	 ax,bx
   jl	  .below
.above:
  call	  read_pit_value
 cmp	 ax,bx
   jg	   .above
 loop	 .below
;sti ;if you need accurate timing uncomment this
ret

reset_pit_timer:
 mov al,00110110b ; count down twice generator
jmp setupcommon
setup_pit_timer:  ; returns status in al
 mov al,00110100b ; rate generator
setupcommon:
cli ;if you need accurate timing comment this refer to above
 out 43h,al
 xor al,al
 out $40,al
 out $40,al
.waitlatch:
 mov al,11100010b ; get timer 0 status
  out 43h,al
  in al,40h
bt ax,6
jc .waitlatch
sti ;if you need accurate timing comment this refer to above
ret

read_pit_value:
;.waitlatch:                                  ; if you have early 8253s comment
; mov al,11100010b ; get timer 0 status       ; this part out
; out 43h,al                                  ; ( wais for latch to be valid )
; in al,40h                                   ;
;bt ax,6                                      ;
;jc .waitlatch                                ;
  mov al,11010010b
cli
  out 43h,al
  in al,40h
  mov ah,al
  in al,40h
sti
  xchg al,ah
ret

msg_startnote:db 'Playing start sound',0
msg_somenotes:db 'Playing some notes',0
msg_exiting:db 'Sound Playing has ended, exiting',0

tonedata: ; negatives are delay
dw 440,-7,880,-4,440,-4,330,-15
dw 440,-7,880,-4,440,-4,330,-15
dw 554,-7,440,-4,330,-4,440,-15
dw 0 ; stop !

startnote:
;  DO               RE             MI      FA              SO              LA              TI
;dw C , -2, CIS, -2, D, -2, DIS, -2, E, -2, F, -2, FIS, -2, G, -2, GIS, -2, A, -2, AIS, -2, H, -2

;or if you prefer tables:
;octave -1
delay_scale = -2
Cm1: dw 131 ; DO
dw delay_scale
CISm1: dw 139
dw delay_scale
Dm1 : dw 147 ; RE
dw delay_scale
DISm1: dw 156
dw delay_scale
Em1: dw 165 ; MI
dw delay_scale
Fm1: dw 175 ; FA
dw delay_scale
FISm1: dw 185
dw delay_scale
Gm1: dw 196 ; SO
dw delay_scale
GISm1: dw 208
dw delay_scale
Am1: dw 220 ; LA
dw delay_scale
AISm1: dw 233
dw delay_scale
Hm1: dw 247 ; TI
dw delay_scale
;octave 0
C0: dw 262 ; DO
dw delay_scale
CIS0: dw 277
dw delay_scale
D0 : dw 294 ; RE
dw delay_scale
DIS0: dw 311
dw delay_scale
E0: dw 330 ; MI
dw delay_scale
F0: dw 349 ; FA
dw delay_scale
FIS0: dw 370
dw delay_scale
G0: dw 392 ; SO
dw delay_scale
GIS0: dw 415
dw delay_scale
A0: dw 440 ; LA
dw delay_scale
AIS0: dw 466
dw delay_scale
H0: dw 494 ; TI
dw delay_scale

;octave 1
C1: dw 523 ; DO
dw delay_scale
CIS1: dw 554
dw delay_scale
D1 : dw 587 ; RE
dw delay_scale
DIS1: dw 622
dw delay_scale
E1: dw 659 ; MI
dw delay_scale
F1: dw 698 ; FA
dw delay_scale
FIS1: dw 740
dw delay_scale
G1: dw 784 ; SO
dw delay_scale
GIS1: dw 831
dw delay_scale
A1: dw 880 ; LA
dw delay_scale
AIS1: dw 932
dw delay_scale
H1: dw 988 ; TI
dw delay_scale

dw 0 ; stop !

; Make the file 512 bytes long
;times 512+256-$ db 0 ; file is org 256 based, so