{****************************************************************************}
{                                                                            }
{ MODULE:         DevSpkr                                                    }
{                                                                            }
{ DESCRIPTION:    Device driver for the PC internal speaker.                 }
{                 It uses timer polling.                                     }
{                                                                            }
{ AUTHOR:         Juan Carlos Ar‚valo                                        }
{                                                                            }
{ MODIFICATIONS:  Nobody (yet ;-)                                            }
{                                                                            }
{ HISTORY:        11-Nov-1992 Description                                    }
{                                                                            }
{ (C) 1992 VangeliSTeam                                                      }
{____________________________________________________________________________}

UNIT DevSpkr;

INTERFACE




{ Device ID String. }

CONST                    
  SpkrDevID = 'Speaker';




IMPLEMENTATION

USES SoundDevices, StrConst;




{----------------------------------------------------------------------------}
{ Device data.                                                               }
{____________________________________________________________________________}

CONST                                     { Default conversion table for 16 KHz. }
  SpkrBaseTabla : ARRAY[0..255] OF BYTE =
        ($40,$40,$40,$40,$40,$40,$40,$40,$40,$40,$3F,$3F,$3F,$3F,$3F,$3F,
         $3F,$3F,$3F,$3F,$3F,$3F,$3E,$3E,$3E,$3E,$3E,$3E,$3E,$3E,$3E,$3E,
         $3D,$3D,$3D,$3D,$3D,$3D,$3D,$3D,$3D,$3C,$3C,$3C,$3C,$3C,$3C,$3C,
         $3C,$3C,$3C,$3B,$3B,$3B,$3B,$3B,$3B,$3B,$3B,$3B,$3B,$3A,$3A,$3A,
         $3A,$3A,$3A,$3A,$3A,$3A,$3A,$39,$39,$39,$39,$39,$39,$39,$39,$39,
         $39,$38,$38,$38,$38,$38,$38,$38,$38,$37,$37,$37,$37,$37,$36,$36,
         $36,$36,$35,$35,$35,$35,$34,$34,$34,$33,$33,$32,$32,$31,$31,$30,
         $30,$2F,$2E,$2D,$2C,$2B,$2A,$29,$28,$27,$26,$25,$24,$23,$22,$21,
         $20,$1F,$1E,$1D,$1C,$1B,$1A,$19,$18,$17,$16,$15,$14,$13,$12,$11,
         $11,$10,$10,$0F,$0F,$0E,$0E,$0D,$0D,$0D,$0C,$0C,$0C,$0C,$0B,$0B,
         $0B,$0B,$0A,$0A,$0A,$0A,$0A,$09,$09,$09,$09,$09,$09,$09,$09,$09,
         $08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$07,$07,$07,$07,
         $07,$07,$07,$06,$06,$06,$06,$06,$06,$06,$06,$06,$06,$06,$05,$05,
         $05,$05,$05,$05,$05,$05,$05,$05,$04,$04,$04,$04,$04,$04,$04,$04,
         $04,$04,$03,$03,$03,$03,$03,$03,$03,$03,$03,$03,$02,$02,$02,$02,
         $02,$02,$02,$02,$02,$01,$01,$01,$01,$01,$01,$01,$01,$01,$01,$01);

VAR
  SpkrTabla : ARRAY[0..255] OF BYTE;   { Conversion table that will be used. }




{$L DEVSpkr}   { Assembler IRQ. }

PROCEDURE SpkrIntHandler; FAR; EXTERNAL;




{----------------------------------------------------------------------------}
{ Name function.                                                             }
{____________________________________________________________________________}

FUNCTION SpkrName : TDevName; FAR;
  BEGIN
    SpkrName := GetString(StrDevSpkrName);
  END;




{----------------------------------------------------------------------------}
{ Autodetect routine. It's always present.                                   }
{____________________________________________________________________________}

FUNCTION DevDetect : BOOLEAN; FAR;
  BEGIN
    DevDetect := TRUE;
  END;




{----------------------------------------------------------------------------}
{ Routine for adjusting the conversion table to the new output freq.         }
{____________________________________________________________________________}

PROCEDURE AdjustTable;
  VAR
    i    : WORD;
    TVal : WORD;
  BEGIN
    TVal := TimerVal SHR 1;
    FOR i := 0 TO 255 DO
      SpkrTabla[i] := (WORD((SpkrBaseTabla[i]-1) * TVal) DIV $39) + 1;
  END;




{----------------------------------------------------------------------------}
{ Device Initialisation routine.                                             }
{____________________________________________________________________________}

PROCEDURE DevInit(Hz: WORD); FAR; 
  BEGIN
    ASM
        IN      AL,61h
        OR      AL,3      
        OUT     61h,AL    { Turn on speaker. }

        MOV     AL,0B6h
        OUT     43h,AL    

        MOV     AL,0B0h
        OUT     43h,AL
        MOV     AL,034h
        OUT     43h,AL

        XOR     AL,AL
        OUT     42h,AL
        OUT     42h,AL
        MOV     AL,10010000b
        OUT     43h,AL    { Select Speaker timer mode. }
    END;

    CalcTimerData(Hz);    { Then do the standard polling initialisation. }
    InitTimer;
    AdjustTable;          { And adjust the table for initial freq.       }
  END;




{----------------------------------------------------------------------------}
{ Device deinitialisation routine.                                           }
{____________________________________________________________________________}

PROCEDURE DevEnd; FAR; ASSEMBLER;
  ASM
        IN      AL,61h
        AND     AL,11111100b 
        OUT     61h,AL       { Turn off speaker. }
  END;




{----------------------------------------------------------------------------}
{ Accesory routines.                                                         }
{____________________________________________________________________________}

PROCEDURE DevChgHz(Hz: WORD); FAR;
  BEGIN
    CalcTimerData(Hz);
    InitTimer;
    AdjustTable;
  END;

PROCEDURE DevPoll; FAR;
  BEGIN
  END;




{----------------------------------------------------------------------------}
{ Device record.                                                             }
{____________________________________________________________________________}

CONST
  SpkrData : TSoundDevice = (
    DevID      : SpkrDevID;
    DMA        : FALSE
  );




{----------------------------------------------------------------------------}
{ Init code.                                                                 }
{____________________________________________________________________________}

BEGIN

  WITH SpkrData DO BEGIN
    Name            := SpkrName;
    AutoDetect      := DevDetect;
    InitRut         := DevInit;
    ChgHzProc       := DevChgHz;
    GetRealFreqProc := GetRealFreq;
    TimerHandler    := SpkrIntHandler;
    PollRut         := DevPoll;
    EndRut          := DevEnd;
  END;

  InitDevice(@SpkrData);

END.
