Page MenuHomeFreeBSD

D35772.id113387.diff
No OneTemporary

D35772.id113387.diff

diff --git a/usr.bin/beep/beep.1 b/usr.bin/beep/beep.1
--- a/usr.bin/beep/beep.1
+++ b/usr.bin/beep/beep.1
@@ -1,5 +1,5 @@
.\"-
-.\" Copyright (c) 2021 Hans Petter Selasky <hselasky@FreeBSD.org>
+.\" Copyright (c) 2021-2022 Hans Petter Selasky <hselasky@FreeBSD.org>
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
@@ -23,7 +23,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd November 4, 2021
+.Dd July 18, 2022
.Dt beep 1
.Os
.Sh NAME
@@ -36,6 +36,8 @@
.Op Fl r Ar sample_rate_hz
.Op Fl d Ar oss_device
.Op Fl g Ar gain
+.Op Fl t Ar UTF-8-text
+.Op Fl n Ar number
.Op Fl B
.Op Fl h
.Sh DESCRIPTION
@@ -60,6 +62,15 @@
.It Fl g
Sets the waveform gain, between 0 and 100 inclusively.
The default is 75.
+.It Fl t
+Render the given UTF-8 text starting at the least significant bit, similarly to Braille.
+Each full character is output separately.
+Up to 22 bits may be output by a single character.
+A small pause separates each character.
+This option can also be combined with other options, like duration and frequency.
+.It Fl n
+Render the given number as binary, starting at the least significant digit.
+This option can also be combined with other options, like duration and frequency.
.It Fl B
Runs the
.Nm
@@ -67,12 +78,27 @@
.It Fl h
Display summary of options.
.El
+.Sh AUDIO RENDERING
+There are two audio symbols.
+Binary zero is encoded like a major chord.
+Binary one is encoded like a diminished chord.
+Refer to western or 12-tone scale music theory for more information.
.Sh EXAMPLES
.Pp
Playback default beep sound using /dev/dsp .
.Bl -tag -width Ds -offset indent
.It $ beep
.El
+.Pp
+Render the value of zero:
+.Bl -tag -width Ds -offset indent
+.It $ beep -n 0
+.El
+.Pp
+Slowly output the alphabeth
+.Bl -tag -width Ds -offset indent
+.It $ beep -t abcdefghijklmnopqrstuvwxyz -D 1000
+.El
.Sh SEE ALSO
.Xr mixer 3 ,
.Xr sound 4 ,
diff --git a/usr.bin/beep/beep.c b/usr.bin/beep/beep.c
--- a/usr.bin/beep/beep.c
+++ b/usr.bin/beep/beep.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2021 Hans Petter Selasky <hselasky@freebsd.org>
+ * Copyright (c) 2021-2022 Hans Petter Selasky <hselasky@freebsd.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -36,6 +36,7 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <assert.h>
#define SAMPLE_RATE_DEF 48000 /* hz */
#define SAMPLE_RATE_MAX 48000 /* hz */
@@ -55,12 +56,24 @@
#define DEFAULT_DEVICE _PATH_DEV "dsp"
+#define MUSIC_CHARS 2ULL
+
static int frequency = DEFAULT_HZ;
static int duration_ms = DURATION_DEF;
static int sample_rate = SAMPLE_RATE_DEF;
static int gain = GAIN_DEF;
static const char *oss_dev = DEFAULT_DEVICE;
static bool background;
+static const uint8_t *text;
+static const uint8_t *number_ptr;
+static uint64_t number_parsed;
+static struct {
+ uint8_t a, b, c; /* frequency exponent in 12ths */
+ int32_t *audio; /* rendered audio */
+} music_char[MUSIC_CHARS] = {
+ { 0, 4, 7, NULL }, /* Major */
+ { 0, 3, 6, NULL }, /* Diminished */
+};
/*
* wave_function_16
@@ -129,6 +142,131 @@
return (retval);
}
+static void
+render_beep(int32_t *buffer, size_t size, float freq, float amp)
+{
+ size_t slope;
+ size_t off; /* buffer offset */
+ float p; /* phase */
+ float d; /* delta phase */
+
+ /* compute slope duration in samples */
+ slope = (DURATION_MIN * sample_rate) / 2000;
+
+ /* set initial phase and delta */
+ p = 0;
+ d = freq / (float)sample_rate;
+
+ /* compute wave */
+ for (p = off = 0; off != size; off++, p += d) {
+ float sample;
+
+ p = p - floorf(p);
+ sample = amp * wave_function_16(p, WAVE_POWER);
+
+ if (off < slope)
+ sample = sample * off / (float)slope;
+ else if (off > (size - slope))
+ sample = sample * (size - off - 1) / (float)slope;
+
+ buffer[off] += sample * 0x7fffff00;
+ }
+}
+
+static void
+render_music_char(uint8_t n, int32_t *buffer, float freq, float amp, size_t size)
+{
+ assert(n < MUSIC_CHARS);
+
+ if (music_char[n].audio == NULL) {
+ music_char[n].audio = calloc(sizeof(music_char[0].audio[0]) * size, 1);
+ if (music_char[n].audio == NULL)
+ errx(1, "out of memory");
+ render_beep(music_char[n].audio, size,
+ freq * powf(2.0f, music_char[n].a / 12.0f), amp / 3.0f);
+ render_beep(music_char[n].audio, size,
+ freq * powf(2.0f, music_char[n].b / 12.0f), amp / 3.0f);
+ render_beep(music_char[n].audio, size,
+ freq * powf(2.0f, music_char[n].c / 12.0f), amp / 3.0f);
+ }
+ memcpy(buffer, music_char[n].audio, size * sizeof(buffer[0]));
+}
+
+static uint32_t
+get_unicode_char(const uint8_t **pptr)
+{
+ const uint8_t *p8;
+ uint32_t ch;
+
+ p8 = *pptr;
+
+ if ((*p8 & 0xc0) == 0xc0) {
+ p8++;
+ while ((*p8 & 0xc0) == 0x80)
+ p8++;
+ switch (p8 - *pptr) {
+ case 1: /* 12-bit */
+ ch = (*pptr)[0] & 0x3f;
+ ch <<= 6;
+ ch |= (*pptr)[1] & 0x3f;
+
+ *pptr = p8;
+ goto done;
+ case 2: /* 17-bit */
+ ch = (*pptr)[0] & 0x1f;
+ ch <<= 6;
+ ch |= (*pptr)[1] & 0x3f;
+ ch <<= 6;
+ ch |= (*pptr)[2] & 0x3f;
+
+ *pptr = p8;
+ goto done;
+ case 3: /* 22-bit */
+ ch = (*pptr)[0] & 0x0f;
+ ch <<= 6;
+ ch |= (*pptr)[1] & 0x3f;
+ ch <<= 6;
+ ch |= (*pptr)[2] & 0x3f;
+ ch <<= 6;
+ ch |= (*pptr)[3] & 0x3f;
+
+ *pptr = p8;
+ goto done;
+ default:
+ break;
+ }
+ }
+ /* not UTF-8 */
+ ch = **pptr;
+ (*pptr) ++;
+done:
+ return (ch);
+}
+
+static size_t
+number_length_in_units(uint64_t number)
+{
+ size_t units = 0;
+
+ do {
+ units++;
+ } while ((number /= MUSIC_CHARS) != 0);
+
+ return (units);
+}
+
+static size_t
+text_length_in_units(const uint8_t *ptr)
+{
+ size_t units = 0;
+
+ while (*ptr) {
+ units += number_length_in_units(get_unicode_char(&ptr));
+ units += 1;
+ }
+ return (units);
+}
+
static void
usage(void)
{
@@ -138,6 +276,8 @@
"\t" "-r <sample rate in HZ, from %d Hz to %d Hz, default %d Hz>\n"
"\t" "-d <OSS device (default %s)>\n"
"\t" "-g <gain from %d to %d, default %d>\n"
+ "\t" "-t <render given UTF-8 based text>\n"
+ "\t" "-n <render given number>\n"
"\t" "-B Run in background\n"
"\t" "-h Show usage\n",
getprogname(),
@@ -153,16 +293,14 @@
main(int argc, char **argv)
{
int32_t *buffer;
- size_t slope;
size_t size;
+ size_t units;
size_t off;
float a;
- float d;
- float p;
int c;
int f;
- while ((c = getopt(argc, argv, "BF:D:r:g:d:h")) != -1) {
+ while ((c = getopt(argc, argv, "BF:D:r:n:t:g:d:h")) != -1) {
switch (c) {
case 'F':
frequency = strtol(optarg, NULL, 10);
@@ -191,12 +329,21 @@
case 'B':
background = true;
break;
+ case 'n':
+ number_ptr = optarg;
+ break;
+ case 't':
+ text = optarg;
+ break;
default:
usage();
break;
}
}
+ if (text != NULL && number_ptr != NULL)
+ errx(1, "-t and -s options are mutually exclusive");
+
if (background && daemon(0, 0) != 0)
errx(1, "daemon(0,0) failed");
@@ -224,38 +371,63 @@
if (ioctl(f, SNDCTL_DSP_GETODELAY, &c) != 0)
errx(1, "ioctl SNDCTL_DSP_GETODELAY failed");
+ if (number_ptr != NULL) {
+ char *end;
+ number_parsed = strtoull(number_ptr, &end, 0);
+ if (*end != 0)
+ errx(1, "invalid number '%s'", number_ptr);
+ units = number_length_in_units(number_parsed);
+ } else if (text != NULL) {
+ units = text_length_in_units(text);
+ } else {
+ units = 1;
+ }
+
size = ((sample_rate * duration_ms) + 999) / 1000;
- buffer = malloc(sizeof(buffer[0]) * size);
+ buffer = calloc(sizeof(buffer[0]) * size, units);
if (buffer == NULL)
errx(1, "out of memory");
- /* compute slope duration in samples */
- slope = (DURATION_MIN * sample_rate) / 2000;
-
/* compute base gain */
a = powf(65536.0f, (float)gain / (float)GAIN_MAX) / 65536.0f;
- /* set initial phase and delta */
- p = 0;
- d = (float)frequency / (float)sample_rate;
+ if (number_ptr != NULL) {
+ off = 0;
- /* compute wave */
- for (p = off = 0; off != size; off++, p += d) {
- float sample;
+ do {
+ render_music_char(number_parsed % MUSIC_CHARS,
+ buffer + off, frequency, a, size);
+ off += size;
+ } while ((number_parsed /= MUSIC_CHARS) != 0);
+ } else if (text != NULL) {
+ off = 0;
- p = p - floorf(p);
- sample = a * wave_function_16(p, WAVE_POWER);
+ while (*text != 0) {
+ uint32_t ch;
- if (off < slope)
- sample = sample * off / (float)slope;
- else if (off > (size - slope))
- sample = sample * (size - off - 1) / (float)slope;
+ ch = get_unicode_char(&text);
- buffer[off] = sample * 0x7fffff00;
+ do {
+ render_music_char(ch % MUSIC_CHARS,
+ buffer + off, frequency, a, size);
+ off += size;
+ } while ((ch /= MUSIC_CHARS) != 0);
+
+ off += size;
+ }
+ } else {
+ render_beep(buffer, size, frequency, a);
+ off = size;
}
- if (write(f, buffer, size * sizeof(buffer[0])) !=
- (ssize_t)(size * sizeof(buffer[0])))
+ /* check whole buffer was filled */
+ assert(off == (size * units));
+
+ for (unsigned i = 0; i != MUSIC_CHARS; i++)
+ free(music_char[i].audio);
+
+ if (write(f, buffer, size * units * sizeof(buffer[0])) !=
+ (ssize_t)(size * units * sizeof(buffer[0])))
errx(1, "failed writing to DSP device(%s)", oss_dev);
free(buffer);

File Metadata

Mime Type
text/plain
Expires
Wed, Nov 26, 8:26 PM (20 h, 37 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
26223294
Default Alt Text
D35772.id113387.diff (9 KB)

Event Timeline