/* libSoX SGI/Amiga AIFF format. * Copyright 1991-2007 Guido van Rossum And Sundry Contributors * * This source code is freely redistributable and may be used for * any purpose. This copyright notice must be maintained. * Guido van Rossum And Sundry Contributors are not responsible for * the consequences of using this software. * * Used by SGI on 4D/35 and Indigo. * This is a subformat of the EA-IFF-85 format. * This is related to the IFF format used by the Amiga. * But, apparently, not the same. * Also AIFF-C format output that is defined in DAVIC 1.4 Part 9 Annex B * (usable for japanese-data-broadcasting, specified by ARIB STD-B24.) */ #include "sox_i.h"#include "aiff.h"#include "id3.h" #include <time.h> /* for time stamping comments */#include <stdlib.h>#include <string.h>#include <stdio.h>#include <errno.h>#include <limits.h> /* forward declarations */static double read_ieee_extended(sox_format_t *);static int aiffwriteheader(sox_format_t *, uint64_t);static int aifcwriteheader(sox_format_t *, uint64_t);static void write_ieee_extended(sox_format_t *, double);static double ConvertFromIeeeExtended(unsigned char*);static void ConvertToIeeeExtended(double, char *);static int textChunk(char **text, char *chunkDescription, sox_format_t * ft);static int commentChunk(char **text, char *chunkDescription, sox_format_t * ft);static void reportInstrument(sox_format_t * ft); int lsx_aiffstartread(sox_format_t * ft){ char buf[5]; uint32_t totalsize; uint32_t chunksize; unsigned short channels = 0; sox_encoding_t enc = SOX_ENCODING_SIGN2; uint32_t frames; unsigned short bits = 0; double rate = 0.0; uint32_t offset = 0; uint32_t blocksize = 0; int foundcomm = 0, foundmark = 0, foundinstr = 0, is_sowt = 0; struct mark { unsigned short id; uint32_t position; char name[40]; } marks[32]; unsigned short looptype; int i, j; unsigned short nmarks = 0; unsigned short sustainLoopBegin = 0, sustainLoopEnd = 0, releaseLoopBegin = 0, releaseLoopEnd = 0; off_t seekto = 0; size_t ssndsize = 0; char *annotation; char *author; char *copyright; char *nametext; uint8_t trash8; uint16_t trash16; uint32_t trash32; int rc; /* FORM chunk */ if (lsx_reads(ft, buf, (size_t)4) == SOX_EOF || strncmp(buf, "FORM", (size_t)4) != 0) { lsx_fail_errno(ft,SOX_EHDR,"AIFF header does not begin with magic word `FORM'"); return(SOX_EOF); } lsx_readdw(ft, &totalsize); if (lsx_reads(ft, buf, (size_t)4) == SOX_EOF || (strncmp(buf, "AIFF", (size_t)4) != 0 && strncmp(buf, "AIFC", (size_t)4) != 0)) { lsx_fail_errno(ft,SOX_EHDR,"AIFF `FORM' chunk does not specify `AIFF' or `AIFC' as type"); return(SOX_EOF); } /* Skip everything but the COMM chunk and the SSND chunk */ /* The SSND chunk must be the last in the file */ while (1) { if (lsx_reads(ft, buf, (size_t)4) == SOX_EOF) { if (seekto > 0) break; else { lsx_fail_errno(ft,SOX_EHDR,"Missing SSND chunk in AIFF file"); return(SOX_EOF); } } if (strncmp(buf, "COMM", (size_t)4) == 0) { /* COMM chunk */ lsx_readdw(ft, &chunksize); lsx_readw(ft, &channels); lsx_readdw(ft, &frames); lsx_readw(ft, &bits); rate = read_ieee_extended(ft); chunksize -= 18; if (chunksize > 0) { lsx_reads(ft, buf, (size_t)4); chunksize -= 4; if (strncmp(buf, "sowt", (size_t)4) == 0) { /* CD audio as read on Mac OS machines */ /* Need to endian swap all the data */ is_sowt = 1; } else if (strncmp(buf, "fl32", (size_t)4) == 0 || strncmp(buf, "FL32", (size_t)4) == 0) { enc = SOX_ENCODING_FLOAT; if (bits != 32) { lsx_fail_errno(ft, SOX_EHDR, "Sample size of %u is not consistent with `fl32' compression type", bits); return SOX_EOF; } } else if (strncmp(buf, "fl64", (size_t)4) == 0 || strncmp(buf, "FL64", (size_t)4) == 0) { enc = SOX_ENCODING_FLOAT; if (bits != 64) { lsx_fail_errno(ft, SOX_EHDR, "Sample size of %u is not consistent with `fl64' compression type", bits); return SOX_EOF; } } else if (strncmp(buf, "NONE", (size_t)4) != 0 && strncmp(buf, "twos", (size_t)4) != 0) { buf[4] = 0; lsx_fail_errno(ft, SOX_EHDR, "Unsupported AIFC compression type `%s'", buf); return(SOX_EOF); } } while(chunksize-- > 0) lsx_readb(ft, &trash8); foundcomm = 1; } else if (strncmp(buf, "SSND", (size_t)4) == 0) { /* SSND chunk */ lsx_readdw(ft, &chunksize); lsx_readdw(ft, &offset); lsx_readdw(ft, &blocksize); chunksize -= 8; ssndsize = chunksize; /* word-align chunksize in case it wasn't * done by writing application already. */ chunksize += (chunksize % 2); /* if can't seek, just do sound now */ if (!ft->seekable) break; /* else, seek to end of sound and hunt for more */ seekto = lsx_tell(ft); lsx_seeki(ft, (off_t)chunksize, SEEK_CUR); } else if (strncmp(buf, "MARK", (size_t)4) == 0) { /* MARK chunk */ lsx_readdw(ft, &chunksize); if (chunksize >= sizeof(nmarks)) { lsx_readw(ft, &nmarks); chunksize -= sizeof(nmarks); } else nmarks = 0; /* Some programs like to always have a MARK chunk * but will set number of marks to 0 and force * software to detect and ignore it. */ if (nmarks == 0) foundmark = 0; else foundmark = 1; /* Make sure its not larger then we support */ if (nmarks > 32) nmarks = 32; for(i = 0; i < nmarks && chunksize; i++) { unsigned char len, read_len, tmp_c; if (chunksize < 6) break; lsx_readw(ft, &(marks[i].id)); lsx_readdw(ft, &(marks[i].position)); chunksize -= 6; /* If error reading length then * don't try to read more bytes * based on that value. */ if (lsx_readb(ft, &len) != SOX_SUCCESS) break; --chunksize; if (len > chunksize) len = chunksize; read_len = len; if (read_len > 39) read_len = 39; for(j = 0; j < len && chunksize; j++) { lsx_readb(ft, &tmp_c); if (j < read_len) marks[i].name[j] = tmp_c; chunksize--; } marks[i].name[read_len] = 0; if ((len & 1) == 0 && chunksize) { chunksize--; lsx_readb(ft, &trash8); } } /* HA HA! Sound Designer (and others) makes */ /* bogus files. It spits out bogus chunksize */ /* for MARK field */ while(chunksize-- > 0) lsx_readb(ft, &trash8); } else if (strncmp(buf, "INST", (size_t)4) == 0) { /* INST chunk */ lsx_readdw(ft, &chunksize); lsx_readsb(ft, &(ft->oob.instr.MIDInote)); lsx_readb(ft, &trash8); lsx_readsb(ft, &(ft->oob.instr.MIDIlow)); lsx_readsb(ft, &(ft->oob.instr.MIDIhi)); /* Low velocity */ lsx_readb(ft, &trash8); /* Hi velocity */ lsx_readb(ft, &trash8); lsx_readw(ft, &trash16);/* gain */ lsx_readw(ft, &looptype); /* sustain loop */ ft->oob.loops[0].type = looptype; lsx_readw(ft, &sustainLoopBegin); /* begin marker */ lsx_readw(ft, &sustainLoopEnd); /* end marker */ lsx_readw(ft, &looptype); /* release loop */ ft->oob.loops[1].type = looptype; lsx_readw(ft, &releaseLoopBegin); /* begin marker */ lsx_readw(ft, &releaseLoopEnd); /* end marker */ foundinstr = 1; } else if (strncmp(buf, "APPL", (size_t)4) == 0) { lsx_readdw(ft, &chunksize); /* word-align chunksize in case it wasn't * done by writing application already. */ chunksize += (chunksize % 2); while(chunksize-- > 0) lsx_readb(ft, &trash8); } else if (strncmp(buf, "ALCH", (size_t)4) == 0) { /* I think this is bogus and gets grabbed by APPL */ /* INST chunk */ lsx_readdw(ft, &trash32); /* ENVS - jeez! */ lsx_readdw(ft, &chunksize); while(chunksize-- > 0) lsx_readb(ft, &trash8); } else if (strncmp(buf, "ANNO", (size_t)4) == 0) { rc = textChunk(&annotation, "Annotation:", ft); if (rc) { /* Fail already called in function */ return(SOX_EOF); } if (annotation) sox_append_comments(&ft->oob.comments, annotation); free(annotation); } else if (strncmp(buf, "COMT", (size_t)4) == 0) { char *comment = NULL; rc = commentChunk(&comment, "Comment:", ft); if (rc) { /* Fail already called in function */ return(SOX_EOF); } if (comment) sox_append_comments(&ft->oob.comments, comment); free(comment); } else if (strncmp(buf, "AUTH", (size_t)4) == 0) { /* Author chunk */ rc = textChunk(&author, "Author:", ft); if (rc) { /* Fail already called in function */ return(SOX_EOF); } free(author); } else if (strncmp(buf, "NAME", (size_t)4) == 0) { /* Name chunk */ rc = textChunk(&nametext, "Name:", ft); if (rc) { /* Fail already called in function */ return(SOX_EOF); } free(nametext); } else if (strncmp(buf, "(c) ", (size_t)4) == 0) { /* Copyright chunk */ rc = textChunk(©right, "Copyright:", ft); if (rc) { /* Fail already called in function */ return(SOX_EOF); } free(copyright); } else if (strncmp(buf, "ID3 ", 4) == 0) { off_t offs; lsx_readdw(ft, &chunksize); offs = lsx_tell(ft); lsx_id3_read_tag(ft, 0); lsx_seeki(ft, offs + chunksize, SEEK_SET); } else { if (lsx_eof(ft)) break; buf[4] = 0; lsx_debug("AIFFstartread: ignoring `%s' chunk", buf); lsx_readdw(ft, &chunksize); if (lsx_eof(ft)) break; /* account for padding after odd-sized chunks */ chunksize += chunksize & 1; /* Skip the chunk using lsx_readb() so we may read from a pipe */ while (chunksize-- > 0) { if (lsx_readb(ft, &trash8) == SOX_EOF) break; } } if (lsx_eof(ft)) break; } /* * if a pipe, we lose all chunks after sound. * Like, say, instrument loops. */ if (ft->seekable) { if (seekto > 0) lsx_seeki(ft, seekto, SEEK_SET); else { lsx_fail_errno(ft,SOX_EOF,"AIFF: no sound data on input file"); return(SOX_EOF); } } /* SSND chunk just read */ if (blocksize != 0) lsx_warn("AIFF header has invalid blocksize. Ignoring but expect a premature EOF"); ssndsize -= offset; while (offset-- > 0) { if (lsx_readb(ft, &trash8) == SOX_EOF) { lsx_fail_errno(ft,errno,"unexpected EOF while skipping AIFF offset"); return(SOX_EOF); } } if (foundcomm) { if (bits <= 8) bits = 8; else if (bits <= 16) bits = 16; else if (bits <= 24) bits = 24; else if (bits <= 32) bits = 32; else if (bits == 64 && enc == SOX_ENCODING_FLOAT) { /* no-op */ } else { lsx_fail_errno(ft,SOX_EFMT,"unsupported sample size in AIFF header: %d", bits); return(SOX_EOF); } } else { if ((ft->signal.channels == SOX_UNSPEC) || (ft->signal.rate == SOX_UNSPEC) || (ft->encoding.encoding == SOX_ENCODING_UNKNOWN) || (ft->encoding.bits_per_sample == 0)) { lsx_report("You must specify # channels, sample rate, signed/unsigned,"); lsx_report("and 8/16 on the command line."); lsx_fail_errno(ft,SOX_EFMT,"Bogus AIFF file: no COMM section."); return(SOX_EOF); } } ssndsize /= bits >> 3; /* Cope with 'sowt' CD tracks as read on Macs */ if (is_sowt) ft->encoding.reverse_bytes = !ft->encoding.reverse_bytes; if (foundmark && !foundinstr) { lsx_debug("Ignoring MARK chunk since no INSTR found."); foundmark = 0; } if (!foundmark && foundinstr) { lsx_debug("Ignoring INSTR chunk since no MARK found."); foundinstr = 0; } if (foundmark && foundinstr) { int i2; int slbIndex = 0, sleIndex = 0; int rlbIndex = 0, rleIndex = 0; /* find our loop markers and save their marker indexes */ for(i2 = 0; i2 < nmarks; i2++) { if(marks[i2].id == sustainLoopBegin) slbIndex = i2; if(marks[i2].id == sustainLoopEnd) sleIndex = i2; if(marks[i2].id == releaseLoopBegin) rlbIndex = i2; if(marks[i2].id == releaseLoopEnd) rleIndex = i2; } ft->oob.instr.nloops = 0; if (ft->oob.loops[0].type != 0) { ft->oob.loops[0].start = marks[slbIndex].position; ft->oob.loops[0].length = marks[sleIndex].position - marks[slbIndex].position; /* really the loop count should be infinite */ ft->oob.loops[0].count = 1; ft->oob.instr.loopmode = SOX_LOOP_SUSTAIN_DECAY | ft->oob.loops[0].type; ft->oob.instr.nloops++; } if (ft->oob.loops[1].type != 0) { ft->oob.loops[1].start = marks[rlbIndex].position; ft->oob.loops[1].length = marks[rleIndex].position - marks[rlbIndex].position; /* really the loop count should be infinite */ ft->oob.loops[1].count = 1; ft->oob.instr.loopmode = SOX_LOOP_SUSTAIN_DECAY | ft->oob.loops[1].type; ft->oob.instr.nloops++; } } reportInstrument(ft); return lsx_check_read_params( ft, channels, rate, enc, bits, (uint64_t)ssndsize, sox_false);} /* print out the MIDI key allocations, loop points, directions etc */static void reportInstrument(sox_format_t * ft){ unsigned loopNum; if(ft->oob.instr.nloops > 0) lsx_report("AIFF Loop markers:"); for(loopNum = 0; loopNum < ft->oob.instr.nloops; loopNum++) { if (ft->oob.loops[loopNum].count) { lsx_report("Loop %d: start: %6lu", loopNum, (unsigned long)ft->oob.loops[loopNum].start); lsx_report(" end: %6lu", (unsigned long)(ft->oob.loops[loopNum].start + ft->oob.loops[loopNum].length)); lsx_report(" count: %6d", ft->oob.loops[loopNum].count); lsx_report(" type: "); switch(ft->oob.loops[loopNum].type & ~SOX_LOOP_SUSTAIN_DECAY) { case 0: lsx_report("off"); break; case 1: lsx_report("forward"); break; case 2: lsx_report("forward/backward"); break; } } } lsx_report("Unity MIDI Note: %d", ft->oob.instr.MIDInote); lsx_report("Low MIDI Note: %d", ft->oob.instr.MIDIlow); lsx_report("High MIDI Note: %d", ft->oob.instr.MIDIhi);} /* Process a text chunk, allocate memory, display it if verbose and return */static int textChunk(char **text, char *chunkDescription, sox_format_t * ft){ uint32_t chunksize0; size_t chunksize; lsx_readdw(ft, &chunksize0); chunksize = chunksize0; /* allocate enough memory to hold the text including a terminating \0 */ if (chunksize != SOX_SIZE_MAX) *text = lsx_malloc((size_t)chunksize+1); else *text = lsx_malloc((size_t)chunksize); if (lsx_readbuf(ft, *text, (size_t) chunksize) != chunksize) { lsx_fail_errno(ft,SOX_EOF,"AIFF: Unexpected EOF in %s header", chunkDescription); return(SOX_EOF); } if (chunksize != SOX_SIZE_MAX) *(*text + chunksize) = '\0'; else *(*text + chunksize-1) = '\0'; if (chunksize % 2) { /* Read past pad byte */ char c; if (lsx_readbuf(ft, &c, (size_t)1) != 1) { lsx_fail_errno(ft,SOX_EOF,"AIFF: Unexpected EOF in %s header", chunkDescription); return(SOX_EOF); } } lsx_debug("%-10s \"%s\"", chunkDescription, *text);Lines 1–500 of 1157. Load more
/* libSoX SGI/Amiga AIFF format. * Copyright 1991-2007 Guido van Rossum And Sundry Contributors * * This source code is freely redistributable and may be used for * any purpose. This copyright notice must be maintained. * Guido van Rossum And Sundry Contributors are not responsible for * the consequences of using this software. * * Used by SGI on 4D/35 and Indigo. * This is a subformat of the EA-IFF-85 format. * This is related to the IFF format used by the Amiga. * But, apparently, not the same. * Also AIFF-C format output that is defined in DAVIC 1.4 Part 9 Annex B * (usable for japanese-data-broadcasting, specified by ARIB STD-B24.) */ #include "sox_i.h" #include "aiff.h" #include "id3.h" #include <time.h> /* for time stamping comments */ #include <stdlib.h> #include <string.h> #include <stdio.h> #include <errno.h> #include <limits.h> /* forward declarations */ static double read_ieee_extended(sox_format_t *); static int aiffwriteheader(sox_format_t *, uint64_t); static int aifcwriteheader(sox_format_t *, uint64_t); static void write_ieee_extended(sox_format_t *, double); static double ConvertFromIeeeExtended(unsigned char*); static void ConvertToIeeeExtended(double, char *); static int textChunk(char **text, char *chunkDescription, sox_format_t * ft); static int commentChunk(char **text, char *chunkDescription, sox_format_t * ft); static void reportInstrument(sox_format_t * ft); int lsx_aiffstartread(sox_format_t * ft) { char buf[5]; uint32_t totalsize; uint32_t chunksize; unsigned short channels = 0; sox_encoding_t enc = SOX_ENCODING_SIGN2; uint32_t frames; unsigned short bits = 0; double rate = 0.0; uint32_t offset = 0; uint32_t blocksize = 0; int foundcomm = 0, foundmark = 0, foundinstr = 0, is_sowt = 0; struct mark { unsigned short id; uint32_t position; char name[40]; } marks[32]; unsigned short looptype; int i, j; unsigned short nmarks = 0; unsigned short sustainLoopBegin = 0, sustainLoopEnd = 0, releaseLoopBegin = 0, releaseLoopEnd = 0; off_t seekto = 0; size_t ssndsize = 0; char *annotation; char *author; char *copyright; char *nametext; uint8_t trash8; uint16_t trash16; uint32_t trash32; int rc; /* FORM chunk */ if (lsx_reads(ft, buf, (size_t)4) == SOX_EOF || strncmp(buf, "FORM", (size_t)4) != 0) { lsx_fail_errno(ft,SOX_EHDR,"AIFF header does not begin with magic word `FORM'"); return(SOX_EOF); } lsx_readdw(ft, &totalsize); if (lsx_reads(ft, buf, (size_t)4) == SOX_EOF || (strncmp(buf, "AIFF", (size_t)4) != 0 && strncmp(buf, "AIFC", (size_t)4) != 0)) { lsx_fail_errno(ft,SOX_EHDR,"AIFF `FORM' chunk does not specify `AIFF' or `AIFC' as type"); return(SOX_EOF); } /* Skip everything but the COMM chunk and the SSND chunk */ /* The SSND chunk must be the last in the file */ while (1) { if (lsx_reads(ft, buf, (size_t)4) == SOX_EOF) { if (seekto > 0) break; else { lsx_fail_errno(ft,SOX_EHDR,"Missing SSND chunk in AIFF file"); return(SOX_EOF); } } if (strncmp(buf, "COMM", (size_t)4) == 0) { /* COMM chunk */ lsx_readdw(ft, &chunksize); lsx_readw(ft, &channels); lsx_readdw(ft, &frames); lsx_readw(ft, &bits); rate = read_ieee_extended(ft); chunksize -= 18; if (chunksize > 0) { lsx_reads(ft, buf, (size_t)4); chunksize -= 4; if (strncmp(buf, "sowt", (size_t)4) == 0) { /* CD audio as read on Mac OS machines */ /* Need to endian swap all the data */ is_sowt = 1; } else if (strncmp(buf, "fl32", (size_t)4) == 0 || strncmp(buf, "FL32", (size_t)4) == 0) { enc = SOX_ENCODING_FLOAT; if (bits != 32) { lsx_fail_errno(ft, SOX_EHDR, "Sample size of %u is not consistent with `fl32' compression type", bits); return SOX_EOF; } } else if (strncmp(buf, "fl64", (size_t)4) == 0 || strncmp(buf, "FL64", (size_t)4) == 0) { enc = SOX_ENCODING_FLOAT; if (bits != 64) { lsx_fail_errno(ft, SOX_EHDR, "Sample size of %u is not consistent with `fl64' compression type", bits); return SOX_EOF; } } else if (strncmp(buf, "NONE", (size_t)4) != 0 && strncmp(buf, "twos", (size_t)4) != 0) { buf[4] = 0; lsx_fail_errno(ft, SOX_EHDR, "Unsupported AIFC compression type `%s'", buf); return(SOX_EOF); } } while(chunksize-- > 0) lsx_readb(ft, &trash8); foundcomm = 1; } else if (strncmp(buf, "SSND", (size_t)4) == 0) { /* SSND chunk */ lsx_readdw(ft, &chunksize); lsx_readdw(ft, &offset); lsx_readdw(ft, &blocksize); chunksize -= 8; ssndsize = chunksize; /* word-align chunksize in case it wasn't * done by writing application already. */ chunksize += (chunksize % 2); /* if can't seek, just do sound now */ if (!ft->seekable) break; /* else, seek to end of sound and hunt for more */ seekto = lsx_tell(ft); lsx_seeki(ft, (off_t)chunksize, SEEK_CUR); } else if (strncmp(buf, "MARK", (size_t)4) == 0) { /* MARK chunk */ lsx_readdw(ft, &chunksize); if (chunksize >= sizeof(nmarks)) { lsx_readw(ft, &nmarks); chunksize -= sizeof(nmarks); } else nmarks = 0; /* Some programs like to always have a MARK chunk * but will set number of marks to 0 and force * software to detect and ignore it. */ if (nmarks == 0) foundmark = 0; else foundmark = 1; /* Make sure its not larger then we support */ if (nmarks > 32) nmarks = 32; for(i = 0; i < nmarks && chunksize; i++) { unsigned char len, read_len, tmp_c; if (chunksize < 6) break; lsx_readw(ft, &(marks[i].id)); lsx_readdw(ft, &(marks[i].position)); chunksize -= 6; /* If error reading length then * don't try to read more bytes * based on that value. */ if (lsx_readb(ft, &len) != SOX_SUCCESS) break; --chunksize; if (len > chunksize) len = chunksize; read_len = len; if (read_len > 39) read_len = 39; for(j = 0; j < len && chunksize; j++) { lsx_readb(ft, &tmp_c); if (j < read_len) marks[i].name[j] = tmp_c; chunksize--; } marks[i].name[read_len] = 0; if ((len & 1) == 0 && chunksize) { chunksize--; lsx_readb(ft, &trash8); } } /* HA HA! Sound Designer (and others) makes */ /* bogus files. It spits out bogus chunksize */ /* for MARK field */ while(chunksize-- > 0) lsx_readb(ft, &trash8); } else if (strncmp(buf, "INST", (size_t)4) == 0) { /* INST chunk */ lsx_readdw(ft, &chunksize); lsx_readsb(ft, &(ft->oob.instr.MIDInote)); lsx_readb(ft, &trash8); lsx_readsb(ft, &(ft->oob.instr.MIDIlow)); lsx_readsb(ft, &(ft->oob.instr.MIDIhi)); /* Low velocity */ lsx_readb(ft, &trash8); /* Hi velocity */ lsx_readb(ft, &trash8); lsx_readw(ft, &trash16);/* gain */ lsx_readw(ft, &looptype); /* sustain loop */ ft->oob.loops[0].type = looptype; lsx_readw(ft, &sustainLoopBegin); /* begin marker */ lsx_readw(ft, &sustainLoopEnd); /* end marker */ lsx_readw(ft, &looptype); /* release loop */ ft->oob.loops[1].type = looptype; lsx_readw(ft, &releaseLoopBegin); /* begin marker */ lsx_readw(ft, &releaseLoopEnd); /* end marker */ foundinstr = 1; } else if (strncmp(buf, "APPL", (size_t)4) == 0) { lsx_readdw(ft, &chunksize); /* word-align chunksize in case it wasn't * done by writing application already. */ chunksize += (chunksize % 2); while(chunksize-- > 0) lsx_readb(ft, &trash8); } else if (strncmp(buf, "ALCH", (size_t)4) == 0) { /* I think this is bogus and gets grabbed by APPL */ /* INST chunk */ lsx_readdw(ft, &trash32); /* ENVS - jeez! */ lsx_readdw(ft, &chunksize); while(chunksize-- > 0) lsx_readb(ft, &trash8); } else if (strncmp(buf, "ANNO", (size_t)4) == 0) { rc = textChunk(&annotation, "Annotation:", ft); if (rc) { /* Fail already called in function */ return(SOX_EOF); } if (annotation) sox_append_comments(&ft->oob.comments, annotation); free(annotation); } else if (strncmp(buf, "COMT", (size_t)4) == 0) { char *comment = NULL; rc = commentChunk(&comment, "Comment:", ft); if (rc) { /* Fail already called in function */ return(SOX_EOF); } if (comment) sox_append_comments(&ft->oob.comments, comment); free(comment); } else if (strncmp(buf, "AUTH", (size_t)4) == 0) { /* Author chunk */ rc = textChunk(&author, "Author:", ft); if (rc) { /* Fail already called in function */ return(SOX_EOF); } free(author); } else if (strncmp(buf, "NAME", (size_t)4) == 0) { /* Name chunk */ rc = textChunk(&nametext, "Name:", ft); if (rc) { /* Fail already called in function */ return(SOX_EOF); } free(nametext); } else if (strncmp(buf, "(c) ", (size_t)4) == 0) { /* Copyright chunk */ rc = textChunk(©right, "Copyright:", ft); if (rc) { /* Fail already called in function */ return(SOX_EOF); } free(copyright); } else if (strncmp(buf, "ID3 ", 4) == 0) { off_t offs; lsx_readdw(ft, &chunksize); offs = lsx_tell(ft); lsx_id3_read_tag(ft, 0); lsx_seeki(ft, offs + chunksize, SEEK_SET); } else { if (lsx_eof(ft)) break; buf[4] = 0; lsx_debug("AIFFstartread: ignoring `%s' chunk", buf); lsx_readdw(ft, &chunksize); if (lsx_eof(ft)) break; /* account for padding after odd-sized chunks */ chunksize += chunksize & 1; /* Skip the chunk using lsx_readb() so we may read from a pipe */ while (chunksize-- > 0) { if (lsx_readb(ft, &trash8) == SOX_EOF) break; } } if (lsx_eof(ft)) break; } /* * if a pipe, we lose all chunks after sound. * Like, say, instrument loops. */ if (ft->seekable) { if (seekto > 0) lsx_seeki(ft, seekto, SEEK_SET); else { lsx_fail_errno(ft,SOX_EOF,"AIFF: no sound data on input file"); return(SOX_EOF); } } /* SSND chunk just read */ if (blocksize != 0) lsx_warn("AIFF header has invalid blocksize. Ignoring but expect a premature EOF"); ssndsize -= offset; while (offset-- > 0) { if (lsx_readb(ft, &trash8) == SOX_EOF) { lsx_fail_errno(ft,errno,"unexpected EOF while skipping AIFF offset"); return(SOX_EOF); } } if (foundcomm) { if (bits <= 8) bits = 8; else if (bits <= 16) bits = 16; else if (bits <= 24) bits = 24; else if (bits <= 32) bits = 32; else if (bits == 64 && enc == SOX_ENCODING_FLOAT) { /* no-op */ } else { lsx_fail_errno(ft,SOX_EFMT,"unsupported sample size in AIFF header: %d", bits); return(SOX_EOF); } } else { if ((ft->signal.channels == SOX_UNSPEC) || (ft->signal.rate == SOX_UNSPEC) || (ft->encoding.encoding == SOX_ENCODING_UNKNOWN) || (ft->encoding.bits_per_sample == 0)) { lsx_report("You must specify # channels, sample rate, signed/unsigned,"); lsx_report("and 8/16 on the command line."); lsx_fail_errno(ft,SOX_EFMT,"Bogus AIFF file: no COMM section."); return(SOX_EOF); } } ssndsize /= bits >> 3; /* Cope with 'sowt' CD tracks as read on Macs */ if (is_sowt) ft->encoding.reverse_bytes = !ft->encoding.reverse_bytes; if (foundmark && !foundinstr) { lsx_debug("Ignoring MARK chunk since no INSTR found."); foundmark = 0; } if (!foundmark && foundinstr) { lsx_debug("Ignoring INSTR chunk since no MARK found."); foundinstr = 0; } if (foundmark && foundinstr) { int i2; int slbIndex = 0, sleIndex = 0; int rlbIndex = 0, rleIndex = 0; /* find our loop markers and save their marker indexes */ for(i2 = 0; i2 < nmarks; i2++) { if(marks[i2].id == sustainLoopBegin) slbIndex = i2; if(marks[i2].id == sustainLoopEnd) sleIndex = i2; if(marks[i2].id == releaseLoopBegin) rlbIndex = i2; if(marks[i2].id == releaseLoopEnd) rleIndex = i2; } ft->oob.instr.nloops = 0; if (ft->oob.loops[0].type != 0) { ft->oob.loops[0].start = marks[slbIndex].position; ft->oob.loops[0].length = marks[sleIndex].position - marks[slbIndex].position; /* really the loop count should be infinite */ ft->oob.loops[0].count = 1; ft->oob.instr.loopmode = SOX_LOOP_SUSTAIN_DECAY | ft->oob.loops[0].type; ft->oob.instr.nloops++; } if (ft->oob.loops[1].type != 0) { ft->oob.loops[1].start = marks[rlbIndex].position; ft->oob.loops[1].length = marks[rleIndex].position - marks[rlbIndex].position; /* really the loop count should be infinite */ ft->oob.loops[1].count = 1; ft->oob.instr.loopmode = SOX_LOOP_SUSTAIN_DECAY | ft->oob.loops[1].type; ft->oob.instr.nloops++; } } reportInstrument(ft); return lsx_check_read_params( ft, channels, rate, enc, bits, (uint64_t)ssndsize, sox_false); } /* print out the MIDI key allocations, loop points, directions etc */ static void reportInstrument(sox_format_t * ft) { unsigned loopNum; if(ft->oob.instr.nloops > 0) lsx_report("AIFF Loop markers:"); for(loopNum = 0; loopNum < ft->oob.instr.nloops; loopNum++) { if (ft->oob.loops[loopNum].count) { lsx_report("Loop %d: start: %6lu", loopNum, (unsigned long)ft->oob.loops[loopNum].start); lsx_report(" end: %6lu", (unsigned long)(ft->oob.loops[loopNum].start + ft->oob.loops[loopNum].length)); lsx_report(" count: %6d", ft->oob.loops[loopNum].count); lsx_report(" type: "); switch(ft->oob.loops[loopNum].type & ~SOX_LOOP_SUSTAIN_DECAY) { case 0: lsx_report("off"); break; case 1: lsx_report("forward"); break; case 2: lsx_report("forward/backward"); break; } } } lsx_report("Unity MIDI Note: %d", ft->oob.instr.MIDInote); lsx_report("Low MIDI Note: %d", ft->oob.instr.MIDIlow); lsx_report("High MIDI Note: %d", ft->oob.instr.MIDIhi); } /* Process a text chunk, allocate memory, display it if verbose and return */ static int textChunk(char **text, char *chunkDescription, sox_format_t * ft) { uint32_t chunksize0; size_t chunksize; lsx_readdw(ft, &chunksize0); chunksize = chunksize0; /* allocate enough memory to hold the text including a terminating \0 */ if (chunksize != SOX_SIZE_MAX) *text = lsx_malloc((size_t)chunksize+1); else *text = lsx_malloc((size_t)chunksize); if (lsx_readbuf(ft, *text, (size_t) chunksize) != chunksize) { lsx_fail_errno(ft,SOX_EOF,"AIFF: Unexpected EOF in %s header", chunkDescription); return(SOX_EOF); } if (chunksize != SOX_SIZE_MAX) *(*text + chunksize) = '\0'; else *(*text + chunksize-1) = '\0'; if (chunksize % 2) { /* Read past pad byte */ char c; if (lsx_readbuf(ft, &c, (size_t)1) != 1) { lsx_fail_errno(ft,SOX_EOF,"AIFF: Unexpected EOF in %s header", chunkDescription); return(SOX_EOF); } } lsx_debug("%-10s \"%s\"", chunkDescription, *text);