home *** CD-ROM | disk | FTP | other *** search
- /*$Author: DCODY $*/
- /*$Date: 09 Feb 1993 08:26:30 $*/
- /*$Header: X:/sccs/pcm/pcmoldc.c_v 1.0 09 Feb 1993 08:26:30 DCODY $*/
- /*$Log: X:/sccs/pcm/pcmoldc.c_v $
- *
- * Rev 1.0 09 Feb 1993 08:26:30 DCODY
- * Initial revision.
- *
- * Rev 1.12 03 Feb 1993 12:09:48 DCODY
- * just more debug statements added, no real changes.
- *
- * Rev 1.11 06 Jan 1993 15:26:34 DCODY
- * corrected two bugs: ContinueThisBlockOutput had a bug in an IF statement
- * where it evaluated the two expressions incorrectly. The second bug was
- * in QueryPCMStream, which returned an incorrect value.
- * Also, some debugging info was added, but commented out.
- *
- * Rev 1.10 08 Dec 1992 17:13:54 DCODY
- * added a new routine: QueryPCMStream to return the number of blocks
- * buffered.
- * Also added, but commented out some debugging code.
- *
- * Rev 1.9 20 Oct 1992 10:07:38 DCODY
- * lots of cosmetic changes. all variables are now initialized so they
- * have memory allocated at compile time.
- *
- * Rev 1.8 06 Oct 1992 15:59:50 DCODY
- * major changes so code is free (freer) from the C libraries. Replaced
- * malloc and fread/fwrite.
- *
- * Rev 1.7 01 Oct 1992 12:05:02 DCODY
- * next stage of completion for PlayThisBlock, RecordThisBlock, etc.
- *
- * Rev 1.6 23 Sep 1992 10:56:34 DCODY
- * more work on playthisblock, continuethisblock...
- *
- * Rev 1.5 26 Aug 1992 10:57:30 DCODY
- * Added Playthisblock and RecordThisBlock
- *
- * Rev 1.4 12 Aug 1992 17:10:30 DCODY
- * major change to eliminate the foreground buffers.
- *
- * Rev 1.3 24 Jul 1992 15:36:14 DCODY
- * changed _fmemcpy to _rfmemcpy
- *
- * Rev 1.2 17 Jul 1992 14:22:50 DCODY
- * InitMVSound() now performed within OpenPCMBuffering().
- *
- * Rev 1.1 23 Jun 1992 17:11:42 DCODY
- * PAS2 update
- *
- * Rev 1.0 15 Jun 1992 09:44:38 BCRANE
- * Initial revision.
- */
- /*$Logfile: X:/sccs/pcm/pcmoldc.c_v $*/
- /*$Modtimes$*/
- /*$Revision: 1.0 $*/
- /*$Workfile: pcmoldc.c $*/
-
-
- ; /*\
- ;---|*|----====< PCMIOC.C >====----
- ;---|*|
- ;---|*| These routines maintain DMA controlled I/O of the Audio Spectrum
- ;---|*|
- ;---|*| Copyright (c) 1991, Media Vision, Inc. All rights reserved.
- ;---|*|
- ; \*/
-
- #include <stdio.h>
- #include <stdlib.h>
-
- #include "pcmio.h"
- #include "common.h"
- #include "mvsound.h"
-
- ; /*\
- ;---|*|-----------====< T H E O R Y O F O P E R A T I O N >====------------
- ;---|*|
- ;---|*| The best DMA controlled PCM output requires a continuous stream of data
- ;---|*| to be available in a real-time environment.
- ;---|*|
- ;---|*| DMA controlled PCM input, with the same real-time requirements, needs
- ;---|*| to be able to keep storing data into memory without pausing.
- ;---|*|
- ;---|*| The following approach is designed to allow the DMA to be setup in
- ;---|*| "auto-initialize" mode, thereby guarenteeing continuous play/record.
- ;---|*|
- ;---|*| To keep the DMA running, multiple divisions of the DMA buffer are
- ;---|*| used to keep the data moving. Due to the fact that DOS is neither
- ;---|*| a real-time, or re-entrant operating system, this code divides up
- ;---|*| the buffer management tasks into a "foreground" and "background" task.
- ;---|*|
- ;---|*| A sample buffer count timer on the Audio Spectrum is used to interrupt
- ;---|*| the CPU when a DMA buffer division has filled or emptied. For our
- ;---|*| purposes here, this amount may be 1/2, 1/4, 1/8th or some smaller
- ;---|*| division of the whole DMA buffer. Note: judgement must be used here
- ;---|*| in selecting the DMA buffer size, and the integral division. Too small
- ;---|*| of an integral may result in broken DMA I/O. A buffer too large never
- ;---|*| hurts anything. (it just reduces the amount of available memory).
- ;---|*|
- ;---|*| ----====< PCM OUTPUT >====----
- ;---|*|
- ;---|*| To perform PCM output ("play"), A linked list of buffer pointers is
- ;---|*| used to fill the DMA buffer by the foregound task. As the DMA runs,
- ;---|*| it will send the buffer contents to the audio card. Here is a visual:
- ;---|*|
- ;---|*|
- ;---|*| Foreground Loads
- ;---|*| the Top Level
- ;---|*| Buffers
- ;---|*|
- ;---|*| ⁄ƒ¬ƒ¬ƒ¬ƒ¬ƒø
- ;---|*| DMA Level Buffers ≥ ≥ ≥ ≥ ≥ ≥
- ;---|*| ¿ƒ¡ƒ¡ƒ¡ƒ¡ƒŸ
- ;---|*|
- ;---|*| ⁄ƒƒƒƒƒƒƒƒƒø
- ;---|*| ≥hardware ≥
- ;---|*| ¿“““ƒƒƒƒƒƒŸ
- ;---|*|
- ;---|*| To actually start the output, the foreground task loads it's
- ;---|*| buffers, then starts the DMA to play the buffer. The background
- ;---|*| task only indicates when each block is played. It will shut down
- ;---|*| the DMA if no more data is present in the buffers.
- ;---|*|
- ;---|*| If the foreground task can keep the linked list of buffers full,
- ;---|*| there should be non-stop PCM output (Good!). If the foreground task
- ;---|*| does not keep up, the background task will be forced to stop the
- ;---|*| the DMA, thereby causing a break in the output (Bad!). Once the DMA
- ;---|*| has stopped, the foreground task will have to restart the DMA a
- ;---|*| second time to continue the flow of data.
- ;---|*|
- ;---|*| ----====< PCM INPUT >====----
- ;---|*|
- ;---|*| To perform PCM input ("record"), the same linked list of buffers
- ;---|*| are also used. This buffer is filled with sampled data from the
- ;---|*| hardware. The background process will increment a global variable for
- ;---|*| each buffer filled. The foreground routine must extract each buffer
- ;---|*| and process it (copy to memory, or write it to disk). Here is a visual:
- ;---|*|
- ;---|*|
- ;---|*| Foreground unloads
- ;---|*| the Top Level
- ;---|*| Buffers
- ;---|*|
- ;---|*| ⁄ƒ¬ƒ¬ƒ¬ƒ¬ƒø
- ;---|*| DMA Level Buffers ≥ ≥ ≥ ≥ ≥ ≥
- ;---|*| ¿ƒ¡ƒ¡ƒ¡ƒ¡ƒŸ
- ;---|*|
- ;---|*| ⁄ƒƒƒƒƒƒƒƒƒø
- ;---|*| ≥hardware ≥
- ;---|*| ¿“““ƒƒƒƒƒƒŸ
- ;---|*|
- ;---|*| To actually start the input, the foreground starts the DMA running to
- ;---|*| begin the transfer. The background task increments the global variable
- ;---|*| as each interrupt occurs. If all the buffers are full, the DMA transfer
- ;---|*| is terminated. The foreground routine must poll this variable to keep
- ;---|*| the data moving out of the DMA buffer.
- ;---|*|
- ;---|*| If the foreground task can keep the linked list of buffers empty,
- ;---|*| there should be non-stop PCM input (Good!). If the foreground task
- ;---|*| does not keep up, the background task will be forced to stop the
- ;---|*| the DMA, thereby causing a break in the input (Bad!). Once the DMA
- ;---|*| has stopped, the foreground task will have to restart the DMA tranfer
- ;---|*| a second time to restart the DMA.
- ;---|*|
- ;---|*| ----====< DATA VARIABLES >====----
- ;---|*|
- ;---|*| The following is a description of the variables shared between the
- ;---|*| foreground and background tasks. There are three global variables,
- ;---|*| and a linked list of buffers shared between the two tasks.
- ;---|*|
- ;---|*| The linked list of buffers uses a "header" to each buffer. This
- ;---|*| header holds the information for linking to the next buffer, whether
- ;---|*| the buffer is full or empty, and the count of bytes in the buffer.
- ;---|*|
- ;---|*| typedef struct _buffptr {
- ;---|*| int status; /* 0=empty, 1=full * /
- ;---|*| int count; /* # of bytes in the buffer * /
- ;---|*| int size; /* total size of read data * /
- ;---|*| char huge *buffer; /* pointer to buffer data * /
- ;---|*| struct _buffptr, *nextptr; /* pointer to next buffer * /
- ;---|*|
- ;---|*| } BuffData,*BuffPtr;
- ;---|*|
- ;---|*| BuffPtr HeadOfBuffers; /* global variable head pointer * /
- ;---|*| int BufferDataCount; /* # of full DMA buffers parts * /
- ;---|*| int DMARunning; /* DMA status (0=off,1=running) * /
- ;---|*| char far *StartOfDMABuffer; /* start of actual DMA buffer * /
- ;---|*| int ProcessedBlockCount; /* # of blocks DMA handled * /
- ;---|*|
- ;---|*| "HeadOfBuffers" points to the first buffer in the linked list.
- ;---|*|
- ;---|*| This linked list is made up of structures containing the buffer
- ;---|*| data and other information. The last entry in the list points
- ;---|*| back to the first entry, thereby creating a circular linked
- ;---|*| list.
- ;---|*| Each buffer has a status word: 0=empty,1=full.
- ;---|*| The count indicates the # of bytes in the buffer. This count
- ;---|*| is used to communication between the foreground and background
- ;---|*| process that data is available. For output, the count tells the
- ;---|*| background that data is available to be loaded in the DMA buffer.
- ;---|*| For input, the count tells the foreground process that there is
- ;---|*| data to be written to disk.
- ;---|*|
- ;---|*| "BufferDataCount" is the key handshaking variable between the
- ;---|*| foreground and background processes. It indicates how many DMA
- ;---|*| buffers divisions contain data.
- ;---|*|
- ;---|*| For output, it holds a count of DMA divisions hold data. This
- ;---|*| global variable is incremented each time a buffer is loaded by
- ;---|*| the foreground task, and decremented when a buffer is emptied
- ;---|*| by the background task.
- ;---|*|
- ;---|*| For input, it holds the number of buffers with data in the DMA
- ;---|*| buffer. It is incremented by the background process and
- ;---|*| decremented by the foreground process.
- ;---|*|
- ;---|*| "DMARunning" is set to true or false depending upon the state
- ;---|*| of the DMA channel. It is set TRUE when the DMA is running (either
- ;---|*| playing or recording), and FALSE when the DMA is turned off.
- ;---|*|
- ;---|*| "ProcessedBlockCount" is the running total of blocks the DMA has
- ;---|*| processed from the last Start I/O call.
- ;---|*|
- ;---|*| For input, this is the total number of dma divisions filled
- ;---|*| by the DMA.
- ;---|*|
- ;---|*| For output, this is the total number of blocks loaded into
- ;---|*| the DMA buffer.
- ;---|*|
- ;---|*| "StartOfDMABuffer" points to the first byte of the DMA circular buffer.
- ;---|*|
- ;---|*| The following routines provide a high level interface to DMA driven
- ;---|*| PCM output:
- ;---|*|
- ;---|*| int OpenPCMBuffering ( int, int, int, int )
- ;---|*|
- ;---|*| This routine is the first routine to be called. It sets
- ;---|*| up the DMA channel, IRQ, and allocates memory for the buffers.
- ;---|*|
- ;---|*| int PCMState ( int, int, int, int )
- ;---|*|
- ;---|*| This routine passes in the sample rate, stereo/mono flag,
- ;---|*| the compression type (0 for 8 bit, 1 for for 4 bit),
- ;---|*| and the PCM data sample size (8 or 16).
- ;---|*|
- ;---|*| int StartFileInput ( FILE *f )
- ;---|*|
- ;---|*| This routine begins recording the PCM data to the disk file.
- ;---|*| The routine returns immediately. The routine,
- ;---|*| "ContinueFileInput" must be called to continue moving data
- ;---|*| from the DMA buffer to to the disk.
- ;---|*|
- ;---|*| int StartBlockInput ( )
- ;---|*|
- ;---|*| This routine begins recording the PCM data. The routine
- ;---|*| returns immediately. Subsequent call must be made to
- ;---|*| "ContinueBlockInput" to receive data from the DMA buffer.
- ;---|*|
- ;---|*| int StartFileOutput ( FILE *f, long )
- ;---|*|
- ;---|*| This routine begins playing the PCM data from the disk file.
- ;---|*| The routine returns immediately. The routine,
- ;---|*| "ContinueFileOutput" must be called to continue moving data
- ;---|*| from the disk to the DMA buffer. The long variable tells how
- ;---|*| many bytes to play.
- ;---|*|
- ;---|*| int StartBlockOutput ( char far * )
- ;---|*|
- ;---|*| This routine begins playing the caller's PCM data. The
- ;---|*| routine returns immediately. The routine, "ContinueBlockOutput"
- ;---|*| must subsequently be called to continue data output.
- ;---|*|
- ;---|*| int ContinueFileInput ( )
- ;---|*|
- ;---|*| This routine checks to see if new data has been loaded into
- ;---|*| the linked list of buffers. If so, the data is written to
- ;---|*| disk, and the buffer is freed up.
- ;---|*|
- ;---|*| int ContinueBlockInput ( char far * )
- ;---|*|
- ;---|*| This routine checks to see if new data has been loaded into
- ;---|*| the linked list of buffers. If so, the data is written to
- ;---|*| the caller's buffer.
- ;---|*|
- ;---|*| int ContinueFileOutput ( )
- ;---|*|
- ;---|*| This routine checks to see if the PCM hardware is
- ;---|*| still playing. This routine MUST be called frequently to
- ;---|*| maintain continuous PCM output.
- ;---|*|
- ;---|*| int ContinueBlockOutput (char far *)
- ;---|*|
- ;---|*| This routine checks to see if the PCM hardware is
- ;---|*| still playing. The caller passes the next block to be
- ;---|*| played. A non-zero return value indicates the block has
- ;---|*| been queued up to be played. A zero value means the buffer
- ;---|*| is currently full, please try again...
- ;---|*|
- ;---|*| void StopDMAIO ( )
- ;---|*|
- ;---|*| This routine is used to prematurely terminate PCM I/O.
- ;---|*|
- ;---|*| void ClosePCMBuffering ( )
- ;---|*|
- ;---|*| This routine is used to close down the whole PCM I/O system.
- ;---|*| This call MUST be made before the caller's program terminates.
- ;---|*|
- ; \*/
-
- ; /*\
- ;---|*|----====< Code Generation >====----
- ; \*/
-
- #define BLOCKOUT 0 /* builds block output code only */
- #define BLOCKIN 0 /* builds block input code only */
- #define FILEOUT 0 /* builds file output code only */
- #define FILEIN 0 /* builds file input code only */
- #define COMMDATA 0 /* builds both common code and data */
-
- #ifdef BUILDBO
- #undef BLOCKOUT
- #define BLOCKOUT 1
- #endif
-
- #ifdef BUILDBI
- #undef BLOCKIN
- #define BLOCKIN 1
- #endif
-
- #ifdef BUILDFO
- #undef FILEOUT
- #define FILEOUT 1
- #endif
-
- #ifdef BUILDFI
- #undef FILEIN
- #define FILEIN 1
- #endif
-
- #ifdef BUILDCO
- #undef COMMDATA
- #define COMMDATA 1
- #endif
-
- ; /*\
- ;---|*|----====< common data for CODE and DATA generation >====----
- ; \*/
-
- /* buffer linked list header structures */
-
- typedef struct _buffptr {
- int status; /* 0=empty, 1=full */
- int count; /* # of bytes in the buffer */
- int size; /* total size of allocated buff */
- char huge *buffer; /* pointer to buffer data */
- struct _buffptr far *nextptr; /* pointer to next buffer hdr */
-
- } BuffData, far *BuffPtr;
-
- #define NODIRECTION 0 /* defines for DirectionFlag */
- #define DMAINPUT 1
- #define DMAOUTPUT 2
-
-
- ; /*\
- ;---|*|----====< Global Data >====----
- ; \*/
-
- #define QUEUESIZE 32 /* 32 entries */
- #define QUEUEMASK 0x1F /* mask to circulate the count */
-
- extern unsigned int MaxBuffCount; /* # of DMA buffer divisions */
- extern unsigned int BufferSize; /* size of each buffer division */
-
- /* shared global variables between the two tasks (in pcmioa.asm) */
-
- extern BuffPtr HeadOfBuffers; /* global variable head pointer */
- extern int BufferDataCount; /* # of full buffers (0=done) */
- extern int DMARunning; /* DMA status (0=off,1=running) */
- extern char huge *DMABuffPtr; /* 128k+1 DMA buffer pointer */
- extern char far *StartOfDMABuffer; /* start of DMA buffer pointer */
- extern int ProcessedBlockCount; /* # of I/O blocks processed */
- extern unsigned long _file_data_length; /* size of data output */
- extern char __pcmdatasize; /* default to 8 bit pcm */
-
- extern FILE *__fptr; /* file pointer for disk I/O */
- extern long __fptrpos; /* file pointer position */
- extern BuffPtr __NextPtr; /* next buffer pointer */
- extern int __DirectionFlag; /* current I/O direction */
- extern char far* __singleblockpointer;/* single shot users buffer */
-
- extern int VoiceActivatedSavedCount;/* # of I/O blocks saved */
-
- /* additional prototypes */
-
- void far * _rfmemcpy ( void far *, void far *, unsigned int );
- void huge * _rfhmemcpy ( void huge *,void huge *,unsigned int );
- void far * _memmalloc ( long );
- void _memmfree ( void far * );
- int _dofread ( char far *, int, int );
- int _dofwrite ( char far *, int, int );
-
- #if BLOCKOUT
- static int _loadtheblock ( char far * );
- #endif
-
- #if FILEOUT
- static int _loadthebuffer ();
- #endif
-
-
-
- ; /*\
- ;---|*|-----------------====================================-----------------
- ;---|*|-----------------====< Start of Executable Code >====-----------------
- ;---|*|-----------------====================================-----------------
- ; \*/
-
- #if FILEIN
- ; /*\
- ;---|*|----====< ASpecialContinueFileInput >====----
- ;---|*|
- ;---|*| This is a special adaptation of the standard, "ContinueDMAInput"
- ;---|*| routine. It will check the noise level in each block before writting
- ;---|*| it out to disk. This way, no data is written until a noise level
- ;---|*| is reached.
- ;---|*|
- ; \*/
- int ASpecialContinueFileInput(noise,goflag)
- int noise; /* offset from silence */
- int goflag; /* record all after first block */
- {
- int temp;
-
- /* if BufferDataCount is non-zero, we must process the DMA data */
-
- while (BufferDataCount) {
-
- /* validate the level of noise before writing it to disk */
-
- if (MakeHalfHistoGram(__NextPtr->buffer,BufferSize,noise) ||
- (VoiceActivatedSavedCount && goflag) ) {
-
- /* if not all data is written, return in error */
-
- if (_dofwrite (__NextPtr->buffer,BufferSize,fileno(__fptr)) != BufferSize) {
- StopDMAIO();
- return (0);
- }
-
- VoiceActivatedSavedCount++;
- }
- else
- ProcessedBlockCount--;
-
- /* move to the next buffer */
-
- __NextPtr->count = __NextPtr->status = 0;
- __NextPtr = __NextPtr->nextptr;
- BufferDataCount--;
- }
-
- /* if at the end of this block, reposition the stream pointer */
-
- if (!DMARunning)
- fseek ( __fptr, __fptrpos, SEEK_SET );
-
- return (DMARunning);
- }
- #endif
-
-
- #if BLOCKIN
- ; /*\
- ;---|*|----====< ContinueBlockInput >====----
- ;---|*|
- ;---|*| This routine checks to see if another buffer can be stored in memory.
- ;---|*| if so, it will load copy the DMA buffer to the caller's local buffer,
- ;---|*| A return value of 0 indicates the caller's buffer is empty.
- ;---|*|
- ; \*/
- int ContinueBlockInput(buff)
- char far *buff;
- {
-
- /* if BufferDataCount is non-zero, we must move the data to memory */
-
- if (BufferDataCount) {
-
- /* data is available, just move it out */
-
- _rfmemcpy (buff,__NextPtr->buffer,BufferSize);
-
- /* move to the next buffer */
-
- __NextPtr->count = __NextPtr->status = 0;
- __NextPtr = __NextPtr->nextptr;
- BufferDataCount--;
-
- /* returns the fact that the data has been loaded */
-
- return(1);
- }
- return (0);
- }
- #endif
-
-
- #if FILEIN
- ; /*\
- ;---|*|----====< ContinueFileInput >====----
- ;---|*|
- ;---|*| This routine checks to see if another buffer can be written to disk.
- ;---|*| if so, it will load copy the buffer to a local buffer, then write it
- ;---|*| out to disk. A return value of 0 indicates recording has stopped,
- ;---|*| which could mean that the disk file is full, so the DMA had to be
- ;---|*| stopped prematurely.
- ;---|*|
- ; \*/
- int ContinueFileInput()
- {
-
- /* if BufferDataCount is non-zero, we must write out the data */
-
- while (BufferDataCount) {
-
- /* data is available, move it out to disk */
-
- /* if not all data is written, return in error */
-
- if (_dofwrite (__NextPtr->buffer,BufferSize,fileno(__fptr)) != BufferSize) {
- StopDMAIO();
- return (0);
- }
-
- /* move to the next buffer */
-
- __NextPtr->status = 0;
- __NextPtr = __NextPtr->nextptr;
- BufferDataCount--;
- }
-
- /* if at the end of this block, reposition the stream pointer */
-
- if (!DMARunning)
- fseek ( __fptr, __fptrpos, SEEK_SET );
-
- return (DMARunning);
- }
- #endif
-
-
- #if BLOCKOUT
- ; /*\
- ;---|*|----====< ContinueBlockOutput >====----
- ;---|*|
- ;---|*| This routine checks to see if another DMA buffer can be loaded.
- ;---|*| If so, it will load the user's block data into an empty buffer.
- ;---|*| A return value of 1 indicates the buffer has been loaded, else
- ;---|*| it must be sent in again until it is loaded.
- ;---|*|
- ; \*/
- int ContinueBlockOutput(buff)
- char far *buff;
- {
-
- /* if the internal count is not max-ed out, try to load the next buffer */
-
- if (BufferDataCount < MaxBuffCount ) {
-
- _loadtheblock (buff);
-
- if (DMARunning == 0) { /* yuck! a DMA break! */
- _resetbuffers();
- StartTheDMAOutput(0);
- }
-
- return (1); /* return running */
- }
- else
- return(0);
- }
- #endif
-
-
- #if FILEOUT
- ; /*\
- ;---|*|----====< ContinueFileOutput >====----
- ;---|*|
- ;---|*| This routine checks to see if another buffer can be loaded. If so, it
- ;---|*| will load the data into an empty buffer. All empty buffers will be
- ;---|*| loaded. A return value of 0 indicates playing has finished.
- ;---|*|
- ; \*/
- int ContinueFileOutput()
- {
-
- /* if BufferDataCount is not max-ed out, try to load the next buffer*/
-
- if (BufferDataCount < MaxBuffCount ) {
-
- if (_loadthebuffer()) {
-
- if (DMARunning == 0) { /* yuck! a DMA break! */
- _resetbuffers();
- if (StartTheDMAOutput(0))
- return(0);
- }
- }
- }
-
- /* if at the end of this block, reposition the stream pointer */
-
- if (!DMARunning)
- fseek ( __fptr, __fptrpos, SEEK_SET );
-
- return (DMARunning); /* return the DMA state */
- }
- #endif
-
-
- #if BLOCKIN
- ; /*\
- ;---|*|----====< StartBlockInput >====----
- ;---|*|
- ;---|*| This routine resets the buffer pointers, then starts up
- ;---|*| the DMA PCM input. Nothing else needs to be done. A return
- ;---|*| value of 0 indicates the DMA failed to startup; No input
- ;---|*| is occuring.
- ;---|*|
- ; \*/
- int StartBlockInput()
- {
-
- /* setup our internal direction flag */
-
- __DirectionFlag = DMAINPUT;
-
- /* Reset the # of blocks seen during I/O processing */
-
- ProcessedBlockCount = 0;
-
- /* Flush all buffers */
-
- _resetbuffers();
-
- /* if the hardware level code isn't gonna work, then return a failure. */
-
- return (!StartTheDMAInput(0));
- }
- #endif
-
-
- #if FILEIN
- ; /*\
- ;---|*|----====< StartFileInput >====----
- ;---|*|
- ;---|*| This routine resets the buffer pointers, then starts up the DMA PCM
- ;---|*| input. Nothing else needs to be done.
- ;---|*|
- ; \*/
- int StartFileInput(f)
- FILE *f;
- {
-
- /* save our local file handle */
-
- __fptr = f;
- __fptrpos = ftell(f);
-
- /* setup our internal direction flag */
-
- __DirectionFlag = DMAINPUT;
-
- /* Reset the # of blocks seen during I/O processing */
-
- ProcessedBlockCount = 0;
-
- /* Flush all buffers and other stuff.. */
-
- _resetbuffers();
- VoiceActivatedSavedCount = 0;
-
- /* start the DMA engine */
-
- return (!StartTheDMAInput(0));
- }
- #endif
-
-
- #if BLOCKOUT
- ; /*\
- ;---|*|----====< StartBlockOutput >====----
- ;---|*|
- ;---|*| This routine allocates and loads the necessary buffers with data from
- ;---|*| the PCM disk file. Upon return, if there is data available, the
- ;---|*| background task will be called to start the DMA. The file handle will
- ;---|*| be saved in a global variable to be access from other foreground
- ;---|*| routines. a non-zero return value indicates PCM output is playing.
- ;---|*|
- ; \*/
- int StartBlockOutput(buff)
- char far *buff;
- {
-
- /* setup our internal direction flag */
-
- __DirectionFlag = DMAOUTPUT;
-
- /* Reset the # of blocks seen during I/O processing */
-
- ProcessedBlockCount = 0;
-
- /* load the DMA buffers */
-
- _resetbuffers();
- _loadtheblock (buff);
-
- /* return good or bad if the engine is started */
-
- return (!StartTheDMAOutput(0));
- }
- #endif
-
-
- #if FILEOUT
- ; /*\
- ;---|*|----====< StartFileOutput >====----
- ;---|*|
- ;---|*| This routine allocates and loads the necessary buffers with data from
- ;---|*| the PCM disk file. Upon return, if there is data available, the
- ;---|*| background task will be called to start the DMA. The file handle will
- ;---|*| be saved in a global variable to be access from other foreground
- ;---|*| routines. a non-zero return value indicates PCM output is playing.
- ;---|*|
- ; \*/
- int StartFileOutput(f,len)
- FILE *f;
- long len;
- {
-
- /* save our local file handle */
-
- __fptr = f;
- __fptrpos = ftell(f);
-
- /* setup our internal direction flag, and the desired length */
-
- __DirectionFlag = DMAOUTPUT;
- _file_data_length = len;
-
- /* Reset the # of blocks seen during I/O processing */
-
- ProcessedBlockCount = 0;
-
- /* if any data is loaded into the buffer, start the DMA & return */
-
- _resetbuffers();
-
- do {
-
- /* get the next buffer full & exit if done */
-
- if (!_loadthebuffer())
- break;
-
- } while (__NextPtr != HeadOfBuffers);
-
- /* return good or bad if the engine is running */
-
- return (!StartTheDMAOutput(0));
-
- }
- #endif
-
-
- #if BLOCKOUT
- ; /*\
- ;---|*|----====< _loadtheblock >====----
- ;---|*|
- ;---|*| This routine loads the block into the DMA buffer.
- ;---|*|
- ; \*/
- static int _loadtheblock(buff)
- char far *buff;
- {
-
- /* load the block of data into the DMA buffer */
-
- _rfmemcpy(__NextPtr->buffer, buff, BufferSize );
-
- /* now that the data is secure, fill out the rest of the header to */
- /* allow the background process to "see" this new data */
-
- __NextPtr->status = 1;
- __NextPtr->count = BufferSize;
- __NextPtr = __NextPtr->nextptr; /* advance the list */
- BufferDataCount++;
-
- /* we have data, return the size */
-
- return (BufferSize);
- }
- #endif
-
-
- #if FILEOUT
- ; /*\
- ;---|*|----====< _loadthebuffer >====----
- ;---|*|
- ;---|*| This routine loads the disk contents into an available buffer.
- ;---|*| A return value of 0 indicates no more data has been loaded.
- ;---|*|
- ; \*/
- static int _loadthebuffer()
- {
- char huge *s;
- register int n;
- long l;
-
- /* reset the header data */
-
- __NextPtr->count = __NextPtr->status = 0;
-
- /* exit if there is no data to be read */
-
- if (feof (__fptr) || (!_file_data_length))
- return (0);
-
- /* adjust the max count we want to process from the file */
-
- if (_file_data_length <= BufferSize) {
- l = _file_data_length;
- _file_data_length = 0;
- }
- else {
- _file_data_length -= (l = (BufferSize & 0xffff));
- }
-
- /* read the data from the file */
-
- if((n = _dofread (__NextPtr->buffer, ((int)(l & 0xffff)),fileno(__fptr) )) == 0)
- return(0);
-
- s = __NextPtr->buffer+n; // point to the end of the block
-
- // flush to the end if not a full buffer worth of data
-
- if (n < BufferSize)
- FlushBuffer (s,BufferSize-n);
-
- /* now that the data is secure, fill out the rest of the header to */
- /* allow the background process to "see" this new data */
-
- __NextPtr->status = 1;
- __NextPtr->count = BufferSize;
- __NextPtr = __NextPtr->nextptr; /* advance the list */
- BufferDataCount++;
-
- /* we have data, return the size */
-
- return (n);
- }
- #endif
-
- ; /*\
- ;---|*| end of PCMIOC.C
- ; \*/
-
-