xref: /illumos-gate/usr/src/cmd/audio/audiotest/wavedata.c (revision d8e10381a0083d7717710b0db7e64707bc0f3ff8)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright (C) 4Front Technologies 1996-2008.
23  *
24  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
25  * Use is subject to license terms.
26  */
27 /*
28  * Purpose: Test sounds for osstest
29  *
30  * Nodoc:
31  */
32 
33 #include <string.h>
34 
35 #include "wavedata.h"
36 
37 static int
38 le_int(const unsigned char *p, int l)
39 {
40 	int i, val;
41 
42 	val = 0;
43 
44 	for (i = l - 1; i >= 0; i--) {
45 		val = (val << 8) | p[i];
46 	}
47 
48 	return (val);
49 }
50 
51 int
52 uncompress_wave(short *outbuf)
53 {
54 #define	WAVE_FORMAT_ADPCM		0x0002
55 
56 	int i, n, dataleft, x, l = sizeof (inbuf);
57 	const unsigned char *hdr = inbuf;
58 	typedef struct {
59 		int coeff1, coeff2;
60 	}
61 	adpcm_coeff;
62 
63 	adpcm_coeff coeff[32];
64 	static int AdaptionTable[] = { 230, 230, 230, 230, 307, 409, 512, 614,
65 	    768, 614, 512, 409, 307, 230, 230, 230
66 	};
67 
68 	unsigned char buf[4096];
69 
70 	int channels = 1;
71 	int p = 12, outp = 0;
72 	int nBlockAlign = 2048;
73 	int wSamplesPerBlock = 2036, wNumCoeff = 7;
74 	int nib;
75 	int ppp;
76 
77 	/* filelen = le_int(&hdr[4], 4); */
78 
79 	while (p < l - 16 && memcmp(&hdr[p], "data", 4) != 0) {
80 		n = le_int(&hdr[p + 4], 4);
81 
82 		if (memcmp(&hdr[p], "fmt ", 4) == 0) {
83 
84 			/* fmt = le_int(&hdr[p + 8], 2); */
85 			channels = le_int(&hdr[p + 10], 2);
86 			/* speed = le_int(&hdr[p + 12], 4); */
87 			nBlockAlign = le_int(&hdr[p + 20], 2);
88 			/* bytes_per_sample = le_int(&hdr[p + 20], 2); */
89 
90 			wSamplesPerBlock = le_int(&hdr[p + 26], 2);
91 			wNumCoeff = le_int(&hdr[p + 28], 2);
92 
93 			x = p + 30;
94 
95 			for (i = 0; i < wNumCoeff; i++) {
96 				coeff[i].coeff1 = (short)le_int(&hdr[x], 2);
97 				x += 2;
98 				coeff[i].coeff2 = (short)le_int(&hdr[x], 2);
99 				x += 2;
100 			}
101 		}
102 
103 		p += n + 8;
104 	}
105 
106 	if (p < l - 16 && memcmp(&hdr[p], "data", 4) == 0) {
107 
108 		dataleft = n = le_int(&hdr[p + 4], 4);
109 		p += 8;
110 
111 /*
112  * Playback procedure
113  */
114 #define	OUT_SAMPLE(s) {				\
115 		if (s > 32767)			\
116 			s = 32767;		\
117 		else if (s < -32768)		\
118 			s = -32768;		\
119 		outbuf[outp++] = s;		\
120 		n += 2;				\
121 		}
122 
123 #define	GETNIBBLE					\
124 		((nib == 0) ?				\
125 		(buf[x + nib++] >> 4) & 0x0f : buf[x++ + --nib] & 0x0f)
126 
127 		outp = 0;
128 
129 		ppp = p;
130 		while (dataleft > nBlockAlign) {
131 			int predictor[2], delta[2], samp1[2], samp2[2];
132 
133 			int x = 0;
134 
135 			(void) memcpy(buf, &inbuf[ppp], nBlockAlign);
136 			ppp += nBlockAlign;
137 			dataleft -= nBlockAlign;
138 
139 			nib = 0;
140 			n = 0;
141 
142 			for (i = 0; i < channels; i++) {
143 				predictor[i] = buf[x];
144 				x++;
145 			}
146 
147 			for (i = 0; i < channels; i++) {
148 				delta[i] = (short)le_int(&buf[x], 2);
149 				x += 2;
150 			}
151 
152 			for (i = 0; i < channels; i++) {
153 				samp1[i] = (short)le_int(&buf[x], 2);
154 				x += 2;
155 				OUT_SAMPLE(samp1[i]);
156 			}
157 
158 			for (i = 0; i < channels; i++) {
159 				samp2[i] = (short)le_int(&buf[x], 2);
160 				x += 2;
161 				OUT_SAMPLE(samp2[i]);
162 			}
163 
164 			while (n < (wSamplesPerBlock * 2 * channels))
165 				for (i = 0; i < channels; i++) {
166 					int pred, new, error_delta, i_delta;
167 
168 					pred = ((samp1[i] *
169 					    coeff[predictor[i]].coeff1)
170 					    + (samp2[i] *
171 					    coeff[predictor[i]].coeff2)) / 256;
172 					i_delta = error_delta = GETNIBBLE;
173 
174 					/* Convert to signed */
175 					if (i_delta & 0x08)
176 						i_delta -= 0x10;
177 
178 					new = pred + (delta[i] * i_delta);
179 					OUT_SAMPLE(new);
180 
181 					delta[i] = delta[i] *
182 					    AdaptionTable[error_delta] / 256;
183 					if (delta[i] < 16)
184 						delta[i] = 16;
185 
186 					samp2[i] = samp1[i];
187 					samp1[i] = new;
188 				}
189 		}
190 
191 	}
192 
193 	return (outp * 2);
194 }
195