#include <sys/ioctl.h>
#include <sys/types.h>
#include <linux/kd.h>
+#include <linux/input.h>
/* I don't know where this number comes from, I admit that freely. A
wonderful human named Raine M. Ekman used it in a program that played
#define CLOCK_TICK_RATE 1193180
#endif
-#define VERSION_STRING "beep-1.2.2"
+#define VERSION_STRING "beep-1.3"
char *copyright =
"Copyright (C) Johnathan Nightingale, 2002. "
"Use and Distribution subject to GPL. "
so that beep can be tucked appropriately into a text-
processing pipe.
*/
+ int verbose; /* verbose output? */
struct beep_parms_t *next; /* in case -n/--new is used. */
} beep_parms_t;
+enum { BEEP_TYPE_CONSOLE, BEEP_TYPE_EVDEV };
+
/* Momma taught me never to use globals, but we need something the signal
handlers can get at.*/
int console_fd = -1;
+int console_type = BEEP_TYPE_CONSOLE;
+char *console_device = NULL;
+
+
+void do_beep(int freq) {
+ if (console_type == BEEP_TYPE_CONSOLE) {
+ if(ioctl(console_fd, KIOCSOUND, freq != 0
+ ? (int)(CLOCK_TICK_RATE/freq)
+ : freq) < 0) {
+ printf("\a"); /* Output the only beep we can, in an effort to fall back on usefulness */
+ perror("ioctl");
+ }
+ } else {
+ /* BEEP_TYPE_EVDEV */
+ struct input_event e;
+
+ e.type = EV_SND;
+ e.code = SND_TONE;
+ e.value = freq;
+
+ write(console_fd, &e, sizeof(struct input_event));
+ }
+}
+
/* If we get interrupted, it would be nice to not leave the speaker beeping in
perpetuity. */
void handle_signal(int signum) {
+
+ if(console_device)
+ free(console_device);
+
switch(signum) {
case SIGINT:
if(console_fd >= 0) {
/* Kill the sound, quit gracefully */
- ioctl(console_fd, KIOCSOUND, 0);
+ do_beep(0);
close(console_fd);
exit(signum);
} else {
/* print usage and exit */
void usage_bail(const char *executable_name) {
printf("Usage:\n%s [-f freq] [-l length] [-r reps] [-d delay] "
- "[-D delay] [-s] [-c]\n",
+ "[-D delay] [-s] [-c] [--verbose | --debug] [-e device]\n",
executable_name);
printf("%s [Options...] [-n] [--new] [Options...] ... \n", executable_name);
printf("%s [-h] [--help]\n", executable_name);
* "-D <delay in ms>" (similar to -d, but delay after last repetition as well)
* "-s" (beep after each line of input from stdin, echo line to stdout)
* "-c" (beep after each char of input from stdin, echo char to stdout)
+ * "--verbose/--debug"
* "-h/--help"
* "-v/-V/--version"
* "-n/--new"
void parse_command_line(int argc, char **argv, beep_parms_t *result) {
int c;
- struct option opt_list[4] = {{"help", 0, NULL, 'h'},
+ struct option opt_list[7] = {{"help", 0, NULL, 'h'},
{"version", 0, NULL, 'V'},
{"new", 0, NULL, 'n'},
+ {"verbose", 0, NULL, 'X'},
+ {"debug", 0, NULL, 'X'},
+ {"device", 1, NULL, 'e'},
{0,0,0,0}};
- while((c = getopt_long(argc, argv, "f:l:r:d:D:schvVn", opt_list, NULL))
+ while((c = getopt_long(argc, argv, "f:l:r:d:D:schvVne:", opt_list, NULL))
!= EOF) {
int argval = -1; /* handle parsed numbers for various arguments */
float argfreq = -1;
(argfreq <= 0))
usage_bail(argv[0]);
else
+ if (result->freq != 0)
+ fprintf(stderr, "WARNING: multiple -f values given, only last "
+ "one is used.\n");
result->freq = argfreq;
break;
case 'l' : /* length */
exit(0);
break;
case 'n' : /* also --new - create another beep */
+ if (result->freq == 0)
+ result->freq = DEFAULT_FREQ;
result->next = (beep_parms_t *)malloc(sizeof(beep_parms_t));
- result->next->freq = DEFAULT_FREQ;
+ result->next->freq = 0;
result->next->length = DEFAULT_LENGTH;
result->next->reps = DEFAULT_REPS;
result->next->delay = DEFAULT_DELAY;
result->next->end_delay = DEFAULT_END_DELAY;
result->next->stdin_beep = DEFAULT_STDIN_BEEP;
+ result->next->verbose = result->verbose;
result->next->next = NULL;
result = result->next; /* yes, I meant to do that. */
break;
+ case 'X' : /* --debug / --verbose */
+ result->verbose = 1;
+ break;
+ case 'e' : /* also --device */
+ console_device = strdup(optarg);
+ break;
case 'h' : /* notice that this is also --help */
default :
usage_bail(argv[0]);
}
}
+ if (result->freq == 0)
+ result->freq = DEFAULT_FREQ;
}
void play_beep(beep_parms_t parms) {
int i; /* loop counter */
+ if(parms.verbose == 1)
+ fprintf(stderr, "[DEBUG] %d times %d ms beeps (%d delay between, "
+ "%d delay after) @ %.2f Hz\n",
+ parms.reps, parms.length, parms.delay, parms.end_delay, parms.freq);
+
/* try to snag the console */
- if((console_fd = open("/dev/console", O_WRONLY)) == -1) {
- fprintf(stderr, "Could not open /dev/console for writing.\n");
+ if(console_device)
+ console_fd = open(console_device, O_WRONLY);
+ else
+ if((console_fd = open("/dev/tty0", O_WRONLY)) == -1)
+ console_fd = open("/dev/vc/0", O_WRONLY);
+
+ if(console_fd == -1) {
+ fprintf(stderr, "Could not open %s for writing\n",
+ console_device != NULL ? console_device : "/dev/tty0 or /dev/vc/0");
printf("\a"); /* Output the only beep we can, in an effort to fall back on usefulness */
perror("open");
exit(1);
}
+
+ if (ioctl(console_fd, EVIOCGSND(0)) != -1)
+ console_type = BEEP_TYPE_EVDEV;
+ else
+ console_type = BEEP_TYPE_CONSOLE;
/* Beep */
for (i = 0; i < parms.reps; i++) { /* start beep */
- if(ioctl(console_fd, KIOCSOUND, (int)(CLOCK_TICK_RATE/parms.freq)) < 0) {
- printf("\a"); /* Output the only beep we can, in an effort to fall back on usefulness */
- perror("ioctl");
- }
+ do_beep(parms.freq);
/* Look ma, I'm not ansi C compatible! */
usleep(1000*parms.length); /* wait... */
- ioctl(console_fd, KIOCSOUND, 0); /* stop beep */
+ do_beep(0); /* stop beep */
if(parms.end_delay || (i+1 < parms.reps))
usleep(1000*parms.delay); /* wait... */
} /* repeat. */
char sin[4096], *ptr;
beep_parms_t *parms = (beep_parms_t *)malloc(sizeof(beep_parms_t));
- parms->freq = DEFAULT_FREQ;
+ parms->freq = 0;
parms->length = DEFAULT_LENGTH;
parms->reps = DEFAULT_REPS;
parms->delay = DEFAULT_DELAY;
parms->end_delay = DEFAULT_END_DELAY;
parms->stdin_beep = DEFAULT_STDIN_BEEP;
+ parms->verbose = 0;
parms->next = NULL;
signal(SIGINT, handle_signal);
parms = next;
}
+ if(console_device)
+ free(console_device);
+
return EXIT_SUCCESS;
}