UNIT DAC;
{
  Rutinas para el manejo del DAC casero, con soporte de doble buffer virtual.
  Por Luis Crespo, FidoNet 2:343/108.21, Internet d8089110@est.fib.upc.es
}

INTERFACE

USES
  Hardware;

  PROCEDURE DACInit;
  PROCEDURE LPT1DAC(b:Byte);
  PROCEDURE LPT2DAC(b:Byte);
  PROCEDURE DACPlayBuf(pBuffer:Pointer; BufferSize:Word; VAR Frec:Word; BufProc:TBufProc; LPTNum:Byte);
  PROCEDURE DACStopBuf;


IMPLEMENTATION

USES
  DOS;

VAR
  OldTimerISR : Pointer;  {Puntero a la antigua ISR del timer}
  pBufDAC     : PByte;    {Puntero al buffer de DMA falso}
  BufSize,                {Tama¤o del buffer}
  BufPos      : Word;     {Offset de la muestra en el buffer}
  NextBuffer  : TBufProc; {Rutina de usuario}

  DACOut      : PROCEDURE (b:Byte);

CONST
  LPT1Addr:Word=$378;
  LPT2Addr:Word=$278;

  PROCEDURE DACInit;
  BEGIN
    IF MemW[$40:$08]<>0 THEN LPT1Addr:=MemW[$40:$08];
    IF MemW[$40:$0A]<>0 THEN LPT2Addr:=MemW[$40:$0A];
  END;

  PROCEDURE LPT1DAC(b:Byte);
  BEGIN
    Port[LPT1Addr]:=b;
  END;

  PROCEDURE LPT2DAC(b:Byte);
  BEGIN
    Port[LPT2Addr]:=b;
  END;


  PROCEDURE TimerISR; INTERRUPT;
  TYPE
    TBarr=ARRAY [0..0] OF Byte;
  BEGIN
    EOI;
    ASM STI END;
    DACOut(TBarr(pBufDAC^)[BufPos]);
    Inc(BufPos);
    IF BufPos=BufSize THEN NextBuffer;
    IF BufPos=BufSize*2 THEN
    BEGIN
      BufPos:=0;
      NextBuffer;
    END;
  END;

  PROCEDURE DACPlayBuf(pBuffer:Pointer; BufferSize:Word; VAR Frec:Word; BufProc:TBufProc; LPTNum:Byte);
  BEGIN
    pBufDAC:=pBuffer;
    BufSize:=BufferSize;
    NextBuffer:=BufProc;
    BufPos:=0;
    IF LPTNum=1 THEN DACOut:=LPT1DAC ELSE DACOut:=LPT2DAC;
    GetIntVec(8,OldTimerISR);
    SetIntVec(8,@TimerISR);
    SetTimerFrec(Frec);
  END;

  PROCEDURE DACStopBuf;
  BEGIN
    ProgTimer0(0);
    SetIntVec(8,OldTimerISR);
  END;


END.

