Lost Tech Archive |
;CHIMER ;------------------------------- ;9/10/1982:ijv ;transferred to MSDOS on 6/2/1984 by ijv ;===================================================== DEVS SEGMENT 'CODE' PUBLIC CHIME ;PROC CHIME,2 ;(pitch,duration) ;Pulse Width generated Chime for IBM PC. ;constants CENTER EQU 32 TIMEHI EQU 10 TIMELO EQU 10 MODE EQU 10110000B ;command for 8253 timer ;ports PORTB EQU 61H ;speaker control port TIMCMD EQU 43H ;timer control port TIMER EQU 42H ;timer2 counter port ;------ data section ------------------------- PITCH DB 00H DUR DB 00H DUMMY DW 0000H ;---------------------------------------------- CHIMECODE PROC FAR ASSUME CS:DEVS,DS:DEVS,ES:DEVS,SS:DEVS ;---------------------------------------------- CHIME PROC FAR CLI PUSH BP MOV BP,SP PUSH DS MOV CX,[BP+6] MOV DUR,CL MOV CX,[BP+8] MOV PITCH,CL MOV DL,31 ;set up max amplitude MOV AL,MODE ;turn timer off if free-running OUT TIMCMD,AL OUT TIMER,AL OUT TIMER,AL IN AL,PORTB ;turn on speaker OR AL,00000011B OUT PORTB,AL ;======= start of time critical code ========= TONE: MOV BH,DUR ;(14) ;do hi part of virtual square wave WAVE: MOV BL,PITCH ;(14) PULSHI: MOV AL,MODE ;( 4) OUT TIMCMD,AL ;(10) ; <-----speaker signal goes low here MOV AL,CENTER ;( 4) ADD AL,DL ;( 3) OUT TIMER,AL ;(10) XOR AL,AL ;( 3) OUT TIMER,AL ;(10) MOV CX,TIMEHI ;( 4) HITIME: LOOP HITIME ;(17*TIMEHI+5) DEC BL ;( 3) virtual square wave width counter JNZ TAIL1 ;(16/4) ;do lo part of virtual square wave MOV BL,PITCH ;(14) PULSLO: MOV AL,MODE ;( 4) OUT TIMCMD,AL ;(10) ; <-----speaker signal goes low here MOV AL,CENTER ;( 4) SUB AL,DL ;( 3) OUT TIMER,AL ;(10) XOR AL,AL ;( 3) OUT TIMER,AL ;(10) MOV CX,TIMELO ;( 4) LOTIME: LOOP LOTIME ;(17*TIMELO+5) DEC BL ;( 3) JNZ TAIL2 ;(16/4) DEC BH ;( 3) duration parameter JNZ TAIL3 ;(16/4) SAR DL,1 ;( 2) cut amplitude in half for next JNZ TONE ;(16/4) ;======= end of time critical code =========== IN AL,PORTB ;turn speaker off AND AL,11111100B OUT PORTB,AL POP DS POP BP STI RET 4 ;------ time adjust sections ----------------- TAIL1: NOP ;( 3) add 41 clocks NOP ;( 3) NOP ;( 3) NOP ;( 3) MOV AX,DUMMY ;(14) JMP PULSHI ;(15) TAIL2: NOP ;( 3) add 41 clocks NOP ;( 3) NOP ;( 3) NOP ;( 3) MOV AX,DUMMY ;(14) JMP PULSLO ;(15) TAIL3: MOV AX,AX ;( 2) add 20 clocks NOP ;( 3) JMP WAVE ;(15) CHIME ENDP CHIMECODE ENDP ;===================================================== DEVS ENDS END |
;Pulse Width Modulated Digital Audio Device Driver for IBM PC. ;============================================================== ; (c)1988 by Ivars Vilums. All Rights Reserved. ;-------------------------------------------------------------- ; ;based on PWM.ASM Pascal procedure by ijv:8/85. ;based on Chime - 9/10/1982:ijv ; as transferred to MSDOS on 6/2/1984 by ijv ; ;-------------------------------------------------------------- ; ;Usage: from MSDOS prompt or batch file: ; ; C>audio ; ; where: ; 'audio' is this program ; ; audio interrupt will be installed at 0F8H and ; a copy of command.com executed. To remove, ; type 'exit' at the command prompt. ; ; To install and run a program such that audio ; automatically is removed at termination of program, ; use: ; C>audio /c [command] ; where: ; audio is this program ; /c needed for proper functioning ; [command] is any DOS command, program, or batch file. ; ;-------------------------------------------------------------- ; ; Audio Interrupt ;---------------- ; ; Int 0F8H ; on entry: AH=0 - play buffer ; DS:BX - address of buffer ; DX - length in bytes of buffer ; AL - PWM cycle length (1 to 6) ; ;-------------------------------------------------------------- ;============================================================================== ;error codes used ;---------------- ;codes returned to DOS on termination. ;can be accessed in batch file using ERRORLEVEL variable. ;MS 4 bits indicates which function failed, ;LS 4 bits indicates error returned by function. COMSPECERROR EQU 10H ;can't find 'COMSPEC=' in ENVIRONMENT ALLOCERROR EQU 20H ;error in allocating buffer ; 27H - arena trashed ; 28H - not enough memory SIZEERROR EQU 30H ;error in reducing program size ; 37H - arena trashed ; 38H - not enough memory ; 39H - invalid block EXECERROR EQU 40H ;error in EXEC function call ; 41H - invalid function ; 42H - file not found ; 48H - not enough memory ; 4AH - bad environment ; 4BH - bad format ;--------------------------------------------- ;Interrupts ;---------- DOSINT EQU 21H ;MSDOS function interrupt vector audioint EQU 065H ;audio interrupt vector. ;MSDOS function call definitions ;------------------------------- PRINTSTR EQU 9 ;function code to print string SETVEC EQU 25H ;function code to set new ISR vector GETVEC EQU 35H ;function code to get current ISR vector GETMEM EQU 48H ;allocate memory function code FREEMEM EQU 49H ;free allocated memory function code MODMEM EQU 4AH ;modify allocated memory blocks function code EXECFUNC EQU 4BH ;function code to run a program TERMFUNC EQU 4CH ;terminate function code ;--------------------------------------------- ;constants MODE EQU 10110000B ;command for 8253 timer PWIDTH EQU 8 ;ports PORTB EQU 61H ;speaker control port TIMCMD EQU 43H ;timer control port TIMER EQU 42H ;timer2 counter port ;---------------------------------------------- ;PSP info offsets ;---------------- ENVSEG EQU 2CH ;PSP offset for segment address of ENVIRONMENT CMDLINE EQU 80H ;location of command line parms in PSP ;--------------------------------------------- ;structure of PBLOCK for EXEC call ;--------------------------------- PRMREC STRUC ENVRECSEG DW ? ;segment address of environment PRMLINER DW ? ;offset address of command line to be passed PRMLINES DW ? ;segment address of command line to be passed DEFFCB1R DW ? ;offset pointer to FCB1 DEFFCB1S DW ? ;segment pointer to FCB1 DEFFCB2R DW ? ;offset pointer to FCB2 DEFFCB2S DW ? ;segment pointer to FCB2 PRMREC ENDS ;--------------------------------------------- CSEG SEGMENT PARA PUBLIC 'CODE' ASSUME CS:CSEG,DS:CSEG ASSUME ES:CSEG,SS:CSEG ORG 100H ;this is a .COM file STARTUP: JMP INIT ;--------------------------------------------- ;Data Area ;--------- NOTICE DB '(c)1988 by Ivars Vilums. All Rights Reserved.' INTSTACK DW 128 DUP(?) ;local stack STACKTOP DW 0 STACKSAVER DW ? ;place to save our stack ptrs. STACKSAVES DW ? OLDVECR DW ? ;place to save interrupt vector we use. OLDVECS DW ? PBLOCK DB 14 DUP(?) ;parameter block for EXEC. REFSTRING DB 'COMSPEC=' ;constant used to find system shell Signon DB 'Audio driver installed.$' Signoff DB 'Audio driver removed.$' ;--------------------------------------------- INIT PROC NEAR ;use internal stack CLI MOV AX,OFFSET STACKTOP MOV SP,AX STI ;free memory beyond this program MOV BX,OFFSET ENDLOC+15 ;length of this program MOV CL,4 ;convert to paragraphs SHR BX,CL ;by div 16 MOV AH,MODMEM INT DOSINT JNC XB1 OR AX,SIZEERROR JMP ERREXIT ;save old vector XB1: PUSH ES MOV AL,audioint MOV AH,GETVEC INT DOSINT MOV OLDVECS,ES MOV OLDVECR,BX POP ES ;set vector to our routine push ds mov ah,SETVEC mov al,audioint mov dx,offset newint int DOSINT pop ds ;save machine state PUSH DS ;save regs and stack PUSH ES CLI MOV CS:STACKSAVER,SP MOV CS:STACKSAVES,SS STI ;set up parameter block for Exec call MOV PBLOCK.ENVRECSEG,00H ;use default environment MOV PBLOCK.PRMLINES,CS ;use parms on command line MOV PBLOCK.PRMLINER,CMDLINE MOV PBLOCK.DEFFCB1S,CS ;point to FCB's in our PSP MOV PBLOCK.DEFFCB1R,5CH MOV PBLOCK.DEFFCB2S,CS MOV PBLOCK.DEFFCB2R,6CH ;get name of system shell from ENVIRONMENT MOV BX,ENVSEG ;find 'COMSPEC=' MOV DS,[BX] MOV SI,0 EX0: CMP BYTE PTR [SI],0 ;end of ENV is 00H JNE EX1 OR AX,COMSPECERROR ;can't find COMSPEC JMP ERREXIT ;stack can be blown EX1: MOV DI,OFFSET REFSTRING ;see if this rec is the one MOV CX,8 CLD REPE CMPSB JE EX3 EX2: INC SI ;advance to end of this rec CMP BYTE PTR [SI],0 ;recs end with 00H JNE EX2 INC SI ;pt to 1st byte of next rec JMP EX0 EX3: MOV DX,SI ;set DS:DX to point to ;drv:[path]\filename.ext of ;current system shell MOV BX,CS MOV ES,BX ;set ES:BX to pt to PBLOCK MOV BX,OFFSET PBLOCK ;do signon message PUSH DS PUSH DX PUSH CS POP DS MOV DX,OFFSET SIGNON MOV AH,PRINTSTR INT DOSINT POP DX POP DS ;execute next program MOV AH,EXECFUNC ;do the EXEC MOV AL,0 INT DOSINT JNC XB3 OR AX,EXECERROR JMP ERREXIT ;restore machine state XB3: CLI MOV SS,CS:STACKSAVES ;get back our internal stack MOV SP,CS:STACKSAVER STI POP ES ;restore segment regs. POP DS ;restore old interrupt vector PUSH DS ;save for later MOV DX,OLDVECR MOV DS,OLDVECS MOV AL,audioint MOV AH,SETVEC INT DOSINT POP DS ;end this program MOV AL,0 ;return code for no errors ;do signoff message PUSH DS PUSH DX PUSH CS POP DS MOV DX,OFFSET SIGNOFF MOV AH,PRINTSTR INT DOSINT POP DX POP DS ENDPROG: MOV AH,TERMFUNC INT DOSINT ERREXIT: JMP ENDPROG ;AL contains return error code INIT ENDP ;-------------------------------------------------------------- ISR PROC FAR ; Interrupt service routine ;-------------------------- PWM PROC NEAR newint: STI PUSH ES PUSH DS PUSH SI PUSH DI PUSH DX PUSH CX PUSH BX PUSH AX CLI MOV AH,AL ;save cycle rate for later MOV AL,MODE ;turn timer off if free-running OUT TIMCMD,AL OUT TIMER,AL OUT TIMER,AL IN AL,PORTB ;turn on speaker OR AL,00000011B OUT PORTB,AL ;======= start of time critical code ========= PULSE: PULSE1: MOV AL,MODE ;( 4) OUT TIMCMD,AL ;(10) ;<-----speaker signal goes low here MOV AL,[BX] ;(10) ;get sample into AL AND AL,0FH ;( 4) ;get low order nibble AND AL,0FH ;( 4) ;time adjustment OUT TIMER,AL ;(10) ;set signal transition time XOR AL,AL ;( 3) OUT TIMER,AL ;(10) XOR CH,CH MOV CL,AH ADLP: ;NOP ;NOP LOOP ADLP INC DX ;( 2) DEC DX ;( 2) JNZ PULSE2 ;(16/4) ;---------------------------------------------- PULSE8: MOV AL,MODE ;( 4) OUT TIMCMD,AL ;(10) ;<-----speaker signal goes low here MOV AL,[BX] ;(10) ;get sample into AL SHR AL,1 ;( 2) ;get high order nibble SHR AL,1 ;( 2) SHR AL,1 ;( 2) SHR AL,1 ;( 2) OUT TIMER,AL ;(10) ;set signal transition time XOR AL,AL ;( 3) OUT TIMER,AL ;(10) XOR CH,CH MOV CL,AH ADLP8: ;NOP ;NOP LOOP ADLP8 ;increment pointer and check for end of buffer INC BX ;( 2) DEC DX ;( 2) JNZ PULSE ;(16/4) JMP DONE ;---------------------------------------------- PULSE7: MOV AL,MODE ;( 4) OUT TIMCMD,AL ;(10) ;<-----speaker signal goes low here MOV AL,[BX] ;(10) ;get sample into AL SHR AL,1 ;( 2) ;get high order nibble SHR AL,1 ;( 2) SHR AL,1 ;( 2) SHR AL,1 ;( 2) OUT TIMER,AL ;(10) ;set signal transition time XOR AL,AL ;( 3) OUT TIMER,AL ;(10) XOR CH,CH MOV CL,AH ADLP7: ;NOP ;NOP LOOP ADLP7 INC DX ;( 2) DEC DX ;( 2) JNZ PULSE8 ;(16/4) ;---------------------------------------------- PULSE6: MOV AL,MODE ;( 4) OUT TIMCMD,AL ;(10) ;<-----speaker signal goes low here MOV AL,[BX] ;(10) ;get sample into AL SHR AL,1 ;( 2) ;get high order nibble SHR AL,1 ;( 2) SHR AL,1 ;( 2) SHR AL,1 ;( 2) OUT TIMER,AL ;(10) ;set signal transition time XOR AL,AL ;( 3) OUT TIMER,AL ;(10) XOR CH,CH MOV CL,AH ADLP6: ;NOP ;NOP LOOP ADLP6 INC DX ;( 2) DEC DX ;( 2) JNZ PULSE7 ;(16/4) ;---------------------------------------------- PULSE2: MOV AL,MODE ;( 4) OUT TIMCMD,AL ;(10) ;<-----speaker signal goes low here MOV AL,[BX] ;(10) ;get sample into AL AND AL,0FH ;( 4) ;get low order nibble AND AL,0FH ;( 4) ;time adjustment OUT TIMER,AL ;(10) ;set signal transition time XOR AL,AL ;( 3) OUT TIMER,AL ;(10) XOR CH,CH MOV CL,AH ADLP2: ;NOP ;NOP LOOP ADLP2 INC DX ;( 2) DEC DX ;( 2) JNZ PULSE3 ;(16/4) ;---------------------------------------------- PULSE5: MOV AL,MODE ;( 4) OUT TIMCMD,AL ;(10) ;<-----speaker signal goes low here MOV AL,[BX] ;(10) ;get sample into AL SHR AL,1 ;( 2) ;get high order nibble SHR AL,1 ;( 2) SHR AL,1 ;( 2) SHR AL,1 ;( 2) OUT TIMER,AL ;(10) ;set signal transition time XOR AL,AL ;( 3) OUT TIMER,AL ;(10) XOR CH,CH MOV CL,AH ADLP5: ;NOP ;NOP LOOP ADLP5 INC DX ;( 2) DEC DX ;( 2) JNZ PULSE6 ;(16/4) ;---------------------------------------------- PULSE3: MOV AL,MODE ;( 4) OUT TIMCMD,AL ;(10) ;<-----speaker signal goes low here MOV AL,[BX] ;(10) ;get sample into AL AND AL,0FH ;( 4) ;get low order nibble AND AL,0FH ;( 4) ;time adjustment OUT TIMER,AL ;(10) ;set signal transition time XOR AL,AL ;( 3) OUT TIMER,AL ;(10) XOR CH,CH MOV CL,AH ADLP3: ;NOP ;NOP LOOP ADLP3 INC DX ;( 2) DEC DX ;( 2) JNZ PULSE4 ;(16/4) ;---------------------------------------------- PULSE4: MOV AL,MODE ;( 4) OUT TIMCMD,AL ;(10) ;<-----speaker signal goes low here MOV AL,[BX] ;(10) ;get sample into AL AND AL,0FH ;( 4) ;get low order nibble AND AL,0FH ;( 4) ;time adjustment OUT TIMER,AL ;(10) ;set signal transition time XOR AL,AL ;( 3) OUT TIMER,AL ;(10) XOR CH,CH MOV CL,AH ADLP4: ;NOP ;NOP LOOP ADLP4 INC DX ;( 2) DEC DX ;( 2) JNZ PULSE5 ;(16/4) ;======= end of time critical code =========== DONE: IN AL,PORTB ;turn speaker off AND AL,11111100B OUT PORTB,AL STI POP AX POP BX POP CX POP DX POP DI POP SI POP DS POP ES IRET PULSET: NOP ;( 3) NOP ;extra 3 for test JMP PULSE1 ;(15) PWM ENDP ISR ENDP ;------------------------------------------------------- ENDLOC DB ? CSEG ENDS END STARTUP |
{$Include:'IBMIntrp.Int'} {$Include:'Devices.Int'} {$Include:'Video.Int'} {$Include:'Grafics.Int'} Program Play(Input,Output); Uses IBMIntrp,Devices,Video,Grafics; Type Bufftype=Array[0..32000] of Byte; Var Buffer:Bufftype; BuffStart,BuffEnd:Integer; Procedure PWM(Vars Start_Address:Byte; Count,Rate:WORD); Const AudioInt=#65; Var Regs:RegList; BufPtr:ADS of Byte; Begin Regs.AX:=Rate; BufPtr:=ads Start_Address; Regs.DS:=BufPtr.S; Regs.BX:=BufPtr.R; Regs.DX:=Count; Intrp(AudioInt,Regs,Regs); End; PROCEDURE ReadBuff; Var Spot:Integer; Divisor,Offset:Integer; X1,X2,Y1,Y2:Byte; FName:LString(80); DFile:File of Byte; BEGIN Write('Name of file to read:'); Readln(FName); Write('Offset:'); Readln(Offset); Write('Divisor:'); Readln(Divisor); Assign(DFile,FName); Reset(DFile); Spot:=0; While (Spot<=8000) and Not(EOF(DFile)) do Begin If Not(EOF(DFile)) then Read(DFile,X1); X2:=X1; Y1:=X1; If Not(EOF(DFile)) then Read(DFile,X2); X1:=Wrd(Ord((X1+X2) div 2) div Divisor); If Not(EOF(DFile)) then Read(DFile,Y1); Y2:=Y1; If Not(EOF(DFile)) then Read(DFile,Y2); Y1:=Wrd(Ord((Y1+Y2) div 2) div Divisor); Buffer[Spot]:=(Y1*16)+X1; Spot:=Spot+1; End; Close(DFile); BuffStart:=0; BuffEnd:=8000; END; PROCEDURE GndBuff; Var Spot:Integer; FillVal:Byte; BEGIN Write('Value to fill with:'); Readln(FillVal); For Spot:=0 to 32000 do Buffer[Spot]:=(FillVal*16)+FillVal; BuffEnd:=32000; END; PROCEDURE Distribs; Var Tally:Array[0..255] of Integer; Min,Max,Spot,DC,Scale:Integer; BEGIN SetGrafMode(Graf320col); DrawLine(31,0,289,0,1); DrawLine(31,199,289,199,1); DrawLine(31,0,31,199,1); DrawLine(289,0,289,199,1); For Spot:=0 to 255 do Tally[Spot]:=0; Min:=Ord(Buffer[BuffStart]); Max:=Min; DC:=Min; For Spot:=BuffStart to BuffEnd do Begin Tally[Ord(Buffer[Spot])]:=Tally[Ord(Buffer[Spot])]+1; If Ord(Buffer[Spot])>Max then Max:=Ord(Buffer[Spot]); If Ord(Buffer[Spot])<Min then Min:=Ord(Buffer[Spot]); End; Scale:=0; For Spot:=0 to 255 do If Tally[Spot]>Scale then Scale:=Tally[Spot]; Scale:=Scale div 197; For Spot:=0 to 254 do DrawLine(Spot+32,Tally[Spot] div Scale,Spot+32,Tally[Spot+1] div Scale,1); Eval(OneKey(True)); SetGrafMode(text80col); END; PROCEDURE SaveBuff; Var BFile:File of Byte; BName:LString(80); Spot:Integer; BEGIN Write('Save as:'); Readln(BName); Assign(BFile,BName); ReWrite(BFile); For Spot:=BuffStart to BuffEnd do Write(BFile,Buffer[Spot]); Close(BFile); END; PROCEDURE LoadBuff; Var BFile:File of Byte; BName:LString(80); BEGIN Write('Name of file:'); Readln(BName); Assign(BFile,BName); Reset(BFile); While Not(EOF(BFile)) and (BuffEnd<32000) do Begin BuffEnd:=BuffEnd+1; Read(BFile,Buffer[BuffEnd]); End; Close(BFile); END; PROCEDURE PlayBuff; Var R:Word; BEGIN Write('Rate:'); Readln(R); While R<256 do Begin PWM(Buffer[BuffStart],Wrd(BuffEnd-BuffStart),R); Write('Rate:'); Readln(R); End; END; PROCEDURE Help; BEGIN Writeln('-> play read load save set fill report help quit <-'); END; PROCEDURE Init; BEGIN BuffStart:=0; BuffEnd:=32000; END; PROCEDURE SetEnds; BEGIN Write('Start:'); Readln(BuffStart); Write(' End:'); Readln(BuffEnd); END; PROCEDURE Commands; Var Done:Boolean; Cmd:LString(80); BEGIN Done:=False; Repeat Write('>'); Readln(Cmd); If Cmd='play' then PlayBuff; If Cmd='load' then LoadBuff; If Cmd='save' then SaveBuff; If Cmd='read' then ReadBuff; If Cmd='fill' then GndBuff; If Cmd='quit' then Done:=True; If Cmd='report' then Distribs; If Cmd='set' then SetEnds; If Cmd='help' then Help; Until Done; END; Begin Help; Commands; End. |