audiobell.c revision 1.2.2.2 1 1.2.2.2 christos /* $NetBSD: audiobell.c,v 1.2.2.2 2019/06/10 22:07:06 christos Exp $ */
2 1.2.2.2 christos
3 1.2.2.2 christos /*
4 1.2.2.2 christos * Copyright (c) 1999 Richard Earnshaw
5 1.2.2.2 christos * Copyright (c) 2004 Ben Harris
6 1.2.2.2 christos *
7 1.2.2.2 christos * Redistribution and use in source and binary forms, with or without
8 1.2.2.2 christos * modification, are permitted provided that the following conditions
9 1.2.2.2 christos * are met:
10 1.2.2.2 christos * 1. Redistributions of source code must retain the above copyright
11 1.2.2.2 christos * notice, this list of conditions and the following disclaimer.
12 1.2.2.2 christos * 2. Redistributions in binary form must reproduce the above copyright
13 1.2.2.2 christos * notice, this list of conditions and the following disclaimer in the
14 1.2.2.2 christos * documentation and/or other materials provided with the distribution.
15 1.2.2.2 christos * 3. All advertising materials mentioning features or use of this software
16 1.2.2.2 christos * must display the following acknowledgement:
17 1.2.2.2 christos * This product includes software developed by the RiscBSD team.
18 1.2.2.2 christos * 4. The name of the author may not be used to endorse or promote products
19 1.2.2.2 christos * derived from this software without specific prior written permission.
20 1.2.2.2 christos *
21 1.2.2.2 christos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 1.2.2.2 christos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 1.2.2.2 christos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 1.2.2.2 christos * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 1.2.2.2 christos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 1.2.2.2 christos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 1.2.2.2 christos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 1.2.2.2 christos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 1.2.2.2 christos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 1.2.2.2 christos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 1.2.2.2 christos */
32 1.2.2.2 christos
33 1.2.2.2 christos #include <sys/types.h>
34 1.2.2.2 christos __KERNEL_RCSID(0, "$NetBSD: audiobell.c,v 1.2.2.2 2019/06/10 22:07:06 christos Exp $");
35 1.2.2.2 christos
36 1.2.2.2 christos #include <sys/audioio.h>
37 1.2.2.2 christos #include <sys/conf.h>
38 1.2.2.2 christos #include <sys/device.h>
39 1.2.2.2 christos #include <sys/malloc.h>
40 1.2.2.2 christos #include <sys/systm.h>
41 1.2.2.2 christos #include <sys/uio.h>
42 1.2.2.2 christos
43 1.2.2.2 christos #include <dev/audio/audio_if.h>
44 1.2.2.2 christos #include <dev/audio/audiovar.h>
45 1.2.2.2 christos #include <dev/audio/audiodef.h>
46 1.2.2.2 christos #include <dev/audio/audiobellvar.h>
47 1.2.2.2 christos
48 1.2.2.2 christos /* 44.1 kHz should reduce hum at higher pitches. */
49 1.2.2.2 christos #define BELL_SAMPLE_RATE 44100
50 1.2.2.2 christos
51 1.2.2.2 christos /*
52 1.2.2.2 christos * dev is a device_t for the audio device to use.
53 1.2.2.2 christos * pitch is the pitch of the bell in Hz,
54 1.2.2.2 christos * period is the length in ms,
55 1.2.2.2 christos * volume is the amplitude in % of max,
56 1.2.2.2 christos * poll is no longer used.
57 1.2.2.2 christos */
58 1.2.2.2 christos void
59 1.2.2.2 christos audiobell(void *dev, u_int pitch, u_int period, u_int volume, int poll)
60 1.2.2.2 christos {
61 1.2.2.2 christos dev_t audio;
62 1.2.2.2 christos int16_t *buf;
63 1.2.2.2 christos struct audiobell_arg bellarg;
64 1.2.2.2 christos audio_file_t *file;
65 1.2.2.2 christos audio_track_t *ptrack;
66 1.2.2.2 christos struct uio auio;
67 1.2.2.2 christos struct iovec aiov;
68 1.2.2.2 christos int i;
69 1.2.2.2 christos int remaincount;
70 1.2.2.2 christos int remainlen;
71 1.2.2.2 christos int wave1count;
72 1.2.2.2 christos int wave1len;
73 1.2.2.2 christos int len;
74 1.2.2.2 christos int16_t vol;
75 1.2.2.2 christos
76 1.2.2.2 christos KASSERT(volume <= 100);
77 1.2.2.2 christos
78 1.2.2.2 christos /* The audio system isn't built for polling. */
79 1.2.2.2 christos if (poll)
80 1.2.2.2 christos return;
81 1.2.2.2 christos
82 1.2.2.2 christos /* Limit the pitch from 20Hz to Nyquist frequency. */
83 1.2.2.2 christos if (pitch > BELL_SAMPLE_RATE / 2)
84 1.2.2.2 christos pitch = BELL_SAMPLE_RATE;
85 1.2.2.2 christos if (pitch < 20)
86 1.2.2.2 christos pitch = 20;
87 1.2.2.2 christos
88 1.2.2.2 christos buf = NULL;
89 1.2.2.2 christos audio = AUDIO_DEVICE | device_unit((device_t)dev);
90 1.2.2.2 christos
91 1.2.2.2 christos memset(&bellarg, 0, sizeof(bellarg));
92 1.2.2.2 christos bellarg.encoding = AUDIO_ENCODING_SLINEAR_NE;
93 1.2.2.2 christos bellarg.precision = 16;
94 1.2.2.2 christos bellarg.channels = 1;
95 1.2.2.2 christos bellarg.sample_rate = BELL_SAMPLE_RATE;
96 1.2.2.2 christos
97 1.2.2.2 christos /* If not configured, we can't beep. */
98 1.2.2.2 christos if (audiobellopen(audio, &bellarg) != 0)
99 1.2.2.2 christos return;
100 1.2.2.2 christos
101 1.2.2.2 christos file = bellarg.file;
102 1.2.2.2 christos ptrack = file->ptrack;
103 1.2.2.2 christos
104 1.2.2.2 christos /* msec to sample count. */
105 1.2.2.2 christos remaincount = period * BELL_SAMPLE_RATE / 1000;
106 1.2.2.2 christos remainlen = remaincount * sizeof(int16_t);
107 1.2.2.2 christos
108 1.2.2.2 christos wave1count = BELL_SAMPLE_RATE / pitch;
109 1.2.2.2 christos wave1len = wave1count * sizeof(int16_t);
110 1.2.2.2 christos
111 1.2.2.2 christos buf = malloc(wave1len, M_TEMP, M_WAITOK);
112 1.2.2.2 christos if (buf == NULL)
113 1.2.2.2 christos goto out;
114 1.2.2.2 christos
115 1.2.2.2 christos /* Generate single square wave. It's enough to beep. */
116 1.2.2.2 christos vol = 32767 * volume / 100;
117 1.2.2.2 christos for (i = 0; i < wave1count / 2; i++) {
118 1.2.2.2 christos buf[i] = vol;
119 1.2.2.2 christos }
120 1.2.2.2 christos vol = -vol;
121 1.2.2.2 christos for (; i < wave1count; i++) {
122 1.2.2.2 christos buf[i] = vol;
123 1.2.2.2 christos }
124 1.2.2.2 christos
125 1.2.2.2 christos /* Write while paused to avoid begin inserted silence. */
126 1.2.2.2 christos ptrack->is_pause = true;
127 1.2.2.2 christos for (; remainlen > 0; remainlen -= wave1len) {
128 1.2.2.2 christos len = uimin(remainlen, wave1len);
129 1.2.2.2 christos aiov.iov_base = (void *)buf;
130 1.2.2.2 christos aiov.iov_len = len;
131 1.2.2.2 christos auio.uio_iov = &aiov;
132 1.2.2.2 christos auio.uio_iovcnt = 1;
133 1.2.2.2 christos auio.uio_offset = 0;
134 1.2.2.2 christos auio.uio_resid = len;
135 1.2.2.2 christos auio.uio_rw = UIO_WRITE;
136 1.2.2.2 christos UIO_SETUP_SYSSPACE(&auio);
137 1.2.2.2 christos if (audiobellwrite(file, &auio) != 0)
138 1.2.2.2 christos goto out;
139 1.2.2.2 christos
140 1.2.2.2 christos if (ptrack->usrbuf.used >= ptrack->usrbuf_blksize * NBLKHW)
141 1.2.2.2 christos ptrack->is_pause = false;
142 1.2.2.2 christos }
143 1.2.2.2 christos /* Here we go! */
144 1.2.2.2 christos ptrack->is_pause = false;
145 1.2.2.2 christos out:
146 1.2.2.2 christos if (buf != NULL)
147 1.2.2.2 christos free(buf, M_TEMP);
148 1.2.2.2 christos audiobellclose(file);
149 1.2.2.2 christos }
150