sm64

A Super Mario 64 decompilation
Log | Files | Refs | README | LICENSE

vadpcm_dec.c (8673B)


      1 #include <unistd.h>
      2 #include <assert.h>
      3 #include <string.h>
      4 #include <stdio.h>
      5 #include <stdlib.h>
      6 #include <signal.h>
      7 #include <fcntl.h>
      8 #include "vadpcm.h"
      9 
     10 static void int_handler(s32 sig)
     11 {
     12     s32 flags;
     13 
     14     flags = fcntl(STDIN_FILENO, F_GETFL, 0);
     15     flags &= ~FNDELAY;
     16     fcntl(STDIN_FILENO, F_SETFL, flags);
     17     exit(0);
     18 }
     19 
     20 static char usage[] = "bitfile";
     21 
     22 #ifdef __sgi
     23 
     24 // Declaring a sigaction like this is wildly unportable; you're supposed to
     25 // assign members one by one in code. We do that in the non-SGI case.
     26 static struct sigaction int_act = {
     27     /* sa_flags =   */ SA_RESTART,
     28     /* sa_handler = */ &int_handler,
     29     /* sa_mask =    */ 0,
     30 };
     31 
     32 #endif
     33 
     34 s32 main(s32 argc, char **argv)
     35 {
     36     s32 c;
     37     u8 cc;
     38     u8 doloop = 0;
     39     s16 order;
     40     s16 version;
     41     s16 nloops;
     42     s16 npredictors;
     43     s32 flags;
     44     s32 ***coefTable = NULL;
     45     s32 i;
     46     s32 j;
     47     s32 *outp;
     48     s32 *state;
     49     s32 done = 0;
     50     s32 num;
     51     u32 ts;
     52     s32 soundPointer;
     53     s32 cType;
     54     s32 offset;
     55     s32 currPos = 0;
     56     s32 nSamples;
     57     s32 framePos;
     58     s32 loopBegin;
     59     s32 left;
     60     ALADPCMloop *aloops;
     61     Chunk FormChunk;
     62     ChunkHeader Header;
     63     CommonChunk CommChunk;
     64     SoundDataChunk SndDChunk;
     65     char *ChunkName;
     66     FILE *ifile;
     67     char *progname = argv[0];
     68 
     69 #ifndef __sgi
     70     nloops = 0;
     71 #endif
     72 
     73     if (argc < 2)
     74     {
     75         fprintf(stderr, "%s %s\n", progname, usage);
     76         exit(1);
     77     }
     78 
     79     while ((c = getopt(argc, argv, "l")) != -1)
     80     {
     81         switch (c)
     82         {
     83         case 'l':
     84             doloop = 1;
     85             break;
     86         }
     87     }
     88 
     89     argv += optind - 1;
     90     if ((ifile = fopen(argv[1], MODE_READ)) == NULL)
     91     {
     92         fprintf(stderr, "%s: bitstream file [%s] could not be opened\n", progname, argv[1]);
     93         exit(1);
     94     }
     95 
     96     state = malloc(16 * sizeof(int));
     97     for (i = 0; i < 16; i++)
     98     {
     99         state[i] = 0;
    100     }
    101 
    102     fread(&FormChunk, sizeof(FormChunk), 1, ifile);
    103     BSWAP32(FormChunk.ckID)
    104     BSWAP32(FormChunk.formType)
    105     if ((FormChunk.ckID != 0x464f524d) || (FormChunk.formType != 0x41494643)) // FORM, AIFC
    106     {
    107         fprintf(stderr, "%s: [%s] is not an AIFF-C File\n", progname, argv[1]);
    108         exit(1);
    109     }
    110 
    111     while (!done)
    112     {
    113         num = fread(&Header, sizeof(Header), 1, ifile);
    114         if (num <= 0)
    115         {
    116             done = 1;
    117             break;
    118         }
    119         BSWAP32(Header.ckID)
    120         BSWAP32(Header.ckSize)
    121 
    122         Header.ckSize++, Header.ckSize &= ~1;
    123         switch (Header.ckID)
    124         {
    125         case 0x434f4d4d: // COMM
    126             offset = ftell(ifile);
    127             num = fread(&CommChunk, sizeof(CommChunk), 1, ifile);
    128             if (num <= 0)
    129             {
    130                 fprintf(stderr, "%s: error parsing file [%s]\n", progname, argv[1]);
    131                 done = 1;
    132             }
    133             BSWAP16(CommChunk.numChannels)
    134             BSWAP16(CommChunk.numFramesH)
    135             BSWAP16(CommChunk.numFramesL)
    136             BSWAP16(CommChunk.sampleSize)
    137             BSWAP16(CommChunk.compressionTypeH)
    138             BSWAP16(CommChunk.compressionTypeL)
    139             cType = (CommChunk.compressionTypeH << 16) + CommChunk.compressionTypeL;
    140             if (cType != 0x56415043) // VAPC
    141             {
    142                 fprintf(stderr, "%s: file [%s] is of the wrong compression type.\n", progname, argv[1]);
    143                 exit(1);
    144             }
    145             if (CommChunk.numChannels != 1)
    146             {
    147                 fprintf(stderr, "%s: file [%s] contains %ld channels, only 1 channel supported.\n", progname, argv[1], (long) CommChunk.numChannels);
    148                 exit(1);
    149             }
    150             if (CommChunk.sampleSize != 16)
    151             {
    152                 fprintf(stderr, "%s: file [%s] contains %ld bit samples, only 16 bit samples supported.\n", progname, argv[1], (long) CommChunk.sampleSize);
    153                 exit(1);
    154             }
    155             nSamples = (CommChunk.numFramesH << 16) + CommChunk.numFramesL;
    156             fseek(ifile, offset + Header.ckSize, SEEK_SET);
    157             break;
    158 
    159         case 0x53534e44: // SSND
    160             offset = ftell(ifile);
    161             fread(&SndDChunk, sizeof(SndDChunk), 1, ifile);
    162             BSWAP32(SndDChunk.offset)
    163             BSWAP32(SndDChunk.blockSize)
    164             // The assert error messages specify line numbers 165/166. Match
    165             // that using a #line directive.
    166 #ifdef __sgi
    167 #  line 164
    168 #endif
    169             assert(SndDChunk.offset == 0);
    170             assert(SndDChunk.blockSize == 0);
    171             soundPointer = ftell(ifile);
    172             fseek(ifile, offset + Header.ckSize, SEEK_SET);
    173             break;
    174 
    175         case 0x4150504c: // APPL
    176             offset = ftell(ifile);
    177             fread(&ts, sizeof(u32), 1, ifile);
    178             BSWAP32(ts)
    179             if (ts == 0x73746f63) // stoc
    180             {
    181                 ChunkName = ReadPString(ifile);
    182                 if (strcmp("VADPCMCODES", ChunkName) == 0)
    183                 {
    184                     fread(&version, sizeof(s16), 1, ifile);
    185                     BSWAP16(version)
    186                     if (version != 1)
    187                     {
    188                         fprintf(stderr, "Non-identical codebook chunk versions\n");
    189                     }
    190                     readaifccodebook(ifile, &coefTable, &order, &npredictors);
    191                 }
    192                 else if (strcmp("VADPCMLOOPS", ChunkName) == 0)
    193                 {
    194                     fread(&version, sizeof(s16), 1, ifile);
    195                     BSWAP16(version)
    196                     if (version != 1)
    197                     {
    198                         fprintf(stderr, "Non-identical loop chunk versions\n");
    199                     }
    200                     aloops = readlooppoints(ifile, &nloops);
    201                 }
    202             }
    203             fseek(ifile, offset + Header.ckSize, SEEK_SET);
    204             break;
    205 
    206         default:
    207             // We don't understand this chunk. Skip it.
    208             fseek(ifile, Header.ckSize, SEEK_CUR);
    209             break;
    210         }
    211     }
    212 
    213     if (coefTable == NULL)
    214     {
    215         // @bug should use progname; argv[0] may be an option
    216         fprintf(stderr, "%s: Codebook missing from bitstream [%s]\n", argv[0], argv[1]);
    217         exit(1);
    218     }
    219 
    220     outp = malloc(16 * sizeof(s32));
    221     for (i = 0; i < order; i++)
    222     {
    223         outp[15 - i] = 0;
    224     }
    225 
    226     fseek(ifile, soundPointer, SEEK_SET);
    227     if (doloop && nloops > 0)
    228     {
    229 #ifndef __sgi
    230         struct sigaction int_act;
    231         int_act.sa_flags = SA_RESTART;
    232         int_act.sa_handler = int_handler;
    233         sigemptyset(&int_act.sa_mask);
    234 #endif
    235 
    236         sigaction(SIGINT, &int_act, NULL);
    237         flags = fcntl(STDIN_FILENO, F_GETFL, 0);
    238         flags |= FNDELAY;
    239         fcntl(STDIN_FILENO, F_SETFL, flags);
    240         for (i = 0; i < nloops; i++)
    241         {
    242             while (currPos < aloops[i].end)
    243             {
    244                 left = aloops[i].end - currPos;
    245                 vdecodeframe(ifile, outp, order, coefTable);
    246                 writeout(stdout, left < 16 ? left : 16, outp, outp, 1);
    247                 currPos += 16;
    248             }
    249 
    250             while (read(STDIN_FILENO, &cc, 1) == 0)
    251             {
    252                 framePos = (aloops[i].start >> 4) + 1;
    253                 fseek(ifile, (framePos * 9) + soundPointer, SEEK_SET);
    254                 for (j = 0; j < 16; j++)
    255                 {
    256                     outp[j] = aloops[i].state[j];
    257                 }
    258                 loopBegin = aloops[i].start & 0xf;
    259                 writeout(stdout, 16 - loopBegin, outp + loopBegin, outp + loopBegin, 1);
    260                 currPos = framePos * 16;
    261                 while (currPos < aloops[i].end)
    262                 {
    263                     left = aloops[i].end - currPos;
    264                     vdecodeframe(ifile, outp, order, coefTable);
    265                     writeout(stdout, left < 16 ? left : 16, outp, outp, 1);
    266                     currPos += 16;
    267                 }
    268             }
    269 
    270             left = 16 - left;
    271             if (left != 0)
    272             {
    273                 writeout(stdout, left, &outp[left], &outp[left], 1);
    274             }
    275 
    276             while (currPos < nSamples)
    277             {
    278                 vdecodeframe(ifile, outp, order, coefTable);
    279                 left = nSamples - currPos;
    280                 writeout(stdout, left < 16 ? left : 16, outp, outp, 1);
    281                 currPos += 16;
    282             }
    283 
    284             flags = fcntl(STDIN_FILENO, F_GETFL, 0);
    285             flags &= ~FNDELAY;
    286             fcntl(STDIN_FILENO, F_SETFL, flags);
    287         }
    288     }
    289     else
    290     {
    291         while (currPos < nSamples)
    292         {
    293             vdecodeframe(ifile, outp, order, coefTable);
    294             writeout(stdout, 16, outp, outp, 1);
    295             currPos += 16;
    296         }
    297     }
    298 
    299     fclose(ifile);
    300     return 0;
    301 }