Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/dev/audio Improve audiobell (and interfaces with audio).
details: https://anonhg.NetBSD.org/src/rev/11b55cd2cd00
branches: trunk
changeset: 457454:11b55cd2cd00
user: isaki <isaki%NetBSD.org@localhost>
date: Wed Jun 26 06:57:45 2019 +0000
description:
Improve audiobell (and interfaces with audio).
- Generate pseudo sine wave if possible. It may improve timbre.
If it cannot represent a sine wave, it falls back to a triangular
wave or a rectangular wave.
- Volume adjustment.
- Calculate playback frequency based on mixer frequency.
Now audiobellopen() initializes playback parameters other than
sample_rate, and new audiobellsetrate() sets sample_rate.
diffstat:
sys/dev/audio/audio.c | 78 ++++++++++++-------------
sys/dev/audio/audiobell.c | 138 +++++++++++++++++++++++++++++++--------------
sys/dev/audio/audiodef.h | 24 +++++++-
sys/dev/audio/audiovar.h | 13 +---
4 files changed, 159 insertions(+), 94 deletions(-)
diffs (truncated from 416 to 300 lines):
diff -r b9fc06c3344a -r 11b55cd2cd00 sys/dev/audio/audio.c
--- a/sys/dev/audio/audio.c Wed Jun 26 00:54:04 2019 +0000
+++ b/sys/dev/audio/audio.c Wed Jun 26 06:57:45 2019 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: audio.c,v 1.20 2019/06/25 13:07:48 isaki Exp $ */
+/* $NetBSD: audio.c,v 1.21 2019/06/26 06:57:45 isaki Exp $ */
/*-
* Copyright (c) 2008 The NetBSD Foundation, Inc.
@@ -142,7 +142,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: audio.c,v 1.20 2019/06/25 13:07:48 isaki Exp $");
+__KERNEL_RCSID(0, "$NetBSD: audio.c,v 1.21 2019/06/26 06:57:45 isaki Exp $");
#ifdef _KERNEL_OPT
#include "audio.h"
@@ -458,28 +458,6 @@
#define SPECIFIED(x) ((x) != ~0)
#define SPECIFIED_CH(x) ((x) != (u_char)~0)
-/*
- * AUDIO_SCALEDOWN()
- * This macro should be used for audio wave data only.
- *
- * The arithmetic shift right (ASR) (in other words, floor()) is good for
- * this purpose, and will be faster than division on the most platform.
- * The division (in other words, truncate()) is not so bad alternate for
- * this purpose, and will be fast enough.
- * (Using ASR is 1.9 times faster than division on my amd64, and 1.3 times
- * faster on my m68k. -- isaki 201801.)
- *
- * However, the right shift operator ('>>') for negative integer is
- * "implementation defined" behavior in C (note that it's not "undefined"
- * behavior). So only if implementation defines '>>' as ASR, we use it.
- */
-#if defined(__GNUC__)
-/* gcc defines '>>' as ASR. */
-#define AUDIO_SCALEDOWN(value, bits) ((value) >> (bits))
-#else
-#define AUDIO_SCALEDOWN(value, bits) ((value) / (1 << (bits)))
-#endif
-
/* Device timeout in msec */
#define AUDIO_TIMEOUT (3000)
@@ -539,7 +517,7 @@
static int filt_audioread_event(struct knote *, long);
static int audio_open(dev_t, struct audio_softc *, int, int, struct lwp *,
- struct audiobell_arg *);
+ audio_file_t **);
static int audio_close(struct audio_softc *, audio_file_t *);
static int audio_read(struct audio_softc *, struct uio *, int, audio_file_t *);
static int audio_write(struct audio_softc *, struct uio *, int, audio_file_t *);
@@ -1782,14 +1760,11 @@
/*
* Open for audiobell.
- * sample_rate, encoding, precision and channels in arg are in-parameter
- * and indicates input encoding.
- * Stores allocated file to arg->file.
- * Stores blocksize to arg->blocksize.
+ * It stores allocated file to *filep.
* If successful returns 0, otherwise errno.
*/
int
-audiobellopen(dev_t dev, struct audiobell_arg *arg)
+audiobellopen(dev_t dev, audio_file_t **filep)
{
struct audio_softc *sc;
int error;
@@ -1804,7 +1779,7 @@
return error;
device_active(sc->sc_dev, DVA_SYSTEM);
- error = audio_open(dev, sc, FWRITE, 0, curlwp, arg);
+ error = audio_open(dev, sc, FWRITE, 0, curlwp, filep);
audio_exit_exclusive(sc);
return error;
@@ -1830,6 +1805,28 @@
return error;
}
+/* Set sample rate for audiobell */
+int
+audiobellsetrate(audio_file_t *file, u_int sample_rate)
+{
+ struct audio_softc *sc;
+ struct audio_info ai;
+ int error;
+
+ sc = file->sc;
+
+ AUDIO_INITINFO(&ai);
+ ai.play.sample_rate = sample_rate;
+
+ error = audio_enter_exclusive(sc);
+ if (error)
+ return error;
+ error = audio_file_setinfo(sc, file, &ai);
+ audio_exit_exclusive(sc);
+
+ return error;
+}
+
/* Playback for audiobell */
int
audiobellwrite(audio_file_t *file, struct uio *uio)
@@ -1848,7 +1845,7 @@
*/
int
audio_open(dev_t dev, struct audio_softc *sc, int flags, int ifmt,
- struct lwp *l, struct audiobell_arg *bell)
+ struct lwp *l, audio_file_t **bellfile)
{
struct audio_info ai;
struct file *fp;
@@ -1912,11 +1909,12 @@
/* Set parameters */
AUDIO_INITINFO(&ai);
- if (bell) {
- ai.play.sample_rate = bell->sample_rate;
- ai.play.encoding = bell->encoding;
- ai.play.channels = bell->channels;
- ai.play.precision = bell->precision;
+ if (bellfile) {
+ /* If audiobell, only sample_rate will be set later. */
+ ai.play.sample_rate = audio_default.sample_rate;
+ ai.play.encoding = AUDIO_ENCODING_SLINEAR_NE;
+ ai.play.channels = 1;
+ ai.play.precision = 16;
ai.play.pause = false;
} else if (ISDEVAUDIO(dev)) {
/* If /dev/audio, initialize everytime. */
@@ -2041,7 +2039,7 @@
}
}
- if (bell == NULL) {
+ if (bellfile == NULL) {
error = fd_allocfile(&fp, &fd);
if (error)
goto bad3;
@@ -2059,8 +2057,8 @@
SLIST_INSERT_HEAD(&sc->sc_files, af, entry);
mutex_exit(sc->sc_intr_lock);
- if (bell) {
- bell->file = af;
+ if (bellfile) {
+ *bellfile = af;
} else {
error = fd_clone(fp, fd, flags, &audio_fileops, af);
KASSERT(error == EMOVEFD);
diff -r b9fc06c3344a -r 11b55cd2cd00 sys/dev/audio/audiobell.c
--- a/sys/dev/audio/audiobell.c Wed Jun 26 00:54:04 2019 +0000
+++ b/sys/dev/audio/audiobell.c Wed Jun 26 06:57:45 2019 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: audiobell.c,v 1.2 2019/05/08 13:40:17 isaki Exp $ */
+/* $NetBSD: audiobell.c,v 1.3 2019/06/26 06:57:45 isaki Exp $ */
/*
* Copyright (c) 1999 Richard Earnshaw
@@ -31,7 +31,7 @@
*/
#include <sys/types.h>
-__KERNEL_RCSID(0, "$NetBSD: audiobell.c,v 1.2 2019/05/08 13:40:17 isaki Exp $");
+__KERNEL_RCSID(0, "$NetBSD: audiobell.c,v 1.3 2019/06/26 06:57:45 isaki Exp $");
#include <sys/audioio.h>
#include <sys/conf.h>
@@ -45,8 +45,40 @@
#include <dev/audio/audiodef.h>
#include <dev/audio/audiobellvar.h>
-/* 44.1 kHz should reduce hum at higher pitches. */
-#define BELL_SAMPLE_RATE 44100
+/*
+ * The hexadecagon is sufficiently close to a sine wave.
+ * Audiobell always outputs this 16 points data but changes its playback
+ * frequency. In addition, audio layer does linear interpolation in the
+ * frequency conversion stage, so the waveform becomes smooth.
+ * When the playback frequency rises (or the device frequency is not enough
+ * high) and one wave cannot be expressed with 16 points, the data is thinned
+ * out by power of two, like 8 points -> 4 points (triangular wave)
+ * -> 2 points (rectangular wave).
+ */
+
+/* Amplitude. Full scale amplitude is too loud. */
+#define A(x) ((x) * 0.6)
+
+/* (sin(2*pi * (x/16)) * 32767 / 100) << 16 */
+static const int32_t sinewave[] = {
+ A( 0),
+ A( 8217813),
+ A( 15184539),
+ A( 19839556),
+ A( 21474181),
+ A( 19839556),
+ A( 15184539),
+ A( 8217813),
+ A( 0),
+ A( -8217814),
+ A(-15184540),
+ A(-19839557),
+ A(-21474182),
+ A(-19839557),
+ A(-15184540),
+ A( -8217814),
+};
+#undef A
/*
* dev is a device_t for the audio device to use.
@@ -60,18 +92,22 @@
{
dev_t audio;
int16_t *buf;
- struct audiobell_arg bellarg;
audio_file_t *file;
audio_track_t *ptrack;
struct uio auio;
struct iovec aiov;
- int i;
- int remaincount;
- int remainlen;
- int wave1count;
- int wave1len;
- int len;
- int16_t vol;
+ u_int i;
+ u_int j;
+ u_int remaincount;
+ u_int remainbytes;
+ u_int wave1count;
+ u_int wave1bytes;
+ u_int blkbytes;
+ u_int len;
+ u_int step;
+ u_int offset;
+ u_int play_sample_rate;
+ u_int mixer_sample_rate;
KASSERT(volume <= 100);
@@ -79,53 +115,69 @@
if (poll)
return;
- /* Limit the pitch from 20Hz to Nyquist frequency. */
- if (pitch > BELL_SAMPLE_RATE / 2)
- pitch = BELL_SAMPLE_RATE;
- if (pitch < 20)
- pitch = 20;
-
buf = NULL;
audio = AUDIO_DEVICE | device_unit((device_t)dev);
- memset(&bellarg, 0, sizeof(bellarg));
- bellarg.encoding = AUDIO_ENCODING_SLINEAR_NE;
- bellarg.precision = 16;
- bellarg.channels = 1;
- bellarg.sample_rate = BELL_SAMPLE_RATE;
-
/* If not configured, we can't beep. */
- if (audiobellopen(audio, &bellarg) != 0)
+ if (audiobellopen(audio, &file) != 0)
return;
- file = bellarg.file;
ptrack = file->ptrack;
+ mixer_sample_rate = ptrack->mixer->track_fmt.sample_rate;
+
+ /* Limit pitch */
+ if (pitch < 20)
+ pitch = 20;
- /* msec to sample count. */
- remaincount = period * BELL_SAMPLE_RATE / 1000;
- remainlen = remaincount * sizeof(int16_t);
+ offset = 0;
+ if (pitch <= mixer_sample_rate / 16) {
+ /* 16-point sine wave */
+ step = 1;
+ } else if (pitch <= mixer_sample_rate / 8) {
+ /* 8-point sine wave */
+ step = 2;
+ } else if (pitch <= mixer_sample_rate / 4) {
+ /* 4-point sine wave, aka, triangular wave */
+ step = 4;
+ } else {
+ /* Rectangular wave */
+ if (pitch > mixer_sample_rate / 2)
+ pitch = mixer_sample_rate / 2;
+ step = 8;
Home |
Main Index |
Thread Index |
Old Index