/******************************************************/
/*  MORSE v1.10                                       */
/*  CW trainer for Soundblaster                       */
/******************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <dos.h>
#include <bios.h>
#include <conio.h>
#include <string.h>
#include <alloc.h>
#include <ctype.h>
#include <time.h>
#include <mem.h>
#include <math.h>
#include <io.h>
#include <fcntl.h>
#include <sb_voice.h>
#include <edgets.h>
#include "morseisr.h"

/* #pragma inline; */

#define MORSE_VERSION "1.10"

#define MORSEBUFSIZE 128   /* Number of entries in morse data buffer */

#define ONOFF           0x8000  /* Top bit controls tone on or off */

#define TRUE  1
#define FALSE 0


unsigned int morsebuf[MORSEBUFSIZE];            /* Communication between    */
                                               /* mainline and int 8 stuff */
unsigned int inptr = 0;
volatile unsigned int outptr = 0;               /* Offsets into morsebuf */

int minlength,maxlength;
int showstat=0;
char *shwstatstr[2]={"Hide","Show"};
char *itonestr[2]={"Off","On"};
char *noisestr[3]={"None", "Hiss", "Pile-Up"};
int mastervol,beepvol,noisevol,lineinvol;
int wpm;
int dah, dit, dit_spacing, letter_spacing, word_spacing;
int noisetype;

char txtfname[81];

int numsamples;
char far *sample[100];

unsigned char letters[] = {
       "ABCDEFGHIJKLMNOPQRSTUVWXYZ���0123456789.,?!:\"'()/-*=~�+@"
};

unsigned char letters2[56];
unsigned char charstat[56];
int numchars;

unsigned int freq,ifreq;
unsigned char beep_on_val, beep_off_val, itone_on_val, itone_off_val;

unsigned int itonestat;

/* Pure sinus tone */
char beep[16] = {
       0X21,0X21,0X00,0X00,0XC0,0XC0,0XFC,0XFC,
       0X00,0X00,0X01,0X00,0X00,0X00,0X00,0X00
};

extern unsigned int ct_io_addx;
extern void fm_write(unsigned char reg,unsigned char data);


FILE* cfgfile;
char cfgfname[81];


unsigned char char_sent[32], char_end[32], char_to_write;
unsigned int char_head = 0, char_tail = 0;
int do_write_char = FALSE;


static unsigned char morsecode[256][7] = {
       "","","", "", "", "", "", "w",                /* 0 to 7 */
       "","w", "w", "", "w", "", "", "",             /* 8 to 15 */
       "", "", "", "", "", "", "", "",                 /* 16 to 23 */
       "", "", "", "", "", "", "", "",                 /* 24 to 31 */
       "w", "..--.", ".-..-.", "", "", "", "", ".----.",  /* ' ' to ''' */
       "-.--.", "-.--.-", "..l..", ".-.-.", "-..-.",   /* '(' to ... */
       "-..-", ".-.-.-", "-..-.",                      /*     ...'/' */
       "-----", ".----", "..---", "...--", "....-",    /* 0 to 4 */
       ".....", "-....", "--...", "---..", "----.",    /* 5 to 9 */
       "---...", "", "", "-...-", "", "..--..", "...-.-",  /* ':' to '@' */
       ".-", "-...", "-.-.", "-..", ".",               /* 'A' to 'E' */
       "..-.", "--.", "....", "..", ".---",            /* 'F' to 'J' */
       "-.-", ".-..", "--", "-.", "---",               /* 'K' to 'O' */
       ".--.", "--.-", ".-.", "...", "-",              /* 'P' to 'T' */
       "..-", "...-", ".--", "-..-", "-.--", "--..",   /* 'U' to 'Z' */
       "", "-..-.", "", "", "", "",                    /* '[' to '`' */
       ".-", "-...", "-.-.", "-..", ".",               /* 'a' to 'e' */
       "..-.", "--.", "....", "..", ".---",            /* 'f' to 'j' */
       "-.-", ".-..", "--", "-.", "---",               /* 'k' to 'o' */
       ".--.", "--.-", ".-.", "...", "-",              /* 'p' to 't' */
       "..-", "...-", ".--", "-..-", "-.--", "--..",   /* 'u' to 'z' */
       "", "", "", "-.-.-", "",                        /* '{' to Del */

       "","","","",".-.-","",".--.-","",               /* 128 - 135  */
       "","","","","","",".-.-",".--.-",               /* 136 - 143  */
       "","","","","---.","","","",                    /* 144 - 151  */
       "","---.","","","","","","",                    /* 152 - 159  */
       "","","","","","","","",                        /* 160 - 167  */
       "","","","","","","","",                        /* 168 - 175  */
       "","","","","","","","",                        /* 176 - 183  */
       "","","","","","","","",                        /* 184 - 191  */
       "","","","","","","","",                        /* 192 - 199  */
       "","","","","","","","",                        /* 200 - 207  */
       "","","","","","","","",                        /* 208 - 215  */
       "","","","","","","","",                        /* 216 - 223  */
       "","","","","","","","",                        /* 224 - 231  */
       "","","","","","","","",                        /* 232 - 239  */
       "","","","","","","","",                        /* 240 - 247  */
       "","","",".-...","","","",""                    /* 248 - 255  */
};



