From a60ea12ccc15969c23852ccc1f7163ac644cb590 Mon Sep 17 00:00:00 2001 From: Peter Hofmann Date: Sun, 18 Jun 2017 07:26:21 +0200 Subject: [PATCH 1/5] rec: Read events from stdin My user doesn't have access to /dev/input/* by default, so I would need to run "rec" as root -- which, in turn, breaks recording audio, because root does not have access to my PulseAudio process. This commit now allows you to do this: $ sudo cat /dev/input/event123 | ./rec --- rec.c | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/rec.c b/rec.c index 62afec2..ca7acd2 100644 --- a/rec.c +++ b/rec.c @@ -21,39 +21,30 @@ int main(int argc, char **argv) char cmd[256]; char fname[256]; FILE *f; - int fd_ev, fd_snd; + int fd_snd; int samples = 0; int triggered = 0; FILE *fout = NULL; int head = 0; int16_t hist[HISTSIZE]; - - if(argc < 2) { - fprintf(stderr, "usage: %s \n", argv[0]); - exit(1); - } + + fprintf(stderr, "Waiting for evdev data on stdin ...\n"); //f = popen("arecord -D plughw:1,0 -f cd -r 44100 -c 1", "r"); f = popen("parec --rate=44100 --format=s16le --channels=1", "r"); fd_snd = fileno(f); - fd_ev = open(argv[1], O_RDONLY); - if(fd_ev == -1) { - perror("Could not open event input"); - exit(1); - } - fd_set fds; while(1) { FD_ZERO(&fds); - FD_SET(fd_ev, &fds); + FD_SET(STDIN_FILENO, &fds); FD_SET(fd_snd, &fds); select(16, &fds, NULL, NULL, NULL); - if(FD_ISSET(fd_ev, &fds)) { + if(FD_ISSET(STDIN_FILENO, &fds)) { - read(fd_ev, &event, sizeof event); + read(STDIN_FILENO, &event, sizeof event); if(event.type != 1) continue; if(event.value == 2) continue; From e9d140e8072478726d17a25fe178d4f8938a8ecc Mon Sep 17 00:00:00 2001 From: Peter Hofmann Date: Sun, 18 Jun 2017 07:47:36 +0200 Subject: [PATCH 2/5] rec: Can now record multiple samples --- rec.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/rec.c b/rec.c index ca7acd2..ac863a4 100644 --- a/rec.c +++ b/rec.c @@ -15,6 +15,22 @@ struct input_event { #define HISTSIZE 60 +void +samplename(char *buf, size_t buf_len, unsigned short code, unsigned int value) +{ + int i; + + for (i = 0; i < 100; i++) + { + snprintf(buf, buf_len, "wav-new/%02x-%d-%d.wav", code, value, i); + if (access(buf, R_OK) == -1) + return; + } + + fprintf(stderr, "Damn, you recorded too many samples for %02x %d\n", code, value); + exit(EXIT_FAILURE); +} + int main(int argc, char **argv) { struct input_event event; @@ -50,7 +66,7 @@ int main(int argc, char **argv) if(event.value == 2) continue; if(triggered == 0) { - snprintf(fname, sizeof fname, "wav-new/%02x-%d.wav", event.code, event.value); + samplename(fname, sizeof fname, event.code, event.value); snprintf(cmd, sizeof cmd, "sox -qq -r 44100 -e signed -b 16 -c 1 -t raw - %s", fname); printf("%02x %d: ", event.code, event.value); fflush(stdout); From 81509a6b1816a01da2d5f3c2c1310c3c3c9003ca Mon Sep 17 00:00:00 2001 From: Peter Hofmann Date: Sun, 18 Jun 2017 07:49:23 +0200 Subject: [PATCH 3/5] rec: Note on how to run --- rec.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/rec.c b/rec.c index ac863a4..dceccb5 100644 --- a/rec.c +++ b/rec.c @@ -44,6 +44,12 @@ int main(int argc, char **argv) int head = 0; int16_t hist[HISTSIZE]; + /* Run like: + * + * $ (sleep 2; sudo stdbuf -i0 -o0 cat /dev/input/event5) | ./rec + * + * Begin with a sleep, so we don't catch the "Return, released" + * event that started this command. */ fprintf(stderr, "Waiting for evdev data on stdin ...\n"); //f = popen("arecord -D plughw:1,0 -f cd -r 44100 -c 1", "r"); From 3dc2a59068cbab6bf5c78e097e7a1a783808d552 Mon Sep 17 00:00:00 2001 From: Peter Hofmann Date: Sun, 18 Jun 2017 08:08:42 +0200 Subject: [PATCH 4/5] rec: Limit to 10 samples, do auto-normalization, adjust min threshold --- rec.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rec.c b/rec.c index dceccb5..45bf7e5 100644 --- a/rec.c +++ b/rec.c @@ -20,7 +20,7 @@ samplename(char *buf, size_t buf_len, unsigned short code, unsigned int value) { int i; - for (i = 0; i < 100; i++) + for (i = 0; i < 10; i++) { snprintf(buf, buf_len, "wav-new/%02x-%d-%d.wav", code, value, i); if (access(buf, R_OK) == -1) @@ -73,7 +73,7 @@ int main(int argc, char **argv) if(triggered == 0) { samplename(fname, sizeof fname, event.code, event.value); - snprintf(cmd, sizeof cmd, "sox -qq -r 44100 -e signed -b 16 -c 1 -t raw - %s", fname); + snprintf(cmd, sizeof cmd, "sox -qq -r 44100 -e signed -b 16 -c 1 -t raw --norm=-3 - %s", fname); printf("%02x %d: ", event.code, event.value); fflush(stdout); fout = popen(cmd, "w"); @@ -90,7 +90,7 @@ int main(int argc, char **argv) if(triggered) { if(samples == 0) { - if(buf < -2000 || buf > 2000) { + if(buf < -1000 || buf > 1000) { samples = 1; printf(">"); fflush(stdout); From 1a7c15297bf022baa5ff1cca576c736235b7b8cc Mon Sep 17 00:00:00 2001 From: Peter Hofmann Date: Sun, 18 Jun 2017 09:47:20 +0200 Subject: [PATCH 5/5] rec: Record based on time and no auto-normalization Amplitude detection didn't work too well for me. :/ rec now keeps 1/32s of history. As soon as we detect a key, that history will be written to the output file. After that, another 1/2s will be recorded to catch all the "zoingggggg" noises. Auto-normalization was a bad idea to begin with. We must find the global peak value of all samples and then normalize all of them using the same gain. --- rec.c | 79 +++++++++++++++++++++++++++++++++-------------------------- 1 file changed, 44 insertions(+), 35 deletions(-) diff --git a/rec.c b/rec.c index 45bf7e5..fca1593 100644 --- a/rec.c +++ b/rec.c @@ -13,7 +13,14 @@ struct input_event { unsigned int value; }; -#define HISTSIZE 60 +/* We keep recording all the time, creating a history of BUF_HIST bytes. + * Once a key action has been registered, we store our history and + * record another BUF_POST bytes. + * + * Those exact values depend on your machine. We don't do + * auto-detection. */ +#define BUF_HIST (44100 / 32) +#define BUF_POST (44100 / 2) void samplename(char *buf, size_t buf_len, unsigned short code, unsigned int value) @@ -38,11 +45,10 @@ int main(int argc, char **argv) char fname[256]; FILE *f; int fd_snd; - int samples = 0; int triggered = 0; FILE *fout = NULL; - int head = 0; - int16_t hist[HISTSIZE]; + int16_t hist[BUF_HIST], post[BUF_POST]; + size_t hist_at = 0; /* Run like: * @@ -53,7 +59,7 @@ int main(int argc, char **argv) fprintf(stderr, "Waiting for evdev data on stdin ...\n"); //f = popen("arecord -D plughw:1,0 -f cd -r 44100 -c 1", "r"); - f = popen("parec --rate=44100 --format=s16le --channels=1", "r"); + f = popen("parec --rate=44100 --format=s16le --channels=1 --latency=2", "r"); fd_snd = fileno(f); fd_set fds; @@ -73,47 +79,50 @@ int main(int argc, char **argv) if(triggered == 0) { samplename(fname, sizeof fname, event.code, event.value); - snprintf(cmd, sizeof cmd, "sox -qq -r 44100 -e signed -b 16 -c 1 -t raw --norm=-3 - %s", fname); + snprintf(cmd, sizeof cmd, "sox -qq -r 44100 -e signed -b 16 -c 1 -t raw - %s", fname); printf("%02x %d: ", event.code, event.value); fflush(stdout); fout = popen(cmd, "w"); - samples = 0; triggered = 1; printf("%02x %d ", event.code, event.value); fflush(stdout); } } - if(FD_ISSET(fd_snd, &fds)) { - int16_t buf; - read(fd_snd, &buf, sizeof buf); - - if(triggered) { - if(samples == 0) { - if(buf < -1000 || buf > 1000) { - samples = 1; - printf(">"); - fflush(stdout); - } - } - - if(fout && samples) { - fwrite(&hist[head], 1, sizeof hist[head], fout); - if(samples > 44000/3) { - fclose(fout); - snprintf(cmd, sizeof(cmd), "paplay %s &", fname); - system(cmd); - printf(".\n"); - fout = NULL; - triggered = 0; - } - } - - if(samples) samples ++; + if (triggered) + { + size_t history_i = 0; + printf(">"); + fflush(stdout); + + /* Write history. */ + for (history_i = 0; history_i < BUF_HIST; history_i++) + { + hist_at++; + hist_at %= BUF_HIST; + fwrite(&hist[hist_at], sizeof (int16_t), 1, fout); } - hist[head] = buf; - head = (head + 1) % HISTSIZE; + /* Record additional samples. */ + fread(&post, BUF_POST, 1, f); + fwrite(&post, BUF_POST, 1, fout); + + /* Close pipe and play back for examination. */ + fclose(fout); + snprintf(cmd, sizeof(cmd), "paplay %s &", fname); + system(cmd); + printf(".\n"); + fout = NULL; + triggered = 0; + hist_at = 0; + } + + if(FD_ISSET(fd_snd, &fds)) { + /* Audio data ready to read but we haven't registered a key, + * so add those two bytes to our history. */ + read(fd_snd, &hist[hist_at], sizeof (int16_t)); + hist_at++; + hist_at %= BUF_HIST; } }