audiobell.c revision 1.2 1 1.2 isaki /* $NetBSD: audiobell.c,v 1.2 2019/05/08 13:40:17 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.2 isaki __KERNEL_RCSID(0, "$NetBSD: audiobell.c,v 1.2 2019/05/08 13:40:17 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.2 isaki /* 44.1 kHz should reduce hum at higher pitches. */
49 1.2 isaki #define BELL_SAMPLE_RATE 44100
50 1.2 isaki
51 1.2 isaki /*
52 1.2 isaki * dev is a device_t for the audio device to use.
53 1.2 isaki * pitch is the pitch of the bell in Hz,
54 1.2 isaki * period is the length in ms,
55 1.2 isaki * volume is the amplitude in % of max,
56 1.2 isaki * poll is no longer used.
57 1.2 isaki */
58 1.2 isaki void
59 1.2 isaki audiobell(void *dev, u_int pitch, u_int period, u_int volume, int poll)
60 1.2 isaki {
61 1.2 isaki dev_t audio;
62 1.2 isaki int16_t *buf;
63 1.2 isaki struct audiobell_arg bellarg;
64 1.2 isaki audio_file_t *file;
65 1.2 isaki audio_track_t *ptrack;
66 1.2 isaki struct uio auio;
67 1.2 isaki struct iovec aiov;
68 1.2 isaki int i;
69 1.2 isaki int remaincount;
70 1.2 isaki int remainlen;
71 1.2 isaki int wave1count;
72 1.2 isaki int wave1len;
73 1.2 isaki int len;
74 1.2 isaki int16_t vol;
75 1.2 isaki
76 1.2 isaki KASSERT(volume <= 100);
77 1.2 isaki
78 1.2 isaki /* The audio system isn't built for polling. */
79 1.2 isaki if (poll)
80 1.2 isaki return;
81 1.2 isaki
82 1.2 isaki /* Limit the pitch from 20Hz to Nyquist frequency. */
83 1.2 isaki if (pitch > BELL_SAMPLE_RATE / 2)
84 1.2 isaki pitch = BELL_SAMPLE_RATE;
85 1.2 isaki if (pitch < 20)
86 1.2 isaki pitch = 20;
87 1.2 isaki
88 1.2 isaki buf = NULL;
89 1.2 isaki audio = AUDIO_DEVICE | device_unit((device_t)dev);
90 1.2 isaki
91 1.2 isaki memset(&bellarg, 0, sizeof(bellarg));
92 1.2 isaki bellarg.encoding = AUDIO_ENCODING_SLINEAR_NE;
93 1.2 isaki bellarg.precision = 16;
94 1.2 isaki bellarg.channels = 1;
95 1.2 isaki bellarg.sample_rate = BELL_SAMPLE_RATE;
96 1.2 isaki
97 1.2 isaki /* If not configured, we can't beep. */
98 1.2 isaki if (audiobellopen(audio, &bellarg) != 0)
99 1.2 isaki return;
100 1.2 isaki
101 1.2 isaki file = bellarg.file;
102 1.2 isaki ptrack = file->ptrack;
103 1.2 isaki
104 1.2 isaki /* msec to sample count. */
105 1.2 isaki remaincount = period * BELL_SAMPLE_RATE / 1000;
106 1.2 isaki remainlen = remaincount * sizeof(int16_t);
107 1.2 isaki
108 1.2 isaki wave1count = BELL_SAMPLE_RATE / pitch;
109 1.2 isaki wave1len = wave1count * sizeof(int16_t);
110 1.2 isaki
111 1.2 isaki buf = malloc(wave1len, M_TEMP, M_WAITOK);
112 1.2 isaki if (buf == NULL)
113 1.2 isaki goto out;
114 1.2 isaki
115 1.2 isaki /* Generate single square wave. It's enough to beep. */
116 1.2 isaki vol = 32767 * volume / 100;
117 1.2 isaki for (i = 0; i < wave1count / 2; i++) {
118 1.2 isaki buf[i] = vol;
119 1.2 isaki }
120 1.2 isaki vol = -vol;
121 1.2 isaki for (; i < wave1count; i++) {
122 1.2 isaki buf[i] = vol;
123 1.2 isaki }
124 1.2 isaki
125 1.2 isaki /* Write while paused to avoid begin inserted silence. */
126 1.2 isaki ptrack->is_pause = true;
127 1.2 isaki for (; remainlen > 0; remainlen -= wave1len) {
128 1.2 isaki len = uimin(remainlen, wave1len);
129 1.2 isaki aiov.iov_base = (void *)buf;
130 1.2 isaki aiov.iov_len = len;
131 1.2 isaki auio.uio_iov = &aiov;
132 1.2 isaki auio.uio_iovcnt = 1;
133 1.2 isaki auio.uio_offset = 0;
134 1.2 isaki auio.uio_resid = len;
135 1.2 isaki auio.uio_rw = UIO_WRITE;
136 1.2 isaki UIO_SETUP_SYSSPACE(&auio);
137 1.2 isaki if (audiobellwrite(file, &auio) != 0)
138 1.2 isaki goto out;
139 1.2 isaki
140 1.2 isaki if (ptrack->usrbuf.used >= ptrack->usrbuf_blksize * NBLKHW)
141 1.2 isaki ptrack->is_pause = false;
142 1.2 isaki }
143 1.2 isaki /* Here we go! */
144 1.2 isaki ptrack->is_pause = false;
145 1.2 isaki out:
146 1.2 isaki if (buf != NULL)
147 1.2 isaki free(buf, M_TEMP);
148 1.2 isaki audiobellclose(file);
149 1.2 isaki }
150