main(int argc, char **argv)
{
       int key;
       int i;

       if(! init())
               exit(1);

       while(1) {
               key = getch();

               switch(key){
                       case '1': random_text(0); break;
                       case '2': random_text(1); break;
                       case '3': text_from_file(); break;
                       case 'c': select_characters(); break;
                       case 'm': set_minmax(); break;
                       case 'w': set_wpm(); break;
                       case 'f': set_tone_freq(); break;
                       case 'i': set_itone(); break;
                       case 'h': show_hide(); break;
                       case 'b': set_backg_noise(); break;
                       case 'v': set_volumes(); break;
                       case 's': save_config(); break;
                       case 'l': load_config(); break;
                       case 'd': list_files(); break;
                       case 'q': quit();
               }
               draw_menu();
       }
}


init()
{
       int i, handle;
       FILE* f;
       unsigned int vocsize;
       unsigned numread,segp;

       if(! sb_voice_init())
               return 0;

       strcpy(cfgfname, "MORSE.CFG");
       if(cfgfile = fopen(cfgfname,"rb"))
               load_config2();
       else {
               wpm = 20;
               for(i = 0; i < 56; i++)
                       charstat[i] = 1;

               minlength=2;
               maxlength=5;
               mastervol=12;
               beepvol=15;
               noisevol=8;
               noisetype=0;
               itonestat=0;
               freq = 4;
               ifreq = 6;
       }

       numchars = 0;

       for(i = 0; i < 56; i++) {
               if (charstat[i])
                       letters2[numchars++] = letters[i];
       }

       randomize();

       numsamples = 0;

       if((handle = _open("MORSE.DAT", O_RDONLY)) == -1) {
               printf("Error opening MORSE.DAT\n");
               sb_voice_exit();
               exit(1);
       }

       while(1){
               DosRead(handle,(char far*)&vocsize,2,&numread);
               if(! numread) break;
               if(allocmem((unsigned)((vocsize+15) >> 4),&segp) != -1) {
                       printf("Malloc error!\n");
                       sb_voice_exit();
                       return 0;
               }

               FP_SEG(sample[numsamples]) = segp;
               FP_OFF(sample[numsamples]) = 0 ;
               DosRead(handle,sample[numsamples],vocsize,&numread);
               numsamples++;
       }

       close(handle);

       inst_morse_isr();
       init_beep();
       set_tone_freq2();
       set_volume2();

       textattr(0x1e);
       hidecur();
       clrscr();
       draw_menu();
       set_wpm2();

       return 1;
}


quit()
{
       int i, k = 0;

       printf_at(2, 24, "Do you really want to quit (y/n)?");

       if(yesno()) {
               textattr(0x07);

               clrscr();

               for(i = 0; i < numsamples; i++)
                       freemem(FP_SEG(sample[i]));

               rest_morse_isr();
               sb_voice_exit();
               showcur();
               exit(0);
       }
}


draw_menu()
{
       clrscr();
       printf("\n");
       printf(" ������������������������������������������Ŀ\n");
       printf(" �  MORSE v%s   by Mats Petersson SM5SXL  �\n", MORSE_VERSION);
       printf(" ��������������������������������������������\n\n\n");
       printf(" 1  Groups of 5 with random characters\n");
       printf(" 2  Variable length groups with random characters\n");
       printf(" 3  Text from file\n");
       printf(" C  Select characters\n");
       printf(" M  Set min/max length for variable length groups\n");
       printf(" W  Set speed in WPM (%d)\n",wpm);
       printf(" F  Set tone frequencies (CW = %d, Interference = %d)\n", freq, ifreq);
       printf(" I  Interference tone on/off (%s)\n",itonestr[itonestat]);
       printf(" H  Show/hide characters (%s)\n",shwstatstr[showstat]);
       printf(" B  Set type of background noise (%s)\n",noisestr[noisetype]);
       printf(" V  Set volume levels\n");
       printf(" S  Save configuration\n");
       printf(" L  Load configuration\n");
       printf(" D  Dir (List files)\n");
       printf(" Q  Quit\n");
}


