Home | History | Annotate | Line # | Download | only in audio
      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