home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
assemblr
/
library
/
sound
/
newbeep
/
newbeep.asm
next >
Wrap
Assembly Source File
|
1992-03-20
|
11KB
|
265 lines
;--------------------------------------------------------------------------
; NEWBEEP.ASM -- redirect DOS's standard BEL to the SoundBlaster FM chips
; ver 1.2 (Wednesday March 6, 1992)
;--------------------------------------------------------------------------
; Copyright (C) 1992, Heath I. Hunnicutt
; This document may be freely distributed if no fee is assigned and the
; document including this notice is unaltered.
;--------------------------------------------------------------------------
; By: heathh@tybalt.cco.caltech.edu -or- @cco.caltech.edu (preferred acct)
; aka hihunn@through.ugcs.caltech.edu (NOT preferred)
;--------------------------------------------------------------------------
; Requires: SoundBlaster sound card or compatible,
; Turbo Assembler from Borland
;--------------------------------------------------------------------------
; Assumes: I/O address of card is based at 0388h.
;--------------------------------------------------------------------------
; Acknowledgements: Ralf Brown -- Interrupt List 29a
; Jeffrey S. Lee -- Programming DOCs for SB FM
;--------------------------------------------------------------------------
; Legal: SoundBlaster is a trademark of Creative Labs, Inc.
; Turbo Assembler is a trademark of Borland International.
;--------------------------------------------------------------------------
;History: 1.0 - Initial posting
; 1.1 - Video call now preserves flags register.
; 1.2 - Broke code into procedures, hopefully useful to programmers,
; used different default I/O address. (388h, not 220h)
; Also, checks for presence of card first! ;)
; Plus, more melodious beep!
; Entirely revamped delay handling! Now beeps decay!
;--------------------------------------------------------------------------
IDEAL ;Depends on TASM's truly ideal mode
MODEL small
SB_Port EQU 0388h ;Base I/O address of card
FM_Reg EQU 0388h ;More descriptive constants
FM_Data EQU 0389h
Delay EQU 36 ;Length of beep (18 = 1sec)
Modulation_FM EQU 0 ;Constants regarding how to
Modulation_Add EQU 1 ;modulate components
CODESEG ;No DATASEG or STACK for TSRs.
Begin:
;Concept: Hook the BIOS video interrupt and watch for BEL characters
; being output.
; Hook the clock tick to time note durations.
OldVideo DD 0 ;Store address of previous Video BIOS routine
OldClock DD 0 ;Store address of previous Clock tick handler
TimeLeft DW 0 ;Count of how many ticks note has left to live
Codes DB 01h,20h ;Waveform select
DB 20h,81h ;No Amplitude modultation / No vibrato
;Sustain until released / No KYB Scaling?
;Operator one octave below voice
DB 23h,81h
DB 40h,10h ;No quieter with high frequency / 12dB attenuated
DB 43h,00h
DB 60h,0F3h ;Fastest attack / Slowest Decay
DB 63h,0F3h
DB 80h,077h ;Sustain level:21 / Release level:21 (?)
DB 83h,07Bh
;Feedback Algorithm and Modulation Technique
;Reg= (Feedback (0-7) SHL 1) OR Mod_Technique
DB 0C0h,(0h OR Modulation_FM) ;Channel 1
DB 0A0h,98h ;Freq MSB. Will be 4D#
DB 0B0h,31h ;Note: D# / Octave: 4 / Voice ON
DB 0FFh,0FFh ;END OF CODES
;Above values will be sent to IO address in sequence.
;Example: Register 20h will be loaded with 81h, 0B0h with 31h
;Based on Jeffrey S. Lee's programming documentation.
PROC NewVideo
;----------------------------------------------------------
;This procedure will become the new video BIOS call handler
;----------------------------------------------------------
pushf ;Preserve flags through cmp
cmp ax,0E07h ;Is function displaying BEL character?
je Handle_This ; y: Jump to our BEL code
popf ; n: Restore original flags...
jmp [DWORD PTR cs:OldVideo] ; ...Pass function on to BIOS
Handle_This:
call _FM_Beep C, OFFSET Codes, SEG Codes
;Doin' da Beep...
popf ;Restore flags, as if it mattered.
iret ;See ya.
ENDP NewVideo
PROC NewClock
;----------------------------------------------------------
;This procedure will become the new timer BIOS call handler
;----------------------------------------------------------
pushf ;Preserve flags
cmp [WORD PTR cs:TimeLeft],0 ;Are we counting?
je @@See_Ya ; n: Skip this
dec [WORD PTR cs:TimeLeft] ; y: Count down
jnz @@See_Ya ;Done?
call _Reset_FM ; y: Silence voice
@@See_Ya:
popf ;Restore flags
jmp [DWORD PTR cs:OldClock] ;Pass through to next handler
ENDP NewClock
PROC SB_Delay
;--------------------------------------
;Delays for cx reads of the status port
;--------------------------------------
push ax dx
mov dx,FM_Reg
@@D:
in al,dx
loop @@D
pop dx ax
ret
ENDP SB_Delay
PROC _FM_Beep
ARG Params:DWORD
;------------------------------
;Produces a tone through the SB
;Preserves all registers
;------------------------------
push bp
mov bp,sp
push cx si ds ;Preserve these registers
call _Reset_FM ;Set the card up
lds si,[Params]
cmp [BYTE PTR si],0FFh ;At end of list?
je Done ; y: Don't program card
Looper:
call _Write_FM_Register C, [si], [si+1]
inc si ;Index to next register/
inc si ; value pair.
cmp [BYTE PTR si],0FFh ;At end of list?
jne Looper ; n: Repeat
mov [TimeLeft],Delay ; y: Store the number of ticks for
; tone
Done:
pop ds si cx ;Restore those precious registers
pop bp
ret
ENDP _FM_Beep
PROC _Reset_FM
;--------------------------------------------------------------------
;Writes zeros to all FM registers, resetting chips (turns off sound.)
;--------------------------------------------------------------------
push cx ;Preserve cx
mov cx,0ffh ;cx holds current register number
Next_Reg:
call _Write_FM_Register C, cx, 0
loop Next_Reg ;Continue until cx = 0
pop cx ;Restore cx
ret ;then return
ENDP _Reset_FM
;void Write_FM_Register(int Reg, int Value)
PROC _Write_FM_Register
ARG Reg:Word,Value:Word
;------------------------------------------------------------
;Writes a given value to a given register, with proper delays
;------------------------------------------------------------
push bp ;preserve bp
mov bp,sp ;Standard Stack frame (for C)
push ax cx dx ;preserve 'em
mov dx,FM_Reg
mov ax,[Reg] ;Register <- reg
out dx,al
mov cx,6 ;Let SB 'swallow' that byte
call SB_Delay
mov dx,FM_Data
mov ax,[Value] ;Data <- Value
out dx,al
mov cx,35 ;Pause
call SB_Delay
pop dx cx ax ;Restore all regs...
pop bp
ret
ENDP _Write_FM_Register
Last:
;=================================================================
;Only the code prior to this label (Last) is kept memory resident.
;=================================================================
PROC _ADLib_Installed
;----------------------------------------------------------------
;Returns: AX==0 and Carry set if no card detected
; AX==-1 and Carry clear if card succesfully detected
;----------------------------------------------------------------
call _Reset_FM
call _Write_FM_Register C, 4, 60h ;Reset timers
call _Write_FM_Register C, 4, 80h ;Enable interrupts
mov dx,FM_Reg
in al,dx ;Read status
and al,0E0h ;Mask bits
jnz @@Sorry ;Not zero -> fail
call _Write_FM_Register C, 2, 0FFh ;Set timer
call _Write_FM_Register C, 4, 21h ;Start timer
mov cx,14000 ;SB_Delay 80 usec
call SB_Delay ;Wait for timer to expire
mov dx,FM_Reg
in al,dx ;Read status
call _Write_FM_Register C, 4, 60h ;Turn off timers
call _Write_FM_Register C, 4, 00h ;Disable interrupts
and ax,00E0h ;Mask bits
cmp al,0C0h ;Desired value?
jne @@Sorry ; n: Fail
mov ax,-1 ; y: Return(-1)
clc ; Clear carry
ret
@@Sorry:
xor ax,ax ;Return(0)
stc ;Set carry
ret
ENDP _ADLib_Installed
No_Card DB "Good job, dude, but you don't have a sound card.",10,13,"$"
Ok DB "NEWBEEP installed in memory.",10,13,"$"
Start:
mov ax,cs ;Set up segments
mov es,ax
mov ds,ax
call _AdLib_Installed ;Is there a card out there?
jnc Go_Ahead ; y: Continue
mov dx,OFFSET No_Card ; n: Print a message of great
mov ah,9 ; disappointment
int 21h
mov ax,4C00h ;exit(0)
int 21h
Go_Ahead:
mov ax,3510h ;Get interrupt vector for Video
int 21h
mov [WORD PTR OldVideo],bx ;Store it in OldVideo
mov ax,es
mov [WORD PTR OldVideo+2],ax
mov dx,OFFSET NewVideo ;ds:dx -> NewVideo
mov ax,2510h ;Set new interrupt vector
int 21h
mov ax,3508h ;Get interrupt vector for Clock
int 21h
mov [WORD PTR OldClock],bx ;Store it in OldClock
mov ax,es
mov [WORD PTR OldClock+2],ax
mov dx,OFFSET NewClock ;ds:dx -> NewClock
mov ax,2508h ;Set new interrupt vector
int 21h
mov dx,OFFSET Ok ;Print message of great joy
mov ah,9
int 21h
mov dx,((Last-Begin)+100h+15)/16 ;Calculate memory size..
mov ax,3100h ;Termiante Stay Resident
int 21h
ENDS
END Start ;Execution begins at Start: label