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