set_minmax()
{
       get_option(2, 24, "Min length: ", "Invalid length",
       &minlength, 1, 80, 2, TRUE, FALSE);

       get_option(2, 24, "Max length: ", "Invalid length",
       &maxlength, 1, 80, 2, TRUE, FALSE);
}


random_text(int mode)
{
       unsigned char rndstring[82];
       unsigned int i, col = 1;
       int strlength, linelength = 0, first = TRUE;

       textattr(0x07);
       clrscr();
       delay(500);

       if(noisetype)
               switch_on_noise();
       if(itonestat)
               switch_on_itone();

       while(! kbhit()) {
               if(mode == 0)
                       strlength = 5;
               else
                       strlength = random(maxlength-(minlength-1)) +
                                    minlength;

               for(i = 0; i < strlength; i++)
                       rndstring[i] = letters2[random(numchars)];

               rndstring[strlength] = 0;

               if(first) {
                       linelength += strlength;
                       first = FALSE;
               } else {
                       linelength += (strlength + 1);
                       if(linelength > 80) {
                               out_char(10);
                               linelength = strlength;
                       } else
                               out_char(' ');
               }
               out_str(rndstring);
       }

       getch();
       stopmorse();

       if(itonestat)
               switch_off_itone();
       if(noisetype)
               switch_off_noise();

       textattr(0x1e);
}



text_from_file()
{
       FILE* f;
       char filestr[81], tmp[81];

       printf_at(2, 24, "Text file to send: ");

       getstr(txtfname, 80, 0);
       if(! strlen(txtfname))
               return;

       if(! (f = fopen(txtfname, "rt"))) {
               sprintf(tmp, "Can't find %s!", txtfname);
               printf_at(2, 24, tmp);
               delay(2000);
               return;
       }

       textattr(0x07);
       clrscr();
       if(noisetype)
               switch_on_noise();
       if(itonestat)
               switch_on_itone();

       while(fgets(filestr,80,f) != NULL) {
               out_str(filestr);
               if(kbhit()) break;
       }
       fclose(f);

       while(inptr != outptr) {        /* Wait for buffer to become empty */
               if(showstat) chk_for_write();
               if(kbhit()) {
                       getch();
                       break;
               }
       }

       stopmorse();

       if(itonestat)
               switch_off_itone();
       if(noisetype)
               switch_off_noise();

       textattr(0x1e);
}


out_str(unsigned char *string)
{
       int i;

       for(i = 0; i < strlen(string); i++) {
               out_char(string[i]);
               if(kbhit()) return;
       }
}


out_char(unsigned int ascii_char) {
       unsigned char ch;
       unsigned char *cp;
       unsigned int was_char;

       cp = morsecode[ascii_char];
       was_char = FALSE;

       while ((ch = *cp++) != '\0') {
               switch (ch) {
               case 'l' :
                       putmorse(letter_spacing);
                       break;
               case 'w' :
                       putmorse(word_spacing);
                       break;
               case '.' :
                       putmorse(dit | ONOFF);
                       putmorse(dit_spacing);
                       was_char = TRUE;
                       break;
               case '-' :
               case '_' :
                       putmorse(dah | ONOFF);
                       putmorse(dit_spacing);
                       was_char = TRUE;
                       break;
               }
       }

       if(showstat) {
               char_sent[char_head] = ascii_char;
               char_end[char_head] = inptr;
               if(++char_head == 32)
                       char_head = 0;
       }

       if (was_char)
               putmorse(letter_spacing);
}


putmorse(unsigned int codeval)
{
       unsigned int tempptr;

       if(kbhit()) return;
       if(showstat) chk_for_write();

       tempptr = inptr + 1;
       if (tempptr >= MORSEBUFSIZE)
               tempptr = 0;

       while (outptr == tempptr) {          /* Wait for space in buffer */
               if(kbhit()) return;
               if(showstat) chk_for_write();
       }

       morsebuf[inptr] = codeval;
       inptr = tempptr;
       return;
}


