home *** CD-ROM | disk | FTP | other *** search
- /* AIFF decoder, (c) Pierre Guerrier 1996 */
- /* e-mail: guerrier@ecoledoc.ibp.fr */
- /* see attached "read_me" file */
- /* version 1.1, released november 1996 */
-
-
- #include <fcntl.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
-
- #define MSDOS 1
- /* change this value to 1 if you are compiling for DOS */
-
-
- #define kNo 0 /* nothing under way */
- #define kArm 1 /* leader caught */
- #define kHead 2 /* syncs found */
- #define kData 3
- #define kNULL (-300)
-
- #define kHeadSync (0x2c | (127<<9))
- #define kDataSync (0x16 | (127<<9))
- #define kHeadSize 256
- #define kDataSize 2048
- #define kCRCSizeH 2
- #define kCRCSizeD 16 /* approximate trailer size */
- #define kCRCpoly 4129 /* used for binary long division in CRC */
- #define kLeadSize 2000 /* leader size in "one" bits */
- #define kTreshold 500 /* duration limit between a 0 and a 1, in CPU clocks */
- #define kTopOut 50 /* <<<<---- problematic !! */
- #define kTopIn 3
-
- FILE *Source;
- FILE *Target;
-
- /* interface and option globals */
-
- long Counter = 0;
- int Right = 0; /* use first channel */
- int Polarity = 0; /* no sign change */
- int Step = 1;
- int Ratio;
- int SlowRate = 4; /* default = SW1 */
- int Verbose = 0;
-
- /* globals for delta->bit->byte levels state machines */
-
- int WMin;
- int W0Low;
- int W0High;
- int W1Low;
- int W1High;
- int WTopIn;
- int WTopOut;
- int WLine;
-
- unsigned int window = 0;
- int bitPt = 0;
- int bytePt = 0;
- int engaged = kNo;
- int accumulator = 0;
-
- /* globals for byte->file level state machine */
-
- char currentFile[17];
- unsigned char BlockBuff[kDataSize+kCRCSizeD];
- int currentBlock;
- unsigned int currentSize = 2048;
- unsigned int currentSize2 = 2048;
- int closeOnNext = 0;
- int isOpen = 0;
- int BlockReady = 0;
-
-
-
-
-
-
-
- /* delta->bits->bytes engine */
-
-
- int sendDelta(int delta)
- {
- int retVal;
-
- window = (window<<1) | (delta > WLine);
- /* shifting window */
-
- switch (engaged) /* finite state machine DSP :-) */
- {
- case kArm:
- if ((window&0xFFFF)==kHeadSync)
- {
- engaged = kHead;
- printf("\nSample %d: Found a HEADER Sync !\n", Counter);
- }
- if ((window&0xFFFF)==kDataSync)
- {
- engaged = kData;
- printf("\nSample %d: Found a BLOCK Sync !\n", Counter);
- }
- bitPt = 0;
- bytePt = 0;
- retVal = kNULL;
- accumulator--;
- if ((accumulator < 0) && (engaged == kArm))
- { engaged = kNo; accumulator = 0; if (Verbose) printf("Disarmed...\n"); }
- break;
-
- case kHead: case kData:
- bitPt++;
- if (bitPt == 8)
- {
- bitPt = 0;
- bytePt++;
- retVal = window & 255;
- if ( ((engaged == kHead) && (bytePt == (kHeadSize+kCRCSizeH))) ||
- ((engaged == kData) && (bytePt == (currentSize+kCRCSizeD))) )
- { engaged = kNo; accumulator = 0; }
- }
- else
- retVal = kNULL;
- break;
-
- case kNo: /* leader management */
- retVal = kNULL;
- if ((window & 0xFFFF) == 0xFFFF) accumulator++;
- if (accumulator > kLeadSize)
- { engaged = kArm;
- if (Verbose) printf("Sample %d: Found a leader ...", Counter);
- accumulator = 8*kHeadSize; }
- break;
- }
-
- return(retVal);
- }
-
-
-
- /* bytes->files engine */
-
- unsigned int CRCupdate(unsigned int CRC, unsigned char new)
- {
- unsigned int aux = CRC ^ (new << 8);
- int i;
-
- for(i=0; i<8; i++)
- if (aux & 0x8000)
- aux = (aux <<= 1) ^ kCRCpoly;
- else
- aux <<= 1;
-
- return(aux);
- }
-
-
- unsigned int CRCheck(unsigned char* buffer, unsigned int size)
- {
- int chunks;
- int error = 0;
- int i,j, offset1,offset2;
- unsigned int CRC;
-
-
- chunks = size >> 8;
-
- for(i=0; i<chunks; i++)
- {
- CRC = 0xFFFF;
- offset1 = 256*i;
- offset2 = 258*i;
- for(j=0; j<256; j++)
- CRC = CRCupdate(CRC, buffer[offset1+j] = buffer[offset2+j]);
- CRCupdate(CRC, 0);
- CRCupdate(CRC, 0);
- if ((~CRC & 0xFFFF) != (buffer[offset2+257]+256*buffer[offset2+256])) error = 1;
- }
-
- return(error);
- }
-
-
-
- void Tape2DOS()
- {
- unsigned char AuxBuff[128];
- unsigned int CRC = 0;
- char nameBuff[12];
- char prevFile[17];
- int newBlock,firstBlock;
- int i,j,s;
- char c,x;
-
- for(i=0; i<16; i++) prevFile[i] = currentFile[i];
- for(i=0; i<16; i++) currentFile[i] = BlockBuff[i];
- prevFile[16] = 0;
- newBlock = BlockBuff[16];
- closeOnNext = BlockBuff[17];
- currentSize2 = currentSize = BlockBuff[19]+256*BlockBuff[20];
- firstBlock = BlockBuff[23];
- if (CRCheck(BlockBuff, kHeadSize))
- fprintf(stderr," **** Incorrect HEADER checksum !\n");
-
- if (Verbose)
- printf(" Found block %d of file %s\n", newBlock, currentFile);
- if (!firstBlock && (newBlock != (currentBlock+1)) )
- fprintf(stderr," **** Missed some blocks of file %s !\n", currentFile);
-
- if (currentSize > kDataSize)
- {
- currentSize = kDataSize;
- fprintf(stderr," **** Block size error !\n");
- }
- else
- if (Verbose) printf(" Data block size %d bytes\n", currentSize);
- i = currentSize & 0xFF00; /* padding */
- if (currentSize & 0xFF) i+= 256;
- currentSize = i;
- currentBlock = newBlock;
- BlockReady = 1;
-
- s = strlen(currentFile); /* name conversion function */
- j = 0;
- for(i=0; i<11; i++)
- {
- if (j<s)
- {
- c = toupper(currentFile[j++]);
- if (c == '.')
- {
- if (i>7) i--;
- else { x = '_'; j--; }
- }
- else
- { if (!isalnum(c)) x = '#'; else x = c; }
- }
- else x = '_';
- nameBuff[i] = x;
- }
- for(j=10; nameBuff[j] == '_'; j--) ;
- nameBuff[j+1] = 0;
-
- if (strncmp(currentFile, prevFile, 16))
- { /* the file names differ */
- if (isOpen)
- {
- if (closeOnNext)
- { /* fine completion */
- closeOnNext = 0;
- fclose(Target);
- isOpen = 0;
- printf(" >>>> File %s terminated...\n", prevFile);
- }
- else
- {
- fclose(Target); /* we missed the end of prev file */
- fprintf(stderr," **** File %s did not terminate properly !\n", currentFile);
- }
- }
- printf(" >>>> Saving tape file %s as disc file %s\n", currentFile, nameBuff);
- Target = fopen(nameBuff, "wb");
- isOpen = 1;
- }
- else /* the file names are identical */
- goto end; /* the header has already been created */
-
- if (Verbose)
- printf(" Indicated total size %d bytes\n", BlockBuff[24]+256*BlockBuff[25]);
- if (BlockBuff[18] & 0xF0) goto end; /* No header for ASCII files */
- if (Verbose)
- {
- printf(" File is not ASCII, creating AMSDOS header:\n");
- switch((BlockBuff[18]&0x0F)>>1)
- {
- case 0:
- printf(" Locomotive BASIC file\n");
- break;
- case 1:
- printf(" Binary File, origin %d, entry %d\n",
- BlockBuff[21]+256*BlockBuff[22],
- BlockBuff[26]+256*BlockBuff[27]);
- break;
- case 2:
- printf(" Binary Screen Image\n");
- break;
- case 3:
- printf(" **** Inconsistent file typing: ASCII\n");
- break;
- }
- }
-
- for(i=0; i<128; i++) AuxBuff[i] = 0;
- for(i=0; i<11; i++)
- if (BlockBuff[i]) AuxBuff[i+1] = BlockBuff[i];
- else AuxBuff[i+1] = ' ';
-
- for(i=18; i<28; i++) AuxBuff[i] = BlockBuff[i];
- AuxBuff[23] = 255;
- AuxBuff[64] = BlockBuff[24];
- AuxBuff[65] = BlockBuff[25];
-
- for (i=0; i<67; i++) CRC += AuxBuff[i];
- AuxBuff[67] = CRC & 255;
- AuxBuff[68] = (CRC >> 8) & 255;
- for (i=0; i<128; i++) fputc(AuxBuff[i], Target);
-
- end:
- }
-
-
- void saveData()
- {
- int i;
-
- if (CRCheck(BlockBuff, currentSize))
- fprintf(stderr, " **** Incorrect DATA checksum !\n");
-
- for(i=0; i<currentSize2; i++)
- fputc(BlockBuff[i], Target);
- printf(" Saving block %d of file %s\n", currentBlock, currentFile);
- BlockReady = 0;
- }
-
- void rescueData()
- {
- int i;
-
- Target = fopen("Rescued.Blocks", "ab");
-
- if (CRCheck(BlockBuff, kDataSize))
- fprintf(stderr, " **** Incorrect DATA checksum !\n");
-
- for(i=0; i<kDataSize; i++)
- fputc(BlockBuff[i], Target);
- fprintf(stderr, " **** One data block rescued !\n");
- fclose(Target);
- }
-
- void SendByte(unsigned char newByte)
- {
- BlockBuff[bytePt-1] = newByte;
-
- if (engaged == kNo) /* the byte received is the last of a block or header */
- { /* bytePt still holds correct count */
- if (bytePt == (currentSize+kCRCSizeD))
- {if (isOpen && BlockReady) saveData(); else rescueData(); }
- /* if data found without header */
- if (bytePt == (kHeadSize+kCRCSizeH)) Tape2DOS();
- }
- }
-
-
-
-
-
- /* wave->delta engine and calling point for other levels */
-
-
- int getNext()
- {
- int buffer, retVal;
-
- Counter++;
- if (Step) fseek(Source, Step, 1);
- if ((buffer = fgetc(Source)) == EOF)
- {
- if (Verbose) printf("%d samples scanned. Offset %d\n",Counter, ftell(Source));
- return(kNULL);
- }
- if (buffer>>7) retVal = buffer-256; else retVal = buffer;
- if (Polarity) retVal = -retVal;
- return(retVal);
- }
-
- long remind = 0;
-
- int filter(int s0, int s1, int delta)
- {
- if (delta<W0Low)
- {
- if ((engaged != kNo) && ( ((s0<0)&&(s1>=0)) || ((!s0)&&(s1>0)) ))
- { if (! (delta<WMin))
- {
- if (Verbose)
- fprintf(stderr," **** Narrow strobe in data, sample %d\n", Counter);
- return(1);
- }
- else return(0);
- }
- else return(0);
- }
- else if (delta<W0High) return( ((s0<0)&&(s1>=0)) || ((!s0)&&(s1>0)) );
- else if (delta<W1Low)
- { /* shitty case */
- if ( ((s0<0)&&(s1>=0)) || ((!s0)&&(s1>0)) )
- {
- if ((engaged != kNo) && Verbose) /* not so important */
- printf(" **** Bad strobe in data at sample %d\n", Counter);
- return(1);
- }
- else return(0);
- }
- else if (delta<W1High) return( ((s0<0)&&(s1>=0)) || ((!s0)&&(s1>0)) );
- else if ((engaged != kNo) || remind )
- {
- if (delta>WTopIn)
- {
- if (Verbose)
- fprintf(stderr," **** Wide strobe in data, samples %d-%d\n", remind, Counter);
- remind = 0;
- return(1); }
- else { if (!remind) remind = Counter; /* begin wide arch */
- return(0); }
- }
- else return(delta > WTopOut);
- }
-
-
- void doProcess()
- {
- int i, last, new, delta, resByte;
-
- for(i=0; i<17; i++) currentFile[i] = 0;
- delta = 1;
-
- while ((new = getNext()) != kNULL)
- {
- if ( filter(new, last, delta) ) /* raising slope inversion */
- {
- resByte = sendDelta(delta); /* bit->bytes/blocks */
- if (resByte != kNULL) SendByte(resByte); /* bytes/blocks->files */
- delta = 1;
- }
- else
- delta++;
-
- last = new;
- }
-
- if (isOpen)
- {
- if ((engaged == kNo) || (engaged == kArm)) /* not in data */
- {
- if (closeOnNext && !BlockReady) /* all fine */
- { if (Verbose) printf(" File %s terminated properly.\n",currentFile);}
- else /* missed some blocks */
- {
- fprintf(stderr," **** File %s did not terminate properly !\n", currentFile);
- rescueData();
- }
- }
- else /* in data */
- {
- fprintf(stderr," **** File %s did not terminate properly !\n", currentFile);
- rescueData();
- }
- }
- else
- if (engaged == kData) rescueData();
- }
-
-
- void makeWindows()
- {
- WLine = (SlowRate*kTreshold)/Ratio; /* (CPU clocks/one)/(ticks/sample) -> sample/one */
- WMin = WLine/2; /* WMin = 2, WTopIn = 15, WTopOut = 250 */
- W0Low = WLine/2 +1; /* WLine = 5, W0Low = 3, W0High = 6, W1Low = 7, W1High = 10 */
- W0High = WLine+1;
- W1Low = (3*WLine)/2;
- W1High = WLine*2;
- WTopIn = kTopIn*WLine;
- WTopOut = kTopOut*WLine;
- }
-
-
- /* data formatting service routine */
-
-
- int checkAIFF()
- {
- int i;
- unsigned char buffer[256];
- char *aux;
- unsigned char bits,channels,exponent,mantissa;
- long rate, nyquist = (9600/SlowRate)*4;
-
- for(i=0; i<255; i++)
- { buffer[i] = fgetc(Source); if (buffer[i] == '\0') buffer[i] = ' ';}
- buffer[i] = '\0';
- if ( (strstr(buffer, "AIFF") != NULL) ||
- ((strstr(buffer, "AIFC") != NULL) && (strstr(buffer, "NONE") != NULL)) )
- {
- aux = strstr(buffer, "COMM");
- channels = *(aux+9);
- bits = *(aux+15);
- exponent = *(aux+17);
- mantissa = *(aux+18);
- rate = (long)mantissa << (exponent-6); /* result is approx. Hz */
-
- if (Verbose)
- printf("File is %d-bit, %d-channeled, %d Hz\n",(int)bits,(int)channels, rate);
- if (rate < nyquist)
- fprintf(stderr, "Unable to process file with optimal Nyquist frequency\n");
- else
- Step *= rate/nyquist; /* will filter high frequencies */
- /* number of CPC clock cycles per sample after Step-decimation: */
- Ratio = (int)( ((long)Step * 3993600L) / rate);
- Step *= channels;
- if (bits>8) Step *= 2;
- if (Verbose)
- printf("Adopting sample step = %d\n", Step);
- Step--; /* because fgetc will move 1 step forward .. */
-
- if ((channels == 1) && Right) printf("File is mono, ignoring -r flag\n");
- fseek ( Source, ((unsigned long)strstr(buffer, "SSND")-(unsigned long)buffer)+16, 0 );
- if ((channels > 1) && Right)
- { fgetc(Source); if (bits>8) fgetc(Source);}
- return(1);
- }
- else
- return(0);
- }
-
-
-
- /* shell interface system below */
-
-
- void doFlags(char *theFlags)
- {
- int i,j;
- char t;
-
- j = strlen(theFlags);
- for(i=1; i<j; i++)
- {t = tolower(theFlags[i]);
- if (t=='r') Right = 1; /* use second audio channel */
- else
- if (t=='v') Verbose = 1;
- else
- if (t=='p') Polarity = 1; /* change signs */
- else
- if ((t >= '1') & (t < '9')) SlowRate = (int)(t-'0');
- else
- { fprintf(stderr,"Unknown option flag: -%c\n",t); exit(4); }
- }
- }
-
-
- void doFile(char *theFile)
- {
- char SourceName[256];
- int i;
-
- #if MSDOS == 1
- sprintf (SourceName, "%s.aif", theFile);
- #else
- sprintf (SourceName, "%s.aiff", theFile);
- #endif
-
- if ((Source = fopen(SourceName,"rb")) == NULL)
- { fprintf(stderr, "Unable to open %s, trying %s\n", SourceName, theFile);
- if ((Source = fopen(theFile,"rb")) == NULL)
- { fprintf(stderr, "Unable to open %s\n", theFile);
- exit(3); } }
-
- if (checkAIFF())
- { makeWindows(); doProcess(); }
- else
- { fprintf(stderr,"File %s is not valid uncompressed AIFF !\n", theFile); exit(2); }
- fclose(Source);
- }
-
-
- int main(int argc, char **argv)
- {
- #if MSDOS == 1
- _fmode = O_BINARY;
- #endif
-
- printf("AIFF Decoder 1.1, (c) 1996 Pierre Guerrier\n");
-
- switch(argc)
- {
- case 2: doFile(argv[1]); exit(0); break;
- case 3:
- if (argv[1][0] == '-') {doFlags(argv[1]); doFile(argv[2]); exit(0); break;}
- default:
- fprintf(stderr,"Usage: %s [-rpvn] file\n where n is in range 1..8\n", argv[0]);
- exit(1);
- break;
- }
- }
-