/* decode.c * Handlers for decoding a kexis stream into a wav stream. * Copyright (C) 2000 Wayde Milas (wmilas@rarcoa.com) * This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include "types.h" #include "decode.h" #include "bits.h" #include "header.h" #include "rice.h" #include "predictor.h" #include "kexis.h" void decompress(KEXISHEADER *kexisHead, OPTIONSTRUCT *options) { size_t holdRead; unsigned long totalBlocks; KEXISBLOCKSTRUCT kexisBlock; PCMBLOCKSTRUCT pcmBlock; options->inFileStream = fopen(options->inFileName, "rb"); if(options->inFileStream == NULL) { sprintf(options->errorString, "Can't open file: %s!", options->inFileName); handle_error(options); } if(options->progress) printf("\nDecoding file: %s\n", options->inFileName); // Suck in the KexisHeader parse_kexis_header(kexisHead, options); totalBlocks = kexisHead->dataLength; pcmBlock.pcmStreamLength = kexisHead->dataLength; totalBlocks = totalBlocks / 2; kexisBlock.data = malloc((sizeof(long)*(options->frameSize/2))); pcmBlock.data = malloc(sizeof(short) * options->frameSize); zero_predictor_table(&kexisBlock.predictor, options); kexisBlock.dataPosition = sizeof(KEXISHEADER); kexisBlock.blockPointer=0; kexisBlock.subBlockPointer=0; pcmBlock.size=0; kexisBlock.sumTotalSize =0; kexisBlock.debugBlockCount = 0; // Fill up the kexisBlock data buffer. holdRead = fread(kexisBlock.data, sizeof(long), options->frameSize/2, options->inFileStream); if(holdRead <= 0) { sprintf(options->errorString, "Error reading from %s!", options->inFileName); handle_error(options); } if(options->predictorVersion == FRAME_PREDICTOR) { pcmBlock.currentAve = bit_suck(&kexisBlock, 3, &pcmBlock, options); pcmBlock.currentMid = bit_suck(&kexisBlock, 3, &pcmBlock, options); } while(kexisBlock.sumTotalSize < totalBlocks) { if(options->progress && options->dec_stdout==0 && (kexisBlock.sumTotalSize % options->frameSize)==0) print_progress(&kexisBlock, kexisBlock.sumTotalSize/2, options, totalBlocks, DECOMPRESS); decode_kexisblock(&kexisBlock, &pcmBlock, options); } write_pcmblock(options, &kexisBlock, &pcmBlock, 0, 1); handle_verbose(options, &kexisBlock, &pcmBlock); free_allocated(&pcmBlock, &kexisBlock, options); } void decode_kexisblock(KEXISBLOCKSTRUCT *kexisBlock, PCMBLOCKSTRUCT *pcmBlock, OPTIONSTRUCT *options) { long diffMid, diffAve, mid, ave; short right, left; rice_decode(kexisBlock, &diffMid, options, pcmBlock, MID); //kexisBlock->debugBlockCount++; rice_decode(kexisBlock, &diffAve, options, pcmBlock, AVE); //kexisBlock->debugBlockCount++; //difference_calc(&kexisBlock->predictor, options->predictorVersion, // diffMid, diffAve, DECOMPRESS); if(options->predictorVersion == FRAME_PREDICTOR) frame_difference_calc(&kexisBlock->predictor, pcmBlock->currentAve, pcmBlock->currentMid, diffMid, diffAve, DECOMPRESS); else difference_calc(&kexisBlock->predictor, options->predictorVersion, diffMid, diffAve, DECOMPRESS); mid = kexisBlock->predictor.diffMid; ave = kexisBlock->predictor.diffAve; // If we are gathering statistics, gather them :P if(options->verbose) collect_prediction_stats(kexisBlock, diffMid, diffAve); if(options->joint == 1) { right = ave - (mid/2); left = right + mid; } else { left = mid; right = ave; } //if(PRED_DEBUG == 1 && kexisBlock->sumTotalSize < 100000) { // printf("%ld: %ld %ld %ld %ld %d %d\n", kexisBlock->sumTotalSize, // diffMid, diffAve, mid, ave, left, right); // } kexisBlock->sumTotalSize +=2; write_pcmblock(options, kexisBlock, pcmBlock, left, 0); write_pcmblock(options, kexisBlock, pcmBlock, right, 0); } void write_pcmblock(OPTIONSTRUCT *options, KEXISBLOCKSTRUCT *kexisBlock, PCMBLOCKSTRUCT *pcmBlock, short data, int now) { int length; WAVHEADER wavHeader; if(options->outFileStream == NULL) { if(options->dec_stdout == 0) { options->outFileName = calloc(1, strlen(options->inFileName)+1); strncpy(options->outFileName, options->inFileName, strlen(options->inFileName)-3); strcat(options->outFileName, "wav\0"); options->outFileStream = fopen(options->outFileName, "wb"); if(options->outFileStream == NULL) { sprintf(options->errorString, "Can't open file: %s!", options->outFileName); handle_error(options); } } else { options->outFileStream = stdout; } create_wave_header(&wavHeader, pcmBlock->pcmStreamLength); length = fwrite(&wavHeader, sizeof(wavHeader), 1, options->outFileStream); if(length != 1) { sprintf(options->errorString, "Error writing Header to %s!", options->outFileName); handle_error(options); } } if(now == 0) { pcmBlock->data[pcmBlock->size] = data; pcmBlock->size++; } if((pcmBlock->size == options->frameSize) || (now==1)) { length = fwrite(pcmBlock->data, sizeof(short), pcmBlock->size, options->outFileStream); if(length != pcmBlock->size) { sprintf(options->errorString, "Error writing to %s!", options->outFileName); handle_error(options); } pcmBlock->size = 0; if(options->predictorVersion == FRAME_PREDICTOR) { pcmBlock->currentAve = bit_suck(kexisBlock, 3, pcmBlock, options); pcmBlock->currentMid = bit_suck(kexisBlock, 3, pcmBlock, options); } } }