/* I wrote BIP because of a need to find specific sounds for my programming
   needs. With this somewhat crude program I can find any sound I want without
   programming and then later include the proper settings in my program. The
   title BIP came from 'The Pink Panther'. The inspector would pronounce the
   word BEEP as BIP.

   This program is given free of charge to everyone, without any warranty
   expressed or implied. I will in no way be held responsible for any damages
   of any kind (real or imaginary) caused by the use or misuse of this
   program.

   Feel free to use any part of the following code for any purpose you
   see fit. Just remember to leave the copyright notice in the BIP program.
   Give credit where credit is due.
*/

#include <stdio.h>
#include <dos.h>

#define  COPYRIGHT1 "B I P >> Beep Tester, Version 2.0\n"
#define  COPYRIGHT2 "(C) Copyright 1989, John Carto, All Rights Reserved."
#define  BACKGROUND set_attr(0x20,0x07,0x01,0x50)/* WHITE ON BLUE BACKGROUND */
#define  WAIT       set_curs(23,0); /* A PLACE TO PRINT MESSAGES */
#define  UP_ARO     0x48
#define  DN_ARO     0x50
#define  SELECT     0x3B           /* F1 KEY */
#define  NUMPUT     0x3C           /* F2 KEY */
#define  STAT1      set_curs(0,25);
#define  STAT2      set_curs(0,51);
#define  STATS      "\x1B[30;46m              Frequency = 500.00  Hz    Duration = 0.5 Seconds               \x1B[37;44m"
#define  HELP       "\x1B[30;46m     F1=Freq./Duration, F2=Manual Input, ENTER=Tone, UP/DN=Fine Tune, ESC=Exit     \x1B[37;44m\x1B[24;1f"
#define  REV1       "Freq.\x1B[37;44m"
#define  REV2       "Duration,\x1B[37;44m"
#define  REV3       "Manual Input,\x1B[37;44m"
#define  REV4       "Tone,\x1B[37;44m"
#define  REV5       "Fine Tune,\x1B[37;44m"
#define  BROWN      "\x1B[30;43m"
#define  CYAN       "\x1B[30;46m"
#define  TMODE      0xB6
#define  FREQSCALE  1193820L
#define  TIMESCALE  40000L
#define  TMODE_PORT 0x43
#define  FREQ_PORT  0x42
#define  BEEP_PORT  0x61
#define  ON         0x4F

        float  freq=500.00, duration=0.5;/* PRESET THE FREQUENCY & DURATION */


main ()

