Rework about the rest note in speaker(4).

- Obsolete the sc_rest callback.  The rest note operation can be done by
  the common spkr layer.  This also fixes PR kern/56060.
  This work-in-progress patch was left in my local tree for years. :(
- Improve calculations of tone and rest length.
This commit is contained in:
isaki 2021-04-03 04:10:30 +00:00
parent 74bd6922f5
commit 398f413a6e
4 changed files with 100 additions and 78 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: spkr_pcppi.c,v 1.12 2021/04/03 03:21:53 isaki Exp $ */
/* $NetBSD: spkr_pcppi.c,v 1.13 2021/04/03 04:10:30 isaki Exp $ */
/*
* Copyright (c) 1990 Eric S. Raymond (esr@snark.thyrsus.com)
@ -43,7 +43,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: spkr_pcppi.c,v 1.12 2021/04/03 03:21:53 isaki Exp $");
__KERNEL_RCSID(0, "$NetBSD: spkr_pcppi.c,v 1.13 2021/04/03 04:10:30 isaki Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -79,8 +79,6 @@ CFATTACH_DECL3_NEW(spkr_pcppi, sizeof(struct spkr_pcppi_softc),
spkr_pcppi_probe, spkr_pcppi_attach, spkr_pcppi_detach, NULL,
spkr_pcppi_rescan, spkr_pcppi_childdet, 0);
#define SPKRPRI (PZERO - 1)
/* emit tone of frequency hz for given number of ticks */
static void
spkr_pcppi_tone(device_t self, u_int xhz, u_int ticks)
@ -92,22 +90,6 @@ spkr_pcppi_tone(device_t self, u_int xhz, u_int ticks)
(*sc->sc_bell_func)(sc->sc_pcppicookie, xhz, ticks, PCPPI_BELL_SLEEP);
}
/* rest for given number of ticks */
static void
spkr_pcppi_rest(device_t self, int ticks)
{
/*
* Set timeout to endrest function, then give up the timeslice.
* This is so other processes can execute while the rest is being
* waited out.
*/
#ifdef SPKRDEBUG
aprint_debug_dev(self, "%s: %d\n", __func__, ticks);
#endif /* SPKRDEBUG */
if (ticks > 0)
tsleep(self, SPKRPRI | PCATCH, device_xname(self), ticks);
}
static int
spkr_pcppi_probe(device_t parent, cfdata_t cf, void *aux)
{
@ -125,7 +107,7 @@ spkr_pcppi_attach(device_t parent, device_t self, void *aux)
sc->sc_pcppicookie = pa->pa_cookie;
sc->sc_bell_func = pa->pa_bell_func;
spkr_attach(self, spkr_pcppi_tone, spkr_pcppi_rest);
spkr_attach(self, spkr_pcppi_tone);
if (!pmf_device_register(self, NULL, NULL))
aprint_error_dev(self, "couldn't establish power handler\n");
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: spkr.c,v 1.18 2021/04/03 03:21:53 isaki Exp $ */
/* $NetBSD: spkr.c,v 1.19 2021/04/03 04:10:30 isaki Exp $ */
/*
* Copyright (c) 1990 Eric S. Raymond (esr@snark.thyrsus.com)
@ -43,7 +43,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: spkr.c,v 1.18 2021/04/03 03:21:53 isaki Exp $");
__KERNEL_RCSID(0, "$NetBSD: spkr.c,v 1.19 2021/04/03 04:10:30 isaki Exp $");
#if defined(_KERNEL_OPT)
#include "wsmux.h"
@ -99,12 +99,10 @@ static void playstring(struct spkr_softc *, const char *, size_t);
*
* Play string interpretation is modelled on IBM BASIC 2.0's PLAY statement;
* M[LNS] are missing and the ~ synonym and octave-tracking facility is added.
* Requires spkr_tone(), spkr_rest(). String play is not interruptible
* except possibly at physical block boundaries.
* String play is not interruptible except possibly at physical block
* boundaries.
*/
#define dtoi(c) ((c) - '0')
/*
* Magic number avoidance...
*/
@ -156,45 +154,82 @@ playinit(struct spkr_softc *sc)
sc->sc_octprefix = true;/* act as though there was an initial O(n) */
}
/* play tone of proper duration for current rhythm signature */
#define SPKRPRI (PZERO - 1)
/* Rest for given number of ticks */
static void
playtone(struct spkr_softc *sc, int pitch, int val, int sustain)
rest(struct spkr_softc *sc, int ticks)
{
int sound, silence, snum = 1, sdenom = 1;
#ifdef SPKRDEBUG
device_printf(sc->sc_dev, "%s: rest for %d ticks\n", __func__, ticks);
#endif /* SPKRDEBUG */
KASSERT(ticks > 0);
tsleep(sc->sc_dev, SPKRPRI | PCATCH, device_xname(sc->sc_dev), ticks);
}
/*
* Play tone of proper duration for current rhythm signature.
* note indicates "O0C" = 0, "O0C#" = 1, "O0D" = 2, ... , and
* -1 indiacates a rest.
* val indicates the length, "L4" = 4, "L8" = 8.
* sustain indicates the number of subsequent dots that extend the sound
* by one a half.
*/
static void
playtone(struct spkr_softc *sc, int note, int val, int sustain)
{
int whole;
int total;
int sound;
int silence;
/* this weirdness avoids floating-point arithmetic */
whole = sc->sc_whole;
for (; sustain; sustain--) {
snum *= NUM_MULT;
sdenom *= DENOM_MULT;
whole *= NUM_MULT;
val *= DENOM_MULT;
}
if (pitch == -1) {
(*sc->sc_rest)(sc->sc_dev, sc->sc_whole
* snum / (val * sdenom));
/* Total length in tick */
total = whole / val;
if (note == -1) {
#ifdef SPKRDEBUG
device_printf(sc->sc_dev, "%s: rest for %d ticks\n",
__func__, total);
#endif /* SPKRDEBUG */
if (total != 0)
rest(sc, total);
return;
}
int fac = sc->sc_whole * (FILLTIME - sc->sc_fill);
int fval = FILLTIME * val;
sound = (sc->sc_whole * snum) / (val * sdenom) - fac / fval;
silence = fac * snum / (fval * sdenom);
/*
* Rest 1/8 (if NORMAL) or 3/8 (if STACCATO) in tick.
* silence should be rounded down.
*/
silence = total * (FILLTIME - sc->sc_fill) / FILLTIME;
sound = total - silence;
#ifdef SPKRDEBUG
device_printf(sc->sc_dev,
"%s: pitch %d for %d ticks, rest for %d ticks\n", __func__,
pitch, sound, silence);
"%s: note %d for %d ticks, rest for %d ticks\n", __func__,
note, sound, silence);
#endif /* SPKRDEBUG */
(*sc->sc_tone)(sc->sc_dev, pitchtab[pitch], sound);
if (sc->sc_fill != LEGATO)
(*sc->sc_rest)(sc->sc_dev, silence);
if (sound != 0)
(*sc->sc_tone)(sc->sc_dev, pitchtab[note], sound);
if (silence != 0)
rest(sc, silence);
}
/* interpret and play an item from a notation string */
static void
playstring(struct spkr_softc *sc, const char *cp, size_t slen)
{
int pitch, lastpitch = OCTAVE_NOTES * DFLT_OCTAVE;
int pitch;
int lastpitch = OCTAVE_NOTES * DFLT_OCTAVE;
#define GETNUM(cp, v) \
for (v = 0; slen > 0 && isdigit((unsigned char)cp[1]); ) { \
@ -357,16 +392,26 @@ playstring(struct spkr_softc *sc, const char *cp, size_t slen)
}
}
/******************* UNIX DRIVER HOOKS BEGIN HERE **************************
*
* This section implements driver hooks to run playstring() and the spkr_tone()
* and spkr_rest() functions defined above.
*/
/******************* UNIX DRIVER HOOKS BEGIN HERE **************************/
#define spkrenter(d) device_lookup_private(&spkr_cd, d)
/*
* Attaches spkr. Specify tone function with the following specification:
*
* void
* tone(device_t self, u_int pitch, u_int tick)
* plays a beep with specified parameters.
* The argument 'pitch' specifies the pitch of a beep in Hz. The argument
* 'tick' specifies the period of a beep in tick(9). This function waits
* to finish playing the beep and then halts it.
* If the pitch is zero, it halts all sound if any (for compatibility
* with the past confused specifications, but there should be no sound at
* this point). And it returns immediately, without waiting ticks. So
* you cannot use this as a rest.
* If the tick is zero, it returns immediately.
*/
void
spkr_attach(device_t self, void (*tone)(device_t, u_int, u_int),
void (*rest)(device_t, int))
spkr_attach(device_t self, void (*tone)(device_t, u_int, u_int))
{
struct spkr_softc *sc = device_private(self);
@ -375,7 +420,6 @@ spkr_attach(device_t self, void (*tone)(device_t, u_int, u_int),
#endif /* SPKRDEBUG */
sc->sc_dev = self;
sc->sc_tone = tone;
sc->sc_rest = rest;
sc->sc_inbuf = NULL;
sc->sc_wsbelldev = NULL;
@ -492,13 +536,21 @@ spkrclose(dev_t dev, int flags, int mode, struct lwp *l)
return 0;
}
/*
* Play tone specified by tp.
* tp->frequency is the frequency (0 means a rest).
* tp->duration is the length in tick (returns immediately if 0).
*/
static void
playonetone(struct spkr_softc *sc, tone_t *tp)
{
if (tp->frequency == 0)
(*sc->sc_rest)(sc->sc_dev, tp->duration);
else
(*sc->sc_tone)(sc->sc_dev, tp->frequency, tp->duration);
if (tp->duration <= 0)
return;
if (tp->frequency == 0)
rest(sc, tp->duration);
else
(*sc->sc_tone)(sc->sc_dev, tp->frequency, tp->duration);
}
int

View File

@ -1,4 +1,4 @@
/* $NetBSD: spkr_audio.c,v 1.10 2021/04/03 03:21:53 isaki Exp $ */
/* $NetBSD: spkr_audio.c,v 1.11 2021/04/03 04:10:30 isaki Exp $ */
/*-
* Copyright (c) 2016 Nathanial Sloss <nathanialsloss@yahoo.com.au>
@ -27,7 +27,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: spkr_audio.c,v 1.10 2021/04/03 03:21:53 isaki Exp $");
__KERNEL_RCSID(0, "$NetBSD: spkr_audio.c,v 1.11 2021/04/03 04:10:30 isaki Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -71,21 +71,11 @@ spkr_audio_tone(device_t self, u_int xhz, u_int ticks)
#ifdef SPKRDEBUG
device_printf(self, "%s: %u %u\n", __func__, xhz, ticks);
#endif /* SPKRDEBUG */
audiobell(sc->sc_audiodev, xhz, hztoms(ticks),
sc->sc_spkr.sc_vol, 0);
}
static void
spkr_audio_rest(device_t self, int ticks)
{
struct spkr_audio_softc *sc = device_private(self);
#ifdef SPKRDEBUG
aprint_debug_dev(self, "%s: %d\n", __func__, ticks);
#endif /* SPKRDEBUG */
if (ticks > 0)
audiobell(sc->sc_audiodev, 0, hztoms(ticks),
sc->sc_spkr.sc_vol, 0);
if (xhz == 0 || ticks == 0)
return;
audiobell(sc->sc_audiodev, xhz, hztoms(ticks), sc->sc_spkr.sc_vol, 0);
}
static int
@ -113,7 +103,7 @@ spkr_audio_attach(device_t parent, device_t self, void *aux)
if (!pmf_device_register(self, NULL, NULL))
aprint_error_dev(self, "couldn't establish power handler\n");
spkr_attach(self, spkr_audio_tone, spkr_audio_rest);
spkr_attach(self, spkr_audio_tone);
}
static int

View File

@ -1,4 +1,4 @@
/* $NetBSD: spkrvar.h,v 1.9 2017/06/11 21:54:22 pgoyette Exp $ */
/* $NetBSD: spkrvar.h,v 1.10 2021/04/03 04:10:30 isaki Exp $ */
#ifndef _SYS_DEV_SPKRVAR_H
#define _SYS_DEV_SPKRVAR_H
@ -18,12 +18,10 @@ struct spkr_softc {
/* attachment-specific hooks */
void (*sc_tone)(device_t, u_int, u_int);
void (*sc_rest)(device_t, int);
u_int sc_vol; /* volume - only for audio skpr */
};
void spkr_attach(device_t,
void (*)(device_t, u_int, u_int), void (*)(device_t, int));
void spkr_attach(device_t, void (*)(device_t, u_int, u_int));
int spkr_detach(device_t, int);