1 /* $NetBSD: audiobell.c,v 1.7 2009/05/07 09:23:01 cegger Exp $ */
4 * Copyright (c) 1999 Richard Earnshaw
5 * Copyright (c) 2004 Ben Harris
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the RiscBSD team.
18 * 4. The name of the author may not be used to endorse or promote products
19 * derived from this software without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 #include <sys/types.h>
34 __KERNEL_RCSID(0, "$NetBSD: audiobell.c,v 1.7 2009/05/07 09:23:01 cegger Exp $");
36 #include <sys/audioio.h>
38 #include <sys/device.h>
39 #include <sys/fcntl.h>
40 #include <sys/malloc.h>
42 #include <sys/systm.h>
45 #include <dev/audio_if.h>
46 #include <dev/audiobellvar.h>
48 extern dev_type_open(audioopen
);
49 extern dev_type_write(audiowrite
);
50 extern dev_type_close(audioclose
);
52 /* Convert a %age volume to an amount to add to u-law values */
53 /* XXX Probably highly inaccurate -- should be regenerated */
54 static const uint8_t volmap
[] = {
55 0x7f, 0x67, 0x5b, 0x53, 0x49, 0x45, 0x41, 0x3e, 0x3a, 0x38,
56 0x36, 0x32, 0x30, 0x2f, 0x2e, 0x2c, 0x2b, 0x2a, 0x28, 0x27,
57 0x26, 0x25, 0x23, 0x22, 0x21, 0x1f, 0x1f, 0x1e, 0x1e, 0x1d,
58 0x1c, 0x1c, 0x1b, 0x1a, 0x1a, 0x19, 0x18, 0x18, 0x17, 0x17,
59 0x16, 0x15, 0x15, 0x14, 0x13, 0x13, 0x12, 0x11, 0x11, 0x10,
60 0x0f, 0x0f, 0x0f, 0x0f, 0x0e, 0x0e, 0x0e, 0x0d, 0x0d, 0x0d,
61 0x0c, 0x0c, 0x0c, 0x0b, 0x0b, 0x0b, 0x0a, 0x0a, 0x0a, 0x09,
62 0x09, 0x09, 0x08, 0x08, 0x08, 0x07, 0x07, 0x07, 0x07, 0x06,
63 0x06, 0x06, 0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x03, 0x03,
64 0x03, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00,
68 /* 1/4 cycle sine wave in u-law */
69 /* XXX Probably highly inaccurate -- should be regenerated */
70 static const uint8_t sinewave
[] = {
71 0xff, 0xd3, 0xc5, 0xbc, 0xb6, 0xb0, 0xad, 0xaa,
72 0xa7, 0xa3, 0xa0, 0x9e, 0x9d, 0x9b, 0x9a, 0x98,
73 0x97, 0x96, 0x94, 0x93, 0x91, 0x90, 0x8f, 0x8e,
74 0x8e, 0x8d, 0x8c, 0x8c, 0x8b, 0x8b, 0x8a, 0x89,
75 0x89, 0x88, 0x88, 0x87, 0x87, 0x86, 0x86, 0x85,
76 0x85, 0x84, 0x84, 0x84, 0x83, 0x83, 0x83, 0x82,
77 0x82, 0x82, 0x81, 0x81, 0x81, 0x81, 0x80, 0x80,
78 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
83 audiobell_ulawscale(uint8_t val
, uint8_t vol
)
88 /* Spot underflow and just return silence */
89 if ((result
^ val
) & 0x80)
95 audiobell_expandwave(uint8_t *buf
, int volume
)
100 KASSERT(volume
>= 0 && volume
<= 100);
101 uvol
= volmap
[volume
];
102 for (i
= 0; i
< 65; i
++)
103 buf
[i
] = audiobell_ulawscale(sinewave
[i
], uvol
);
104 for (i
= 65; i
< 128; i
++)
105 buf
[i
] = buf
[128 - i
];
106 for (i
= 128; i
< 256; i
++)
107 buf
[i
] = buf
[i
- 128] ^ 0x80;
111 * The algorithm here is based on that described in the RISC OS Programmer's
112 * Reference Manual (pp1624--1628).
115 audiobell_synthesize(uint8_t *buf
, u_int pitch
, u_int period
, u_int volume
)
120 wave
= malloc(256, M_TEMP
, M_WAITOK
);
121 if (wave
== NULL
) return -1;
122 audiobell_expandwave(wave
, volume
);
123 pitch
= pitch
* 65536 / 8000;
124 period
= period
* 8; /* 8000 / 1000 */
127 for (; period
!= 0; period
--) {
128 *buf
++ = wave
[phase
>> 8];
137 audiobell(void *arg
, u_int pitch
, u_int period
, u_int volume
, int poll
)
139 device_t audio
= arg
;
144 /* The audio system isn't built for polling. */
147 /* If not configured, we can't beep. */
148 if (audioopen(AUDIO_DEVICE
| device_unit(audio
), FWRITE
, 0, NULL
) != 0)
151 buf
= malloc(period
* 8, M_TEMP
, M_WAITOK
);
152 if (buf
== NULL
) goto out
;
153 if (audiobell_synthesize(buf
, pitch
, period
, volume
) != 0) goto out
;
155 aiov
.iov_base
= (void *)buf
;
156 aiov
.iov_len
= period
* 8;
157 auio
.uio_iov
= &aiov
;
160 auio
.uio_resid
= period
* 8;
161 auio
.uio_rw
= UIO_WRITE
;
162 UIO_SETUP_SYSSPACE(&auio
);
164 audiowrite(AUDIO_DEVICE
| device_unit(audio
), &auio
, 0);
167 if (buf
!= NULL
) free(buf
, M_TEMP
);
168 audioclose(AUDIO_DEVICE
| device_unit(audio
), FWRITE
, 0, NULL
);