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