Home | History | Annotate | Line # | Download | only in audio
audiobell.c revision 1.3
      1  1.3  isaki /*	$NetBSD: audiobell.c,v 1.3 2019/06/26 06:57:45 isaki Exp $	*/
      2  1.2  isaki 
      3  1.2  isaki /*
      4  1.2  isaki  * Copyright (c) 1999 Richard Earnshaw
      5  1.2  isaki  * Copyright (c) 2004 Ben Harris
      6  1.2  isaki  *
      7  1.2  isaki  * Redistribution and use in source and binary forms, with or without
      8  1.2  isaki  * modification, are permitted provided that the following conditions
      9  1.2  isaki  * are met:
     10  1.2  isaki  * 1. Redistributions of source code must retain the above copyright
     11  1.2  isaki  *    notice, this list of conditions and the following disclaimer.
     12  1.2  isaki  * 2. Redistributions in binary form must reproduce the above copyright
     13  1.2  isaki  *    notice, this list of conditions and the following disclaimer in the
     14  1.2  isaki  *    documentation and/or other materials provided with the distribution.
     15  1.2  isaki  * 3. All advertising materials mentioning features or use of this software
     16  1.2  isaki  *    must display the following acknowledgement:
     17  1.2  isaki  *	This product includes software developed by the RiscBSD team.
     18  1.2  isaki  * 4. The name of the author may not be used to endorse or promote products
     19  1.2  isaki  *    derived from this software without specific prior written permission.
     20  1.2  isaki  *
     21  1.2  isaki  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     22  1.2  isaki  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     23  1.2  isaki  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     24  1.2  isaki  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     25  1.2  isaki  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     26  1.2  isaki  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     27  1.2  isaki  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     28  1.2  isaki  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     29  1.2  isaki  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     30  1.2  isaki  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     31  1.2  isaki  */
     32  1.2  isaki 
     33  1.2  isaki #include <sys/types.h>
     34  1.3  isaki __KERNEL_RCSID(0, "$NetBSD: audiobell.c,v 1.3 2019/06/26 06:57:45 isaki Exp $");
     35  1.2  isaki 
     36  1.2  isaki #include <sys/audioio.h>
     37  1.2  isaki #include <sys/conf.h>
     38  1.2  isaki #include <sys/device.h>
     39  1.2  isaki #include <sys/malloc.h>
     40  1.2  isaki #include <sys/systm.h>
     41  1.2  isaki #include <sys/uio.h>
     42  1.2  isaki 
     43  1.2  isaki #include <dev/audio/audio_if.h>
     44  1.2  isaki #include <dev/audio/audiovar.h>
     45  1.2  isaki #include <dev/audio/audiodef.h>
     46  1.2  isaki #include <dev/audio/audiobellvar.h>
     47  1.2  isaki 
     48  1.3  isaki /*
     49  1.3  isaki  * The hexadecagon is sufficiently close to a sine wave.
     50  1.3  isaki  * Audiobell always outputs this 16 points data but changes its playback
     51  1.3  isaki  * frequency.  In addition, audio layer does linear interpolation in the
     52  1.3  isaki  * frequency conversion stage, so the waveform becomes smooth.
     53  1.3  isaki  * When the playback frequency rises (or the device frequency is not enough
     54  1.3  isaki  * high) and one wave cannot be expressed with 16 points, the data is thinned
     55  1.3  isaki  * out by power of two, like 8 points -> 4 points (triangular wave)
     56  1.3  isaki  * -> 2 points (rectangular wave).
     57  1.3  isaki  */
     58  1.3  isaki 
     59  1.3  isaki /* Amplitude.  Full scale amplitude is too loud. */
     60  1.3  isaki #define A(x) ((x) * 0.6)
     61  1.3  isaki 
     62  1.3  isaki /* (sin(2*pi * (x/16)) * 32767 / 100) << 16 */
     63  1.3  isaki static const int32_t sinewave[] = {
     64  1.3  isaki 	A(        0),
     65  1.3  isaki 	A(  8217813),
     66  1.3  isaki 	A( 15184539),
     67  1.3  isaki 	A( 19839556),
     68  1.3  isaki 	A( 21474181),
     69  1.3  isaki 	A( 19839556),
     70  1.3  isaki 	A( 15184539),
     71  1.3  isaki 	A(  8217813),
     72  1.3  isaki 	A(        0),
     73  1.3  isaki 	A( -8217814),
     74  1.3  isaki 	A(-15184540),
     75  1.3  isaki 	A(-19839557),
     76  1.3  isaki 	A(-21474182),
     77  1.3  isaki 	A(-19839557),
     78  1.3  isaki 	A(-15184540),
     79  1.3  isaki 	A( -8217814),
     80  1.3  isaki };
     81  1.3  isaki #undef A
     82  1.2  isaki 
     83  1.2  isaki /*
     84  1.2  isaki  * dev is a device_t for the audio device to use.
     85  1.2  isaki  * pitch is the pitch of the bell in Hz,
     86  1.2  isaki  * period is the length in ms,
     87  1.2  isaki  * volume is the amplitude in % of max,
     88  1.2  isaki  * poll is no longer used.
     89  1.2  isaki  */
     90  1.2  isaki void
     91  1.2  isaki audiobell(void *dev, u_int pitch, u_int period, u_int volume, int poll)
     92  1.2  isaki {
     93  1.2  isaki 	dev_t audio;
     94  1.2  isaki 	int16_t *buf;
     95  1.2  isaki 	audio_file_t *file;
     96  1.2  isaki 	audio_track_t *ptrack;
     97  1.2  isaki 	struct uio auio;
     98  1.2  isaki 	struct iovec aiov;
     99  1.3  isaki 	u_int i;
    100  1.3  isaki 	u_int j;
    101  1.3  isaki 	u_int remaincount;
    102  1.3  isaki 	u_int remainbytes;
    103  1.3  isaki 	u_int wave1count;
    104  1.3  isaki 	u_int wave1bytes;
    105  1.3  isaki 	u_int blkbytes;
    106  1.3  isaki 	u_int len;
    107  1.3  isaki 	u_int step;
    108  1.3  isaki 	u_int offset;
    109  1.3  isaki 	u_int play_sample_rate;
    110  1.3  isaki 	u_int mixer_sample_rate;
    111  1.2  isaki 
    112  1.2  isaki 	KASSERT(volume <= 100);
    113  1.2  isaki 
    114  1.2  isaki 	/* The audio system isn't built for polling. */
    115  1.2  isaki 	if (poll)
    116  1.2  isaki 		return;
    117  1.2  isaki 
    118  1.2  isaki 	buf = NULL;
    119  1.2  isaki 	audio = AUDIO_DEVICE | device_unit((device_t)dev);
    120  1.2  isaki 
    121  1.2  isaki 	/* If not configured, we can't beep. */
    122  1.3  isaki 	if (audiobellopen(audio, &file) != 0)
    123  1.2  isaki 		return;
    124  1.2  isaki 
    125  1.2  isaki 	ptrack = file->ptrack;
    126  1.3  isaki 	mixer_sample_rate = ptrack->mixer->track_fmt.sample_rate;
    127  1.2  isaki 
    128  1.3  isaki 	/* Limit pitch */
    129  1.3  isaki 	if (pitch < 20)
    130  1.3  isaki 		pitch = 20;
    131  1.2  isaki 
    132  1.3  isaki 	offset = 0;
    133  1.3  isaki 	if (pitch <= mixer_sample_rate / 16) {
    134  1.3  isaki 		/* 16-point sine wave */
    135  1.3  isaki 		step = 1;
    136  1.3  isaki 	} else if (pitch <= mixer_sample_rate / 8) {
    137  1.3  isaki 		/* 8-point sine wave */
    138  1.3  isaki 		step = 2;
    139  1.3  isaki 	} else if (pitch <= mixer_sample_rate / 4) {
    140  1.3  isaki 		/* 4-point sine wave, aka, triangular wave */
    141  1.3  isaki 		step = 4;
    142  1.3  isaki 	} else {
    143  1.3  isaki 		/* Rectangular wave */
    144  1.3  isaki 		if (pitch > mixer_sample_rate / 2)
    145  1.3  isaki 			pitch = mixer_sample_rate / 2;
    146  1.3  isaki 		step = 8;
    147  1.3  isaki 		offset = 4;
    148  1.3  isaki 	}
    149  1.2  isaki 
    150  1.3  isaki 	wave1count = __arraycount(sinewave) / step;
    151  1.3  isaki 	play_sample_rate = pitch * wave1count;
    152  1.3  isaki 	audiobellsetrate(file, play_sample_rate);
    153  1.3  isaki 
    154  1.3  isaki 	/* msec to sample count */
    155  1.3  isaki 	remaincount = play_sample_rate * period / 1000;
    156  1.3  isaki 	/* Roundup to full wave */
    157  1.3  isaki 	remaincount = roundup(remaincount, wave1count);
    158  1.3  isaki 	remainbytes = remaincount * sizeof(int16_t);
    159  1.3  isaki 	wave1bytes = wave1count * sizeof(int16_t);
    160  1.3  isaki 
    161  1.3  isaki 	blkbytes = ptrack->usrbuf_blksize;
    162  1.3  isaki 	blkbytes = rounddown(blkbytes, wave1bytes);
    163  1.3  isaki 	blkbytes = uimin(blkbytes, remainbytes);
    164  1.3  isaki 	buf = malloc(blkbytes, M_TEMP, M_WAITOK);
    165  1.2  isaki 	if (buf == NULL)
    166  1.2  isaki 		goto out;
    167  1.2  isaki 
    168  1.3  isaki 	/* Generate sinewave with specified volume */
    169  1.3  isaki 	j = offset;
    170  1.3  isaki 	for (i = 0; i < blkbytes / sizeof(int16_t); i++) {
    171  1.3  isaki 		/* XXX audio already has track volume feature though #if 0 */
    172  1.3  isaki 		buf[i] = AUDIO_SCALEDOWN(sinewave[j] * (int)volume, 16);
    173  1.3  isaki 		j += step;
    174  1.3  isaki 		j %= __arraycount(sinewave);
    175  1.2  isaki 	}
    176  1.2  isaki 
    177  1.3  isaki 	/* Write while paused to avoid inserting silence. */
    178  1.2  isaki 	ptrack->is_pause = true;
    179  1.3  isaki 	for (; remainbytes > 0; remainbytes -= len) {
    180  1.3  isaki 		len = uimin(remainbytes, blkbytes);
    181  1.2  isaki 		aiov.iov_base = (void *)buf;
    182  1.2  isaki 		aiov.iov_len = len;
    183  1.2  isaki 		auio.uio_iov = &aiov;
    184  1.2  isaki 		auio.uio_iovcnt = 1;
    185  1.2  isaki 		auio.uio_offset = 0;
    186  1.2  isaki 		auio.uio_resid = len;
    187  1.2  isaki 		auio.uio_rw = UIO_WRITE;
    188  1.2  isaki 		UIO_SETUP_SYSSPACE(&auio);
    189  1.2  isaki 		if (audiobellwrite(file, &auio) != 0)
    190  1.2  isaki 			goto out;
    191  1.2  isaki 
    192  1.2  isaki 		if (ptrack->usrbuf.used >= ptrack->usrbuf_blksize * NBLKHW)
    193  1.2  isaki 			ptrack->is_pause = false;
    194  1.2  isaki 	}
    195  1.2  isaki 	/* Here we go! */
    196  1.2  isaki 	ptrack->is_pause = false;
    197  1.2  isaki out:
    198  1.2  isaki 	if (buf != NULL)
    199  1.2  isaki 		free(buf, M_TEMP);
    200  1.2  isaki 	audiobellclose(file);
    201  1.2  isaki }
    202