stopmorse()
{
       fm_write(0xb0, beep_off_val);       /* Turn off beep and     */
       inptr = outptr = 0;                 /* reset buffer pointers */
       char_head = char_tail = 0;
       delay_cntr = 0;
}


switch_on_noise()
{
       int i;

       set_voc_vol(0);
       switch(noisetype) {
               case 1: play_voc(sample[0], 0); break;
               case 2: play_voc(sample[1], 0); break;
       }
       for(i = 0; i < noisevol+1; i++) {
               set_voc_vol(i);
               delay(40);
       }
       delay(1000);
}

switch_off_noise()
{
       int i;

       for(i = noisevol; i > -1; i--) {
               set_voc_vol(i);
               delay(40);
       }
       stop_voc();
}

switch_on_itone()
{
       fm_write(0xb1, itone_on_val);         /* Beep ON */
}
switch_off_itone()
{
       fm_write(0xb1, itone_off_val);
}


select_characters()
{
       int i, key, k;
       unsigned char kstr[2], *ptr;

       draw_chars();

       while(1) {
               if(bioskey(1)) {
                       key = bioskey(0);
                       k = key & 0xff;
                       if(k == 27) break;

                       switch(k) {
                               case 0:
                                       k = (key >> 8) & 0xff;

                                       switch(k){
                                               case 38:
                                                       for(i=0;i<29;i++)
                                                       charstat[i] ^= 1;
                                                       break;
                                               case 49:
                                                       for(i=29;i<39;i++)
                                                       charstat[i] ^= 1;
                                                       break;
                                               case 45:
                                                       for(i=39;i<56;i++)
                                                       charstat[i] ^= 1;
                                                       break;
                                       }

                                       break;
                               default:
                                       switch(k) {
                                               case 134:  /* � */
                                                       k = 143;
                                                       break;
                                               case 132:  /* � */
                                                       k = 142;
                                                       break;
                                               case 148:  /* � */
                                                       k = 153;
                                                       break;
                                               default:
                                                       k = toupper(k);
                                       }
                                       charstat[strchr(letters, k) - letters] ^= 1;
                       }
                       draw_chars();
               }
       }

       numchars = 0;
       for(i = 0; i < 56; i++) {
               if (charstat[i])
                       letters2[numchars++] = letters[i];
       }
}

draw_chars()
{
       int i;

       gotoxy(2, 23);

       for(i = 0; i < 56; i++) {
               printf("%c", letters[i]);

               if((i == 28) || (i == 38))
                       printf("  ");
       }

       printf("\n ");

       for(i = 0; i < 56; i++) {
               if(charstat[i])
                       printf("X");
               else
                       printf(" ");

               if((i == 28) || (i == 38))
                       printf("  ");
       }
}



set_wpm()
{
       get_option(2, 24, "New speed in WPM: ", "Invalid speed",
       &wpm, 1, 999, 3, TRUE, FALSE);
       set_wpm2();
}


set_wpm2()
{
       float dit_msec;
       unsigned int x_wpm = wpm, count, factor = 1;

       if(x_wpm < 23) {
               while(x_wpm < 23) {
                       x_wpm += wpm;
                       factor++;
               }
       }

       dit_msec = 60000.0 / (float)x_wpm / 50.0;
       count = (unsigned int)floor((dit_msec * 1193.181) + 0.5);

       dit = 1 * factor;
       dit_spacing = dit;
       dah = dit * 3;
       letter_spacing = dah - dit_spacing;
       word_spacing = dit * 7 - letter_spacing;

       set_timer_count(count);
}


set_tone_freq()
{
       get_option(2, 24, "Frequency CW: ", "Invalid frequency",
       &freq, 100, 9999, 4, TRUE, FALSE);

       get_option(2, 24, "Frequency interference: ", "Invalid frequency",
       &ifreq, 100, 9999, 4, TRUE, FALSE);

       set_tone_freq2();
}

set_tone_freq2()
{
       int block, fnum;

       freq_to_fnum(freq, &block, &fnum);
       fm_write(0xa0, fnum & 0xff);
       beep_on_val = 0x20 | ((block & 0x7) << 2) | ((fnum >> 8) & 0x3);
       beep_off_val = beep_on_val & 0xdf;

       freq_to_fnum(ifreq, &block, &fnum);
       fm_write(0xa1, fnum & 0xff);
       itone_on_val = 0x20 | ((block & 0x7) << 2) | ((fnum >> 8) & 0x3);
       itone_off_val = itone_on_val & 0xdf;
}

