Further keyer improvements: update commands for both physical and type-in keyers
authordttsp <dttsp>
Thu, 28 Apr 2005 15:21:42 +0000 (15:21 +0000)
committerdttsp <dttsp>
Thu, 28 Apr 2005 15:21:42 +0000 (15:21 +0000)
jDttSP/keyb.c
jDttSP/keyd.c

index 158b18f7a75506ad52e388661b145c62b1d74c02..14e128b8a9c4815f176a90223ea648fecedf4e28 100644 (file)
@@ -76,6 +76,12 @@ int ditspacesize, dahspacesize,
     risesize, fallsize;
 double riseincr, fallincr;
 
+#define MAX_ESC (512)
+#define ESC_L '<'
+#define ESC_R '>'
+
+void inlinecmd(char *, int);
+
 void jack_ringbuffer_clear(jack_ringbuffer_t *, int);
 void jack_ringbuffer_restart(jack_ringbuffer_t *, int);
 void send_sound(COMPLEX *, int);
@@ -98,6 +104,21 @@ reader_thread(void) {
   // keep reading 1 char at a time
   while ((c = getchar()) != EOF) {
     
+    // inline command?
+    if (c == ESC_L) {
+      int i = 0;
+      char buf[MAX_ESC];
+      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;
+      inlinecmd(buf, i);
+      continue;
+    }
+
     // is char mapped to morse?
     if (m = get_morse(c)) {
       
@@ -158,6 +179,7 @@ reader_thread(void) {
     }
   }
   
+ finish:
   // indicate EOF on input
   sem_wait(&reader);
   morsel.type = ME_EOF;
@@ -168,9 +190,7 @@ reader_thread(void) {
 void
 sound_thread(void) {
   int i, k = 0;
-  double ofreq = freq * 2.0 * M_PI / SAMP_RATE,
-         phase = 0.0,
-         scale = pow(10.0, gain / 20.0);
+  double ofreq, scale, phase = 0.0;
   COMPLEX z, delta_z;
 
   // keep looking for sub-element segments, one at a time
@@ -185,7 +205,10 @@ sound_thread(void) {
 
     // requires playing some tone?
     if (morsel.type != ME_ZERO) {
-      // yes, set up CORDIC tone generation
+      // yes, reset params and
+      // set up CORDIC tone generation
+      ofreq = freq * 2.0 * M_PI / SAMP_RATE;
+      scale = pow(10.0, gain / 20.0);
       if (phase > HUGE_PHASE) phase -= HUGE_PHASE;
       z = Cmplx(cos(phase), sin(phase));
       delta_z = Cmplx(cos(ofreq), sin(ofreq));
@@ -291,6 +314,33 @@ jack_callback(jack_nframes_t nframes, void *arg) {
   }
 }
 
+void
+resetparam(void) {
+  morsel.wpm = wpm;
+  morsel.rise = morsel.fall = ramp;
+  morsel.rate = SAMP_RATE;
+
+  ditspacesize = SAMP_RATE * 1.2 / morsel.wpm + 0.5;
+  dahspacesize = 3 * ditspacesize;
+  charspacesize = dahspacesize;
+  wordspacesize = 7 * ditspacesize;
+
+  risesize = SAMP_RATE * morsel.rise / 1e3 + 0.5;
+  if (risesize > 1)
+    riseincr = 1.0 / (risesize - 1);
+  else
+    riseincr = 1.0;
+
+  fallsize = SAMP_RATE * morsel.fall / 1e3 + 0.5;
+  if (fallsize > 1)
+    fallincr = -1.0 / (fallsize - 1);
+  else
+    fallincr = -1.0;
+
+  ditstdysize = ditspacesize - risesize - fallsize;
+  dahstdysize = dahspacesize - risesize - fallsize;
+}
+
 int
 main(int argc, char **argv) {
   int i;
@@ -321,29 +371,7 @@ main(int argc, char **argv) {
 
   //------------------------------------------------------------
 
-  morsel.wpm = wpm;
-  morsel.rise = morsel.fall = ramp;
-  morsel.rate = SAMP_RATE;
-
-  ditspacesize = SAMP_RATE * 1.2 / morsel.wpm + 0.5;
-  dahspacesize = 3 * ditspacesize;
-  charspacesize = dahspacesize;
-  wordspacesize = 7 * ditspacesize;
-
-  risesize = SAMP_RATE * morsel.rise / 1e3 + 0.5;
-  if (risesize > 1)
-    riseincr = 1.0 / (risesize - 1);
-  else
-    riseincr = 1.0;
-
-  fallsize = SAMP_RATE * morsel.fall / 1e3 + 0.5;
-  if (fallsize > 1)
-    fallincr = -1.0 / (fallsize - 1);
-  else
-    fallincr = -1.0;
-
-  ditstdysize = ditspacesize - risesize - fallsize;
-  dahstdysize = dahspacesize - risesize - fallsize;
+  resetparam();
 
   //------------------------------------------------------------
 
@@ -433,9 +461,12 @@ char *morse_table[128] = {
   /* 028  FS */ 0, /* 029  GS */ 0, /* 030  RS */ 0, /* 031  US */ 0,
   /* 032  SP */ 0,
   /* 033   ! */ "...-.",       // [SN]
-  /* 034   " */ 0, /* 035   # */ 0, /* 036   $ */ 0,
+  /* 034   " */ 0,
+  /* 035   # */ 0,
+  /* 036   $ */ 0,
   /* 037   % */ ".-...",       // [AS]
-  /* 038   & */ 0, /* 039   ' */ 0,
+  /* 038   & */ 0,
+  /* 039   ' */ 0,
   /* 040   ( */ "-.--.",       // [KN]
   /* 041   ) */ 0,
   /* 042   * */ "...-.-",      // [SK]
@@ -454,7 +485,9 @@ char *morse_table[128] = {
   /* 055   7 */ "--...",
   /* 056   8 */ "---..",
   /* 057   9 */ "----.",
-  /* 058   : */ 0, /* 059   ; */ 0, /* 060   < */ 0,
+  /* 058   : */ 0,
+  /* 059   ; */ 0,
+  /* 060   < */ 0,
   /* 061   = */ "-...-",       // [BT]
   /* 062   > */ 0,
   /* 063   ? */ "..__..",      // [IMI]
@@ -485,8 +518,12 @@ char *morse_table[128] = {
   /* 088   X */ "-..-",
   /* 089   Y */ "-.--",
   /* 090   Z */ "--..",
-  /* 091   [ */ 0, /* 092   \ */ 0, /* 093   ] */ 0, /* 094   ^ */ 0,
-  /* 095   _ */ 0, /* 096   ` */ 0,
+  /* 091   [ */ 0,
+  /* 092   \ */ 0,
+  /* 093   ] */ 0,
+  /* 094   ^ */ 0,
+  /* 095   _ */ 0,
+  /* 096   ` */ 0,
   /* 097   a */ ".-",
   /* 098   b */ "-...",
   /* 099   c */ "-.-.",
@@ -513,6 +550,24 @@ char *morse_table[128] = {
   /* 120   x */ "-..-",
   /* 121   y */ "-.--",
   /* 122   z */ "--..",
-  /* 123   { */ 0, /* 124   | */ 0, /* 125   } */ 0, /* 126   ~ */ 0,
+  /* 123   { */ 0,
+  /* 124   | */ 0,
+  /* 125   } */ 0,
+  /* 126   ~ */ 0,
   /* 127 DEL */ 0
 };
+
+void
+inlinecmd(char *buf, int len) {
+  if (!buf || len < 1) return;
+  if (!strncmp(buf, "wpm", 3)) {
+    wpm = atof(buf + 3);
+    resetparam();
+  } else if (!strncmp(buf, "ramp", 4)) {
+    ramp = atof(buf + 4);
+    resetparam();
+  } else if (!strncmp(buf, "freq", 4))
+    freq = atof(buf + 4);
+  else if (!strncmp(buf, "gain", 4))
+    gain = atof(buf + 4);
+}
index 61d7ac86dda72483107434151d0410206ed4fd4a..091f6651f19e0d5493558044691494e411d573ab 100644 (file)
@@ -60,8 +60,8 @@ Bridgewater, NJ 08807
 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;
 
@@ -72,7 +72,7 @@ jack_nframes_t size;
 
 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;
 
 //------------------------------------------------------------
 
@@ -127,8 +127,11 @@ send_silence(void) {
   }
 }
 
+//------------------------------------------------------------------------
+
 // sound/silence generation
 // tone turned on/off asynchronously
+
 void
 sound_thread(void) {
   for (;;) {
@@ -140,18 +143,24 @@ sound_thread(void) {
       // 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;
@@ -170,6 +179,7 @@ timed_delay(void) {
 }
 
 // key down? (real or via keyer logic)
+
 BOOLEAN
 read_key(double del) {
   if (iambic)
@@ -178,8 +188,10 @@ read_key(double del) {
     return read_straight_key_serial(ks, fdser);
 }
 
+//------------------------------------------------------------------------
+
 // main keyer loop
-// 
+
 void
 key_thread(void) {
 
@@ -202,6 +214,70 @@ 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";
@@ -250,18 +326,31 @@ main(int argc, char **argv) {
       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);
 
   //------------------------------------------------------------
 
@@ -335,8 +424,10 @@ main(int argc, char **argv) {
 
   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);
 
   //------------------------------------------------------------
 
@@ -361,6 +452,7 @@ main(int argc, char **argv) {
 
   pthread_join(play, 0);
   pthread_join(key, 0);
+  pthread_join(update, 0);
   jack_client_close(client);
 
   //------------------------------------------------------------