Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F137785737
D35772.id113387.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
9 KB
Referenced Files
None
Subscribers
None
D35772.id113387.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D35772: beep(1): Add support for rendering text and numbers as audio.
Attached
Detach File
Event Timeline
Log In to Comment