autone.c 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. #include <assert.h>
  2. #include <errno.h>
  3. #include <inttypes.h>
  4. #include <limits.h>
  5. #include <signal.h>
  6. #include <stddef.h>
  7. #include <stdint.h>
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <string.h>
  11. #include <unistd.h>
  12. #ifdef USE_CAPSICUM
  13. #include <sys/capsicum.h>
  14. #endif
  15. #include <err.h>
  16. #include <sysexits.h>
  17. #include "au.h"
  18. #include "common.h"
  19. #ifdef SIGINFO
  20. #define IFINFO(x) x
  21. #else
  22. #define IFINFO(x)
  23. #endif
  24. typedef void (au_tone)(struct au *, void *, size_t);
  25. #ifdef SIGINFO
  26. static size_t info_out = 0;
  27. #endif
  28. #ifdef SIGINFO
  29. static void siginfo(int);
  30. #endif
  31. static size_t au_putsample(struct au *, void *, uint32_t);
  32. static au_tone square;
  33. static au_tone sawtooth;
  34. static au_tone triangle;
  35. const struct {
  36. const char *str;
  37. au_tone *func;
  38. } ftab[] = {
  39. { "square", &square },
  40. { "sq", &square },
  41. { "sawtooth", &sawtooth },
  42. { "saw", &sawtooth },
  43. { "triangle", &triangle },
  44. { "tri", &triangle },
  45. { NULL, NULL }
  46. };
  47. int
  48. main(int argc, char *argv[])
  49. {
  50. #ifdef USE_CAPSICUM
  51. cap_rights_t rights;
  52. #endif
  53. struct au au = AU_INITIALIZER;
  54. au_tone *tone = square;
  55. void *b;
  56. char *p;
  57. ssize_t r;
  58. size_t ssize;
  59. size_t bsize;
  60. size_t samples;
  61. size_t n = 0;
  62. size_t i;
  63. double dfreq = 440;
  64. double l = 0;
  65. unsigned long ul;
  66. int raw = 0;
  67. int c;
  68. close(STDIN_FILENO);
  69. #ifdef USE_CAPSICUM
  70. if (cap_enter() == -1 && errno != ENOSYS)
  71. err(EX_OSERR, "Could not enter capibility mode");
  72. cap_rights_init(&rights, CAP_WRITE);
  73. if (cap_rights_limit(STDOUT_FILENO, &rights) == -1 &&
  74. errno != ENOSYS)
  75. err(EX_OSERR, "Could not limit the standard output");
  76. if (cap_rights_limit(STDERR_FILENO, &rights) == -1 &&
  77. errno != ENOSYS)
  78. err(EX_OSERR, "Could not limit the standard error");
  79. #endif
  80. #ifdef USE_PLEDGE
  81. pledge("stdio", NULL);
  82. #endif
  83. au.au_chan = 1;
  84. while ((c = getopt(argc, argv, "Rc:e:f:l:n:r:t:")) != -1)
  85. switch (c) {
  86. case 'R':
  87. raw = 1;
  88. break;
  89. case 'c':
  90. au.au_chan = strtou32(optarg);
  91. break;
  92. case 'e':
  93. if ((au.au_enc = au_strenc(optarg)) == 0)
  94. err(EX_USAGE, "Bad encoding %s",
  95. optarg);
  96. break;
  97. case 'f':
  98. errno = 0;
  99. dfreq = strtod(optarg, &p);
  100. if (dfreq < 0)
  101. errno = ERANGE;
  102. if (errno != 0 || p == optarg || *p != '\0')
  103. err(EX_USAGE, "Invalid frequency %s",
  104. optarg);
  105. break;
  106. case 'l':
  107. errno = 0;
  108. l = strtod(optarg, &p);
  109. if (l < 0)
  110. errno = ERANGE;
  111. if (errno != 0 || p == optarg || *p != '\0')
  112. err(EX_USAGE, "Invalid time %s",
  113. optarg);
  114. n = 0;
  115. break;
  116. case 'n':
  117. errno = 0;
  118. ul = strtoul(optarg, &p, 0);
  119. if (ul > SIZE_MAX)
  120. errno = ERANGE;
  121. if (errno != 0 || p == optarg)
  122. err(EX_USAGE, "Invalid number %s",
  123. optarg);
  124. n = ul;
  125. break;
  126. case 'r':
  127. au.au_rate = strtou32(optarg);
  128. break;
  129. case 't':
  130. for (i = 0; ftab[i].str != NULL; i++)
  131. if (strcasecmp(optarg, ftab[i].str) ==
  132. 0)
  133. break;
  134. if (ftab[i].str == NULL)
  135. errx(EX_USAGE, "Invalid type %s",
  136. optarg);
  137. tone = ftab[i].func;
  138. break;
  139. default:
  140. goto usage;
  141. }
  142. if (optind != argc)
  143. goto usage;
  144. #ifdef SIGINFO
  145. (void)signal(SIGINFO, &siginfo);
  146. #endif
  147. samples = (size_t)((double)au.au_rate / dfreq);
  148. ssize = au_ssize(&au);
  149. bsize = samples * ssize;
  150. if ((b = malloc(bsize)) == NULL)
  151. err(EX_OSERR, "Could not allocate the buffer");
  152. if (n == 0)
  153. n = (size_t)(l * (double)au.au_rate / (double)samples +
  154. 0.5);
  155. if (!raw) {
  156. if (n != 0)
  157. au.au_size = n * bsize > UINT32_MAX ?
  158. UINT32_MAX : n * bsize;
  159. (void)au_puthdr(&au, b);
  160. if (nwrite(STDOUT_FILENO, b, AU_SIZE) != AU_SIZE)
  161. err(EX_IOERR, "Could not write audio header");
  162. }
  163. tone(&au, b, samples);
  164. if (n == 0)
  165. while ((r = write(STDOUT_FILENO, b, bsize)) > 0)
  166. IFINFO(info_out += r / ssize);
  167. else
  168. for (; n > 0; n--) {
  169. if (write(STDOUT_FILENO, b, bsize) != bsize)
  170. err(EX_IOERR, "Write error");
  171. IFINFO(info_out += bsize / ssize);
  172. }
  173. free(b);
  174. return (0);
  175. usage:
  176. (void)fprintf(stderr, "usage: autone [-R] [-c channels] "
  177. "[-e encoding] [-f frequnecy]\n"
  178. " [-l length] [-n cycles] [-r rate] "
  179. "[-t type]\n");
  180. return (EX_USAGE);
  181. }
  182. #ifdef SIGINFO
  183. void
  184. siginfo(int sig)
  185. {
  186. /* autone: XXXXXX samples out */
  187. char b[8 + 6 + 13];
  188. size_t i = 0;
  189. (void)memcpy(b + i, "autone: ", 8);
  190. i += 8;
  191. i += szwrite(b + i, info_out, NULL, NULL);
  192. if (b[i - 1] == 'B')
  193. i -= 2;
  194. (void)memcpy(b + i, " samples out\n", 13);
  195. i += 13;
  196. (void)write(STDERR_FILENO, b, i);
  197. }
  198. #endif
  199. size_t
  200. au_putsample(struct au *au, void *buf, uint32_t v)
  201. {
  202. const uint32_t end = 1;
  203. char tb[sizeof(double)];
  204. uint8_t *b = buf;
  205. double d;
  206. float f;
  207. uint32_t l;
  208. uint32_t i;
  209. assert(au != NULL && buf != NULL);
  210. l = au_vsize(au);
  211. switch (au->au_enc) {
  212. case AU_PCM8:
  213. /* FALLTHROUGH */
  214. case AU_PCM16:
  215. /* FALLTHROUGH */
  216. case AU_PCM24:
  217. /* FALLTHROUGH */
  218. case AU_PCM32:
  219. for (i = 0; i < l; i++)
  220. tb[i] = (v >> (sizeof(v) - i - 1) * 8) & 0xFF;
  221. break;
  222. case AU_FLOAT32:
  223. f = (v >> 31) ? -(float)(~v + 1) / (float)PCM32_MIN :
  224. (float)v / (float)PCM32_MAX;
  225. if (*(char *)&end)
  226. for (i = 0; i < sizeof(d); i++)
  227. tb[i] = ((char *)&f)[sizeof(f) - i - 1];
  228. else
  229. (void)memcpy(tb, &f, sizeof(f));
  230. break;
  231. case AU_FLOAT64:
  232. d = (v >> 31) ? -(double)(~v + 1) / (double)PCM32_MIN :
  233. (double)v / (double)PCM32_MAX;
  234. if (*(char *)&end)
  235. for (i = 0; i < sizeof(d); i++)
  236. tb[i] = ((char *)&d)[sizeof(d) - i - 1];
  237. else
  238. (void)memcpy(tb, &d, sizeof(d));
  239. break;
  240. default:
  241. errx(EX_USAGE, "Unsupported encoding %"PRIu32,
  242. au->au_enc);
  243. }
  244. for (i = 0; i < au->au_chan; i++, b += l)
  245. (void)memcpy(b, tb, l);
  246. return (l * au->au_chan);
  247. }
  248. void
  249. square(struct au *au, void *buf, size_t samples)
  250. {
  251. uint8_t *b = buf;
  252. size_t i;
  253. assert(au != NULL && buf != NULL);
  254. for (i = 0; i < samples / 2; i++)
  255. b += au_putsample(au, b, PCM32_MIN);
  256. for (; i < samples; i++)
  257. b += au_putsample(au, b, PCM32_MAX);
  258. }
  259. void
  260. sawtooth(struct au *au, void *buf, size_t samples)
  261. {
  262. uint8_t *b = buf;
  263. size_t i;
  264. uint32_t t;
  265. uint32_t v;
  266. assert(au != NULL && buf != NULL);
  267. t = UINT32_MAX / samples;
  268. for (i = 0, v = 0; i < samples; i++, v += t)
  269. b += au_putsample(au, b, v);
  270. }
  271. void
  272. triangle(struct au *au, void *buf, size_t samples)
  273. {
  274. uint8_t *b = buf;
  275. size_t a;
  276. size_t i;
  277. uint32_t t;
  278. uint32_t t0;
  279. uint32_t t1;
  280. uint32_t v;
  281. assert(au != NULL && buf != NULL);
  282. a = samples % 4;
  283. t0 = UINT32_MAX / samples * 2;
  284. t1 = UINT32_MAX / (samples + 4) * 2;
  285. t = t0;
  286. for (i = 0, t = a == 0 ? t0 : t1, a -= a != 0, v = 0;
  287. i < samples && v <= PCM32_MAX; i++, v += t)
  288. b += au_putsample(au, b, v);
  289. for (v = PCM32_MAX, t = a == 0 ? t0 : t1, a -= a != 0;
  290. i < samples && (v -= t) <= PCM32_MAX; i++)
  291. b += au_putsample(au, b, v);
  292. for (v = UINT32_MAX, t = a == 0 ? t0 : t1, a -= a != 0;
  293. i < samples && (v -= t) >= PCM32_MIN; i++)
  294. b += au_putsample(au, b, v);
  295. for (v = PCM32_MIN, t = a == 0 ? t0 : t1, a -= a != 0;
  296. i < samples && (v += t) >= PCM32_MIN; i++)
  297. b += au_putsample(au, b, v);
  298. }