/******************************************************/
/* MORSE v1.20 */
/* CW trainer for Soundblaster */
/******************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <dos.h>
#include <bios.h>
#include <dir.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 <w1.h>
#include <windprot.h>
#include <color.h>
#include <sb.h>
#include <edgets.h>
#include <bk_delay.h>
#include "morseisr.h"
/* #pragma inline; */
#define MORSE_VERSION "1.20"
#define MORSEBUFSIZE 128 /* Number of entries in morse data buffer */
#define ONOFF 0x8000 /* Top bit controls tone on or off */
#define CHAR_COMPLETED 0x4000
#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"};
int mastervol,beepvol,noisevol,lineinvol;
int wpm;
int dah, dit, dit_spacing, letter_spacing, word_spacing;
int noisetype;
char txtfname[81];
unsigned char far *dma_buf;
int numsamples;
unsigned char far *sample[10], far *quit_sample;
unsigned long sampsize[10], quit_sampsize;
unsigned char letters[] = {
"ABCDEFGHIJKLMNOPQRSTUVWXYZ���0123456789.,?!:\"'()/-*=~�+@"
};
unsigned char used_letters[56];
unsigned char letter_stat[56];
int num_used;
unsigned int freq, ifreq;
unsigned char beep_on_val, beep_off_val, itone_on_val, itone_off_val;
unsigned int attack, release;
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 void fm_write(unsigned char reg,unsigned char data);
FILE* cfgfile;
char cfgfname[81];
unsigned char char_to_write = 0;
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 't': set_at_rel(); 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 'j': jump_to_dos(); break;
case 'q': quit();
}
draw_menu();
}
}
init()
{
int i, handle;
FILE* f;
unsigned int wavsize;
unsigned numread, segp;
struct WAVhdr wav_hdr;
sb_init(0x220, 5, 1);
sb_set_samprate(11025);
dsp_voice(1);
strcpy(cfgfname, "MORSE.CFG");
if(cfgfile = fopen(cfgfname,"rb"))
load_config2();
else {
wpm = 20;
for(i = 0; i < 56; i++)
letter_stat[i] = 1;
minlength=2;
maxlength=5;
mastervol=12;
beepvol=15;
noisevol=8;
noisetype=1;
itonestat=0;
freq = 700;
ifreq = 720;
attack = 12;
release = 12;
}
num_used = 0;
for(i = 0; i < 56; i++) {
if (letter_stat[i])
used_letters[num_used++] = letters[i];
}
randomize();
dma_buf = aligned_malloc(65536L);
if((handle = _open("MORSE.DAT", O_RDONLY)) == -1) {
printf("Error opening MORSE.DAT\n");
sb_exit();
exit(1);
}
numsamples = 0;
while(1) {
DosRead(handle, (char far *)&wavsize, 2, &numread);
if(! numread) break;
DosRead(handle, (struct WAVhdr far*)&wav_hdr, 44, &numread);
allocmem((wav_hdr.data_length + 15L) >> 4, &segp);
sample[numsamples] = MK_FP(segp, 0);
DosRead(handle, sample[numsamples], wav_hdr.data_length, &numread);
sampsize[numsamples] = wav_hdr.data_length - 1;
lseek(handle, wavsize - (44 + wav_hdr.data_length), SEEK_CUR);
numsamples++;
}
close(handle);
if((handle = _open("QRT.WAV", O_RDONLY)) == -1) {
printf("Error opening QRT.WAV\n");
sb_exit();
exit(1);
}
DosRead(handle, (struct WAVhdr far*)&wav_hdr, 44, &numread);
allocmem((wav_hdr.data_length + 15L) >> 4, &segp);
quit_sample = MK_FP(segp, 0);
DosRead(handle, quit_sample, wav_hdr.data_length, &numread);
quit_sampsize = wav_hdr.data_length - 1;
close(handle);
inst_morse_isr();
init_beep();
set_at_rel2();
set_tone_freq2();
set_volume2();
qinit();
textattr(0x1e);
hidecur();
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()) {
sb_set_volume(MIXER_VOICE, 0xff);
_fmemcpy(dma_buf, quit_sample, quit_sampsize);
sb_play(dma_buf, quit_sampsize - 1, quit_sampsize - 1, 0);
while(! block_done);
for(i = 0; i < numsamples; i++)
freemem(FP_SEG(sample[i]));
rest_morse_isr();
sb_exit();
textattr(0x07);
qfill(1, 1, 25, 80, 0x07, ' ');
gotorc(1, 1);
showcur();
exit(0);
}
}
draw_menu()
{
char tmp[82];
vsync();
qfill(1, 1, 25, 80, 0x1e, ' ');
qwrite(2, 2, 0x1e, "������������������������������������������Ŀ");
sprintf(tmp, "� MORSE v%s by Mats Petersson SM5SXL �", MORSE_VERSION);
qwrite(3, 2, 0x1e, tmp);
qwrite(4, 2, 0x1e, "��������������������������������������������");
qwrite(6, 2, 0x1e, "1 Groups of 5 with random characters");
qwrite(7, 2, 0x1e, "2 Variable length groups with random characters");
qwrite(8, 2, 0x1e, "3 Text from file");
qwrite(9, 2, 0x1e, "C Select characters");
sprintf(tmp, "M Set min/max length [Min %d Max %d]", minlength, maxlength);
qwrite(10, 2, 0x1e, tmp);
sprintf(tmp, "W Set speed in WPM [%d]", wpm);
qwrite(11, 2, 0x1e, tmp);
sprintf(tmp, "F Set tone frequencies [CW %d Interference %d]", freq, ifreq);
qwrite(12, 2, 0x1e, tmp);
sprintf(tmp, "T Set CW tone attack/release [Attack %d Release %d]", attack, release);
qwrite(13, 2, 0x1e, tmp);
sprintf(tmp, "I Interference tone on/off [%s]",itonestr[itonestat]);
qwrite(14, 2, 0x1e, tmp);
sprintf(tmp, "H Show/hide characters [%s]",shwstatstr[showstat]);
qwrite(15, 2, 0x1e, tmp);
sprintf(tmp, "B Set background noise sample [%d]", noisetype);
qwrite(16, 2, 0x1e, tmp);
sprintf(tmp, "V Set volume levels [Total %u Tones %u BG %u Line-In %u]",
mastervol, beepvol, noisevol, lineinvol);
qwrite(17, 2, 0x1e, tmp);
qwrite(18, 2, 0x1e, "S Save configuration");
qwrite(19, 2, 0x1e, "L Load configuration");
qwrite(20, 2, 0x1e, "D Dir (List files)");
qwrite(21, 2, 0x1e, "J Jump to DOS");
qwrite(22, 2, 0x1e, "Q Quit");
}
set_minmax()
{
int old_minlength, old_maxlength;
old_minlength = minlength;
get_option(2, 24, "Min length: ", "Invalid length",
&minlength, 1, 80, 2, TRUE, FALSE);
if(maxlength < minlength)
maxlength = minlength;
old_maxlength = maxlength;
while(1) {
get_option(2, 24, "Max length: ", "Invalid length",
&maxlength, 1, 80, 2, TRUE, FALSE);
if(maxlength < minlength) {
gotoxy(2, 24);
printf("Max length cannot be smaller than Min length!\n");
bk_delay(1500);
gotoxy(2, 24);
printf("%-78s", " ");
maxlength = old_maxlength;
} else
break;
}
}
random_text(int mode)
{
unsigned char rndstring[82];
unsigned int i, col = 1;
int strlength, linelength = 0, old_linelength, first = TRUE;
textattr(0x07);
clrscr();
delay(500);
if(noisetype)
switch_on_noise();
if(itonestat)
switch_on_itone();
while(! esc_key()) {
if(mode == 0)
strlength = 5;
else
strlength = random(maxlength-(minlength-1)) +
minlength;
for(i = 0; i < strlength; i++)
rndstring[i] = used_letters[random(num_used)];
rndstring[strlength] = 0;
if(first) {
linelength += strlength;
first = FALSE;
} else {
old_linelength = linelength;
linelength += (strlength + 1);
if(linelength > 80) {
if(old_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);
bk_delay(1500);
return;
}
textattr(0x07);
clrscr();
if(noisetype)
switch_on_noise();
if(itonestat)
switch_on_itone();
while((! esc_key()) && fgets(filestr,80,f))
out_str(filestr);
fclose(f);
while((! esc_key()) && (inptr != outptr)) /* Wait for buffer to empty */
if(showstat) chk_for_write();
if(esc_key()) getch();
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(esc_key()) return;
if(showstat) chk_for_write();
}
}
out_char(unsigned int ascii_char) {
unsigned char ch, *cp;
unsigned int i, was_char, val, len, last_pos;
cp = morsecode[ascii_char];
if((*cp) == 0) return;
was_char = FALSE;
len = strlen(cp);
last_pos = len - 1;
for(i = 0; i < len; i++) {
switch(*(cp + i)) {
case 'l' :
val = letter_spacing;
break;
case 'w' :
val = word_spacing;
break;
case '.' :
putmorse(dit | ONOFF);
val = dit_spacing;
was_char = TRUE;
break;
case '-' :
case '_' :
putmorse(dah | ONOFF);
val = dit_spacing;
was_char = TRUE;
break;
}
if(i == last_pos)
val |= CHAR_COMPLETED | (ascii_char << 5);
putmorse(val);
}
if (was_char)
putmorse(letter_spacing);
}
putmorse(unsigned int codeval)
{
unsigned int tempptr;
if(esc_key()) return;
if(showstat) chk_for_write();
tempptr = (inptr + 1) & (MORSEBUFSIZE - 1);
while (outptr == tempptr) { /* Wait for space in buffer */
if(esc_key()) 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 */
delay_cntr = 0;
}
switch_on_noise()
{
int i;
unsigned int len;
unsigned char far *smp;
set_voc_vol(0);
smp = sample[noisetype - 1];
len = sampsize[noisetype - 1];
_fmemcpy(dma_buf, smp, len);
sb_play(dma_buf, len - 1, 4095, 1);
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);
}
sb_stop();
}
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) {
key = bioskey(0);
k = key & 0xff;
if(k == 27) break;
if(k == 0) {
k = (key >> 8) & 0xff;
switch(k) {
case 38: /* Alt-L */
for(i=0;i<29;i++)
letter_stat[i] ^= 1;
break;
case 49: /* Alt-N */
for(i=29;i<39;i++)
letter_stat[i] ^= 1;
break;
case 45: /* Alt-X */
for(i=39;i<56;i++)
letter_stat[i] ^= 1;
break;
}
} else {
switch(k) {
case 134: /* � */
k = 143;
break;
case 132: /* � */
k = 142;
break;
case 148: /* � */
k = 153;
break;
default:
k = toupper(k);
}
letter_stat[strchr(letters, k) - letters] ^= 1;
}
draw_chars();
}
num_used = 0;
for(i = 0; i < 56; i++) {
if (letter_stat[i])
used_letters[num_used++] = letters[i];
}
}
draw_chars()
{
char tmp[82], tmp2[3];
int i;
strcpy(tmp, "");
for(i = 0; i < 56; i++) {
sprintf(tmp2, "%c", letters[i]);
strcat(tmp, tmp2);
if((i == 28) || (i == 38))
strcat(tmp, " ");
}
qwrite(24, 2, 0x1e, tmp);
strcpy(tmp, "");
for(i = 0; i < 56; i++) {
if(letter_stat[i])
strcat(tmp, "�");
else
strcat(tmp, " ");
if((i == 28) || (i == 38))
strcat(tmp, " ");
}
qwrite(25, 2, 0x1e, tmp);
}
set_wpm()
{
get_option(2, 24, "New speed in WPM: ", "Invalid speed",
&wpm, 5, 999, 3, TRUE, FALSE);
set_wpm2();
}
set_wpm2()
{
float dit_msec;
unsigned int x_wpm = wpm, count, dit_adjust = 1;
if(x_wpm < 23) { /* 23 WPM = approximate limit for */
while(x_wpm < 23) { /* timer count to be within 65535 */
x_wpm += wpm; /* If below 23 WPM, then multiply */
dit_adjust++; /* it enough times to be above, */
} /* and adjust the number of ticks */
} /* for a 'dit' accordingly */
dit_msec = 60000.0 / (float)x_wpm / 50.0;
count = (unsigned int)floor((dit_msec * 1193.181) + 0.5);
dit = 1 * dit_adjust;
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, 10, 6213, 4, TRUE, FALSE);
get_option(2, 24, "Frequency interference: ", "Invalid frequency",
&ifreq, 10, 6213, 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;
}
set_at_rel()
{
get_option(2, 24, "Attack: ", "Invalid attack value",
&attack, 0, 15, 4, TRUE, FALSE);
get_option(2, 24, "Release: ", "Invalid release value",
&release, 0, 15, 4, TRUE, FALSE);
set_at_rel2();
}
set_at_rel2()
{
fm_write(0x60, (beep[4] & 0x0f) | (attack << 4)); /* attack/decay rate */
fm_write(0x63, (beep[5] & 0x0f) | (attack << 4));
fm_write(0x80, (beep[6] & 0xf0) | release); /* sustain level/release rate */
fm_write(0x83, (beep[7] & 0xf0) | release);
}
show_hide()
{
showstat ^= 1;
}
set_backg_noise()
{
char tmp[81];
sprintf(tmp, "Sample to use as background noise (1 - %d, or 0 for none): ",
numsamples);
get_option(2, 24, tmp, "Value out of range", &noisetype, 0, numsamples, 1,
TRUE, FALSE);
}
set_itone()
{
itonestat ^= 1;
}
set_volumes()
{
get_vols();
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()
{
sb_set_volume(MIXER_MASTER, (mastervol << 4) + mastervol);
sb_set_volume(MIXER_FM, (beepvol << 4) + beepvol);
sb_set_volume(MIXER_LINE, (lineinvol << 4) + lineinvol);
get_vols();
}
set_voc_vol(int vol)
{
sb_set_volume(MIXER_VOICE, (vol << 4) + vol);
}
get_vols()
{
mastervol = sb_get_volume(MIXER_MASTER) & 0x0f;
beepvol = sb_get_volume(MIXER_FM) & 0x0f;
lineinvol = sb_get_volume(MIXER_LINE) & 0x0f;
}
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(&letter_stat, 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(&attack, 2, 1, cfgfile);
fwrite(&release, 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);
bk_delay(1500);
} else {
load_config2();
num_used = 0;
for(i=0;i<56;i++) {
if (letter_stat[i])
used_letters[num_used++] = letters[i];
}
set_wpm2();
}
}
load_config2()
{
fread(&wpm, 2, 1, cfgfile);
fread(&letter_stat, 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(&attack, 2, 1, cfgfile);
fread(&release, 2, 1, cfgfile);
fread(&itonestat, 2, 1, cfgfile);
set_tone_freq2();
set_volume2();
fclose(cfgfile);
}
list_files()
{
textattr(0x07);
qfill(1, 1, 25, 80, 0x07, ' ');
gotorc(1, 1);
system("dir /w /p /on");
printf("\nPress any key to return to MORSE\n");
getch();
textattr(0x1e);
}
jump_to_dos()
{
char s[82], *oldprompt;
textattr(0x07);
qfill(1, 1, 25, 80, 0x07, ' ');
gotorc(1, 1);
showcur();
oldprompt = getenv("PROMPT");
putenv("PROMPT=$_Type EXIT to return to MORSE$_$p$g");
system("command");
strcpy(s, "PROMPT=");
strcat(s, oldprompt);
putenv(s); /* restore old prompt */
hidecur();
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);
bk_delay(1500);
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(char_to_write) {
putchar(char_to_write);
char_to_write = 0;
}
}
esc_key()
{
int k = bioskey(1);
if(k && ((k & 0xff) != 27)) {
bioskey(0);
k = 0;
}
return k;
}