{

        int   chk, code, OK;
        int   i, j;

        set_curs(0,0);
        for(i=0;i<25;i++) { set_curs(i,0); (BACKGROUND);} /* COLOR ON */
        set_curs(0,0);
        printf(STATS);
        printf(HELP);
        printf(COPYRIGHT1);
        printf(COPYRIGHT2);
        set_curs(1,5); printf(BROWN); printf(REV1);
        WAIT
        chk = 1;
        while (1)
          { code = getcode();
            switch (code)
              { case UP_ARO: /* INCREMENT THE CURRENT VARIABLE */
                        set_curs(1,24); printf(CYAN); printf(REV3);
                        set_curs(1,56); printf(BROWN); printf(REV5);
                        if(chk == 1 && freq < 30000.00)
                          { freq += 0.01; printf(CYAN);
                            STAT1 printf("%7.2f\x1B[37;44m", freq);
                          }
                        else if(chk != 1 && duration < 5.0)
                          { duration += 0.1; printf(CYAN);
                            STAT2 printf("%2.1f\x1B[37;44m", duration);
                          }
                        WAIT
                        break;
                case DN_ARO: /* DECREMENT THE CURRENT VARIABLE */
                        set_curs(1,24); printf(CYAN); printf(REV3);
                        set_curs(1,56); printf(BROWN); printf(REV5);
                        if(chk == 1 && freq > 0.01)
                          { freq -= 0.01; printf(CYAN); STAT1
                            printf("%7.2f\x1B[37;44m", freq);
                          }
                        else if(chk != 1 && duration > 0.2)
                          { duration -= 0.1; printf(CYAN);
                            STAT2 printf("%2.1f\x1B[37;44m", duration);
                          }
                        WAIT
                        break;
                case SELECT: /* SELECT THE CURRENT VARIABLE */
                        if(chk == 1)
                         { chk = -1;
                           set_curs(1,5); printf(CYAN); printf(REV1);
                           set_curs(1,11); printf(BROWN); printf(REV2);
                           WAIT
                         }
                        else
                         { chk = 1;
                           set_curs(1,5); printf(BROWN); printf(REV1);
                           set_curs(1,11); printf(CYAN); printf(REV2);
                           WAIT
                         }
                        break;
                case NUMPUT:               /* MANUAL INPUT */
                        set_curs(1,24); printf(BROWN); printf(REV3);
                        set_curs(1,56); printf(CYAN); printf(REV5);
retry:                  WAIT
                        set_attr(0x20,0x07,0x01,0x50);  /* ERASE LINE */
                        if(chk == 1)
                         { printf("Enter Desired Frequency: ");
                           scanf("%f", &freq);
								   fflush(stdin);
                           if(freq < 30000.01 && freq > 0.01)
                            { printf(CYAN); STAT1
                              printf("%7.2f\x1B[37;44m", freq);
                            }
                           else
                            goto retry;
                         }
                        else 
                         { printf("Enter Desired Duration: ");
                           scanf("%f", &duration);
                           fflush(stdin);
                           if(duration < 5.1 && duration > 0.1)
                            { printf(CYAN); STAT2
                              printf("%2.1f\x1B[37;44m", duration);
                            }
                           else
                            goto retry;
                         }
                        set_curs(1,24); printf(CYAN); printf(REV3);
                        WAIT;
                        break;
                case 13:        /* ENTER KEY, BEEP ACCORDING TO SETTINGS */
                        set_curs(1,56); printf(CYAN); printf(REV5);
                        set_curs(1,44); printf(BROWN); printf(REV4);
                        tone();
                        set_curs(1,44); printf(CYAN); printf(REV4);
                        WAIT
                        break;
                case 27:        /* ESC KEY, EXIT BIP */
                        goto leave;
                default:
                        break;
              }
          }
leave:  printf("\x1B[0m");
        printf("\x1B[2J");              /* CLEAR SCREEN */
}

/* SET CURSOR POSITION */

set_curs(row, col)
int row, col;

{
        union REGS regs;

        regs.h.ah = 2;                  /* SET POSITION */
        regs.h.bh = 0;                  /* FOR PAGE 0   */
        regs.h.dh = row;                /* CURRENT ROW  */
        regs.h.dl = col;                /* CURRENT COL  */
        int86(0x10, &regs, &regs);      /* INTERRUPT 10h*/
}

/* SET ATTRIBUTES */

set_attr(character, fore, back, count)
char character;
int fore, back, count;

{
        union REGS regs;
                                /* IF BIT 7 IS 1, XOR CHARACTER ONTO SCREEN */

        regs.h.ah = 0x09;
        regs.h.bh = 0;
        regs.x.cx = count;
        regs.h.al = character;
        regs.h.bl = fore | back << 4;
        int86(0x10, &regs, &regs);      /* INTERRUPT 10h*/
}

/* FUNCTION TO GET USER INPUT */

int getcode()

{       int key;

        if((key=getch()) != 0) return(key);
        return(getch());
}

/* TONE */

tone()

{
        int     highbt, lowbt, port;
        long    i, count, divisor;

        divisor = FREQSCALE / freq;
        highbt  = divisor / 256;
        lowbt   = divisor % 256;
        count   = TIMESCALE * duration;
        outp(TMODE_PORT, TMODE);
        outp(FREQ_PORT, lowbt);
        outp(FREQ_PORT, highbt);
        port = inp(BEEP_PORT);
        outp(BEEP_PORT, ON);
        for(i=1;i<count;i++);
        outp(BEEP_PORT, port);
}
