/********************************************************/ /*** 4 bit ADPCM compression code ***/ /*** originally written by Perry R. Cook for ***/ /*** SIGGRAPH 1998 audio compression course. ***/ /*** This program takes a 16 bit linear signed ***/ /*** sound file and compresses it 4:1. ***/ /*** Use adpcmdec.c to decompress files. ***/ /********************************************************/ #include #include #include #include #define MAX_STEP 2048 #define MIN_STEP 16 #include "../waveio.h" int main(short argc, char *argv[]) { FILE *file_in,*file_out; long i; short XHAT1=0,Xn,Dn; short deln,del1=8; short delndec,del1dec=8,ln1dec; short ln1=1,sign,temp; short data[4]; unsigned short data_out; struct soundhdr hdr; float M[16] = {0.909,0.909,0.909,0.909,1.21,1.4641,1.771561,2.143589, 0.909,0.909,0.909,0.909,1.21,1.4641,1.771561,2.143589}; float del_table[16] = {0.0,0.25,0.5,0.75,1.0,1.25,1.5,1.75, 0.0,-0.25,-0.5,-0.75,-1.0,-1.25,-1.5,-1.75}; if (argc==3) { if (argv[2][strlen(argv[2])-1] != 'p') { printf("You should be creating a .adp file for output\n"); exit(0); } file_in = opensoundin(argv[1],&hdr); if (!file_in) { fprintf(stderr,"Input File Error\n"); exit(0); } #ifdef LITTLENDIAN hdr.format_tag = 259; #endif /* we're not creating a valid adpcm .wav file here. we're just */ /* scamming the header to preserve sample rate, etc. we only hack */ /* the format field, so nobody tries to play it as valid 16bit PCM. */ file_out = fopen(argv[2],"wb"); if (file_out) { #ifdef LITTLENDIAN fwrite(&hdr,44,1,file_out); #endif while(fread(&data,2,4,file_in)) { data_out = 0; for (i=0;i<4;i++) { Xn = data[i]; Dn = Xn - XHAT1; // Form delta signal deln = del1 * M[ln1]; // Get new delta temp = deln - MIN_STEP; // delta < min ??? if (temp<0) { // Skip 1 on positive deln = MIN_STEP; // set it to min } temp = MAX_STEP - deln; // delta > max ??? if (temp<0) { // Skip 1 on positive deln = MAX_STEP; // set it to max } del1 = deln; // Stash delta ln1 = 0; temp = Dn; // to set flags if (temp<0) { // Skip on positive ln1 = 8; // Else set negative Dn = -Dn; // bit in code word } temp = deln - Dn; // Check magnitude if (temp<0) { // Skip 2 on positive ln1 += 4; // set MSB in code word Dn -= deln; // decrease magnitude } temp = deln*0.5 - Dn; // Check magnitude if (temp<0) { // Skip 2 on positive ln1 += 2; // set 2SB in code word Dn -= deln*0.5; // decrease magnitude } temp = deln*0.25 - Dn; // Check magnitude if (temp<0) { // Skip 2 on positive ln1 += 1; // set LSB in code word } /******************* DECODER EMULATION *********************/ ln1dec = ln1; delndec = del1dec * M[ln1dec]; // form new delta temp = delndec - MIN_STEP; // test against min if (temp<0) // Skip 1 on positive delndec = MIN_STEP; // set to min temp = MAX_STEP - delndec; // test against max if (temp<0) // Skip 1 on positive delndec = MAX_STEP; // set to max del1dec = delndec; // save delta XHAT1 += delndec * del_table[ln1dec]; // do sample update if (XHAT1>32000 || XHAT1<-32000) // Skip if no saturate XHAT1 *= 0.95; // Else fix it /*************************************************************/ data_out = (data_out << 4) + ln1; } fwrite(&data_out,2,1,file_out); } } else { fprintf(stderr,"File troubles. Check names, paths, etc.\n"); } fclose(file_in); fclose(file_out); } else { fprintf(stderr,"format is: adpcmcod inputFile.wav(snd) outputFile.adp\n\n"); exit(0); } exit(1); }