KeyerState ks;
KeyerLogic kl;
-pthread_t play, key;
-sem_t clock_fired, keyer_started;
+pthread_t play, key, update;
+sem_t clock_fired, keyer_started, update_ok;
int fdser, fdrtc;
CWToneGen gen;
BOOLEAN playing = FALSE, iambic = FALSE;
-double wpm = 18.0, freq = 750.0;
+double wpm = 18.0, freq = 750.0, ramp = 5.0, gain = -3.0;
//------------------------------------------------------------
}
}
+//------------------------------------------------------------------------
+
// sound/silence generation
// tone turned on/off asynchronously
+
void
sound_thread(void) {
for (;;) {
// returns FALSE when it's actually done.
playing = CWTone(gen);
send_tone();
- } else
+ } else {
send_silence();
+ // only let updates run when we've just generated silence
+ sem_post(&update_ok);
+ }
}
pthread_exit(0);
}
+//------------------------------------------------------------------------
+
// basic heartbeat
// returns actual dur in msec since last tick;
// uses Linux rtc interrupts.
// other strategies will work too, so long as they
// provide a measurable delay in msec.
+
double
timed_delay(void) {
double del, std = 1000 / (double) RTC_RATE;
}
// key down? (real or via keyer logic)
+
BOOLEAN
read_key(double del) {
if (iambic)
return read_straight_key_serial(ks, fdser);
}
+//------------------------------------------------------------------------
+
// main keyer loop
-//
+
void
key_thread(void) {
pthread_exit(0);
}
+//------------------------------------------------------------------------
+
+// update keyer parameters via text input from stdin
+// <wpm xxx> -> set keyer speed to xxx
+// <gain xxx> -> set gain to xxx (dB)
+// <freq xxx> -> set freq to xxx
+// <ramp xxx> -> set attack/decay times to xxx ms
+
+#define MAX_ESC (512)
+#define ESC_L '<'
+#define ESC_R '>'
+
+void
+updater(void) {
+ for (;;) {
+ int c;
+
+ // get or wait for next input char
+ if ((c = getchar()) == EOF) goto finish;
+
+ // if we see the beginning of a command,
+ if (c == ESC_L) {
+ int i = 0;
+ char buf[MAX_ESC];
+
+ // gather up the remainder
+ while ((c = getchar()) != EOF) {
+ if (c == ESC_R) break;
+ buf[i] = c;
+ if (++i >= (MAX_ESC - 1)) break;
+ }
+ if (c == EOF) goto finish;
+ buf[i] = 0;
+
+ // wait until changes are safe
+ sem_wait(&update_ok);
+
+ if (!strncmp(buf, "wpm", 3))
+ ks->wpm = wpm = atof(buf + 3);
+ else if (!strncmp(buf, "ramp", 4)) {
+ ramp = atof(buf + 4);
+ setCWToneGenVals(gen, gain, freq, ramp, ramp);
+ } else if (!strncmp(buf, "freq", 4)) {
+ freq = atof(buf + 4);
+ setCWToneGenVals(gen, gain, freq, ramp, ramp);
+ } else if (!strncmp(buf, "gain", 4)) {
+ gain = atof(buf + 4);
+ setCWToneGenVals(gen, gain, freq, ramp, ramp);
+ } else if (!strncmp(buf, "quit", 4))
+ goto finish;
+
+ } // otherwise go around again
+ }
+
+ // we saw an EOF or quit; kill other threads and exit neatly
+
+ finish:
+ pthread_cancel(play);
+ pthread_cancel(key);
+ pthread_exit(0);
+}
+
+//------------------------------------------------------------------------
+
PRIVATE void
jack_xrun(void *arg) {
char *str = "xrun";
case 'i':
iambic = TRUE;
break;
+ case 'g':
+ gain = atof(argv[++i]);
+ break;
+ case 'r':
+ ramp = atof(argv[++i]);
+ break;
case 'w':
wpm = atof(argv[++i]);
break;
default:
- fprintf(stderr, "keyd [-i] [-w wpm]\n");
+ fprintf(stderr,
+ "keyd [-i] [-w wpm] [-g gain_dB] [-r ramp_ms]\n");
exit(1);
}
else break;
+ if (i < argc) {
+ if (!freopen(argv[i], "r", stdin))
+ perror(argv[i]), exit(1);
+ i++;
+ }
+
//------------------------------------------------------------
- gen = newCWToneGen(-3.0, freq, 5.0, 5.0, TONE_SIZE, 48000.0);
+ gen = newCWToneGen(gain, freq, ramp, ramp, TONE_SIZE, 48000.0);
//------------------------------------------------------------
sem_init(&clock_fired, 0, 0);
sem_init(&keyer_started, 0, 0);
+ sem_init(&update_ok, 0, 0);
pthread_create(&play, 0, (void *) sound_thread, 0);
pthread_create(&key, 0, (void *) key_thread, 0);
+ pthread_create(&update, 0, (void *) updater, 0);
//------------------------------------------------------------
pthread_join(play, 0);
pthread_join(key, 0);
+ pthread_join(update, 0);
jack_client_close(client);
//------------------------------------------------------------