Path: blob/master/tools/sdk-tools/adpcm/vadpcm_enc.c
7861 views
#include <string.h>1#include <assert.h>2#include <stdio.h>3#include <stdlib.h>4#include <getopt.h>5#include "vadpcm.h"67static char usage[] = "[-t -l min_loop_length] -c codebook aifcfile compressedfile";89int main(int argc, char **argv)10{11s32 c;12char *progname = argv[0];13s16 nloops = 0;14s16 numMarkers;15s16 *inBuffer;16s16 ts;17s32 minLoopLength = 800;18s32 ***coefTable = NULL;19s32 *state;20s32 order;21s32 npredictors;22s32 done = 0;23s32 truncate = 0;24s32 num;25s32 tableSize;26s32 nsam;27s32 left;28u32 newEnd;29s32 nRepeats;30s32 i;31s32 j;32s32 k;33s32 nFrames;34s32 offset;35s32 cChunkPos;36s32 currentPos;37s32 soundPointer = 0;38s32 startPointer = 0;39s32 startSoundPointer = 0;40s32 cType;41s32 nBytes = 0;42u32 loopEnd;43char *compName = "VADPCM ~4-1";44char *appCodeName = "VADPCMCODES";45char *appLoopName = "VADPCMLOOPS";46u8 strnLen;47Chunk AppChunk;48Chunk FormChunk;49ChunkHeader CSndChunk;50ChunkHeader Header;51CommonChunk CommChunk;52SoundDataChunk SndDChunk;53InstrumentChunk InstChunk;54Loop *loops = NULL;55ALADPCMloop *aloops;56Marker *markers;57CodeChunk cChunk;58char filename[1024];59FILE *fhandle;60FILE *ifile;61FILE *ofile;6263if (argc < 2)64{65fprintf(stderr, "%s %s\n", progname, usage);66exit(1);67}6869while ((c = getopt(argc, argv, "tc:l:")) != -1)70{71switch (c)72{73case 'c':74if (sscanf(optarg, "%s", filename) == 1)75{76if ((fhandle = fopen(filename, "r")) == NULL)77{78fprintf(stderr, "Codebook file %s could not be opened\n", filename);79exit(1);80}81if (readcodebook(fhandle, &coefTable, &order, &npredictors) != 0)82{83fprintf(stderr, "Error reading codebook\n");84exit(1);85}86}87break;8889case 't':90truncate = 1;91break;9293case 'l':94sscanf(optarg, "%d", &minLoopLength);95break;9697default:98break;99}100}101102if (coefTable == 0)103{104fprintf(stderr, "You should specify a coefficient codebook with the [-c] option\n");105exit(1);106}107108argv += optind - 1;109if ((ifile = fopen(argv[1], MODE_READ)) == NULL)110{111fprintf(stderr, "%s: input file [%s] could not be opened.\n", progname, argv[1]);112exit(1);113}114if ((ofile = fopen(argv[2], MODE_WRITE)) == NULL)115{116fprintf(stderr, "%s: output file [%s] could not be opened.\n", progname, argv[2]);117exit(1);118}119120state = malloc(16 * sizeof(s32));121for (i = 0; i < 16; i++)122{123state[i] = 0;124}125126#ifndef __sgi127// If there is no instrument chunk, make sure to output zeroes instead of128// garbage. (This matches how the IRIX -g-compiled version behaves.)129memset(&InstChunk, 0, sizeof(InstChunk));130#endif131132inBuffer = malloc(16 * sizeof(s16));133134fread(&FormChunk, sizeof(Chunk), 1, ifile);135BSWAP32(FormChunk.ckID)136BSWAP32(FormChunk.ckSize)137BSWAP32(FormChunk.formType)138139// @bug This doesn't check for FORM for AIFF files, probably due to mistaken operator precedence.140if (!((FormChunk.ckID == 0x464f524d && // FORM141FormChunk.formType == 0x41494643) || // AIFC142FormChunk.formType == 0x41494646)) // AIFF143{144fprintf(stderr, "%s: [%s] is not an AIFF-C File\n", progname, argv[1]);145exit(1);146}147148while (!done)149{150num = fread(&Header, 8, 1, ifile);151if (num <= 0)152{153done = 1;154break;155}156BSWAP32(Header.ckID)157BSWAP32(Header.ckSize)158159Header.ckSize++, Header.ckSize &= ~1;160switch (Header.ckID)161{162case 0x434f4d4d: // COMM163offset = ftell(ifile);164num = fread(&CommChunk, sizeof(CommonChunk), 1, ifile);165if (num <= 0)166{167fprintf(stderr, "%s: error parsing file [%s]\n", progname, argv[1]);168done = 1;169}170BSWAP16(CommChunk.numChannels)171BSWAP16(CommChunk.numFramesH)172BSWAP16(CommChunk.numFramesL)173BSWAP16(CommChunk.sampleSize)174if (FormChunk.formType != 0x41494646) // AIFF175{176BSWAP16(CommChunk.compressionTypeH)177BSWAP16(CommChunk.compressionTypeL)178cType = (CommChunk.compressionTypeH << 16) + CommChunk.compressionTypeL;179if (cType != 0x4e4f4e45) // NONE180{181fprintf(stderr, "%s: file [%s] contains compressed data.\n", progname, argv[1]);182exit(1);183}184}185if (CommChunk.numChannels != 1)186{187fprintf(stderr, "%s: file [%s] contains %ld channels, only 1 channel supported.\n", progname, argv[1], (long) CommChunk.numChannels);188exit(1);189}190if (CommChunk.sampleSize != 16)191{192fprintf(stderr, "%s: file [%s] contains %ld bit samples, only 16 bit samples supported.\n", progname, argv[1], (long) CommChunk.sampleSize);193exit(1);194}195fseek(ifile, offset + Header.ckSize, SEEK_SET);196break;197198case 0x53534e44: // SSND199offset = ftell(ifile);200fread(&SndDChunk, sizeof(SoundDataChunk), 1, ifile);201BSWAP32(SndDChunk.offset)202BSWAP32(SndDChunk.blockSize)203// The assert error messages specify line numbers 219/220. Match204// that using a #line directive.205#ifdef __sgi206# line 218207#endif208assert(SndDChunk.offset == 0);209assert(SndDChunk.blockSize == 0);210soundPointer = ftell(ifile);211fseek(ifile, offset + Header.ckSize, SEEK_SET);212break;213214case 0x4d41524b: // MARK215offset = ftell(ifile);216fread(&numMarkers, sizeof(s16), 1, ifile);217BSWAP16(numMarkers)218markers = malloc(numMarkers * sizeof(Marker));219for (i = 0; i < numMarkers; i++)220{221fread(&markers[i], sizeof(Marker), 1, ifile);222BSWAP16(markers[i].MarkerID)223BSWAP16(markers[i].positionH)224BSWAP16(markers[i].positionL)225fread(&strnLen, 1, 1, ifile);226if ((strnLen & 1) != 0)227{228fseek(ifile, strnLen, SEEK_CUR);229}230else231{232fseek(ifile, strnLen + 1, SEEK_CUR);233}234}235fseek(ifile, offset + Header.ckSize, SEEK_SET);236break;237238case 0x494e5354: // INST239offset = ftell(ifile);240fread(&InstChunk, sizeof(InstrumentChunk), 1, ifile);241BSWAP16(InstChunk.sustainLoop.playMode)242BSWAP16(InstChunk.sustainLoop.beginLoop)243BSWAP16(InstChunk.sustainLoop.endLoop)244BSWAP16(InstChunk.releaseLoop.playMode)245BSWAP16(InstChunk.releaseLoop.beginLoop)246BSWAP16(InstChunk.releaseLoop.endLoop)247aloops = malloc(2 * sizeof(ALADPCMloop));248loops = malloc(2 * sizeof(Loop));249if (InstChunk.sustainLoop.playMode == 1)250{251loops[nloops].beginLoop = InstChunk.sustainLoop.beginLoop;252loops[nloops].endLoop = InstChunk.sustainLoop.endLoop;253nloops++;254}255if (InstChunk.releaseLoop.playMode == 1)256{257loops[nloops].beginLoop = InstChunk.releaseLoop.beginLoop;258loops[nloops].endLoop = InstChunk.releaseLoop.endLoop;259nloops++;260}261fseek(ifile, offset + Header.ckSize, SEEK_SET);262break;263264default:265fseek(ifile, Header.ckSize, SEEK_CUR);266break;267}268}269270FormChunk.formType = 0x41494643; // AIFC271BSWAP32(FormChunk.ckID)272BSWAP32(FormChunk.ckSize)273BSWAP32(FormChunk.formType)274fwrite(&FormChunk, sizeof(Chunk), 1, ofile);275276Header.ckID = 0x434f4d4d; // COMM277Header.ckSize = sizeof(CommonChunk) + 1 + 11;278BSWAP32(Header.ckID)279BSWAP32(Header.ckSize)280fwrite(&Header, sizeof(ChunkHeader), 1, ofile);281CommChunk.compressionTypeH = 0x5641; // VA282CommChunk.compressionTypeL = 0x5043; // PC283cChunkPos = ftell(ofile);284// CommChunk written later285fwrite(&CommChunk, sizeof(CommonChunk), 1, ofile);286strnLen = sizeof("VADPCM ~4-1") - 1;287fwrite(&strnLen, 1, 1, ofile);288fwrite(compName, strnLen, 1, ofile);289290Header.ckID = 0x494e5354; // INST291Header.ckSize = sizeof(InstrumentChunk);292BSWAP32(Header.ckID)293BSWAP32(Header.ckSize)294fwrite(&Header, sizeof(ChunkHeader), 1, ofile);295BSWAP16(InstChunk.sustainLoop.playMode)296BSWAP16(InstChunk.sustainLoop.beginLoop)297BSWAP16(InstChunk.sustainLoop.endLoop)298BSWAP16(InstChunk.releaseLoop.playMode)299BSWAP16(InstChunk.releaseLoop.beginLoop)300BSWAP16(InstChunk.releaseLoop.endLoop)301fwrite(&InstChunk, sizeof(InstrumentChunk), 1, ofile);302303tableSize = order * 2 * npredictors * 8;304strnLen = sizeof("VADPCMCODES") - 1;305AppChunk.ckID = 0x4150504c; // APPL306AppChunk.ckSize = 4 + tableSize + 1 + strnLen + sizeof(CodeChunk);307AppChunk.formType = 0x73746f63; // stoc308BSWAP32(AppChunk.ckID)309BSWAP32(AppChunk.ckSize)310BSWAP32(AppChunk.formType)311fwrite(&AppChunk, sizeof(Chunk), 1, ofile);312cChunk.version = 1;313cChunk.order = order;314cChunk.nEntries = npredictors;315BSWAP16(cChunk.version)316BSWAP16(cChunk.order)317BSWAP16(cChunk.nEntries)318fwrite(&strnLen, 1, 1, ofile);319fwrite(appCodeName, strnLen, 1, ofile);320fwrite(&cChunk, sizeof(CodeChunk), 1, ofile);321322for (i = 0; i < npredictors; i++)323{324for (j = 0; j < order; j++)325{326for (k = 0; k < 8; k++)327{328ts = coefTable[i][k][j];329BSWAP16(ts)330fwrite(&ts, sizeof(s16), 1, ofile);331}332}333}334335currentPos = 0;336if (soundPointer > 0)337{338fseek(ifile, soundPointer, SEEK_SET);339}340else341{342fprintf(stderr, "%s: Error in sound chunk", progname);343exit(1);344}345346soundPointer = ftell(ofile);347// CSndChunk written later348fwrite(&CSndChunk, sizeof(ChunkHeader), 1, ofile);349BSWAP32(SndDChunk.offset)350BSWAP32(SndDChunk.blockSize)351fwrite(&SndDChunk, sizeof(SoundDataChunk), 1, ofile);352startSoundPointer = ftell(ifile);353for (i = 0; i < nloops; i++)354{355if (lookupMarker(&aloops[i].start, loops[i].beginLoop, markers, numMarkers) != 0)356{357fprintf(stderr, "%s: Start loop marker not found\n", progname);358}359else if (lookupMarker(&aloops[i].end, loops[i].endLoop, markers, numMarkers) != 0)360{361fprintf(stderr, "%s: End loop marker not found\n", progname);362}363else364{365startPointer = startSoundPointer + aloops[i].start * 2;366nRepeats = 0;367newEnd = aloops[i].end;368while (newEnd - aloops[i].start < minLoopLength)369{370nRepeats++;371newEnd += aloops[i].end - aloops[i].start;372}373374while (currentPos <= aloops[i].start)375{376if (fread(inBuffer, sizeof(s16), 16, ifile) == 16)377{378BSWAP16_MANY(inBuffer, 16)379vencodeframe(ofile, inBuffer, state, coefTable, order, npredictors, 16);380currentPos += 16;381nBytes += 9;382}383else384{385fprintf(stderr, "%s: Not enough samples in file [%s]\n", progname, argv[1]);386exit(1);387}388}389390for (j = 0; j < 16; j++)391{392if (state[j] >= 0x8000)393{394state[j] = 0x7fff;395}396if (state[j] < -0x7fff)397{398state[j] = -0x7fff;399}400aloops[i].state[j] = state[j];401}402403aloops[i].count = -1;404while (nRepeats > 0)405{406for (; currentPos + 16 < aloops[i].end; currentPos += 16)407{408if (fread(inBuffer, sizeof(s16), 16, ifile) == 16)409{410BSWAP16_MANY(inBuffer, 16)411vencodeframe(ofile, inBuffer, state, coefTable, order, npredictors, 16);412nBytes += 9;413}414}415left = aloops[i].end - currentPos;416fread(inBuffer, sizeof(s16), left, ifile);417BSWAP16_MANY(inBuffer, left)418fseek(ifile, startPointer, SEEK_SET);419fread(inBuffer + left, sizeof(s16), 16 - left, ifile);420BSWAP16_MANY(inBuffer + left, 16 - left)421vencodeframe(ofile, inBuffer, state, coefTable, order, npredictors, 16);422nBytes += 9;423currentPos = aloops[i].start - left + 16;424nRepeats--;425}426aloops[i].end = newEnd;427}428}429430nFrames = (CommChunk.numFramesH << 16) + CommChunk.numFramesL;431if ((nloops > 0U) & truncate)432{433lookupMarker(&loopEnd, loops[nloops - 1].endLoop, markers, numMarkers);434nFrames = (loopEnd + 16 < nFrames ? loopEnd + 16 : nFrames);435}436437while (currentPos < nFrames)438{439if (nFrames - currentPos < 16)440{441nsam = nFrames - currentPos;442}443else444{445nsam = 16;446}447448if (fread(inBuffer, 2, nsam, ifile) == nsam)449{450BSWAP16_MANY(inBuffer, nsam)451vencodeframe(ofile, inBuffer, state, coefTable, order, npredictors, nsam);452currentPos += nsam;453nBytes += 9;454}455else456{457fprintf(stderr, "Missed a frame!\n");458break;459}460}461462if (nBytes % 2)463{464nBytes++;465ts = 0;466fwrite(&ts, 1, 1, ofile);467}468469if (nloops > 0)470{471strnLen = sizeof("VADPCMLOOPS") - 1;472AppChunk.ckID = 0x4150504c; // APPL473AppChunk.ckSize = nloops * sizeof(ALADPCMloop) + strnLen + 4 + 1 + 2 + 2;474AppChunk.formType = 0x73746f63; // stoc475BSWAP32(AppChunk.ckID)476BSWAP32(AppChunk.ckSize)477BSWAP32(AppChunk.formType)478fwrite(&AppChunk, sizeof(Chunk), 1, ofile);479fwrite(&strnLen, 1, 1, ofile);480fwrite(appLoopName, strnLen, 1, ofile);481ts = 1;482BSWAP16(ts)483fwrite(&ts, sizeof(s16), 1, ofile);484BSWAP16(nloops)485fwrite(&nloops, sizeof(s16), 1, ofile);486BSWAP16(nloops)487for (i = 0; i < nloops; i++)488{489BSWAP32(aloops[i].start)490BSWAP32(aloops[i].end)491BSWAP32(aloops[i].count)492BSWAP16_MANY(aloops[i].state, 16)493fwrite(&aloops[i], sizeof(ALADPCMloop), 1, ofile);494}495}496497fseek(ofile, soundPointer, SEEK_SET);498CSndChunk.ckID = 0x53534e44; // SSND499CSndChunk.ckSize = nBytes + 8;500BSWAP32(CSndChunk.ckID)501BSWAP32(CSndChunk.ckSize)502fwrite(&CSndChunk, sizeof(ChunkHeader), 1, ofile);503fseek(ofile, cChunkPos, SEEK_SET);504nFrames = nBytes * 16 / 9;505CommChunk.numFramesH = nFrames >> 16;506CommChunk.numFramesL = nFrames & 0xffff;507BSWAP16(CommChunk.numChannels)508BSWAP16(CommChunk.numFramesH)509BSWAP16(CommChunk.numFramesL)510BSWAP16(CommChunk.sampleSize)511BSWAP16(CommChunk.compressionTypeH)512BSWAP16(CommChunk.compressionTypeL)513fwrite(&CommChunk, sizeof(CommonChunk), 1, ofile);514fclose(ifile);515fclose(ofile);516return 0;517}518519520