From 79da489739d38558172655e11f0cf23d9f1ee121 Mon Sep 17 00:00:00 2001 From: dttsp Date: Thu, 28 Apr 2005 15:21:42 +0000 Subject: [PATCH] Further keyer improvements: update commands for both physical and type-in keyers --- jDttSP/keyb.c | 121 ++++++++++++++++++++++++++++++++++++-------------- jDttSP/keyd.c | 106 ++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 187 insertions(+), 40 deletions(-) diff --git a/jDttSP/keyb.c b/jDttSP/keyb.c index 158b18f..14e128b 100644 --- a/jDttSP/keyb.c +++ b/jDttSP/keyb.c @@ -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); +} diff --git a/jDttSP/keyd.c b/jDttSP/keyd.c index 61d7ac8..091f665 100644 --- a/jDttSP/keyd.c +++ b/jDttSP/keyd.c @@ -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 +// -> set keyer speed to xxx +// -> set gain to xxx (dB) +// -> set freq to 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); //------------------------------------------------------------ -- 2.37.2