show_hide()
{
       showstat ^= 1;
}

set_backg_noise()
{
       char tmp[81];

       sprintf(tmp, "Type of background noise (0=%s, 1=%s, 2=%s): ",
               noisestr[0], noisestr[1], noisestr[2]);

       get_option(2, 24, tmp, "Invalid type", &noisetype, 0, 2, 1,
       TRUE, FALSE);
}


set_itone()
{
       itonestat ^= 1;
}


set_volumes()
{
       outportb(ct_io_addx + 4, 0x22);
       mastervol = inportb(ct_io_addx+5) & 0xf;

       outportb(ct_io_addx + 4, 0x26);
       beepvol = inportb(ct_io_addx+5) & 0xf;

       outportb(ct_io_addx + 4, 0x2E);
       lineinvol = inportb(ct_io_addx+5) & 0xf;


       get_option(2, 24, "Total: ", "Invalid volume",
       &mastervol, 0, 15, 2, TRUE, FALSE);

       get_option(2, 24, "Tones: ", "Invalid volume",
       &beepvol, 0, 15, 2, TRUE, FALSE);

       get_option(2, 24, "Background noise: ", "Invalid volume",
       &noisevol, 0, 15, 2, TRUE, FALSE);

       get_option(2, 24, "Line In: ", "Invalid volume",
       &lineinvol, 0, 15, 2, TRUE, FALSE);

       set_volume2();
}

set_volume2()
{
       outportb(ct_io_addx + 4, 0x22);
       outportb(ct_io_addx + 5, (mastervol << 4) + mastervol);
       outportb(ct_io_addx + 4, 0x26);
       outportb(ct_io_addx + 5, (beepvol << 4) + beepvol);
       outportb(ct_io_addx + 4, 0x2e);
       outportb(ct_io_addx + 5, (lineinvol << 4) + lineinvol);
}


set_voc_vol(int vol)
{
       outportb(ct_io_addx + 4, 0x04);
       outportb(ct_io_addx + 5, (vol << 4) + vol);
}


save_config()
{
       printf_at(2, 24, "Save as: ");

       getstr(cfgfname, 80, 0);
       if(! strlen(cfgfname))
               return;

       chk_ext(cfgfname, "cfg");

       printf_at(2, 24, "Saving configuration...");
       cfgfile=fopen(cfgfname, "wb");

       fwrite(&wpm, 2, 1, cfgfile);
       fwrite(&charstat, 1, 56, cfgfile);
       fwrite(&minlength, 2, 1, cfgfile);
       fwrite(&maxlength, 2, 1, cfgfile);
       fwrite(&mastervol, 2, 1, cfgfile);
       fwrite(&beepvol, 2, 1, cfgfile);
       fwrite(&noisevol, 2, 1, cfgfile);
       fwrite(&noisetype, 2, 1, cfgfile);
       fwrite(&lineinvol, 2, 1, cfgfile);
       fwrite(&freq, 2, 1, cfgfile);
       fwrite(&ifreq, 2, 1, cfgfile);
       fwrite(&itonestat,2,1,cfgfile);

       fclose(cfgfile);
       delay(1000);
}

load_config()
{
       char tmp[81];
       int i;

       printf_at(2, 24, "Configuration file to load: ");

       getstr(cfgfname, 80, 0);
       if(! strlen(cfgfname))
               return;

       chk_ext(cfgfname, "cfg");

       if(! (cfgfile=fopen(cfgfname,"rb"))) {
               sprintf(tmp, "Can't find %s!", cfgfname);
               printf_at(2, 24, tmp);
               delay(1000);
       } else {
               load_config2();
               numchars = 0;
               for(i=0;i<56;i++) {
                       if (charstat[i])
                               letters2[numchars++] = letters[i];
               }
               set_wpm2();
       }
}

load_config2()
{
       fread(&wpm, 2, 1, cfgfile);
       fread(&charstat, 1, 56, cfgfile);
       fread(&minlength, 2, 1, cfgfile);
       fread(&maxlength, 2, 1, cfgfile);
       fread(&mastervol, 2, 1, cfgfile);
       fread(&beepvol, 2, 1, cfgfile);
       fread(&noisevol, 2, 1, cfgfile);
       fread(&noisetype, 2, 1, cfgfile);
       fread(&lineinvol, 2, 1, cfgfile);
       fread(&freq, 2, 1, cfgfile);
       fread(&ifreq, 2, 1, cfgfile);
       fread(&itonestat, 2, 1, cfgfile);

       set_tone_freq2();
       set_volume2();

       fclose(cfgfile);
}


