1 /*	$Id: lpcm.c,v 1.20 2007/09/19 13:22:10 toad32767 Exp $ */
2 
3 /*-
4  * Copyright (c) 2005, 2006, 2007 Marco Trillo
5  *
6  * Permission is hereby granted, free of charge, to any
7  * person obtaining a copy of this software and associated
8  * documentation files (the "Software"), to deal in the
9  * Software without restriction, including without limitation
10  * the rights to use, copy, modify, merge, publish,
11  * distribute, sublicense, and/or sell copies of the
12  * Software, and to permit persons to whom the Software is
13  * furnished to do so, subject to the following conditions:
14  *
15  * The above copyright notice and this permission notice
16  * shall be included in all copies or substantial portions of
17  * the Software.
18  *
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
20  * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
21  * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
22  * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
23  * OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
24  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
25  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
26  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27  */
28 
29 #define LIBAIFF 1
30 #include <libaiff/libaiff.h>
31 #include <libaiff/endian.h>
32 #include "private.h"
33 #include <stdio.h>
34 #include <string.h>
35 #include <stdlib.h>
36 
37 #ifdef HAVE_SYS_TYPES_H
38 #include <sys/types.h>
39 #endif
40 
41 void
lpcm_swap_samples(int segmentSize,int flags,void * from,void * to,int nsamples)42 lpcm_swap_samples(int segmentSize, int flags, void *from, void *to, int nsamples)
43 {
44 	register int n = nsamples;
45 	register int i;
46 	/* 8 bit */
47 	uint8_t *fubytes = (uint8_t *) from;
48 	uint8_t *ubytes = (uint8_t *) to;
49 	/* 16 bit */
50 	int16_t *fwords = (int16_t *) from;
51 	int16_t *words = (int16_t *) to;
52 	/* 32 bit */
53 	int32_t *fdwords = (int32_t *) from;
54 	int32_t *dwords = (int32_t *) to;
55 	/* 24 bit */
56 	uint8_t x, y, z;
57 
58 	/*
59 	 * Do we really need to do something?
60 	 */
61 	if (from == to && !(flags & LPCM_NEED_SWAP))
62 		return;
63 
64 	switch (segmentSize) {
65 	case 2:
66 		if (flags & LPCM_NEED_SWAP) {
67 			for (i = 0; i < n; ++i)
68 				words[i] = ARRANGE_ENDIAN_16(fwords[i]);
69 		} else {
70 			memmove(words, fwords, n << 1 /* n * 2 */);
71 		}
72 		break;
73 	case 3:
74 		if (flags & LPCM_NEED_SWAP) {
75 			n *= 3;
76 			for (i = 0; i < n; i += 3) {
77 				x = fubytes[i];
78 				y = fubytes[i + 1];
79 				z = fubytes[i + 2];
80 
81 				ubytes[i] = z;
82 				ubytes[i + 1] = y;
83 				ubytes[i + 2] = x;
84 			}
85 			n /= 3;
86 		} else {
87 			memmove(ubytes, fubytes, n * 3);
88 		}
89 		break;
90 	case 4:
91 		if (flags & LPCM_NEED_SWAP) {
92 			for (i = 0; i < n; ++i)
93 				dwords[i] = ARRANGE_ENDIAN_32(fdwords[i]);
94 		} else {
95 			memmove(dwords, fdwords, n << 2 /* n * 4 */);
96 		}
97 		break;
98 	}
99 
100 	return;
101 }
102 
103 static size_t
lpcm_read_lpcm(AIFF_Ref r,void * buffer,size_t len)104 lpcm_read_lpcm(AIFF_Ref r, void *buffer, size_t len)
105 {
106 	int n;
107 	uint32_t clen;
108 	size_t slen;
109 	size_t bytes_in;
110 	size_t bytesToRead;
111 
112 	n = (int) len;
113 	len -= n % r->segmentSize;
114 	n /= r->segmentSize;
115 
116 	slen = (size_t) (r->soundLen) - (size_t) (r->pos);
117 	bytesToRead = MIN(len, slen);
118 
119 	if (bytesToRead == 0)
120 		return 0;
121 
122 	bytes_in = fread(buffer, 1, bytesToRead, r->fd);
123 	if (bytes_in > 0)
124 		clen = (uint32_t) bytes_in;
125 	else
126 		clen = 0;
127 	r->pos += clen;
128 
129 	lpcm_swap_samples(r->segmentSize, r->flags, buffer, buffer, n);
130 
131 	return bytes_in;
132 }
133 
134 static int
lpcm_seek(AIFF_Ref r,uint64_t pos)135 lpcm_seek(AIFF_Ref r, uint64_t pos)
136 {
137 	long of;
138 	uint32_t b;
139 
140 	b = (uint32_t) pos * r->nChannels * r->segmentSize;
141 	if (b >= r->soundLen)
142 		return 0;
143 	of = (long) b;
144 
145 	if (fseek(r->fd, of, SEEK_CUR) < 0) {
146 		return -1;
147 	}
148 	r->pos = b;
149 	return 1;
150 }
151 
152 /*
153  * Dequantize LPCM (buffer) to floating point PCM (samples)
154  */
155 void
lpcm_dequant(int segmentSize,void * buffer,float * outSamples,int nSamples)156 lpcm_dequant(int segmentSize, void *buffer, float *outSamples, int nSamples)
157 {
158 	switch (segmentSize) {
159 		case 4:
160 		  {
161 			  int32_t *integers = (int32_t *) buffer;
162 
163 			  while (nSamples-- > 0)
164 				{
165 				  outSamples[nSamples] = (float) integers[nSamples] / 2147483648.0;
166 				}
167 			  break;
168 		  }
169 		case 3:
170 		  {
171 			  uint8_t *b = (uint8_t *) buffer;
172 			  int32_t integer;
173 			  int sgn;
174 
175 			  while (nSamples-- > 0)
176 				{
177 #ifdef WORDS_BIGENDIAN
178 				  sgn = b[0] & 0x80;
179 
180 				  integer = ((int32_t) b[0] << 16) +
181 					  ((int32_t) b[1] << 8) +
182 					  (int32_t) b[2];
183 #else
184 				  sgn = b[2] & 0x80;
185 
186 				  integer = ((int32_t) b[2] << 16) +
187 					  ((int32_t) b[1] << 8) +
188 					  (int32_t) b[0];
189 #endif /* WORDS_BIGENDIAN */
190 
191 				  if (sgn)
192 					{
193 					  /*
194 					   * sign propagation
195 					   * (host CPU must use two's complement ordering)
196 					   */
197 					  integer = (int32_t) (0xFF000000 | (uint32_t) integer);
198 					}
199 
200 				  outSamples[nSamples] = (float) integer / 8388608.0;
201 				  b += 3;
202 				}
203 			  break;
204 		  }
205 		case 2:
206 		  {
207 			  int16_t *integers = (int16_t *) buffer;
208 
209 			  while (nSamples-- > 0)
210 				{
211 				  outSamples[nSamples] = (float) integers[nSamples] / 32768.0;
212 				}
213 			  break;
214 		  }
215 		case 1:
216 		  {
217 			  int8_t *integers = (int8_t *) buffer;
218 
219 			  while (nSamples-- > 0)
220 				{
221 				  outSamples[nSamples] = (float) integers[nSamples] / 128.0;
222 				}
223 			  break;
224 		  }
225 	}
226 }
227 
228 static int
lpcm_read_float32(AIFF_Ref r,float * buffer,int nSamples)229 lpcm_read_float32(AIFF_Ref r, float *buffer, int nSamples)
230 {
231 	size_t len, slen, bytesToRead, bytes_in;
232 	uint32_t clen;
233 	int nSamplesRead;
234 
235 	len = (size_t) nSamples * r->segmentSize;
236 	slen = (size_t) (r->soundLen) - (size_t) (r->pos);
237 	bytesToRead = MIN(len, slen);
238 	if (bytesToRead == 0)
239 		return 0;
240 
241 	if (r->buffer2 == NULL || r->buflen2 < bytesToRead) {
242 		if (r->buffer2 != NULL)
243 			free(r->buffer2);
244 		r->buffer2 = malloc(bytesToRead);
245 		if (r->buffer2 == NULL) {
246 			r->buflen2 = 0;
247 			return 0;
248 		}
249 		r->buflen2 = bytesToRead;
250 	}
251 
252 	bytes_in = fread(r->buffer2, 1, bytesToRead, r->fd);
253 	if (bytes_in > 0)
254 		clen = (uint32_t) bytes_in;
255 	else
256 		clen = 0;
257 	r->pos += clen;
258 	nSamplesRead = (int) clen / (r->segmentSize);
259 
260 	lpcm_swap_samples(r->segmentSize, r->flags, r->buffer2, r->buffer2, nSamplesRead);
261 	lpcm_dequant(r->segmentSize, r->buffer2, buffer, nSamplesRead);
262 
263 	return nSamplesRead;
264 }
265 
266 
267 struct decoder lpcm = {
268 	AUDIO_FORMAT_LPCM,
269 	NULL,
270 	lpcm_read_lpcm,
271 	lpcm_read_float32,
272 	lpcm_seek,
273 	NULL
274 };
275 
276