[Back to SOUND SWAG index]  [Back to Main SWAG index]  [Original]

UNIT Tone;  {$S-,R-,D-,L-}

    (* TONE.PAS - Sound Module for Turbo Pascal 6.0 - Turbo Vision
     * Written by Richard R. Sands
     * Compuserve ID 70274,103
     * January 1991
     *
     * NOTE: Do Not Overlay
     *)

INTERFACE

   Procedure Sound(Hz:Word);
   Procedure NoSound;
   Procedure Delay(MS : Word);

   Procedure Beep(Hz, MS:Word);
     { Same as
               Sound(Hz);
               Delay(MS);
               NoSound;       ...but with more efficient code. }

   Procedure BoundsBeep;
     { Used for signalling a boundry or invalid command }

   Procedure ErrorBeep;
     { Used for signalling an error condition }

   Procedure AttentionBeep;
     { Used for signalling the user }

IMPLEMENTATION

  VAR
    OneMS : Word;

{ ------------------------------------------------------------------------- }
Procedure Beep(Hz, MS:Word); assembler;
     { Make the Sound at Frequency Hz for MS milliseconds }
  ASM
    MOV  BX,Hz
    MOV  AX,34DDH
    MOV  DX,0012H
    CMP  DX,BX
    JNC  @Stop
    DIV  BX
    MOV  BX,AX
    IN          AL,61H
    TEST AL,3
    JNZ  @99
    OR          AL,3
    OUT  61H,AL
    MOV  AL,0B6H
    OUT  43H,AL
 @99:
    MOV  AL,BL
    OUT  42H,AL
    MOV  AL,BH
    OUT  42H,AL
 @Stop:
 {$IFOPT G+}
    PUSH MS
 {$ELSE }
    MOV  AX, MS   { push delay time }
    PUSH AX
  {$ENDIF }
    CALL Delay    { and wait... }

    IN   AL, $61  { Now turn off the speaker }
    AND  AL, $FC
    OUT  $61, AL
  end;

{ ------------------------------------------------------------------------- }
Procedure BoundsBeep; assembler;
  asm
  {$IFOPT G+ }
     PUSH 1234      { Pass the Frequency }
     PUSH 10        { Pass the delay time }
  {$ELSE}
     MOV  AX, 1234  { Pass the Frequency }
     PUSH AX
     MOV  AX, 10    { Pass the delay time }
     PUSH AX
   {$ENDIF }
     CALL Beep
  end;

{ ------------------------------------------------------------------------- }
Procedure ErrorBeep; assembler;
  asm
  {$IFOPT G+ }
     PUSH 800   { Pass the Frequency }
     PUSH 75    { Pass the delay time }
  {$ELSE}
     MOV  AX, 800  { Pass the Frequency }
     PUSH AX
     MOV  AX, 75   { Pass the delay time }
     PUSH AX
  {$ENDIF }
     CALL Beep
  end;

{ ------------------------------------------------------------------------- }
Procedure AttentionBeep; assembler;
  asm
  {$IFOPT G+ }
     PUSH 660   { Pass the Frequency }
     PUSH 50    { Pass the delay time }
  {$ELSE}
     MOV  AX, 660  { Pass the Frequency }
     PUSH AX
     MOV  AX, 50   { Pass the delay time }
     PUSH AX
  {$ENDIF }
     CALL Beep
  end;

{ ------------------------------------------------------------------------- }
Procedure Sound(Hz:Word); assembler;
   ASM
      MOV  BX,Hz
      MOV  AX,34DDH
      MOV  DX,0012H
      CMP  DX,BX
      JNC  @DONE
      DIV  BX
      MOV  BX,AX
      IN   AL,61H
      TEST AL,3
      JNZ  @99
      OR   AL,3
      OUT  61H,AL
      MOV  AL,0B6H
      OUT  43H,AL
@99:  MOV  AL,BL
      OUT  42H,AL
      MOV  AL,BH
      OUT  42H,AL
@DONE:
  end;

{ ------------------------------------------------------------------------- }
Procedure NoSound; assembler;
  asm
     IN   AL, $61
     AND  AL, $FC
     OUT  $61, AL
  end;

{ ------------------------------------------------------------------------- }
procedure DelayOneMS; assembler;
  asm
     PUSH CX         { Save CX }
     MOV  CX, OneMS  { Loop count into CX }
  @1:
     LOOP @1         { Wait one millisecond }
     POP  CX         { Restore CX }
  end;

{ ------------------------------------------------------------------------- }
Procedure Delay(ms:Word); assembler;
  asm
     MOV  CX, ms    
     JCXZ @2           
  @1:
     CALL DelayOneMS
     LOOP @1
  @2:
  end;

{ ------------------------------------------------------------------------- }
Procedure Calibrate_Delay; assembler;
  asm   
     MOV  AX,40h         
     MOV  ES,AX          
     MOV  DI,6Ch          { ES:DI is the low word of BIOS timer count }
     MOV  OneMS,55        { Initial value for One MS's time }
     XOR  DX,DX           { DX = 0 }
     MOV  AX,ES:[DI]      { AX = low word of timer }
  @1:
     CMP  AX,ES:[DI]      { Keep looking at low word of timer }
     JE   @1              { until its value changes... }
     MOV  AX,ES:[DI]      { ...then save it }
  @2:
     CAll DelayOneMs      { Delay for a count of OneMS (55) }
     INC  DX              { Increment loop counter }
     CMP  AX,ES:[DI]      { Keep looping until the low word }
     JE   @2              { of the timer count changes again }
     MOV  OneMS, DX       { DX has new OneMS }
  end;

BEGIN
  Calibrate_Delay
END.

{ ==============================  DEMO ==================================}

Program ToneTest;

USES Tone;

begin
   ErrorBeep;
   Delay(500);
   AttentionBeep;
   Delay(500);
   BoundsBeep;
   Delay(500);
   Beep(440, 250);
end.

[Back to SOUND SWAG index]  [Back to Main SWAG index]  [Original]