Category : Assembly Language Source Code
Archive   : TRISOUND.ZIP
Filename : TRI.ASM
comment *This routine produces polyphonic music with three
voices. The frequencies and durations of the notes
are passed to this routine in an integer array.
Called from BASIC via:
CALL TRI(TUNE%(0))
Where:
TUNE% is an integer array
TUNE% is treated by TRI as data words with the three most
significant bits identifying the type of data. 000 causes
the routine to terminate and return to BASIC. 001 sets
the duration of play of the voices before being updated.
010 sets the tempo of the playback. 011 is unused. 100
sets the period for voice 1 which is slightly louder than
the rest. 101 sets the period for voice 2. 110 sets the
period for voice 3.
*
cseg segment
assume CS&gml.cseg, DS&gml.cseg, ES&gml.nothing
; db 0FDH ;indicates BLOAD file
; dw 0 ;segment--BASIC will use default
; dw 0 ;offset--specify in BLOAD command
; dw rtn_len ;length of the routine
spkr_io equ 61H
tri proc far
push bp
mov bp,sp
mov ax,(bp+6) ;get address of TUNE%(0) off stack
sub ax,2 ;required for first time in sort
push ax ;save on stack
mov ax,1FFFH ;default tempo data
push ax ;save on stack
push ax ;initialize tempo counter
xor ax,ax ;must write 0 into voice count and
mov bx,ax ; data registers
mov dx,ax
mov si,ax
mov bp,ax
mov di,ax
mov es,ax
;
;This section sorts the tune data into the appropriate registers
;Voice period data is stored in ES for voice 1, DI for voice 2,
;and SI for voice 3. The voice period count is stored in BX for
;voice 1, DX for voice 2, and BP for voice 3.
;
sort: push bx
push dx
push bp
sort_1: mov bp,sp
mov bx,(bp+10) ;get tune pointer
add bx,2 ;point to next tune data
mov (bp+10),bx ;restore updated tune pointer
mov ax,(bx) ;get tune data in AX
mov dx,ax ;make a copy in DX
and dx,1FFFH ;strip off 3 data type bits
shl ax,1 ;move msb into carry bit
jnc sort_4 ;jump if end, duration, or tempo data
shl ax,1 ;move 2nd msb into carry bit
jc sort_3 ;jump if voice 3 data
shl ax,1 ;move 3rd msb into carry bit
jc sort_2 ;jump if voice 2 data
mov es,dx ;store voice 1 data in ES
jmp sort_1
sort_2: mov di,dx ;store voice 2 data in DI
jmp sort_1
sort_3: mov si,dx ;store voice 3 data in SI
jmp sort_1 ;ignore
sort_4: shl ax,1 ;move 2nd msb into carry bit
jnc sort_6 ;jump if end or duration bit
jnc sort_6 ;jump if end or duration data
shl ax,1
jnc sort_5 ;jump if tempo data
jmp sort_1 ;ignore
sort_5: mov (bp+8),dx ;store tempo
mov (bp+6),dx ;initialize tempo counter
jmp sort_1
sort_6: shl ax,1 ;move 3rd msb into carry
jc sort_7 ;jump if duration
jmp end
sort_7: mov cx,dx ;store duration data
pop bp
pop dx
pop bx
cli ;turn off interrupts during play
loop: pop ax ;get current tempo count
dec ax ;subtract 1
push ax ;restore tempo count
jnz play ;jump if some tempo remains
pop ax ;reset tempo counter
pop ax
push ax
push ax
loop play ;decrement duration counter
sti ;turn ints back on during sort
jmp sort ;get new tune data if duration up
;
;This routine plays the notes until the duration counter in CX
;reaches zero. At that time, the new data is sorted.
;
play: add bx,si ;add voice 3 data to count
rol bx,1 ;get msb of voice 3 count
mov al,12H ;keeps keyboard clk on and
rcl al,1 ; casette motor relay off
rcl al,1
out spkr_io,al ;output voice 3 state to speaker
ror bx,1 ;restore bx to original state
add dx,di ;add voice 2 data to count
rol dx,1
mov al,12H
rcl al,1
rcl al,1
out spkr_io,al
ror dx,1
mov ax,es
add bp,ax ;add voice 1 data to count
rol bp,1
mov al,12H
rcl al,1
rcl al,1
out spkr_io,al
ror bp,1
jmp loop
end: add sp,12
pop bp
mov ax,cs
mov es,ax
ret 2
tri endp
rtn_len equ $-tri ;length of routine for header
cseg ends
end tri
Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!
This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.
But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/