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