1 /* $Id: aifx.c,v 1.24 2007/09/19 11:49:46 toad32767 Exp $ */
2
3 /*-
4 * Copyright (c) 2005, 2006 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 <stdio.h>
31 #include <string.h>
32 #include <stdlib.h>
33 #include <libaiff/libaiff.h>
34 #include <libaiff/endian.h>
35 #include "private.h"
36
37
38 int
init_aifx(AIFF_Ref r)39 init_aifx(AIFF_Ref r)
40 {
41 int bps, wSegmentSize;
42 double sRate;
43 uint8_t buffer[10];
44 uint32_t len;
45 CommonChunk p;
46 IFFType aFmt;
47
48 if (!find_iff_chunk(AIFF_COMM, r, &len))
49 return (-1);
50
51 if (len < 18)
52 return (-1);
53
54 if (fread(&(p.numChannels), 1, 2, r->fd) < 2 ||
55 fread(&(p.numSampleFrames), 1, 4, r->fd) < 4 ||
56 fread(&(p.sampleSize), 1, 2, r->fd) < 2 ||
57 fread(buffer, 1, 10, r->fd) < 10)
58 return (-1);
59
60 p.numChannels = ARRANGE_BE16(p.numChannels);
61 p.numSampleFrames = ARRANGE_BE32(p.numSampleFrames);
62 p.sampleSize = ARRANGE_BE16(p.sampleSize);
63 sRate = ieee754_read_extended(buffer);
64
65 r->nSamples = (uint64_t) (p.numSampleFrames);
66 r->nChannels = (int) p.numChannels;
67 r->samplingRate = sRate;
68 r->bitsPerSample = (int) p.sampleSize;
69
70 bps = (int) (p.sampleSize);
71 wSegmentSize = bps >> 3; /* bps / 8 */
72 if (bps & 7) /* if( bps % 8 != 0 ) */
73 ++wSegmentSize;
74 r->segmentSize = wSegmentSize;
75
76 if (len >= 22 && r->format == AIFF_TYPE_AIFC) {
77 if (fread(&aFmt, 1, 4, r->fd) < 4)
78 return (-1);
79 switch (aFmt) {
80 case AUDIO_FORMAT_LPCM: /* 'NONE' */
81 case AUDIO_FORMAT_lpcm: /* 'lpcm' (not standard) */
82 case AUDIO_FORMAT_twos: /* 'twos' */
83 aFmt = AUDIO_FORMAT_LPCM;
84 r->flags |= LPCM_BIG_ENDIAN;
85 break;
86
87 case AUDIO_FORMAT_ULAW: /* 'ULAW' */
88 case AUDIO_FORMAT_ulaw: /* 'ulaw' */
89 aFmt = AUDIO_FORMAT_ULAW;
90 r->segmentSize = 2;
91 r->bitsPerSample = 14;
92 break;
93
94 case AUDIO_FORMAT_ALAW: /* 'ALAW' */
95 case AUDIO_FORMAT_alaw: /* 'alaw' */
96 aFmt = AUDIO_FORMAT_ALAW;
97 r->segmentSize = 2;
98 r->bitsPerSample = 13;
99 break;
100
101 case AUDIO_FORMAT_sowt: /* 'sowt' */
102 aFmt = AUDIO_FORMAT_LPCM;
103 r->flags |= LPCM_LTE_ENDIAN;
104 break;
105
106 case AUDIO_FORMAT_FL32: /* 'FL32' */
107 case AUDIO_FORMAT_fl32: /* 'fl32' */
108 aFmt = AUDIO_FORMAT_FL32;
109 r->segmentSize = 4;
110 r->bitsPerSample = 32;
111 r->flags |= LPCM_BIG_ENDIAN;
112 break;
113
114 default:
115 aFmt = AUDIO_FORMAT_UNKNOWN;
116 }
117 r->audioFormat = aFmt;
118
119 /*
120 * Read the description string if
121 * the F_NOTSEEKABLE flag is set
122 */
123 if (len > 22 && (r->flags & F_NOTSEEKABLE)) {
124 int count = PASCALInGetLength(r->fd);
125 while (count-- > 0) {
126 if (getc(r->fd) < 0)
127 return (-1);
128 }
129 }
130 } else {
131 r->audioFormat = AUDIO_FORMAT_LPCM;
132 r->flags |= LPCM_BIG_ENDIAN;
133 }
134
135 return (1);
136 }
137
138 int
read_aifx_marker(AIFF_Ref r,int * id,uint64_t * position,char ** name)139 read_aifx_marker(AIFF_Ref r, int *id, uint64_t * position, char **name)
140 {
141 uint16_t nMarkers;
142 uint32_t cklen;
143 int n;
144 Marker m;
145
146 if (r->stat != 2) {
147 if (!find_iff_chunk(AIFF_MARK, r, &cklen))
148 return (0);
149 if (cklen < 2)
150 return (-1);
151 if (fread(&nMarkers, 1, 2, r->fd) < 2)
152 return (-1);
153 nMarkers = ARRANGE_BE16(nMarkers);
154 r->nMarkers = (int) nMarkers;
155 r->markerPos = 0;
156 r->stat = 2;
157 }
158 n = r->nMarkers;
159 if (r->markerPos >= n) {
160 r->stat = 0;
161 return (0);
162 }
163 if (fread(&(m.id), 1, 2, r->fd) < 2 ||
164 fread(&(m.position), 1, 4, r->fd) < 4)
165 return (-1);
166 m.id = ARRANGE_BE16(m.id);
167 m.position = ARRANGE_BE32(m.position);
168
169 if (name != NULL) {
170 int l;
171 *name = PASCALInRead(r->fd, &l);
172 } else {
173 int l = PASCALInGetLength(r->fd);
174
175 if (!(r->flags & F_NOTSEEKABLE)) {
176 if (fseek(r->fd, (long) l, SEEK_CUR) < 0)
177 return (-1);
178 } else {
179 while (l-- > 0) {
180 if (getc(r->fd) < 0)
181 return (-1);
182 }
183 }
184 }
185
186 *id = (int) m.id;
187 *position = (uint64_t) (m.position);
188 ++(r->markerPos);
189
190 return (1);
191 }
192
193 int
get_aifx_instrument(AIFF_Ref r,Instrument * inpi)194 get_aifx_instrument(AIFF_Ref r, Instrument * inpi)
195 {
196 int i;
197 uint32_t cklen;
198 int8_t buffer[6];
199 int16_t gain;
200 AIFFLoop sustainLoop, releaseLoop;
201 int ids[4];
202 int id;
203 uint32_t pos;
204 uint32_t positions[4];
205 char *name;
206
207 if (!find_iff_chunk(AIFF_INST, r, &cklen))
208 return (0);
209 if (cklen != 20)
210 return (0);
211 if (fread(buffer, 1, 6, r->fd) < 6)
212 return (0);
213 if (fread(&gain, 1, 2, r->fd) < 2)
214 return (0);
215 if (fread(&sustainLoop, 1, 6, r->fd) < 6)
216 return (0);
217 if (fread(&releaseLoop, 1, 6, r->fd) < 6)
218 return (0);
219
220 inpi->baseNote = buffer[0];
221 inpi->detune = buffer[1];
222 inpi->lowNote = buffer[2];
223 inpi->highNote = buffer[3];
224 inpi->lowVelocity = buffer[4];
225 inpi->highVelocity = buffer[5];
226 inpi->gain = ARRANGE_BE16(gain);
227 inpi->sustainLoop.playMode = ARRANGE_BE16(sustainLoop.playMode);
228 inpi->releaseLoop.playMode = ARRANGE_BE16(releaseLoop.playMode);
229
230 /* Read the MarkerId`s for the positions */
231 ids[0] = (int) (ARRANGE_BE16(sustainLoop.beginLoop));
232 ids[1] = (int) (ARRANGE_BE16(sustainLoop.endLoop));
233 ids[2] = (int) (ARRANGE_BE16(releaseLoop.beginLoop));
234 ids[3] = (int) (ARRANGE_BE16(releaseLoop.endLoop));
235
236 /* Read the positions */
237 memset(positions, 0, 16 /* 4*4 */ ); /* by default set them to 0 */
238 for (;;) {
239 uint64_t p;
240 if (read_aifx_marker(r, &id, &p, &name) < 1) {
241 break;
242 }
243 pos = (uint32_t) p;
244 if (name)
245 free(name);
246 for (i = 0; i < 4; ++i) {
247 if (id == ids[i])
248 positions[i] = pos;
249 }
250 }
251
252 inpi->sustainLoop.beginLoop = (uint64_t) (positions[0]);
253 inpi->sustainLoop.endLoop = (uint64_t) (positions[1]);
254 inpi->releaseLoop.beginLoop = (uint64_t) (positions[2]);
255 inpi->releaseLoop.endLoop = (uint64_t) (positions[3]);
256
257 return (1);
258 }
259
260 int
do_aifx_prepare(AIFF_Ref r)261 do_aifx_prepare(AIFF_Ref r)
262 {
263 uint32_t clen;
264 SoundChunk s;
265 long of;
266 ASSERT(sizeof(SoundChunk) == 8);
267
268 if (!find_iff_chunk(AIFF_SSND, r, &clen))
269 return (-1);
270 if (clen < 8)
271 return (-1);
272 clen -= 8;
273 r->soundLen = (uint64_t) clen;
274 r->pos = 0;
275 if (fread(&s, 1, 8, r->fd) < 8) {
276 return (-1);
277 }
278 s.offset = ARRANGE_BE32(s.offset);
279 if (s.offset)
280 r->soundLen -= (uint64_t) (s.offset);
281 of = (long) s.offset;
282
283 /*
284 * FIXME: What is s.blockSize?
285 */
286 if (of > 0) {
287 if (!(r->flags & F_NOTSEEKABLE)) {
288 if (fseek(r->fd, of, SEEK_CUR) < 0)
289 return (-1);
290 } else {
291 while (of-- > 0) {
292 if (getc(r->fd) < 0)
293 return (-1);
294 }
295 }
296 }
297
298 return (1);
299 }
300
301 struct s_encName {
302 IFFType enc;
303 const char *name;
304 };
305 #define kNumEncs 6
306 static struct s_encName encNames[kNumEncs] = {
307 {AUDIO_FORMAT_LPCM, "Signed integer (big-endian) linear PCM"},
308 {AUDIO_FORMAT_twos, "Signed integer (big-endian) linear PCM"},
309 {AUDIO_FORMAT_sowt, "Signed integer (little-endian) linear PCM"},
310 {AUDIO_FORMAT_FL32, "Signed IEEE-754 single precision (big-endian) "
311 "floating point PCM"},
312 {AUDIO_FORMAT_ULAW, "Signed 8-bit mu-Law floating point PCM"},
313 {AUDIO_FORMAT_ALAW, "Signed 8-bit A-Law floating point PCM"}
314 };
315
316 char *
get_aifx_enc_name(IFFType enc)317 get_aifx_enc_name (IFFType enc)
318 {
319 int i;
320 struct s_encName* e = encNames;
321
322 for (i = 0; i < kNumEncs; ++i) {
323 if (e[i].enc == enc)
324 return (char *) (e[i].name);
325 }
326
327 return (NULL);
328 }
329
330