home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Audio 4.94 - Over 11,000 Files
/
audio-11000.iso
/
msdos
/
sndbords
/
proaudio
/
pas_sdk1
/
pas
/
subs
/
pcm
/
pcmioa.asm
< prev
next >
Wrap
Assembly Source File
|
1992-09-28
|
15KB
|
669 lines
;$Author: DCODY $
;$Date: 23 Sep 1992 10:57:04 $
;$Header: X:/sccs/pcm/pcmioa.asv 1.4 23 Sep 1992 10:57:04 DCODY $
;$Log: X:/sccs/pcm/pcmioa.asv $
;
; Rev 1.4 23 Sep 1992 10:57:04 DCODY
; more work on playthisblock, continuethisblock...
;
; Rev 1.3 26 Aug 1992 10:58:26 DCODY
; added Playthisblock and RecordthisBlock support routines
;
; Rev 1.2 12 Aug 1992 17:10:56 DCODY
; major change to eliminate the foreground buffers and background
; processing responsibilities.
;
; Rev 1.1 23 Jun 1992 17:11:34 DCODY
; PAS2 update
;
; Rev 1.0 15 Jun 1992 09:44:36 BCRANE
; Initial revision.
;$Logfile: X:/sccs/pcm/pcmioa.asv $
;$Modtimes$
;$Revision: 1.4 $
;$Workfile: pcmioa.asm $
page 64,131
Title PCMIOA -- Background Task for PCM I/O
; /*\
;---|*|
;---|*|------------====< PCMIOA.ASM >====------------
;---|*|
;---|*| Copyright (c) 1991, Media Vision, Inc. All rights reserved
;---|*|
; \*/
.xlist
include model.inc
include masm.inc
include common.inc
include binary.inc
.list
PCMCODEVERSION equ 0003h ; version 00.03
;
;-----------------------================================-----------------------
;-----------------------====< Code/Data Generation >====-----------------------
;-----------------------================================-----------------------
;
BLOCKOUT = 0 ; builds block output code only
BLOCKIN = 0 ; builds block input code only
COMMDATA = 0 ; builds both common code and data
ifdef BUILDBO
BLOCKOUT = 1
endif
ifdef BUILDBI
BLOCKIN = 1
endif
ifdef BUILDCO
COMMDATA = 1
endif
;
;---------------------------========================---------------------------
;---------------------------====< DATA SECTION >====---------------------------
;---------------------------========================---------------------------
;
.data
;
; Code Model Dependencies
;
if @datasize
cptr equ <dword> ; C pointer is FAR
else
cptr equ <word> ; C pointer is NEAR
endif
NODIRECTION equ 0
DMAINPUT equ 1
DMAOUTPUT equ 2
PCMFILEINPUT equ DMAINPUT
PCMFILEOUTPUT equ DMAOUTPUT
PCMBLOCKINPUT equ DMAINPUT+80h
PCMBLOCKOUTPUT equ DMAOUTPUT+80h
;
; Structure Definitions
;
buffptr struc
BPstatus dw 0 ; 0=empty, 1=full
BPcount dw 0 ; # of bytes in the buffer
BPsize dw 0 ; total size of allocated buff
BPbuffer dd 0 ; pointer to buffer data
if @datasize
BPnextptr dd 0 ; pointer to buffer data
else
BPnextptr dw 0 ; pointer to buffer data
endif
buffptr ends
;
;--------------====< code generation dependent declarations >====------------
;
if COMMDATA
;
; Local data declarations
;
public CountdownBuffers
CountdownBuffers db 00 ; countdown value
public NextDMAPtr
NextDMAPtr dd 00 ; our pointer to the DMA's buffer
public DMAUnitSize
DMAUnitSize dw 00 ; size of DMA buffer divisions
public __callersroutine
if @codesize
__callersroutine dd 00
else
__callersroutine dw 00
endif
else
extrn __callersroutine :word
extrn __NextPtr :dword ; pointer to circular buffer list
;
; Local data declarations
;
extrn CountdownBuffers :byte ; countdown value
extrn NextDMAPtr :dword ; our pointer to the DMA's buffer
extrn DMAUnitSize :word ; size of DMA buffer divisions
endif
externPTR HeadOfBuffers ; pointer to buffer linked list
extrn BufferDataCount :word ; # of full buffers (0=done)
extrn DMARunning :word ; DMA status (0=off,1=running)
extrn StartOfDMABuffer :dword ; always a far * to start of DMA buffer
extrn __pcmdatasize :byte ; default to 8 bit pcm
extrn MaxBuffCount :word ; count of DMA blocks
extrn ProcessedBlockCount:word; # of full buffers (0=done)
extrn __synccallback :dword ; callback to application at int
;
;---------------------------========================---------------------------
;---------------------------====< CODE SECTION >====---------------------------
;---------------------------========================---------------------------
;
.code
externADDR InitPCM ; initialize the PCM low level code
externADDR StopPCM ; Kill the PCM hardware
externADDR PCMPlay ; start the PCM output
externADDR PCMRecord ; start the PCM input
externADDR UserFunc ; sets up the call-back routine
if (BLOCKOUT or BLOCKIN)
externADDR _resetdmaptrs ; reset the criticals
endif
if COMMDATA
;
; /*\
;---|*|
;---|*|------------====< BackgroundInit( int, int ) >====------------
;---|*|
;---|*| Initialize our internal variables, etc...
;---|*|
;---|*| Entry Conditions:
;---|*| wParm1 - Size of DMA buffer
;---|*| wParm2 - # of DMA buffer divisions
;---|*|
;---|*| Exit Conditions:
;---|*| No return value
;---|*|
;---|*| Functionality:
;---|*|
;---|*| Clear interrupt mechanisms.
;---|*| Disable DMA channel.
;---|*| Set DMARunning to 0;
;---|*|
; \*/
public BackgroundInit
BackgroundInit proc
push bp
mov bp,sp
push es
;
; get the # of buffers in the linked list
;
mov ax,wParm1
mov [DMAUnitSize],ax ; max size of each DMA division
;
; flush any prior low-level setup
;
call InitPCM
mov DMARunning,0 ; signal it dead
;
; all done, return home
;
pop es
pop bp
ret
BackgroundInit endp
endif ; COMMDATA
if BLOCKOUT
; /*\
;---|*|
;---|*|--------------====< FlushBuffer >====-----------------
;---|*|
;---|*| Flush the buffer by filling it with silence (value of 0x80)
;---|*|
;---|*| Entry Conditions:
;---|*| dParm1 is the far pointer to the block
;---|*| wParm2 is an unsigned integer which is the block length
;---|*|
;---|*| Exit Conditions:
;---|*| DX:AX hold the ending pointer
;---|*|
;---|*| Prototype:
;---|*|
;---|*| char far * FlushBuffer (char far *, int)
;---|*|
;---|*|
; \*/
public FlushBuffer
FlushBuffer proc
push bp
mov bp,sp
push es
push di
pushf
cld
les di,dParm1 ; grab 2 words off the stack
mov cx,wParm3 ; wParm3 is used to skip the 2nd word
cmp [__pcmdatasize],9 ; 8 bit sets the carry
sbb al,al ; al = ff if 8 bit PCM
and al,80h ; al = 80 if 8 bit, 00 if 16 bit
jcxz @F
rep stosb
@@:
mov dx,es ; return the ending ptr
mov ax,di
popf
pop di
pop es
pop bp
ret
FlushBuffer endp
endif ; BLOCKOUT
if BLOCKIN
; /*\
;---|*|
;---|*|------------====< StartTheDMAInput() >====------------
;---|*|
;---|*| Calculate the H/W timer value (internal routine)
;---|*|
;---|*| Entry Conditions:
;---|*| pointer to a routine
;---|*|
;---|*| Exit Conditions:
;---|*| AX = 0 indicates DMA running
;---|*| AX = -1 indicates a failure
;---|*|
;---|*| Functionality:
;---|*|
;---|*| Reset input pointer to the DMA buffer.
;---|*| Load next buffer of data into the DMA buffer.
;---|*| Enable DMA & interrupts.
;---|*| Set DMARunning to 1;
;---|*|
; \*/
public StartTheDMAInput
StartTheDMAInput proc
push bp
mov bp,sp
push es
;
; Reset the DMA's internal buffer pointer & counter
;
call _resetdmaptrs ; reset the criticals
;
; Validate some critical data
;
mov ax,-1 ; setup for bad return
cmp DMAUnitSize,0 ; we must have a valid size of units
jz stdmaout_bad
les bx,[NextDMAPtr] ; we must have a valid DMA buffer
mov cx,es
or bx,cx
jz stdmaout_bad
;
; setup the callers callback
;
if @codesize
mov ax,wParm1+0
mov dx,wParm1+2
mov wptr [__callersroutine+0],ax
mov wptr [__callersroutine+2],dx
else
mov ax,wParm1+0
mov [__callersroutine],ax
endif
;
; setup our call-back routine
;
lea ax,InputBackgroundTask
push cs
push ax
call UserFunc
add sp,4
;
; The DMA is loaded, let'er rip!!!
;
call PCMRecord
mov DMARunning,1
sub ax,ax
;
stdmaout_bad:
pop es
pop bp
ret
StartTheDMAInput endp
endif ; BLOCKIN
if BLOCKOUT
; /*\
;---|*|
;---|*|------------====< StartTheDMAOutput() >====------------
;---|*|
;---|*| Calculate the H/W timer value (internal routine)
;---|*|
;---|*| Entry Conditions:
;---|*| None
;---|*|
;---|*| Exit Conditions:
;---|*| AX = 0 indicates DMA running
;---|*| AX = -1 indicates a failure
;---|*|
;---|*| Functionality:
;---|*|
;---|*| Reset input pointer to the DMA buffer.
;---|*| Load next buffer of data into the DMA buffer.
;---|*| Enable DMA & interrupts.
;---|*| Set DMARunning to 1;
;---|*|
; \*/
public StartTheDMAOutput
StartTheDMAOutput proc
push bp
mov bp,sp
push es
;
; Reset the DMA's internal buffer pointer & counter
;
call _resetdmaptrs ; reset the criticals
;
; Validate some critical data
;
mov ax,-1 ; setup for bad return
cmp DMAUnitSize,0 ; we must have a valid size of units
jz stdmaout_bad
les bx,[NextDMAPtr] ; we must have a valid DMA buffer
mov cx,es
or bx,cx
jz stdmaout_bad
;
; setup the callers callback
;
if @codesize
mov ax,wParm1+0
mov dx,wParm1+2
mov wptr [__callersroutine+0],ax
mov wptr [__callersroutine+2],dx
else
mov ax,wParm1+0
mov [__callersroutine],ax
endif
;
; setup our call-back routine
;
lea ax,OutputBackgroundTask
push cs
push ax
call UserFunc
add sp,4
;
; The DMA is loaded, let'er rip!!!
;
call PCMPlay
mov DMARunning,1
sub ax,ax
;
stdmaout_bad:
pop es
pop bp
ret
StartTheDMAOutput endp
endif ;; BLOCKOUT
;
;--------------------------=============================-----------------------
;--------------------------====< Internal Routines >====-----------------------
;--------------------------=============================-----------------------
;
if BLOCKIN
; /*\
;---|*|
;---|*|------------====< InputBackgroundTask() >====------------
;---|*|
;---|*| This is the interrupt code for processing DMA-buffer-has-data interrupts
;---|*|
;---|*| Entry Conditions:
;---|*| None
;---|*|
;---|*| Exit Conditions:
;---|*| None
;---|*|
;---|*| Interrupt handling:
;---|*|
;---|*| if Next Buffer has data,
;---|*| Kill-the-DMA;
;---|*| set DMARunning to 0;
;---|*| exit interrupt.
;---|*| else
;---|*| Load DMA into Next buffer.
;---|*|
;---|*| Increment BufferDataCount.
;---|*| Increment ProcessBlockCount.
;---|*|
; \*/
InputBackgroundTask proc far
push ax ; save the entire state
push bx
push cx
push dx
push si
push di
push ds
push es
;
; initialize the segment registers to point to our local static segment
;
mov ax,@data ; load our data segment
mov ds,ax ; DS too in case of failure
;
; Save the next DMA pointer, increment our internal buffer-loaded count
;
inc ProcessedBlockCount ; total block count the DMA has seen
inc BufferDataCount ; tell the world, we have new data
mov ax,BufferDataCount
cmp ax,MaxBuffCount
jb inbkgrtsk_exit
;
; Yuck! We just ran out of buffer space, we must kill the DMA
;
call StopPCM ; kill the interrupts...
mov DMARunning,0
;
inbkgrtsk_exit:
if @codesize
cmp wptr [__callersroutine+2],0 ; if there is no vector, just exit
jz @F
call dptr [__callersroutine] ; call the user routine
@@:
else
cmp wptr [__callersroutine],0 ; if there is no vector, just exit
jz @F
call wptr [__callersroutine] ; call the user routine
@@:
endif
;
; Call the application level it it wants a slice of time...
;
cmp wptr [__synccallback+2],0 ; if no App. vector, just exit
jz @F
call dptr [__synccallback] ; if no App. vector, just exit
@@:
;
; finally, all done.
;
pop es
pop ds
pop di
pop si
pop dx
pop cx
pop bx
pop ax
retf
InputBackgroundTask endp
endif ; BLOCKIN
if BLOCKOUT
; /*\
;---|*|
;---|*|------------====< OutputBackgroundTask() >====------------
;---|*|
;---|*| This is the interrupt code for processing DMA buffer
;---|*| empty interrupts for the file output routines.
;---|*|
;---|*| Entry Conditions:
;---|*| None
;---|*|
;---|*| Exit Conditions:
;---|*| None
;---|*|
;---|*| Interrupt handling:
;---|*|
;---|*| If BufferDataCount is zero,
;---|*| Kill-the-DMA;
;---|*| set DMARunning to 0;
;---|*|
;---|*| Attempt to load as many blocks as possible into the DMA buffer.
;---|*|
;---|*| If data is loaded and DMARunning = 0,
;---|*| restart the DMA;
;---|*| set DMARunning to -1;
;---|*|
;---|*| Exit interrupt.
;---|*|
; \*/
OutputBackgroundTask proc far
push ax ; save the entire state
push bx
push cx
push dx
push si
push di
push ds
push es
;
; initialize the data segment to point to our local static segment
;
mov ax,@data ; load our data segment
mov ds,ax
;
; We just finished a block. If done (0), stop the DMA, else go load another
;
inc ProcessedBlockCount ; total block count the DMA has seen
sub BufferDataCount,1 ; decrement the internal buffered data
adc BufferDataCount,0 ; count down to zero
jnz bkgrtsk_05 ; more data, go load it...
;
; Yuck! We just ran out of data, we must silence the DMA
;
call StopPCM ; kill the interrupts...
mov DMARunning,0
;
bkgrtsk_05:
if @codesize
cmp wptr [__callersroutine+2],0 ; if there is no vector, just exit
jz @F
call dptr [__callersroutine] ; call the user routine
@@:
else
cmp wptr [__callersroutine],0 ; if there is no vector, just exit
jz @F
call wptr [__callersroutine] ; call the user routine
@@:
endif
;
; Call the application level it it wants a slice of time...
;
cmp wptr [__synccallback+2],0 ; if no App. vector, just exit
jz @F
call dptr [__synccallback] ; if no App. vector, just exit
@@:
;
; finally, all done.
;
pop es
pop ds
pop di
pop si
pop dx
pop cx
pop bx
pop ax
retf
OutputBackgroundTask endp
endif ; BLOCKOUT
if COMMDATA
;
; /*\
;---|*|
;---|*|------------====< _resetdmaptrs >====----------------
;---|*|
;---|*| Reset the DMA starting point
;---|*|
;---|*| Entry Conditions:
;---|*| DS points to the default data segment
;---|*|
;---|*| Exit Conditions:
;---|*| None
;---|*|
; \*/
_resetdmaptrs proc
push es
;
; load the number of buffer divisions. this tells us when to wrap the DMA buff
;
mov al,byte ptr [MaxBuffCount]
mov [CountdownBuffers],al
;
; reset the DMA buffer offset
;
les ax,[StartOfDMABuffer]
mov wptr [NextDMAPtr+0],ax
mov wptr [NextDMAPtr+2],es
pop es
ret
_resetdmaptrs endp
endif ; COMMDATA
; /*\
;---|*| end of PCMIOA.ASM
; \*/
end