aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorReiner Herrmann <reiner@reiner-h.de>2017-04-04 20:11:42 +0200
committerReiner Herrmann <reiner@reiner-h.de>2017-04-04 20:11:42 +0200
commit18ee0090216f2c79c5d19d9f17d86b416447a60d (patch)
tree3a73c3dd1ad3ef120ea5692a1f4793c8c7c02fa3
parentd32ba584db65e1611162de1b7d1e019f049fac86 (diff)
Non-blocking input handling
-rw-r--r--metronome.c84
1 files changed, 84 insertions, 0 deletions
diff --git a/metronome.c b/metronome.c
index 14293ac..7515452 100644
--- a/metronome.c
+++ b/metronome.c
@@ -1,11 +1,15 @@
#include <stdio.h>
#include <stdint.h>
+#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <errno.h>
#include <getopt.h>
#include <time.h>
#include <sys/time.h>
+#include <sys/select.h>
+#include <termios.h>
+#include <unistd.h>
#include <alsa/asoundlib.h>
#define SAMPLE_RATE 8000
@@ -65,6 +69,70 @@ static int set_alsa_params(snd_pcm_t *pcm_handle)
return 0;
}
+static int toggle_nonblocking_input()
+{
+ static struct termios *saved_termios = NULL;
+ int ret = 0;
+
+ if (saved_termios) {
+ /* restore old settings */
+ if ((ret = tcsetattr(STDIN_FILENO, TCSANOW, saved_termios)) < 0) {
+ printf("Failed restoring termios settings: %s\n", strerror(errno));
+ }
+ free(saved_termios);
+ saved_termios = NULL;
+ } else {
+ struct termios new_termios;
+
+ /* get and backup current settings */
+ saved_termios = malloc(sizeof(struct termios));
+ if (tcgetattr(STDIN_FILENO, saved_termios) < 0) {
+ printf("Failed retrieving current termios setings: %s\n", strerror(errno));
+ free(saved_termios);
+ saved_termios = NULL;
+ return -1;
+ }
+ memcpy(&new_termios, saved_termios, sizeof(struct termios));
+
+ /* disable echo and canonical mode (line by line input; line editing) */
+ new_termios.c_lflag &= ~(ICANON | ECHO);
+
+ if ((ret = tcsetattr(STDIN_FILENO, TCSANOW, &new_termios)) < 0) {
+ printf("Failed setting to changed termios: %s\n", strerror(errno));
+ }
+ }
+
+ return ret;
+}
+
+static int input_available()
+{
+ struct timeval timeout = {0, 0};
+ int count;
+ fd_set inputs;
+
+ FD_ZERO(&inputs);
+ FD_SET(STDIN_FILENO, &inputs);
+
+ count = select(STDIN_FILENO+1, &inputs, NULL, NULL, &timeout);
+ if (count == -1) {
+ printf("Failed checking stdin status: %s\n", strerror(errno));
+ return 0;
+ }
+
+ return count == 1 && FD_ISSET(STDIN_FILENO, &inputs);
+}
+
+static int handle_keypress(char c)
+{
+ switch(c) {
+ case 'q':
+ return -1;
+ }
+
+ return 0;
+}
+
static void prepare_tones()
{
int i, amplitude = 20;
@@ -131,6 +199,14 @@ static int play(snd_pcm_t *pcm_handle, const char *pattern, int bpm)
play_tone(pcm_handle, 's');
while(1) {
+ if (input_available()) {
+ char c;
+ read(STDIN_FILENO, &c, 1);
+ if (handle_keypress(c) < 0) {
+ return 0;
+ }
+ }
+
if (clock_gettime(CLOCK_MONOTONIC, &cur_t) == -1) {
printf("Failed getting time: %s\n", strerror(errno));
return -1;
@@ -191,6 +267,10 @@ int main(int argc, char *argv[])
return 1;
}
+ if (toggle_nonblocking_input() < 0) {
+ return 1;
+ }
+
if (snd_pcm_open(&pcm_handle, "default", SND_PCM_STREAM_PLAYBACK, 0) < 0) {
printf("Failed opening device\n");
return 1;
@@ -205,5 +285,9 @@ int main(int argc, char *argv[])
snd_pcm_close(pcm_handle);
+ if (toggle_nonblocking_input() < 0) {
+ return 1;
+ }
+
return 0;
}