Код:
;
; PIANO.A86 [For 'CP/M-86 For The IBM']
; Play Musical Notes Using The Keyboard's Number Keys
; Freeware from Kirk Lawrence
;
; (Uses Timer2 to run the PC speaker.)
;
; To assemble: ASM86 PIANO
; GENCMD PIANO
;
cseg
org 100h
jmp start
;
off db 27,'0',27,'c',0,27,'b',7,27,'n',27,'E$'
keys1 db ' Э ЫЫЫЭ ЫЫЫЭ ЫЫЫЫЭЫЫЫЫЭ ЫЫЫЭ ЫЫЫЫЭЫЫЫЫЭ ЫЫЫЭ ЫЫЫЭ '
db ' ЫЫЫЫЭЫЫЫЫ Ю',13,10,'$'
keys2 db ' ЫЭЫЫЫЫЫЭЫЫЫЫЫЭЫЫЫЫЫЭЫЫЫЫЫЭЫЫЫЫЫЭЫЫЫЫЫЭЫЫЫЫЫЭЫЫЫЫЫЭЫЫЫЫЫЭ'
db 'ЫЫЫЫЫЭЫЫЫЫЫЮЫ',13,10,'$'
keys3 db 27,'c',07,27,'b',0
db 27,'Y',41,59,'1',27,'Y',41,65,'2',27,'Y',41,71,'3'
db 27,'Y',41,77,'4',27,'Y',41,83,'5',27,'Y',41,89,'6'
db 27,'Y',41,95,'7',27,'Y',41,101,'8$'
scrn db 27,'c',0,27,'b',03,27,'Y',49,53
db 'ЫЫЯЯЫЫ ЫЫ ЫЫЯЯЫЫ ЫЫЮЯЫЫ ЫЫЯЯЫЫ'
db 27,'Y',50,53
db 'ЫЫЬЬЫЫ ЫЫ ЫЫЬЬЫЫ ЫЫ ЫЫ ЫЫ ЫЫ'
db 27,'Y',51,53
db 'ЫЫ ЫЫ ЫЫ ЫЫ ЫЫ ЫЫ ЫЫ ЫЫ'
db 27,'Y',52,53
db 'ЯЯ ЯЯ ЯЯ ЯЯ ЯЯ ЯЯ ЯЯЯЯЯЯ'
db 27,'Y',53,59,27,'b',05,'Freeware from Kirk Lawrence'
db 27,'Y',55,53,27,'b',07,'ESC',27,'b',03,' to quit.'
db 27,'Y',55,71,27,'b',04,254,254,254,27,'Y',55,79
db 27,'b',03,'Sustain: ',27,'b',07
soff db 27,'Y',55,88,'Off$'
sonn db 27,'Y',55,88,'On $'
flag db 0 ;our 'sustain' mode flag
stor db 0 ;storage variable for keypress data
onn db 27,'E',27,'m',27,'1$'
table dw 262 ;Middle C
dw 294 ;D
dw 330 ;E
dw 347 ;F
dw 392 ;G
dw 440 ;A
dw 494 ;B
dw 524 ;C
pos db 27,'Y',40
col db 58
db '$'
mark db ' $'
unmark db 219,219,219,'$'
;
; Turn off the status line and cursor, set screen colors,
; and clear the screen.
;
start:
mov dx,offset off
call prt_str
;
; Draw the keyboard keys on the user screen.
;
mov cx,6 ;set loop timer
rpt1:
push cx
mov dx,offset keys1
call prt_str
pop cx
loop rpt1
;
mov cx,5 ;set loop timer
rpt2:
push cx
mov dx,offset keys2
call prt_str
pop cx
loop rpt2
;
; Draw the numbers on the on-screen keyboard keys.
;
mov dx,offset keys3
call prt_str
;
; Draw the remainder of the user screen.
;
mov dx,offset scrn
call prt_str
;
; Get a user keypress (1 to 8).
;
get_key:
mov ah,0 ;function 0 - wait for keypress
int 16h ;call ROM BIOS keyboard services
cmp al,27 ;was ESC pressed?
jz exit ;yes, so go exit
cmp al,32 ;was SPACE BAR pressed?
je toggle ;yes, so go toggle the 'SUSTAIN' function
;
; Filter out all keys except '1' through '8' by checking the scan code.
;
cmp ah,02h ;less than '1'?
jl get_key ;yes, so ignore it
cmp ah,09h ;greater than '8'?
jg get_key ;yes, so ignore it
;
; Convert keypress data to musical note data.
;
sub al,31h ;change ASCII to digit
mov stor,al ;store value for visual indicator
and al,00000111b ;mask off upper 5 bits
shl al,1 ;* by 2 (2 bytes/word)
cbw ;byte --> word in AX
mov bx,ax ;put in BX (for table)
xor ax,ax ;zero out AX
mov dx,12h ;(high word)
mov si,offset table ;point SI to first entry in musical note table
add si,bx ;add the needed number of table word offsets
mov cx,[si] ;move the value from table location into CX...
div cx ;...and divide DX:AX by this value
mov bx,ax ;save the quotient in BX
;
; If 'sustain' mode is on, turn off the visual on-screen key indicator.
;
cmp flag,1 ;is sustain mode 'on'?
jne sound_it ;no, so go sound the note
push ax ;preserve AX
push bx ;preserve BX
push dx ;preserve DX
call de_mark ;go turn off visual key indicator
pop dx ;restore DX
pop bx ;restore BX
pop ax ;restore AX
;
; Set 1/pitch into timer, then play the note through the PC speaker.
;
sound_it:
mov dx,43h ;timer 2 port address
mov al,10110110b ;put magic number...
out dx,al ;...into timer2
mov ax,bx ;1/pitch into AX
mov dx,42h ;LSB into AL
out dx,al ;send it to Timer2
mov al,ah ;MSB in AL
out dx,al ;send it to Timer2
mov dx,61h ;port 61h in DX
in al,dx ;read port value into AL
or al,3 ;turn on bits 0 and 1...
out dx,al ;...to turn on speaker
;
; Visually indicate the pressed key on the screen.
;
call set_col ;go compute value for screen locating sequence
mov dx,offset pos ;point to our screen locating sequence
call prt_str ;print it
mov dx,offset mark ;point to our screen indicator mark
call prt_str ;print it
;
; If 'sustain' function is on, go get another keypress.
; If 'sustain' function is off, sound note for 2/18ths of a
; second, clear the keyboard buffer, turn the note off,
; turn off the on-screen key indicator, and go get another
; keypress.
;
cmp flag,1 ;is 'sustain' mode on?
je get_key ;yes, so go get another keypress
call delay ;no, so go generate a short delay
call spkr_off ;go turn off the speaker
call de_mark ;go turn off on-screen key indicator
jmp get_key ;go get another keypress
;
; Turn off the speaker. Turn on the status line and cursor,
; clear the screen, and exit.
;
exit:
call spkr_off ;go turn off the speaker
mov dx,offset onn ;point to screen control sequence
call prt_str ;print it
xor cx,cx ;function 0 - reset system
int 224 ;call BDOS services
;
; Routine to toggle the 'SUSTAIN' function.
;
toggle:
cmp flag,1 ;is 'sustain' mode currently on?
je sust_off ;yes, so go turn it off
mov flag,1 ;no, so turn it on
mov dx,offset sonn ;point to on-screen 'On' message
jmp sust_done ;go print it
sust_off:
call spkr_off ;go silence the speaker
call de_mark ;go turn off visual on-screen key indicator
mov flag,0 ;turn off 'sustain' mode
mov dx,offset soff ;point to on-screen 'Off' message
sust_done:
call prt_str ;go print it
jmp get_key ;go get another keypress
;
;====================================================================
;
; Following are the program's called sub-routines.
;
;====================================================================
;
; Routine to turn off the speaker.
;
spkr_off:
push dx ;preserve DX
mov dx,61h ;port 61h in DX
in al,dx ;read port value into AL
and al,11111100b ;mask lower 2 bits...
out dx,al ;...and send it to the port
pop dx ;restore DX
ret ;return to caller
;
; Routine to delay for 2/18ths of a second.
;
delay:
mov ah,00h ;function 0 - get timer tick
int 01Ah ;call ROM BIOS time-of-day services
add dx,2 ;add our delay value to DX
mov bx,dx ;store result in BX
pozz:
int 01Ah ;call ROM BIOS time-of-day services
cmp dx,bx ;has the delay duration passed?
jl pozz ;no, so go check again
;
; Routine to clear the keyboard buffer (to prevent over-run
; if the user holds a key down).
;
push es ;preserve ES
push di ;preserve DI
mov ax,40h ;BIOS segment in AX
mov es,ax ;transfer to ES
mov ax,1Ah ;keyboard head pointer in AX
mov di,ax ;transfer to DI
mov ax,1Eh ;keyboard buffer start in AX
mov es: word ptr [di],ax ;transfer to head pointer
inc di ;bump pointer to...
inc di ;...keyboard tail pointer
mov es: word ptr [di],ax ;transfer to tail pointer
pop di ;restore DI
pop es ;restore ES
ret ;return to caller
;
; Routine to set screen location for the visual keypress indicator.
; (The variable 'stor' contains a hex representation [0h through 7h]
; of which key was pressed.)
;
; This routine is a bit clumsy, but what do you expect in a free
; program? ;)
;
set_col:
cmp stor,0 ;key 1 pressed?
je complete ;yes
add col,6 ;no, so increase our screen column value
cmp stor,1 ;key 2 pressed?
je complete ;yes
add col,6 ;no, so increase our screen column value
cmp stor,2 ;key 3 pressed?
je complete ;yes
add col,6 ;no, so increase our screen column value
cmp stor,3 ;key 4 pressed?
je complete ;yes
add col,6 ;no, so increase our screen column value
cmp stor,4 ;key 5 pressed?
je complete ;yes
add col,6 ;no, so increase our screen column value
cmp stor,5 ;key 6 pressed?
je complete ;yes
add col,6 ;no, so increase our screen column value
cmp stor,6 ;key 7 pressed?
je complete ;yes
add col,6 ;no, so it must be key 8
complete:
ret ;return to caller
;
; Routine to turn off the visual key indicator on the screen.
;
de_mark:
mov dx,offset pos ;point to scrren-positioning sequence
call prt_str ;print it
mov dx,offset unmark ;point to the 'unmark' sequence
call prt_str ;print it
mov col,58 ;reset the default 'column' value
ret ;return to caller
;
; Routine to print a string (in offset DX) to the screen.
;
prt_str:
mov cl,09h ;function 9 - print string
int 224 ;call BDOS services
ret ;return to caller
;
end
Запускаю PIANO.CMD вот таким батником