h_pad.c revision 1.3 1 1.3 isaki /* $NetBSD: h_pad.c,v 1.3 2019/06/20 12:14:46 isaki Exp $ */
2 1.1 pooka
3 1.1 pooka /*
4 1.1 pooka * Copyright (c) 2010 Antti Kantee. All Rights Reserved.
5 1.1 pooka *
6 1.1 pooka * Redistribution and use in source and binary forms, with or without
7 1.1 pooka * modification, are permitted provided that the following conditions
8 1.1 pooka * are met:
9 1.1 pooka * 1. Redistributions of source code must retain the above copyright
10 1.1 pooka * notice, this list of conditions and the following disclaimer.
11 1.1 pooka * 2. Redistributions in binary form must reproduce the above copyright
12 1.1 pooka * notice, this list of conditions and the following disclaimer in the
13 1.1 pooka * documentation and/or other materials provided with the distribution.
14 1.1 pooka *
15 1.1 pooka * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
16 1.1 pooka * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 1.1 pooka * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 1.1 pooka * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 1.1 pooka * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 1.1 pooka * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 1.1 pooka * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 1.1 pooka * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 1.1 pooka * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 1.1 pooka * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 1.1 pooka * SUCH DAMAGE.
26 1.1 pooka */
27 1.1 pooka
28 1.1 pooka #include <sys/types.h>
29 1.1 pooka
30 1.1 pooka #include <rump/rump.h>
31 1.1 pooka #include <rump/rump_syscalls.h>
32 1.1 pooka
33 1.1 pooka #include <err.h>
34 1.1 pooka #include <fcntl.h>
35 1.3 isaki #include <stdbool.h>
36 1.1 pooka #include <stdio.h>
37 1.1 pooka #include <stdlib.h>
38 1.1 pooka #include <string.h>
39 1.1 pooka #include <unistd.h>
40 1.3 isaki #include <sys/audioio.h>
41 1.1 pooka
42 1.1 pooka #include "h_pad_musa.c"
43 1.1 pooka
44 1.1 pooka /*
45 1.3 isaki * Stuff some audio into /dev/audio, read it from /dev/pad.
46 1.1 pooka */
47 1.1 pooka
48 1.1 pooka #define BUFSIZE 1024
49 1.1 pooka
50 1.3 isaki static const int16_t mulaw_to_slinear16[256] = {
51 1.3 isaki 0x8284, 0x8684, 0x8a84, 0x8e84, 0x9284, 0x9684, 0x9a84, 0x9e84,
52 1.3 isaki 0xa284, 0xa684, 0xaa84, 0xae84, 0xb284, 0xb684, 0xba84, 0xbe84,
53 1.3 isaki 0xc184, 0xc384, 0xc584, 0xc784, 0xc984, 0xcb84, 0xcd84, 0xcf84,
54 1.3 isaki 0xd184, 0xd384, 0xd584, 0xd784, 0xd984, 0xdb84, 0xdd84, 0xdf84,
55 1.3 isaki 0xe104, 0xe204, 0xe304, 0xe404, 0xe504, 0xe604, 0xe704, 0xe804,
56 1.3 isaki 0xe904, 0xea04, 0xeb04, 0xec04, 0xed04, 0xee04, 0xef04, 0xf004,
57 1.3 isaki 0xf0c4, 0xf144, 0xf1c4, 0xf244, 0xf2c4, 0xf344, 0xf3c4, 0xf444,
58 1.3 isaki 0xf4c4, 0xf544, 0xf5c4, 0xf644, 0xf6c4, 0xf744, 0xf7c4, 0xf844,
59 1.3 isaki 0xf8a4, 0xf8e4, 0xf924, 0xf964, 0xf9a4, 0xf9e4, 0xfa24, 0xfa64,
60 1.3 isaki 0xfaa4, 0xfae4, 0xfb24, 0xfb64, 0xfba4, 0xfbe4, 0xfc24, 0xfc64,
61 1.3 isaki 0xfc94, 0xfcb4, 0xfcd4, 0xfcf4, 0xfd14, 0xfd34, 0xfd54, 0xfd74,
62 1.3 isaki 0xfd94, 0xfdb4, 0xfdd4, 0xfdf4, 0xfe14, 0xfe34, 0xfe54, 0xfe74,
63 1.3 isaki 0xfe8c, 0xfe9c, 0xfeac, 0xfebc, 0xfecc, 0xfedc, 0xfeec, 0xfefc,
64 1.3 isaki 0xff0c, 0xff1c, 0xff2c, 0xff3c, 0xff4c, 0xff5c, 0xff6c, 0xff7c,
65 1.3 isaki 0xff88, 0xff90, 0xff98, 0xffa0, 0xffa8, 0xffb0, 0xffb8, 0xffc0,
66 1.3 isaki 0xffc8, 0xffd0, 0xffd8, 0xffe0, 0xffe8, 0xfff0, 0xfff8, 0xfffc,
67 1.3 isaki 0x7d7c, 0x797c, 0x757c, 0x717c, 0x6d7c, 0x697c, 0x657c, 0x617c,
68 1.3 isaki 0x5d7c, 0x597c, 0x557c, 0x517c, 0x4d7c, 0x497c, 0x457c, 0x417c,
69 1.3 isaki 0x3e7c, 0x3c7c, 0x3a7c, 0x387c, 0x367c, 0x347c, 0x327c, 0x307c,
70 1.3 isaki 0x2e7c, 0x2c7c, 0x2a7c, 0x287c, 0x267c, 0x247c, 0x227c, 0x207c,
71 1.3 isaki 0x1efc, 0x1dfc, 0x1cfc, 0x1bfc, 0x1afc, 0x19fc, 0x18fc, 0x17fc,
72 1.3 isaki 0x16fc, 0x15fc, 0x14fc, 0x13fc, 0x12fc, 0x11fc, 0x10fc, 0x0ffc,
73 1.3 isaki 0x0f3c, 0x0ebc, 0x0e3c, 0x0dbc, 0x0d3c, 0x0cbc, 0x0c3c, 0x0bbc,
74 1.3 isaki 0x0b3c, 0x0abc, 0x0a3c, 0x09bc, 0x093c, 0x08bc, 0x083c, 0x07bc,
75 1.3 isaki 0x075c, 0x071c, 0x06dc, 0x069c, 0x065c, 0x061c, 0x05dc, 0x059c,
76 1.3 isaki 0x055c, 0x051c, 0x04dc, 0x049c, 0x045c, 0x041c, 0x03dc, 0x039c,
77 1.3 isaki 0x036c, 0x034c, 0x032c, 0x030c, 0x02ec, 0x02cc, 0x02ac, 0x028c,
78 1.3 isaki 0x026c, 0x024c, 0x022c, 0x020c, 0x01ec, 0x01cc, 0x01ac, 0x018c,
79 1.3 isaki 0x0174, 0x0164, 0x0154, 0x0144, 0x0134, 0x0124, 0x0114, 0x0104,
80 1.3 isaki 0x00f4, 0x00e4, 0x00d4, 0x00c4, 0x00b4, 0x00a4, 0x0094, 0x0084,
81 1.3 isaki 0x0078, 0x0070, 0x0068, 0x0060, 0x0058, 0x0050, 0x0048, 0x0040,
82 1.3 isaki 0x0038, 0x0030, 0x0028, 0x0020, 0x0018, 0x0010, 0x0008, 0x0000,
83 1.3 isaki };
84 1.3 isaki
85 1.3 isaki #define DPRINTF(n, fmt...) do { \
86 1.3 isaki if (debug >= (n)) \
87 1.3 isaki printf(fmt); \
88 1.3 isaki } while (0)
89 1.3 isaki
90 1.3 isaki int debug;
91 1.3 isaki
92 1.1 pooka int
93 1.1 pooka main(int argc, char *argv[])
94 1.1 pooka {
95 1.3 isaki struct audio_info ai;
96 1.1 pooka int padfd, audiofd;
97 1.1 pooka ssize_t n;
98 1.3 isaki int i;
99 1.3 isaki int nframe;
100 1.3 isaki int outlen;
101 1.3 isaki uint32_t *outbuf;
102 1.3 isaki uint32_t *outp;
103 1.3 isaki int inplen;
104 1.3 isaki uint32_t *inpbuf;
105 1.3 isaki uint32_t actual;
106 1.3 isaki uint32_t expected;
107 1.3 isaki int c;
108 1.3 isaki enum {
109 1.3 isaki PRE,
110 1.3 isaki BODY,
111 1.3 isaki POST,
112 1.3 isaki } phase;
113 1.3 isaki
114 1.3 isaki while ((c = getopt(argc, argv, "d")) != -1) {
115 1.3 isaki switch (c) {
116 1.3 isaki case 'd':
117 1.3 isaki debug++;
118 1.3 isaki break;
119 1.3 isaki default:
120 1.3 isaki errx(1, "unknown option");
121 1.3 isaki }
122 1.3 isaki }
123 1.1 pooka
124 1.3 isaki /* Make input buffer (and it is also expected data). */
125 1.3 isaki inplen = sizeof(musa) * 4;
126 1.3 isaki inpbuf = (uint32_t *)malloc(inplen);
127 1.3 isaki if (inpbuf == NULL)
128 1.3 isaki err(1, "malloc: inpbuf");
129 1.3 isaki
130 1.3 isaki /* mulaw:mono to slinear_le16:stereo */
131 1.3 isaki for (i = 0; i < (int)sizeof(musa); i++) {
132 1.3 isaki int16_t s = mulaw_to_slinear16[musa[i]];
133 1.3 isaki uint32_t v = htole16((uint16_t)s);
134 1.3 isaki inpbuf[i] = (v << 16) | v;
135 1.3 isaki }
136 1.3 isaki
137 1.3 isaki outlen = BUFSIZE;
138 1.3 isaki outbuf = (uint32_t *)malloc(outlen);
139 1.3 isaki if (outbuf == NULL)
140 1.3 isaki err(1, "malloc: outbuf");
141 1.3 isaki
142 1.3 isaki DPRINTF(1, "init\n");
143 1.1 pooka rump_init();
144 1.2 nat padfd = rump_sys_open("/dev/pad0", O_RDONLY);
145 1.2 nat if (padfd == -1)
146 1.2 nat err(1, "open pad");
147 1.2 nat
148 1.1 pooka audiofd = rump_sys_open("/dev/audio0", O_RDWR);
149 1.1 pooka if (audiofd == -1)
150 1.1 pooka err(1, "open audio");
151 1.1 pooka
152 1.3 isaki DPRINTF(1, "ioctl\n");
153 1.3 isaki /* pad is SLINEAR_LE, 16bit, 2ch, 44100Hz. */
154 1.3 isaki AUDIO_INITINFO(&ai);
155 1.3 isaki ai.play.encoding = AUDIO_ENCODING_SLINEAR_LE;
156 1.3 isaki ai.play.precision = 16;
157 1.3 isaki ai.play.channels = 2;
158 1.3 isaki ai.play.sample_rate = 44100;
159 1.3 isaki n = rump_sys_ioctl(audiofd, AUDIO_SETINFO, &ai);
160 1.3 isaki if (n == -1)
161 1.3 isaki err(1, "ioctl");
162 1.3 isaki
163 1.3 isaki DPRINTF(1, "write %d\n", inplen);
164 1.3 isaki n = rump_sys_write(audiofd, inpbuf, inplen);
165 1.3 isaki if (n == -1)
166 1.1 pooka err(1, "write");
167 1.3 isaki if (n != inplen)
168 1.3 isaki errx(1, "write: n=%zd < %d", n, inplen);
169 1.1 pooka
170 1.3 isaki phase = PRE;
171 1.3 isaki i = 0;
172 1.3 isaki nframe = 0;
173 1.3 isaki outp = NULL;
174 1.3 isaki for (;;) {
175 1.3 isaki /* Read to outbuf when it is empty. */
176 1.3 isaki if (nframe == 0) {
177 1.3 isaki n = rump_sys_read(padfd, outbuf, outlen);
178 1.3 isaki if (n == -1)
179 1.3 isaki err(1, "read");
180 1.3 isaki if (n == 0)
181 1.3 isaki errx(1, "read: EOF");
182 1.3 isaki /* XXX Should I recover from this? */
183 1.3 isaki if (n % 4 != 0)
184 1.3 isaki errx(1, "read: n=%zd", n);
185 1.3 isaki
186 1.3 isaki nframe = n / 4;
187 1.3 isaki outp = outbuf;
188 1.3 isaki }
189 1.3 isaki
190 1.3 isaki if (phase == PRE) {
191 1.3 isaki /* Skip preceding silence part. */
192 1.3 isaki if (*outp == 0) {
193 1.3 isaki outp++;
194 1.3 isaki nframe--;
195 1.3 isaki } else {
196 1.3 isaki /* This is the first frame. */
197 1.3 isaki phase = BODY;
198 1.3 isaki }
199 1.3 isaki } else if (phase == BODY) {
200 1.3 isaki /* Compare wavedata. */
201 1.3 isaki expected = le32dec(outp);
202 1.3 isaki actual = le32dec(inpbuf + i);
203 1.3 isaki DPRINTF(2, "[%d] %08x %08x\n", i, actual, expected);
204 1.3 isaki if (actual != expected) {
205 1.3 isaki errx(1, "bad output [%d] %08x %08x",
206 1.3 isaki i, actual, expected);
207 1.3 isaki }
208 1.3 isaki outp++;
209 1.3 isaki nframe--;
210 1.3 isaki i++;
211 1.3 isaki if (i >= (int)sizeof(musa)) {
212 1.3 isaki phase = POST;
213 1.3 isaki i = 0;
214 1.3 isaki }
215 1.3 isaki } else if (phase == POST) {
216 1.3 isaki /*
217 1.3 isaki * There is no way to determine the end of playback.
218 1.3 isaki * Therefore it detects and terminates with some
219 1.3 isaki * continuous silence.
220 1.3 isaki */
221 1.3 isaki actual = le32dec(outp);
222 1.3 isaki if (actual != 0)
223 1.3 isaki errx(1, "bad post output: %08x", actual);
224 1.3 isaki outp++;
225 1.3 isaki nframe--;
226 1.3 isaki i++;
227 1.3 isaki if (i >= (int)ai.play.sample_rate / 100)
228 1.3 isaki break;
229 1.3 isaki }
230 1.1 pooka }
231 1.3 isaki DPRINTF(1, "success\n");
232 1.3 isaki return 0;
233 1.1 pooka }
234