123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320 |
- #include <assert.h>
- #include <errno.h>
- #include <inttypes.h>
- #include <limits.h>
- #include <signal.h>
- #include <stddef.h>
- #include <stdint.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <unistd.h>
- #ifdef USE_CAPSICUM
- #include <sys/capsicum.h>
- #endif
- #include <err.h>
- #include <sysexits.h>
- #include "au.h"
- #include "common.h"
- #ifdef SIGINFO
- #define IFINFO(x) x
- #else
- #define IFINFO(x)
- #endif
- typedef void (au_tone)(struct au *, void *, size_t);
- #ifdef SIGINFO
- static size_t info_out = 0;
- #endif
- #ifdef SIGINFO
- static void siginfo(int);
- #endif
- static size_t au_putsample(struct au *, void *, uint32_t);
- static au_tone square;
- static au_tone sawtooth;
- static au_tone triangle;
- const struct {
- const char *str;
- au_tone *func;
- } ftab[] = {
- { "square", &square },
- { "sq", &square },
- { "sawtooth", &sawtooth },
- { "saw", &sawtooth },
- { "triangle", &triangle },
- { "tri", &triangle },
- { NULL, NULL }
- };
- int
- main(int argc, char *argv[])
- {
- #ifdef USE_CAPSICUM
- cap_rights_t rights;
- #endif
- struct au au = AU_INITIALIZER;
- au_tone *tone = square;
- void *b;
- char *p;
- ssize_t r;
- size_t ssize;
- size_t bsize;
- size_t samples;
- size_t n = 0;
- size_t i;
- double dfreq = 440;
- double l = 0;
- unsigned long ul;
- int raw = 0;
- int c;
- close(STDIN_FILENO);
- #ifdef USE_CAPSICUM
- if (cap_enter() == -1 && errno != ENOSYS)
- err(EX_OSERR, "Could not enter capibility mode");
- cap_rights_init(&rights, CAP_WRITE);
- if (cap_rights_limit(STDOUT_FILENO, &rights) == -1 &&
- errno != ENOSYS)
- err(EX_OSERR, "Could not limit the standard output");
- if (cap_rights_limit(STDERR_FILENO, &rights) == -1 &&
- errno != ENOSYS)
- err(EX_OSERR, "Could not limit the standard error");
- #endif
- #ifdef USE_PLEDGE
- pledge("stdio", NULL);
- #endif
- au.au_chan = 1;
- while ((c = getopt(argc, argv, "Rc:e:f:l:n:r:t:")) != -1)
- switch (c) {
- case 'R':
- raw = 1;
- break;
- case 'c':
- au.au_chan = strtou32(optarg);
- break;
- case 'e':
- if ((au.au_enc = au_strenc(optarg)) == 0)
- err(EX_USAGE, "Bad encoding %s",
- optarg);
- break;
- case 'f':
- errno = 0;
- dfreq = strtod(optarg, &p);
- if (dfreq < 0)
- errno = ERANGE;
- if (errno != 0 || p == optarg || *p != '\0')
- err(EX_USAGE, "Invalid frequency %s",
- optarg);
- break;
- case 'l':
- errno = 0;
- l = strtod(optarg, &p);
- if (l < 0)
- errno = ERANGE;
- if (errno != 0 || p == optarg || *p != '\0')
- err(EX_USAGE, "Invalid time %s",
- optarg);
- n = 0;
- break;
- case 'n':
- errno = 0;
- ul = strtoul(optarg, &p, 0);
- if (ul > SIZE_MAX)
- errno = ERANGE;
- if (errno != 0 || p == optarg)
- err(EX_USAGE, "Invalid number %s",
- optarg);
- n = ul;
- break;
- case 'r':
- au.au_rate = strtou32(optarg);
- break;
- case 't':
- for (i = 0; ftab[i].str != NULL; i++)
- if (strcasecmp(optarg, ftab[i].str) ==
- 0)
- break;
- if (ftab[i].str == NULL)
- errx(EX_USAGE, "Invalid type %s",
- optarg);
- tone = ftab[i].func;
- break;
- default:
- goto usage;
- }
- if (optind != argc)
- goto usage;
- #ifdef SIGINFO
- (void)signal(SIGINFO, &siginfo);
- #endif
- samples = (size_t)((double)au.au_rate / dfreq);
- ssize = au_ssize(&au);
- bsize = samples * ssize;
- if ((b = malloc(bsize)) == NULL)
- err(EX_OSERR, "Could not allocate the buffer");
- if (n == 0)
- n = (size_t)(l * (double)au.au_rate / (double)samples +
- 0.5);
- if (!raw) {
- if (n != 0)
- au.au_size = n * bsize > UINT32_MAX ?
- UINT32_MAX : n * bsize;
- (void)au_puthdr(&au, b);
- if (nwrite(STDOUT_FILENO, b, AU_SIZE) != AU_SIZE)
- err(EX_IOERR, "Could not write audio header");
- }
- tone(&au, b, samples);
- if (n == 0)
- while ((r = write(STDOUT_FILENO, b, bsize)) > 0)
- IFINFO(info_out += r / ssize);
- else
- for (; n > 0; n--) {
- if (write(STDOUT_FILENO, b, bsize) != bsize)
- err(EX_IOERR, "Write error");
- IFINFO(info_out += bsize / ssize);
- }
- free(b);
- return (0);
- usage:
- (void)fprintf(stderr, "usage: autone [-R] [-c channels] "
- "[-e encoding] [-f frequnecy]\n"
- " [-l length] [-n cycles] [-r rate] "
- "[-t type]\n");
- return (EX_USAGE);
- }
- #ifdef SIGINFO
- void
- siginfo(int sig)
- {
- /* autone: XXXXXX samples out */
- char b[8 + 6 + 13];
- size_t i = 0;
- (void)memcpy(b + i, "autone: ", 8);
- i += 8;
- i += szwrite(b + i, info_out, NULL, NULL);
- if (b[i - 1] == 'B')
- i -= 2;
- (void)memcpy(b + i, " samples out\n", 13);
- i += 13;
- (void)write(STDERR_FILENO, b, i);
- }
- #endif
- size_t
- au_putsample(struct au *au, void *buf, uint32_t v)
- {
- const uint32_t end = 1;
- char tb[sizeof(double)];
- uint8_t *b = buf;
- double d;
- float f;
- uint32_t l;
- uint32_t i;
- assert(au != NULL && buf != NULL);
- l = au_vsize(au);
- switch (au->au_enc) {
- case AU_PCM8:
- /* FALLTHROUGH */
- case AU_PCM16:
- /* FALLTHROUGH */
- case AU_PCM24:
- /* FALLTHROUGH */
- case AU_PCM32:
- for (i = 0; i < l; i++)
- tb[i] = (v >> (sizeof(v) - i - 1) * 8) & 0xFF;
- break;
- case AU_FLOAT32:
- f = (v >> 31) ? -(float)(~v + 1) / (float)PCM32_MIN :
- (float)v / (float)PCM32_MAX;
- if (*(char *)&end)
- for (i = 0; i < sizeof(d); i++)
- tb[i] = ((char *)&f)[sizeof(f) - i - 1];
- else
- (void)memcpy(tb, &f, sizeof(f));
- break;
- case AU_FLOAT64:
- d = (v >> 31) ? -(double)(~v + 1) / (double)PCM32_MIN :
- (double)v / (double)PCM32_MAX;
- if (*(char *)&end)
- for (i = 0; i < sizeof(d); i++)
- tb[i] = ((char *)&d)[sizeof(d) - i - 1];
- else
- (void)memcpy(tb, &d, sizeof(d));
- break;
- default:
- errx(EX_USAGE, "Unsupported encoding %"PRIu32,
- au->au_enc);
- }
- for (i = 0; i < au->au_chan; i++, b += l)
- (void)memcpy(b, tb, l);
- return (l * au->au_chan);
- }
- void
- square(struct au *au, void *buf, size_t samples)
- {
- uint8_t *b = buf;
- size_t i;
- assert(au != NULL && buf != NULL);
- for (i = 0; i < samples / 2; i++)
- b += au_putsample(au, b, PCM32_MIN);
- for (; i < samples; i++)
- b += au_putsample(au, b, PCM32_MAX);
- }
- void
- sawtooth(struct au *au, void *buf, size_t samples)
- {
- uint8_t *b = buf;
- size_t i;
- uint32_t t;
- uint32_t v;
- assert(au != NULL && buf != NULL);
- t = UINT32_MAX / samples;
- for (i = 0, v = 0; i < samples; i++, v += t)
- b += au_putsample(au, b, v);
- }
- void
- triangle(struct au *au, void *buf, size_t samples)
- {
- uint8_t *b = buf;
- size_t a;
- size_t i;
- uint32_t t;
- uint32_t t0;
- uint32_t t1;
- uint32_t v;
- assert(au != NULL && buf != NULL);
- a = samples % 4;
- t0 = UINT32_MAX / samples * 2;
- t1 = UINT32_MAX / (samples + 4) * 2;
- t = t0;
- for (i = 0, t = a == 0 ? t0 : t1, a -= a != 0, v = 0;
- i < samples && v <= PCM32_MAX; i++, v += t)
- b += au_putsample(au, b, v);
- for (v = PCM32_MAX, t = a == 0 ? t0 : t1, a -= a != 0;
- i < samples && (v -= t) <= PCM32_MAX; i++)
- b += au_putsample(au, b, v);
- for (v = UINT32_MAX, t = a == 0 ? t0 : t1, a -= a != 0;
- i < samples && (v -= t) >= PCM32_MIN; i++)
- b += au_putsample(au, b, v);
- for (v = PCM32_MIN, t = a == 0 ? t0 : t1, a -= a != 0;
- i < samples && (v += t) >= PCM32_MIN; i++)
- b += au_putsample(au, b, v);
- }
|