2000 /******************************************************/ /* MORSE v1.10 */ /* CW trainer for Soundblaster */ /******************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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 2000 )) + 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); pri 100e ntf_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(®s, ®s, &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; } } . 0