home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Audio 4.94 - Over 11,000 Files
/
audio-11000.iso
/
msdos
/
misc
/
sample20
/
samplasm.asm
< prev
next >
Wrap
Assembly Source File
|
1989-05-20
|
23KB
|
769 lines
;
; SAMPLASM.ASM
; ------------
;
; One voice sampler playback system using fractional addition 16/3/89
;
; with optional patch to drive PC speaker using PWM
;
; For use with SAMPLER.PAS V2
;
;
;
;
; (C) Copyright 1989 by Rowan McKenzie
;
; You may copy these files or use the source code only
; for non-profit purposes. Please contact me if you wish to use any
; part of the package for commercial purposes.
;
;
; Rowan McKenzie
; 35 Moore Ave,
; Croydon 3136
; Vic Australia
;
;
;
; This code provides the assembler section of SAMPLER.PAS
;
; This version uses the system timer for sample timing, and is therefore
; clock speed independent, although the CPU must be able to keep up with
; the interrupt rate (20kHz!).
;
;
;
; Notes:
; ------
;
; To assemble the D to A converter version, set pwm equ false
;
; To assemble the PWM version, set pwm equ true
;
; The D/A version uses the system timer (at 20kHz) to synchronise output
; samples (and to make the code clock speed independent)
;
; The PWM version uses the system timer in the same way, but triggers the
; speaker timer channel as a monostable whose pulse length is proportional
; to the sample value. Note that time constants are all scaled assuming
; 20kHz sample rate. If another sample rate is used, these will need to be
; recalculated. Also, faster sampling rates mean lower effective resolution
; from the one shot because it is clocked at a fixed frequency. The current
; setup gives the equivalent of a 6 bit d/a converter (I know that's not
; very good, but it's better than most PC speakers can justify!)
;
;
;
; Variables defined in Pascal source:
; -----------------------------------
;
; release is a boolean variable indicating whether key releases should
; terminate sound playback
;
; loop is a boolean variable indicating that the loop section of the sample
; should be played continuously after playback is complete
;
; daout is an integer variable containing the d/a converter port
; (for D/A version)
;
; increment is an integer variable containing a fractional increment constant which
; determines the pitch of the note to be played
;
; bufloop is an integer variable containing the offset of the start of the
; loop section
;
; bufend is an integer variable containing the offset of the end of the sample
; (for when the sample code is implemented)
;
; bufstart is an integer variable containing the offset of the start of the
; sample
;
; kbdmode is a boolean variable indicating whether keyboard service routine
; should pass control to bios (false) or handle the key itself (true)
;
; kbdflag is a byte variable to indicate a key has been pressed during replay
;
; keyval is a byte variable which will contain the scan code of a key pressed
; during replay
;
; tconstant is a byte variable which sets the system timer rate (20kHz)
;
; timer is a boolean variable which indicates the timer should be used
; to determine how long notes should last
;
; tinterval is an integer variable indicating how long a note should be
; played for (no. interrupts mod modulus)
;
; modulus is a byte variable which determines after how many interrupts the
; tinterval counter should be decremented
;
; song is a boolean variable indicating whether a song is being played
;
; trigger is an integer variable describing the minimum input level required
; to begin sampling
;
page 255,132
title sampler asm module
; ===== Equates =====
true equ 1
false equ 0
pwm equ false ;pwm version if true else d/a version
tdelay equ 2 ;delay constant between samples while
; waiting for trigger
lshiftr equ 170 ;scan code for left shift release
rshiftr equ 182
tccont equ 43h ;control reg of 8253 timer chip
tccount equ 42h ;counter reg 2 (speaker)
speaker equ 97 ;speaker port for PWM version
data segment word public
;
; data
;
extrn tconstant:word,keyval:word,kbdflag:word,bufstart:word
extrn bufend:word,bufloop:word,increment:word,daout:word,loop:word
extrn release:word,timer:word,tinterval:word,modulus:word,song:word
extrn trigger:word,kbdmode:word,quickexit:word,buffer:word
extrn bufferw:word,bufflen:word
sysold dd ? ;temp storage for old system int vector
sptemp dw ? ;storage for sp for quick exit
duration dw ? ;duration counter
modul db ? ;local modulus counter
data ends
code segment byte public
assume cs:code,ds:data
public restore,sample,initial,replay,replayt,scalewave,echo
kbdold dd ? ;temp storage for old kbd int vector
dstemp dw ? ;holds ds incase it's needed
;************************************************************
;
; Restore - restore int vectors and exits
;
;************************************************************
restore proc near
cli ;restore old kbd interrupt
push ds
mov dx,word ptr cs:[kbdold]
mov ds,word ptr cs:[kbdold+2]
mov ax,2509h
int 21h ;restore old kbd vector
pop ds
if pwm
mov al,0b6h
out tccont,al ;change timer to square wave gen mode
in al,speaker
and al,0fch
out speaker,al ;speaker one shot disable
endif
sti
ret
restore endp
;***********************************************************************
;
; Initialise - save int vector contents, replace with my version
;
;***********************************************************************
initial proc near
cli
mov cs:[dstemp],ds
mov ax,3509h ;get old kbd int
int 21h
mov word ptr cs:[kbdold],bx ;save it
mov word ptr cs:[kbdold+2],es
mov dx,offset kbdint
push ds
mov ax,cs
mov ds,ax
mov ax,2509h
int 21h ;replace with mine
pop ds
mov byte ptr [kbdflag],0 ;no key activity
if pwm
mov al,0b6h
out tccont,al ;change timer to square wave gen mode
mov al,byte ptr[tconstant]
shr al,1
out tccount,al ;produce mean equivalent dc voltage
xor al,al
out tccount,al
in al,speaker
or al,3
out speaker,al ;speaker one shot enable
else
mov dx,[daout]
mov al,127
out dx,al
endif
sti
ret
initial endp
;******************************************************************************
;
; Sample data from A/D port
;
;******************************************************************************
sample proc near
cli
in al,21h
or al,98h ;disable comms, printer interrupts
out 21h,al
mov ax,3508h
int 21h ;get system timer vector
mov word ptr [sysold],bx
mov word ptr [sysold+2],es ;and save it
mov dx,offset sysint
push ds
mov ax,cs
mov ds,ax
mov ax,2508h
int 21h ;replace with new one
pop ds
mov ah,byte ptr [trigger]
mov dx,[daout]
trig: in al,dx ;wait for trigger level
mov cx,tdelay
tdel: loop tdel ;delay before next sample taken
cmp al,ah
jc trig
mov al,36h
out 43h,al
mov al,byte ptr [tconstant]
out 40h,al ;set to ~20kHz system timer!
mov al,0
out 40h,al
sti
mov bx,[bufstart]
mov di,[bufend]
mov es,[buffer+2]
sync: hlt ;wait for system interrupt
in al,dx
mov es:[bx],al ;store sample
inc bx
cmp bx,di
jbe sync ;until buffer full
call vrestore
cli
in al,21h
and al,67h
out 21h,al
sti
ret
sample endp
;******************************************************************************
;
; Scale waveform for PWM replay
;
;******************************************************************************
scalewave proc near
push ds
mov es,[bufferw+2] ;copy from buffer to bufferw with scale
mov si,[bufferw]
mov cx,bufflen
inc cx
mov di,[buffer]
mov ds,[buffer+2]
sloop: mov al,[di] ;div 4 +1
shr al,1
shr al,1
inc al
mov es:[si],al
inc si
inc di
loop sloop
pop ds
ret
scalewave endp
;*************************************************************************
;
; Echo - echos A/D to D/A for monitoring
;
;*************************************************************************
echo proc near
cli
push bp
in al,21h
or al,98h ;disable comms, printer interrupts
out 21h,al
mov [sptemp],sp ;remember sp incase kbd abort
mov al,1
mov byte ptr [quickexit],al
mov ax,3508h
int 21h ;get system timer vector
mov word ptr [sysold],bx
mov word ptr [sysold+2],es ;and save it
mov dx,offset sysint
push ds
mov ax,cs
mov ds,ax
mov ax,2508h
int 21h ;replace with new one
pop ds
if pwm
mov al,0b0h
out tccont,al ;change timer to one shot mode
mov al,255
out tccount,al
mov al,0
out tccount,al
mov al,90h
out tccont,al
endif
mov al,36h
out 43h,al
mov al,byte ptr [tconstant]
out 40h,al ;set to ~20kHz system timer!
mov al,0
out 40h,al
sti
if pwm
in al,speaker
or al,3
out speaker,al ;speaker one shot enable
else
mov dx,[daout]
endif
eloop:
if pwm
mov dx,[daout]
endif
in al,dx
if pwm
shr al,1
shr al,1
inc al
mov dx,tccount
out dx,al ;activate one shot
out dx,al ;seems to need this else distortion
else
out dx,al
endif
hlt ;wait for system interrupt
jmp eloop ;exit via exitr
echo endp
;*************************************************************************
;
; Replay - plays stored sound under interrupt control using fractional
; addition, handles loop function, looks for keypresses
;
;*************************************************************************
replay proc near
cli
in al,21h
or al,98h ;disable comms, printer interrupts
out 21h,al
push bp
mov [sptemp],sp ;remember sp incase kbd abort
mov al,1
mov byte ptr [quickexit],al
mov ax,3508h
int 21h ;get system timer vector
mov word ptr [sysold],bx
mov word ptr [sysold+2],es ;and save it
mov dx,offset sysint
push ds
mov ax,cs
mov ds,ax
mov ax,2508h
int 21h ;replace with new one
pop ds
if pwm
mov al,0b0h
out tccont,al ;change timer to one shot mode
mov al,255
out tccount,al
mov al,0
out tccount,al
mov al,90h
out tccont,al
endif
mov al,36h
out 43h,al
mov al,byte ptr [tconstant]
out 40h,al ;set to ~20kHz system timer!
mov al,0
out 40h,al
sti
if pwm
in al,speaker
or al,3
out speaker,al ;speaker one shot enable
endif
loopa: mov bx,[tinterval]
mov si,bx ;local note duration counter
mov bl,byte ptr [modulus]
mov [modul],bl ;local modulus counter
if pwm
mov es,[bufferw+2]
else
mov es,[buffer+2]
endif
mov bx,[bufstart]
mov bp,[increment]
mov ah,byte ptr [loop]
ife pwm
mov dx,[daout]
else
mov dx,tccount
endif
repeat: mov di,[bufend]
mov ch,bl
mov cl,0
loops: add cx,bp ; fractional add (ch.cl is result)
mov bl,ch ; lsnib of buffer pointer
adc bh,0
waiti: mov al,es:[bx] ; get sample
hlt ;wait for system interrupt
if pwm
out dx,al ;activate one shot
out dx,al ;seems to need this else distortion
else
out dx,al
endif
testlop: cmp bx,di
jb loops
test ah,ah ;loop mode?
jz exitr
mov bx,[bufloop]
jmp repeat ;yes, restart from loop position
exitr: mov al,0
mov byte ptr [quickexit],al
call vrestore
cli
in al,21h ;enable serial/parallel ints
and al,67h
out 21h,al
sti
pop bp
ret
replay endp
;*************************************************************************
;
; Replayt - plays stored sound under interrupt control using fractional
; addition, handles loop function, looks for keypresses. this
; version uses timer control
;
;*************************************************************************
replayt proc near
cli
in al,21h
or al,98h ;disable comms, printer interrupts
out 21h,al
push bp
mov [sptemp],sp ;remember sp incase kbd abort
mov al,1
mov byte ptr [quickexit],al
mov ax,3508h
int 21h ;get system timer vector
mov word ptr [sysold],bx
mov word ptr [sysold+2],es ;and save it
mov dx,offset sysint
push ds
mov ax,cs
mov ds,ax
mov ax,2508h
int 21h ;replace with new one
pop ds
if pwm
mov al,0b0h
out tccont,al ;change timer to one shot mode
mov al,255
out tccount,al
mov al,0
out tccount,al
mov al,90h
out tccont,al
endif
mov al,36h
out 43h,al
mov al,byte ptr [tconstant]
out 40h,al ;set to ~20kHz system timer!
mov al,0
out 40h,al
sti
if pwm
in al,speaker
or al,3
out speaker,al ;speaker one shot enable
endif
loopat: mov si,[tinterval] ;local note duration counter
mov bl,byte ptr [modulus]
mov [modul],bl ;local modulus counter
if pwm
mov es,[bufferw+2]
else
mov es,[buffer+2]
endif
mov bx,[bufstart]
mov bp,[increment]
mov ah,[modul]
ife pwm
mov dx,[daout]
else
mov dx,tccount
endif
repeatt: mov di,[bufend]
mov ch,bl
mov cl,0
loopst: add cx,bp ; fractional add (ch.cl is result)
mov bl,ch ; lsnib of buffer pointer
adc bh,0
waitit: mov al,es:[bx] ; get sample
hlt ;wait for system interrupt
if pwm
out dx,al ;activate one shot
out dx,al ;seems to need this else distortion
else
out dx,al
endif
dec ah ;time to dec tinterval?
jz ntestlop
cmp bx,di
jb loopst
test byte ptr [loop],0ffh ;loop mode?
jz waith
mov bx,[bufloop]
jmp repeatt ;yes, restart from loop position
ntestlop: dec si ;see if time up
mov al,byte ptr [modulus] ;reset modulus counter
mov ah,al
js timeupt ; yep, go and check if song mode
cmp bx,di ;2nd copy of testlop avoids jump
jb loopst
test byte ptr [loop],0ffh ;loop mode?
jz waith
mov bx,[bufloop]
jmp repeatt ;yes, restart from loop position
timeupt: test byte ptr [song],0ffh ;song mode?
jnz exitrt ;yes, immediate exit
jmp loopat ;no, loop back to start of sound
waith: test si,0ffffh ;wait for full duration
jns waitit ;wait for keyboard or timer
exitrt: jmp exitr
replayt endp
;
; local procedures
;
;
; Speaker interrupt service routine
;
; Does nothing except synchronise output operations
;
sysint proc far
push ax
mov al,20h
out 20h,al ;EOI to int controller
pop ax
iret
sysint endp
;
; Comm1,2 interrupt service routine
;
; Prevents mouse activity from slowing cpu during sampling/replay
;
comint proc far
push ax
mov al,20h
out 20h,al ;EOI to int controller
pop ax
iret
comint endp
;
; Custom keyboard interrupt handler - handles keypresses, key releases (if
; desired), modifies kbd flags. Note if TP4 kbd or screen
; procedure was in progress, DS may have been changed, so restore
; from dstemp.
;
kbdint proc far ;custom keyboard interrupt handler
push ds
mov ds,cs:[dstemp]
test byte ptr [kbdmode],0ffh ;handle key here?
jnz kserv
pop ds
jmp cs:kbdold ;no, give to bios
kserv: push ax
in al,60h ;get key code
cmp al,lshiftr ;always note shift releases
jz notrel
cmp al,rshiftr
jz notrel
test byte ptr [release],0ffh ;release sensitive?
jnz isrel
test al,al ;no, ignore if key released
js pressd
jmp notrel
isrel: ;release sensitive
cmp al,byte ptr [keyval] ;ignore if same key as last time
jz pressd ; ie ignore autorepeat
test al,al
jns notrel ;if keydown, go record it
mov ah,al
xor ah,byte ptr [keyval]
cmp ah,129 ;record release of last key but
jns pressd ; not release of older key
notrel: mov byte ptr [keyval],al ;record keypressed
mov byte ptr [kbdflag],al
pressd: mov al,0ffh
in al,61h
or al,80h
out 61h,al
and al,7fh
out 61h,al
mov al,20h ;EOI
out 20h,al
pop ax
test byte ptr [quickexit],0ffh
jz noquick
test byte ptr [kbdflag],0ffh
jz noquick
mov es,[sptemp]
pop ds
push es
pop sp
jmp exitr
noquick: pop ds
iret
kbdint endp
vrestore proc near ;restore hardware, system timer vector
cli
mov al,36h
out 43h,al
xor al,al
out 40h,al ;restore system timer frequency
out 40h,al
mov al,0b6h
out tccont,al ;change timer to square wave gen mode
mov al,byte ptr[tconstant]
shr al,1
out tccount,al ;produce mean equivalent dc voltage
xor al,al
out tccount,al
push ds
lds dx,sysold
mov ax,2508h ;restore old system timer vec
int 21h
pop ds
sti
ret
vrestore endp
code ends
end