list_files()
{
       textattr(0x07);
       clrscr();
       system("dir /w /p /on");
       printf("\nPress any key to return to MORSE\n");
       getch();
       textattr(0x1e);
}


init_beep()
{
       /* Beep tone */

       fm_write(0x20, beep[0]);            /* am/vib/ksr/multiple */
       fm_write(0x23, beep[1]);

       fm_write(0x40, beep[2]);            /* ksl/total level */
       fm_write(0x43, beep[3]);

       fm_write(0x60, beep[4]);            /* attack/decay rate */
       fm_write(0x63, beep[5]);

       fm_write(0x80, beep[6]);            /* sustain level/release rate */
       fm_write(0x83, beep[7]);

       fm_write(0xe0, beep[8]);            /*  wave select */
       fm_write(0xe3, beep[9]);

       fm_write(0xc0, beep[10]);           /* feedback/connection */

/* Interference tone */

       fm_write(0x21, beep[0]);            /* am/vib/ksr/multiple */
       fm_write(0x24, beep[1]);

       fm_write(0x41, beep[2]);            /* ksl/total level */
       fm_write(0x44, beep[3]);

       fm_write(0x61, beep[4]);            /* attack/decay rate */
       fm_write(0x64, beep[5]);

       fm_write(0x81, beep[6]);            /* sustain level/release rate */
       fm_write(0x84, beep[7]);

       fm_write(0xe1, beep[8]);            /*  wave select */
       fm_write(0xe4, beep[9]);

       fm_write(0xc1, beep[10]);           /* feedback/connection */
}


DosRead (int handle, char far *Buffer, unsigned wLen, unsigned *wByteRead)
{
       union REGS regs;
       struct SREGS segregs;

       regs.h.ah = 0x3f ;
       regs.x.bx = handle;
       regs.x.dx = FP_OFF(Buffer);
       regs.x.cx = wLen;
       segregs.ds = FP_SEG(Buffer);

       intdosx(&regs, &regs, &segregs);

       if(regs.x.cflag)    /* error */
               *wByteRead = 0;
       else
               *wByteRead = regs.x.ax ;

       return(*wByteRead);
}


GetCurX()
{
       asm{
               push bx
               push cx

               mov ah,03h
               mov ch,0
               mov cl,24
               mov bh,0
               int 10h

               mov al,dl
               mov ah,0

               pop cx
               pop bx
       }
}


printf_at(int x, int y, char *s)
{
       gotoxy(x, y);
       printf(s);
}


getstr(char *s, int maxlen, int mk_upper)
{
       showcur();
       edgets(s, maxlen, mk_upper);
       hidecur();
       gotoxy(2, 24);
       printf("                                                                                ");
}


get_option(int x, int y, char *prompt, char *errtxt, int *val, int low_limit,
int high_limit, int nr_digits, int show_curr_val, int disp_add)
{
       char s[6];
       int val_add = 0, val_tmp;

       if(disp_add)
               val_add++;

       while(1) {
               gotoxy(x, y);
               printf(prompt);
               showcur();
               if(show_curr_val)
                       sprintf(s, "%d", (*val) + val_add);
               else
                       strcpy(s, "");
               edgets(s, nr_digits, 1);
               hidecur();
               gotoxy(x, y);
               if(! strlen(s))
                       return 0;
               val_tmp = atoi(s) - val_add;
               if((val_tmp >= low_limit) && (val_tmp <= high_limit)) {
                       (*val) = val_tmp;
                       gotoxy(x, y);
                       printf("%-78s", " ");
                       return 1;
               }

               gotoxy(x, y);
               printf("%-78s", errtxt);
               getch();
               gotoxy(x, y);
               printf("%-78s", " ");
       }
}


freq_to_fnum (int freq, int *block, int *fnum)
{
       static int f, octave;

       f = freq;

       octave = 5;

       if (f == 0)
               octave = 0;
       else if (f < 261) {
               while (f < 261) {
                       octave--;
                       f <<= 1;
               }
       } else if (f > 493) {
               while (f > 493) {
                       octave++;
                       f >>= 1;
               }
       }

       if (octave > 7)
               octave = 7;

       (*fnum) = freq * (1L << (20L - octave)) / 49716L;
       (*block) = octave;
}


chk_for_write()
{
       if(do_write_char) {
               putchar(char_to_write);
               do_write_char = FALSE;
       }
}