1 /*	$Id: libaiff.c,v 1.38 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 <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 static struct decoder* decoders[] = {
38 	&lpcm,
39 	&ulaw,
40 	&alaw,
41 	&float32,
42 	NULL
43 };
44 
45 static AIFF_Ref AIFF_ReadOpen (const char *, int);
46 static AIFF_Ref AIFF_WriteOpen (const char *, int);
47 static void AIFF_ReadClose (AIFF_Ref);
48 static int AIFF_WriteClose (AIFF_Ref);
49 static void* InitBuffer (AIFF_Ref, size_t);
50 static void DestroyBuffer (AIFF_Ref);
51 static int DoWriteSamples (AIFF_Ref, void *, size_t, int);
52 static int Prepare (AIFF_Ref);
53 static void Unprepare (AIFF_Ref);
54 static struct decoder* FindDecoder (IFFType);
55 
56 AIFF_Ref
AIFF_OpenFile(const char * file,int flags)57 AIFF_OpenFile(const char *file, int flags)
58 {
59 	AIFF_Ref ref = NULL;
60 
61 	if (flags & F_RDONLY) {
62 		ref = AIFF_ReadOpen(file, flags);
63 	} else if (flags & F_WRONLY) {
64 		ref = AIFF_WriteOpen(file, flags);
65 	}
66 
67 	return ref;
68 }
69 
70 int
AIFF_CloseFile(AIFF_Ref ref)71 AIFF_CloseFile(AIFF_Ref ref)
72 {
73 	int r;
74 
75 	if (!ref)
76 		return -1;
77 	if (ref->flags & F_RDONLY) {
78 		AIFF_ReadClose(ref);
79 		r = 1;
80 	} else if (ref->flags & F_WRONLY) {
81 		r = AIFF_WriteClose(ref);
82 	} else {
83 		r = -1;
84 	}
85 
86 	return r;
87 }
88 
89 static AIFF_Ref
AIFF_ReadOpen(const char * file,int flags)90 AIFF_ReadOpen(const char *file, int flags)
91 {
92 	AIFF_Ref r;
93 	IFFHeader hdr;
94 
95 	r = malloc(kAIFFRefSize);
96 	if (!r) {
97 		return NULL;
98 	}
99 	r->fd = fopen(file, "rb");
100 	if (r->fd == NULL) {
101 		free(r);
102 		return NULL;
103 	}
104 	r->flags = F_RDONLY | flags;
105 	if (fread(&hdr, 1, 4, r->fd) < 4) {
106 		fclose(r->fd);
107 		free(r);
108 		return NULL;
109 	}
110 	switch (hdr.hid) {
111 	case AIFF_TYPE_IFF:
112 		/* Continue reading the IFF header */
113 		if (fread(&(hdr.len), 1, 8, r->fd) < 8) {
114 			fclose(r->fd);
115 			free(r);
116 			return NULL;
117 		}
118 		if (hdr.len == 0) {
119 			fclose(r->fd);
120 			free(r);
121 			return NULL;
122 		}
123 		/*
124  		 * Check the format type (AIFF or AIFC)
125  		 */
126 		r->format = hdr.fid;
127 		switch (r->format) {
128 		case AIFF_TYPE_AIFF:
129 		case AIFF_TYPE_AIFC:
130 			break;
131 		default:
132 			fclose(r->fd);
133 			free(r);
134 			return NULL;
135 		}
136 
137 		if (init_aifx(r) < 1) {
138 			fclose(r->fd);
139 			free(r);
140 			return NULL;
141 		}
142 		break;
143 	default:
144 		fclose(r->fd);
145 		free(r);
146 		return NULL;
147 	}
148 
149 	r->stat = 0;
150 	r->buffer = NULL;
151 	r->buflen = 0;
152 
153 	return r;
154 }
155 
156 char *
AIFF_GetAttribute(AIFF_Ref r,IFFType attrib)157 AIFF_GetAttribute(AIFF_Ref r, IFFType attrib)
158 {
159 	if (!r || !(r->flags & F_RDONLY))
160 		return NULL;
161 	Unprepare(r);
162 
163 	switch (r->format) {
164 	case AIFF_TYPE_AIFF:
165 	case AIFF_TYPE_AIFC:
166 		return get_iff_attribute(r, attrib);
167 	default:
168 		return NULL;
169 	}
170 	return NULL;
171 }
172 
173 int
AIFF_ReadMarker(AIFF_Ref r,int * id,uint64_t * pos,char ** name)174 AIFF_ReadMarker(AIFF_Ref r, int *id, uint64_t * pos, char **name)
175 {
176 	if (!r || !(r->flags & F_RDONLY))
177 		return -1;
178 	Unprepare(r);
179 
180 	switch (r->format) {
181 	case AIFF_TYPE_AIFF:
182 	case AIFF_TYPE_AIFC:
183 		return read_aifx_marker(r, id, pos, name);
184 	default:
185 		return 0;
186 	}
187 	return 0;
188 }
189 
190 int
AIFF_GetInstrumentData(AIFF_Ref r,Instrument * i)191 AIFF_GetInstrumentData(AIFF_Ref r, Instrument * i)
192 {
193 	if (!r || !(r->flags & F_RDONLY))
194 		return (-1);
195 	Unprepare(r);
196 
197 	switch (r->format) {
198 	case AIFF_TYPE_AIFF:
199 	case AIFF_TYPE_AIFC:
200 		return get_aifx_instrument(r, i);
201 	default:
202 		return (0);
203 	}
204 }
205 
206 int
AIFF_GetAudioFormat(AIFF_Ref r,uint64_t * nSamples,int * channels,double * samplingRate,int * bitsPerSample,int * segmentSize)207 AIFF_GetAudioFormat(AIFF_Ref r, uint64_t * nSamples, int *channels,
208     double *samplingRate, int *bitsPerSample, int *segmentSize)
209 {
210 	if (!r || !(r->flags & F_RDONLY))
211 		return (-1);
212 
213 	if (nSamples)
214 		*nSamples = r->nSamples;
215 	if (channels)
216 		*channels = r->nChannels;
217 	if (samplingRate)
218 		*samplingRate = r->samplingRate;
219 	if (bitsPerSample)
220 		*bitsPerSample = r->bitsPerSample;
221 	if (segmentSize)
222 		*segmentSize = r->segmentSize;
223 
224 	return (1);
225 }
226 
227 static int
Prepare(AIFF_Ref r)228 Prepare (AIFF_Ref r)
229 {
230 	int res;
231 	struct decoder *dec;
232 
233 	if (r->stat != 1) {
234 		switch (r->format) {
235 		case AIFF_TYPE_AIFF:
236 		case AIFF_TYPE_AIFC:
237 			res = do_aifx_prepare(r);
238 			break;
239 		default:
240 			res = -1;
241 		}
242 		if (res < 1)
243 			return res;
244 		if ((dec = FindDecoder(r->audioFormat)) == NULL)
245 			return -1;
246 		if (dec->construct) {
247 			if ((res = dec->construct(r)) < 1)
248 				return res;
249 		}
250 
251 		r->decoder = dec;
252 		r->stat = 1;
253 	}
254 
255 	return 1;
256 }
257 
258 static void
Unprepare(AIFF_Ref r)259 Unprepare (AIFF_Ref r)
260 {
261 	struct decoder *dec;
262 
263 	if (r->stat == 1) {
264 		dec = r->decoder;
265 		if (dec->delete)
266 			dec->delete(r);
267 	}
268 	r->stat = 0;
269 }
270 
271 static struct decoder*
FindDecoder(IFFType fmt)272 FindDecoder (IFFType fmt)
273 {
274 	struct decoder **dd, *d;
275 
276 	for (dd = decoders; (d = *dd) != NULL; ++dd)
277 	  {
278 		if (d->fmt == fmt)
279 			return d;
280 	  }
281 
282 	return NULL;
283 }
284 
285 size_t
AIFF_ReadSamples(AIFF_Ref r,void * buffer,size_t len)286 AIFF_ReadSamples(AIFF_Ref r, void *buffer, size_t len)
287 {
288 	struct decoder *dec;
289 
290 	if (!r || !(r->flags & F_RDONLY) || Prepare(r) < 1)
291 		return 0;
292 	dec = r->decoder;
293 
294 	return dec->read_lpcm(r, buffer, len);
295 }
296 
297 int
AIFF_ReadSamplesFloat(AIFF_Ref r,float * buffer,int nSamplePoints)298 AIFF_ReadSamplesFloat(AIFF_Ref r, float *buffer, int nSamplePoints)
299 {
300 	int res;
301 	struct decoder *dec;
302 
303 	if (!r || !(r->flags & F_RDONLY))
304 		return -1;
305 	if (nSamplePoints % (r->nChannels) != 0)
306 		return 0;
307 	if ((res = Prepare(r)) < 1)
308 		return res;
309 	dec = r->decoder;
310 
311 	return dec->read_float32(r, buffer, nSamplePoints);
312 }
313 
314 int
AIFF_Seek(AIFF_Ref r,uint64_t framePos)315 AIFF_Seek(AIFF_Ref r, uint64_t framePos)
316 {
317 	int res = 0;
318 	struct decoder *dec;
319 
320 	if (!r || !(r->flags & F_RDONLY))
321 		return -1;
322 	if (r->flags & F_NOTSEEKABLE)
323 		return -1;
324 	Unprepare(r);
325 	if ((res = Prepare(r)) < 1)
326 		return res;
327 	dec = r->decoder;
328 
329 	return dec->seek(r, framePos);
330 }
331 
332 int
AIFF_ReadSamples32Bit(AIFF_Ref r,int32_t * samples,int nSamplePoints)333 AIFF_ReadSamples32Bit(AIFF_Ref r, int32_t * samples, int nSamplePoints)
334 {
335 	int n = nSamplePoints;
336 	void *buffer;
337 	int i, j;
338 	size_t h;
339 	size_t len;
340 	int segmentSize;
341 	int32_t *dwords;
342 	int16_t *words;
343 	int8_t *sbytes;
344 	uint8_t *inbytes;
345 	uint8_t *outbytes;
346 	uint8_t x, y, z;
347 
348 	if (!r || !(r->flags & F_RDONLY))
349 		return -1;
350 	if (n % (r->nChannels) != 0)
351 		return 0;
352 
353 	if (n < 1 || r->segmentSize == 0) {
354 		if (r->buffer) {
355 			free(r->buffer);
356 			r->buffer = NULL;
357 			r->buflen = 0;
358 		}
359 		return -1;
360 	}
361 	segmentSize = r->segmentSize;
362 	len = (size_t) n * segmentSize;
363 
364 	if ((r->buflen) < len) {
365 		if (r->buffer)
366 			free(r->buffer);
367 		r->buffer = malloc(len);
368 		if (!(r->buffer)) {
369 			return -1;
370 		}
371 		r->buflen = len;
372 	}
373 	buffer = r->buffer;
374 
375 	h = AIFF_ReadSamples(r, buffer, len);
376 	if (h < (size_t) segmentSize) {
377 		free(r->buffer);
378 		r->buffer = NULL;
379 		r->buflen = 0;
380 		return 0;
381 	}
382 	n = (int) h;
383 	if (n % segmentSize != 0) {
384 		free(r->buffer);
385 		r->buffer = NULL;
386 		r->buflen = 0;
387 		return -1;
388 	}
389 	n /= segmentSize;
390 
391 	switch (segmentSize) {
392 	case 4:
393 		dwords = (int32_t *) buffer;
394 		for (i = 0; i < n; ++i)
395 			samples[i] = dwords[i];
396 		break;
397 	case 3:
398 		inbytes = (uint8_t *) buffer;
399 		outbytes = (uint8_t *) samples;
400 		n <<= 2;	/* n *= 4 */
401 		j = 0;
402 
403 		for (i = 0; i < n; i += 4) {
404 			x = inbytes[j++];
405 			y = inbytes[j++];
406 			z = inbytes[j++];
407 #ifdef WORDS_BIGENDIAN
408 			outbytes[i] = x;
409 			outbytes[i + 1] = y;
410 			outbytes[i + 2] = z;
411 			outbytes[i + 3] = 0;
412 #else
413 			outbytes[i] = 0;
414 			outbytes[i + 1] = x;
415 			outbytes[i + 2] = y;
416 			outbytes[i + 3] = z;
417 #endif
418 		}
419 
420 		n >>= 2;
421 		break;
422 	case 2:
423 		words = (int16_t *) buffer;
424 		for (i = 0; i < n; ++i) {
425 			samples[i] = (int32_t) (words[i]) << 16;
426 		}
427 		break;
428 	case 1:
429 		sbytes = (int8_t *) buffer;
430 		for (i = 0; i < n; ++i) {
431 			samples[i] = (int32_t) (sbytes[i]) << 24;
432 		}
433 		break;
434 	}
435 
436 	return n;
437 }
438 
439 
440 static void
AIFF_ReadClose(AIFF_Ref r)441 AIFF_ReadClose(AIFF_Ref r)
442 {
443 	if (r->buffer)
444 		free(r->buffer);
445 	if (r->buffer2)
446 		free(r->buffer2);
447 	Unprepare(r);
448 	fclose(r->fd);
449 	free(r);
450 	return;
451 }
452 
453 static AIFF_Ref
AIFF_WriteOpen(const char * file,int flags)454 AIFF_WriteOpen(const char *file, int flags)
455 {
456 	AIFF_Ref w;
457 	IFFHeader hdr;
458 	ASSERT(sizeof(IFFHeader) == 12);
459 
460 	w = malloc(kAIFFRefSize);
461 	if (!w) {
462 err0:
463 		return NULL;
464 	}
465 
466 	/*
467 	 * Simultaneous open for reading & writing
468 	 */
469 	w->fd = fopen(file, "w+b");
470 	if (w->fd == NULL) {
471 err1:
472 		free(w);
473 		goto err0;
474 	}
475 	hdr.hid = ARRANGE_BE32(AIFF_FORM);
476 	w->len = 4;
477 	hdr.len = ARRANGE_BE32(4);
478 	if (flags & F_AIFC)
479 		hdr.fid = ARRANGE_BE32(AIFF_AIFC);
480 	else
481 		hdr.fid = ARRANGE_BE32(AIFF_AIFF);
482 
483 	if (fwrite(&hdr, 1, 12, w->fd) < 12) {
484 err2:
485 		fclose(w->fd);
486 		goto err1;
487 	}
488 	w->stat = 0;
489 	w->segmentSize = 0;
490 	w->buffer = NULL;
491 	w->buflen = 0;
492 	w->tics = 0;
493 
494 	/*
495 	 * If writing AIFF-C, write the required FVER chunk
496 	 */
497 	if (flags & F_AIFC) {
498 		IFFChunk chk;
499 		uint32_t vers;
500 		ASSERT(sizeof(IFFChunk) == 8);
501 
502 		chk.id = ARRANGE_BE32(AIFF_FVER);
503 		chk.len = ARRANGE_BE32(4);
504 		vers = ARRANGE_BE32(AIFC_STD_DRAFT_082691);
505 
506 		if (fwrite(&chk, 1, 8, w->fd) < 8 ||
507 		    fwrite(&vers, 1, 4, w->fd) < 4) {
508 			goto err2;
509 		}
510 
511 		w->len += 12;
512 
513 		/*
514 		 * If no endianness specified for AIFF-C,
515 		 * default to big endian
516 		 */
517 		if (!(flags & (LPCM_LTE_ENDIAN | LPCM_BIG_ENDIAN))) {
518 			flags |= LPCM_BIG_ENDIAN;
519 		}
520 	} else {
521 		/*
522 		 * If writing regular AIFF, make sure we
523 		 * write big-endian data
524 		 */
525 		flags &= ~LPCM_LTE_ENDIAN;
526 		flags |= LPCM_BIG_ENDIAN;
527 	}
528 
529 	w->flags = F_WRONLY | flags;
530 
531 	return w;
532 }
533 
534 int
AIFF_SetAttribute(AIFF_Ref w,IFFType attr,char * value)535 AIFF_SetAttribute(AIFF_Ref w, IFFType attr, char *value)
536 {
537 	if (!w || !(w->flags & F_WRONLY))
538 		return -1;
539 	return set_iff_attribute(w, attr, value);
540 }
541 
542 int
AIFF_CloneAttributes(AIFF_Ref w,AIFF_Ref r,int cloneMarkers)543 AIFF_CloneAttributes(AIFF_Ref w, AIFF_Ref r, int cloneMarkers)
544 {
545 	int rval, ret;
546 	int doneReadingMarkers;
547 
548 	if (!w || !(w->flags & F_WRONLY))
549 		return -1;
550 
551 	/*
552 	 * first of all, clone the IFF attributes
553 	 */
554 	rval = clone_iff_attributes(w, r);
555 
556 	doneReadingMarkers = !cloneMarkers;
557 	if (!doneReadingMarkers) {
558 		int mMarkerId;
559 		uint64_t mMarkerPos;
560 		char *mMarkerName;
561 
562 		if ((ret = AIFF_StartWritingMarkers(w)) < 1)
563 			return ret;
564 
565 		do {
566 			if (AIFF_ReadMarker(r, &mMarkerId, &mMarkerPos, &mMarkerName) < 1)
567 				doneReadingMarkers = 1;
568 			else {
569 				ret = AIFF_WriteMarker(w, mMarkerPos, mMarkerName);
570 				rval = (rval > 0 ? ret : rval); /* preserve previous errors */
571 			}
572 		} while (!doneReadingMarkers);
573 
574 		if ((ret = AIFF_EndWritingMarkers(w)) < 1)
575 			return ret;
576 	}
577 
578 	return rval;
579 }
580 
581 int
AIFF_SetAudioFormat(AIFF_Ref w,int channels,double sRate,int bitsPerSample)582 AIFF_SetAudioFormat(AIFF_Ref w, int channels, double sRate, int bitsPerSample)
583 {
584 	uint8_t buffer[10];
585 	CommonChunk c;
586 	IFFChunk chk;
587 	IFFType enc;
588 	uint32_t ckLen = 18;
589 	char* encName = NULL;
590 	ASSERT(sizeof(IFFChunk) == 8);
591 
592 	if (!w || !(w->flags & F_WRONLY))
593 		return -1;
594 	if (w->stat != 0)
595 		return 0;
596 
597 	if (w->flags & F_AIFC) {
598 		/*
599 		 * On AIFF-C we need to write
600 		 * the encoding plus a description string
601 		 * in PASCAL-style format
602 		 */
603 		ckLen += 4;
604 		if (w->flags & LPCM_LTE_ENDIAN)
605 			enc = AUDIO_FORMAT_sowt;
606 		else
607 			enc = AUDIO_FORMAT_LPCM;
608 
609 		encName = get_aifx_enc_name(enc);
610 		ckLen += PASCALOutGetLength(encName);
611 	}
612 
613 	chk.id = ARRANGE_BE32(AIFF_COMM);
614 	chk.len = ARRANGE_BE32(ckLen);
615 
616 	if (fwrite(&chk, 1, 8, w->fd) < 8) {
617 		return -1;
618 	}
619 	/* Fill in the chunk */
620 	c.numChannels = (uint16_t) channels;
621 	c.numChannels = ARRANGE_BE16(c.numChannels);
622 	c.numSampleFrames = 0;
623 	c.sampleSize = (uint16_t) bitsPerSample;
624 	c.sampleSize = ARRANGE_BE16(c.sampleSize);
625 	ieee754_write_extended(sRate, buffer);
626 
627 	/*
628 	 * Write out the data.
629 	 * Write each independent field separately,
630 	 * since sizeof(CommonChunk) % 2 != 0,
631 	 * so aligning may occur and insert some
632 	 * zeros between our fields!
633 	 */
634 	if (fwrite(&(c.numChannels), 1, 2, w->fd) < 2
635 	    || fwrite(&(c.numSampleFrames), 1, 4, w->fd) < 4
636 	    || fwrite(&(c.sampleSize), 1, 2, w->fd) < 2
637 	    || fwrite(buffer, 1, 10, w->fd) < 10) {
638 		return -1;
639 	}
640 
641 	/*
642 	 * On AIFF-C, write the encoding + encstring
643 	 * (encstring is a PASCAL string)
644 	 */
645 	if (w->flags & F_AIFC) {
646 		if (fwrite(&enc, 1, 4, w->fd) != 4)
647 			return -1;
648 		if (PASCALOutWrite(w->fd, encName) < 2)
649 			return -1;
650 	}
651 
652 	/*
653 	 * We need to return here later
654 	 * (to update the 'numSampleFrames'),
655 	 * so store the current writing position
656 	 *
657 	 * ( note that w->len is total file length - 8 ,
658 	 * so we need to add 8 to get a valid offset ).
659 	 */
660 	w->len += 8;
661 	w->commonOffSet = w->len;
662 	w->len += ckLen;
663 	w->segmentSize = bitsPerSample >> 3;
664 	if (bitsPerSample & 7)
665 		++(w->segmentSize);
666 	w->stat = 1;
667 
668 	return 1;
669 }
670 
671 int
AIFF_StartWritingSamples(AIFF_Ref w)672 AIFF_StartWritingSamples(AIFF_Ref w)
673 {
674 	IFFChunk chk;
675 	SoundChunk s;
676 	ASSERT(sizeof(SoundChunk) == 8);
677 
678 	if (!w || !(w->flags & F_WRONLY))
679 		return -1;
680 	if (w->stat != 1)
681 		return 0;
682 
683 	chk.id = ARRANGE_BE32(AIFF_SSND);
684 	chk.len = ARRANGE_BE32(8);
685 
686 	if (fwrite(&chk, 1, 8, w->fd) < 8) {
687 		return -1;
688 	}
689 	/*
690 	 * We don`t use these values
691 	 */
692 	s.offset = 0;
693 	s.blockSize = 0;
694 
695 	if (fwrite(&s, 1, 8, w->fd) < 8) {
696 		return -1;
697 	}
698 	w->len += 8;
699 	w->soundOffSet = w->len;
700 	w->len += 8;
701 	w->sampleBytes = 0;
702 	w->stat = 2;
703 
704 	return 1;
705 }
706 
707 static void *
InitBuffer(AIFF_Ref w,size_t len)708 InitBuffer(AIFF_Ref w, size_t len)
709 {
710 	if (w->buflen < len) {
711 modsize:
712 		w->tics = 0;
713 
714 		if (w->buffer)
715 			free(w->buffer);
716 		w->buffer = malloc(len);
717 
718 		if (!(w->buffer)) {
719 			w->buflen = 0;
720 			return NULL;
721 		}
722 		w->buflen = len;
723 
724 	} else if (w->buflen > len) {
725 		if (++(w->tics) == 3)
726 			goto modsize;
727 	}
728 	return (w->buffer);
729 }
730 
731 static void
DestroyBuffer(AIFF_Ref w)732 DestroyBuffer(AIFF_Ref w)
733 {
734 	if (w->buffer)
735 		free(w->buffer);
736 
737 	w->buffer = 0;
738 	w->buflen = 0;
739 	w->tics = 0;
740 
741 	return;
742 }
743 
744 static int
DoWriteSamples(AIFF_Ref w,void * samples,size_t len,int readOnlyBuf)745 DoWriteSamples(AIFF_Ref w, void *samples, size_t len, int readOnlyBuf)
746 {
747 	int n;
748 	uint32_t sampleBytes;
749 	void *buffer;
750 
751 	if (!w || !(w->flags & F_WRONLY))
752 		return -1;
753 	if (w->stat != 2)
754 		return 0;
755 
756 	n = (int) len;
757 	if (n % (w->segmentSize) != 0)
758 		return 0;
759 	n /= w->segmentSize;
760 
761 	if (readOnlyBuf) {
762 		buffer = InitBuffer(w, len);
763 		if (buffer == NULL)
764 			return -1;
765 	} else {
766 		buffer = samples;
767 	}
768 
769 	lpcm_swap_samples(w->segmentSize, w->flags, samples, buffer, n);
770 
771 	if (fwrite(buffer, 1, len, w->fd) < len) {
772 		return -1;
773 	}
774 	sampleBytes = (uint32_t) len;
775 	w->sampleBytes += sampleBytes;
776 	w->len += sampleBytes;
777 
778 	return 1;
779 }
780 
781 int
AIFF_WriteSamples(AIFF_Ref w,void * samples,size_t len)782 AIFF_WriteSamples(AIFF_Ref w, void *samples, size_t len)
783 {
784 	return DoWriteSamples(w, samples, len, 1);
785 }
786 
787 
788 int
AIFF_WriteSamples32Bit(AIFF_Ref w,int32_t * samples,int nsamples)789 AIFF_WriteSamples32Bit(AIFF_Ref w, int32_t * samples, int nsamples)
790 {
791 	register int i, j;
792 	register int n = nsamples;
793 	void *buffer;
794 	size_t len;
795 	int32_t cursample;
796 	int16_t *words;
797 	int8_t *sbytes;
798 	uint8_t *inbytes, *outbytes;
799 
800 	if (!w || !(w->flags & F_WRONLY))
801 		return -1;
802 	if (w->stat != 2 || w->segmentSize == 0 || n < 1) {
803 		return -1;
804 	}
805 	len = (size_t) n * w->segmentSize;
806 
807 	buffer = InitBuffer(w, len);
808 	if (!buffer)
809 		return -1;
810 
811 	switch (w->segmentSize) {
812 	case 4:
813 		memcpy(buffer, samples, n << 2); /* n * 4 */
814 		break;
815 	case 3:
816 		inbytes = (uint8_t *) samples;
817 		outbytes = (uint8_t *) buffer;
818 		j = 0;
819 		n *= 3;
820 		for (i = 0; i < n; i += 3) {
821 #ifdef WORDS_BIGENDIAN
822 			outbytes[i + 0] = inbytes[j++];
823 			outbytes[i + 1] = inbytes[j++];
824 			outbytes[i + 2] = inbytes[j++];
825 			j++;
826 #else
827 			j++;
828 			outbytes[i + 0] = inbytes[j++];
829 			outbytes[i + 1] = inbytes[j++];
830 			outbytes[i + 2] = inbytes[j++];
831 #endif
832 		}
833 		n /= 3;
834 		break;
835 	case 2:
836 		words = (int16_t *) buffer;
837 		for (i = 0; i < n; ++i) {
838 			cursample = samples[i] >> 16;
839 			words[i] = (int16_t) cursample;
840 		}
841 		break;
842 	case 1:
843 		sbytes = (int8_t *) buffer;
844 		for (i = 0; i < n; ++i) {
845 			cursample = samples[i] >> 24;
846 			sbytes[i] = (int8_t) cursample;
847 		}
848 		break;
849 	}
850 
851 	return DoWriteSamples(w, buffer, len, 0);
852 }
853 
854 /*
855  * WARNING: do not mix fread() & fwrite(), use fseek() before !
856  */
857 int
AIFF_EndWritingSamples(AIFF_Ref w)858 AIFF_EndWritingSamples(AIFF_Ref w)
859 {
860 	uint32_t segment;
861 	long of;
862 	IFFChunk chk;
863 	CommonChunk c;
864 	uint32_t len, curpos;
865 
866 	if (!w || !(w->flags & F_WRONLY))
867 		return -1;
868 	if (w->stat != 2)
869 		return 0;
870 
871 	DestroyBuffer(w);
872 	if (w->sampleBytes & 1) {
873 		fputc(0, w->fd);
874 		++(w->sampleBytes);
875 		++(w->len);
876 	}
877 	/*
878 	 * XXX: AIFF files are 32-bit
879 	 */
880 	curpos = (uint32_t) (w->len) + 8;
881 
882 	of = (long) (w->soundOffSet);
883 	if (fseek(w->fd, of, SEEK_SET) < 0) {
884 		return -1;
885 	}
886 	if (fread(&chk, 1, 8, w->fd) < 8) {
887 		return -1;
888 	}
889 	if (chk.id != ARRANGE_BE32(AIFF_SSND)) {
890 		return -1;
891 	}
892 	len = ARRANGE_BE32(chk.len);
893 	len += (uint32_t) (w->sampleBytes);
894 	chk.len = ARRANGE_BE32(len);
895 
896 	if (fseek(w->fd, of, SEEK_SET) < 0) {
897 		return -1;
898 	}
899 	if (fwrite(&chk, 1, 8, w->fd) < 8) {
900 		return -1;
901 	}
902 	of = (long) (w->commonOffSet);
903 	if (fseek(w->fd, of, SEEK_SET) < 0) {
904 		return -1;
905 	}
906 	if (fread(&chk, 1, 8, w->fd) < 8) {
907 		return -1;
908 	}
909 
910 	if (chk.id != ARRANGE_BE32(AIFF_COMM)) {
911 		return -1;
912 	}
913 	if (fread(&(c.numChannels), 1, 2, w->fd) < 2
914 	    || fread(&(c.numSampleFrames), 1, 4, w->fd) < 4
915 	    || fread(&(c.sampleSize), 1, 2, w->fd) < 2) {
916 		return -1;
917 	}
918 	/* Correct the data of the chunk */
919 	c.numChannels = ARRANGE_BE16(c.numChannels);
920 	c.sampleSize = ARRANGE_BE16(c.sampleSize);
921 	segment = w->segmentSize;
922 
923 	c.numSampleFrames = ((uint32_t) (w->sampleBytes) / c.numChannels) / segment;
924 	c.numChannels = ARRANGE_BE16(c.numChannels);
925 	c.numSampleFrames = ARRANGE_BE32(c.numSampleFrames);
926 	c.sampleSize = ARRANGE_BE16(c.sampleSize);
927 
928 	/* Write out */
929 	of += 10;
930 	if (fseek(w->fd, of, SEEK_SET) < 0) {
931 		return -1;
932 	}
933 	if (fwrite(&(c.numSampleFrames), 1, 4, w->fd) < 4) {
934 		return -1;
935 	}
936 	/* Return back to current position in the file. */
937 	of = (long) curpos;
938 	if (fseek(w->fd, of, SEEK_SET) < 0) {
939 		return -1;
940 	}
941 	w->stat = 3;
942 
943 	return 1;
944 }
945 
946 int
AIFF_StartWritingMarkers(AIFF_Ref w)947 AIFF_StartWritingMarkers(AIFF_Ref w)
948 {
949 	IFFChunk chk;
950 	uint16_t nMarkers = 0;
951 
952 	if (!w || !(w->flags & F_WRONLY))
953 		return -1;
954 	if (w->stat != 3)
955 		return -1;
956 
957 	chk.id = ARRANGE_BE32(AIFF_MARK);
958 	chk.len = ARRANGE_BE16(2);
959 
960 	if (fwrite(&chk, 1, 8, w->fd) < 8)
961 		return -1;
962 	w->len += 8;
963 	w->markerOffSet = w->len;
964 	if (fwrite(&nMarkers, 1, 2, w->fd) < 2)
965 		return -1;
966 	w->len += 2;
967 
968 	w->markerPos = 0;
969 	w->stat = 4;
970 
971 	return 1;
972 }
973 
974 int
AIFF_WriteMarker(AIFF_Ref w,uint64_t position,char * name)975 AIFF_WriteMarker(AIFF_Ref w, uint64_t position, char *name)
976 {
977 	Marker m;
978 
979 	if (!w || !(w->flags & F_WRONLY))
980 		return -1;
981 	if (w->stat != 4)
982 		return -1;
983 
984 	/* max. number of markers --> 0xFFFF */
985 	if (w->markerPos == 0xFFFF)
986 		return 0;
987 
988 	m.id = (MarkerId) (w->markerPos + 1);
989 	m.id = ARRANGE_BE16(m.id);
990 	m.position = (uint32_t) position; /* XXX: AIFF is a 32-bit format */
991 	m.position = ARRANGE_BE32(m.position);
992 
993 	if (fwrite(&(m.id), 1, 2, w->fd) < 2 ||
994 	    fwrite(&(m.position), 1, 4, w->fd) < 4)
995 		return -1;
996 	w->len += 6;
997 
998 	if (name) {
999 		int l;
1000 
1001 		if ((l = PASCALOutWrite(w->fd, name)) < 2)
1002 			return -1;
1003 		w->len += l;
1004 	} else {
1005 		if (fwrite("\0\0", 1, 2, w->fd) != 2)
1006 			return -1;
1007 		w->len += 2;
1008 	}
1009 
1010 	++(w->markerPos);
1011 	return 1;
1012 }
1013 
1014 int
AIFF_EndWritingMarkers(AIFF_Ref w)1015 AIFF_EndWritingMarkers(AIFF_Ref w)
1016 {
1017 	IFFType ckid;
1018 	uint32_t cklen, curpos;
1019 	long offSet;
1020 	uint16_t nMarkers;
1021 
1022 	if (!w || !(w->flags & F_WRONLY))
1023 		return -1;
1024 	if (w->stat != 4)
1025 		return -1;
1026 
1027 	curpos = (uint32_t) (w->len) + 8;
1028 	cklen = (uint32_t) (w->len);
1029 	cklen -= (uint32_t) (w->markerOffSet);
1030 	cklen = ARRANGE_BE32(cklen);
1031 
1032 	offSet = (long) (w->markerOffSet);
1033 	if (fseek(w->fd, offSet, SEEK_SET) < 0) {
1034 		return -1;
1035 	}
1036 	if (fread(&ckid, 1, 4, w->fd) < 4)
1037 		return -1;
1038 
1039 	if (ckid != ARRANGE_BE32(AIFF_MARK)) {
1040 		return -1;
1041 	}
1042 
1043 	/*
1044 	 * Correct the chunk length
1045 	 * and the nMarkers field
1046 	 */
1047 	nMarkers = (uint16_t) (w->markerPos);
1048 	nMarkers = ARRANGE_BE16(nMarkers);
1049 
1050 	/* XXX: this is bogus, but required by this API */
1051 	if (fseek(w->fd, offSet + 4, SEEK_SET) < 0) {
1052 		return -1;
1053 	}
1054 	if (fwrite(&cklen, 1, 4, w->fd) < 4
1055 	    || fwrite(&nMarkers, 1, 2, w->fd) < 2) {
1056 		return -1;
1057 	}
1058 	/* Return back to current writing position */
1059 	offSet = (long) curpos;
1060 	if (fseek(w->fd, offSet, SEEK_SET) < 0) {
1061 		return -1;
1062 	}
1063 	w->stat = 3;
1064 	return 1;
1065 }
1066 
1067 static int
AIFF_WriteClose(AIFF_Ref w)1068 AIFF_WriteClose(AIFF_Ref w)
1069 {
1070 	int ret = 1;
1071 	IFFHeader hdr;
1072 
1073 	if (w->stat != 3) {
1074 		ret = 2;
1075 	}
1076 	if (fseek(w->fd, 0, SEEK_SET) < 0) {
1077 		fclose(w->fd);
1078 		free(w);
1079 		return -1;
1080 	}
1081 	if (fread(&hdr, 1, 12, w->fd) < 12) {
1082 		fclose(w->fd);
1083 		free(w);
1084 		return -1;
1085 	}
1086 	if (hdr.hid != ARRANGE_BE32(AIFF_FORM)) {
1087 		fclose(w->fd);
1088 		free(w);
1089 		return -1;
1090 	}
1091 	/* Fix the 'length' field */
1092 	hdr.len = (uint32_t) (w->len);
1093 	hdr.len = ARRANGE_BE32(hdr.len);
1094 
1095 	if (fseek(w->fd, 0, SEEK_SET) < 0) {
1096 		fclose(w->fd);
1097 		free(w);
1098 		return -1;
1099 	}
1100 	if (fwrite(&hdr, 1, 12, w->fd) < 12) {
1101 		fclose(w->fd);
1102 		free(w);
1103 		return -1;
1104 	}
1105 	/* Now fclose, free & return */
1106 	fclose(w->fd);
1107 	free(w);
1108 	return ret;
1109 }
1110 
1111 
1112 /* assertion failed */
1113 void
AIFFAssertionFailed(const char * fil,int lin)1114 AIFFAssertionFailed (const char * fil, int lin)
1115 {
1116 
1117 	fprintf(stderr, "%s: assertion at %s:%d failed\n",
1118 			PACKAGE_STRING,
1119 			(char *) fil,
1120 			lin
1121 			);
1122 	fprintf(stderr, "%s: please report this bug at <%s>\n",
1123 			PACKAGE_STRING,
1124 			PACKAGE_BUGREPORT
1125 			);
1126 
1127 #ifdef HAVE_ABORT
1128 	abort();
1129 #else
1130 	/* XXX */
1131 #endif
1132 }
1133 
1134