1 /* decode.c
2  * Handlers for decoding a kexis stream into a wav stream.
3  * Copyright (C) 2000 Wayde Milas (wmilas@rarcoa.com)
4  *
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9 
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14 
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18 */
19 
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <math.h>
23 #include <string.h>
24 #include "types.h"
25 #include "decode.h"
26 #include "bits.h"
27 #include "header.h"
28 #include "rice.h"
29 #include "predictor.h"
30 #include "kexis.h"
31 
decompress(KEXISHEADER * kexisHead,OPTIONSTRUCT * options)32 void decompress(KEXISHEADER *kexisHead, OPTIONSTRUCT *options)
33 {
34 	size_t	holdRead;
35 	unsigned long totalBlocks;
36 	KEXISBLOCKSTRUCT kexisBlock;
37 	PCMBLOCKSTRUCT pcmBlock;
38 
39 	options->inFileStream = fopen(options->inFileName, "rb");
40   if(options->inFileStream == NULL) {
41     sprintf(options->errorString, "Can't open file: %s!", options->inFileName);
42     handle_error(options);
43   }
44 
45 	if(options->progress)
46 		printf("\nDecoding file: %s\n", options->inFileName);
47 
48 	// Suck in the KexisHeader
49 	parse_kexis_header(kexisHead, options);
50 
51 	totalBlocks = kexisHead->dataLength;
52 	pcmBlock.pcmStreamLength = kexisHead->dataLength;
53 	totalBlocks = totalBlocks / 2;
54 
55 	kexisBlock.data = malloc((sizeof(long)*(options->frameSize/2)));
56 	pcmBlock.data = malloc(sizeof(short) * options->frameSize);
57 	zero_predictor_table(&kexisBlock.predictor, options);
58 	kexisBlock.dataPosition = sizeof(KEXISHEADER);
59 	kexisBlock.blockPointer=0;
60 	kexisBlock.subBlockPointer=0;
61 	pcmBlock.size=0;
62 	kexisBlock.sumTotalSize =0;
63 	kexisBlock.debugBlockCount = 0;
64 
65 	// Fill up the kexisBlock data buffer.
66   holdRead = fread(kexisBlock.data, sizeof(long), options->frameSize/2,
67   	options->inFileStream);
68   if(holdRead <= 0) {
69   	sprintf(options->errorString, "Error reading from %s!",
70     	options->inFileName);
71     handle_error(options);
72   }
73 
74 	if(options->predictorVersion == FRAME_PREDICTOR) {
75 		pcmBlock.currentAve = bit_suck(&kexisBlock, 3, &pcmBlock, options);
76 		pcmBlock.currentMid = bit_suck(&kexisBlock, 3, &pcmBlock, options);
77 	}
78 
79 	while(kexisBlock.sumTotalSize < totalBlocks) {
80 
81 		if(options->progress && options->dec_stdout==0
82 			&& (kexisBlock.sumTotalSize % options->frameSize)==0)
83 			print_progress(&kexisBlock, kexisBlock.sumTotalSize/2, options,
84 				totalBlocks, DECOMPRESS);
85 
86 		decode_kexisblock(&kexisBlock, &pcmBlock, options);
87 	}
88 
89 	write_pcmblock(options, &kexisBlock, &pcmBlock, 0, 1);
90 	handle_verbose(options, &kexisBlock, &pcmBlock);
91 	free_allocated(&pcmBlock, &kexisBlock, options);
92 }
93 
decode_kexisblock(KEXISBLOCKSTRUCT * kexisBlock,PCMBLOCKSTRUCT * pcmBlock,OPTIONSTRUCT * options)94 void decode_kexisblock(KEXISBLOCKSTRUCT *kexisBlock, PCMBLOCKSTRUCT *pcmBlock,
95 	OPTIONSTRUCT *options)
96 {
97 	long  diffMid, diffAve, mid, ave;
98 	short	right, left;
99 
100 	rice_decode(kexisBlock, &diffMid, options, pcmBlock, MID);
101 	//kexisBlock->debugBlockCount++;
102 	rice_decode(kexisBlock, &diffAve, options, pcmBlock, AVE);
103 	//kexisBlock->debugBlockCount++;
104 
105 	//difference_calc(&kexisBlock->predictor, options->predictorVersion,
106 	//	diffMid, diffAve, DECOMPRESS);
107 	if(options->predictorVersion == FRAME_PREDICTOR)
108 		frame_difference_calc(&kexisBlock->predictor, pcmBlock->currentAve,
109 			pcmBlock->currentMid, diffMid, diffAve, DECOMPRESS);
110 	else
111 		difference_calc(&kexisBlock->predictor, options->predictorVersion,
112 			diffMid, diffAve, DECOMPRESS);
113 
114 	mid = kexisBlock->predictor.diffMid;
115 	ave = kexisBlock->predictor.diffAve;
116 
117 	// If we are gathering statistics, gather them :P
118 	if(options->verbose)
119 		collect_prediction_stats(kexisBlock, diffMid, diffAve);
120 
121 	if(options->joint == 1) {
122 		right = ave - (mid/2);
123 		left = right + mid;
124 	}
125 	else {
126 		left = mid;
127 		right = ave;
128 	}
129 
130 	//if(PRED_DEBUG == 1 && kexisBlock->sumTotalSize < 100000) {
131 	//	printf("%ld:  %ld  %ld  %ld  %ld  %d  %d\n", kexisBlock->sumTotalSize,
132 	//  diffMid, diffAve, mid, ave, left, right);
133 	// }
134 
135 	kexisBlock->sumTotalSize +=2;
136 
137 	write_pcmblock(options, kexisBlock, pcmBlock, left, 0);
138 	write_pcmblock(options, kexisBlock, pcmBlock, right, 0);
139 }
140 
write_pcmblock(OPTIONSTRUCT * options,KEXISBLOCKSTRUCT * kexisBlock,PCMBLOCKSTRUCT * pcmBlock,short data,int now)141 void write_pcmblock(OPTIONSTRUCT *options, KEXISBLOCKSTRUCT *kexisBlock,
142 	PCMBLOCKSTRUCT *pcmBlock, short data, int now)
143 {
144 	int length;
145 	WAVHEADER	wavHeader;
146 
147 	if(options->outFileStream == NULL) {
148 		if(options->dec_stdout == 0) {
149 			options->outFileName = calloc(1, strlen(options->inFileName)+1);
150 			strncpy(options->outFileName, options->inFileName,
151 				strlen(options->inFileName)-3);
152 			strcat(options->outFileName, "wav\0");
153 
154 			options->outFileStream = fopen(options->outFileName, "wb");
155 			if(options->outFileStream == NULL) {
156 				sprintf(options->errorString, "Can't open file: %s!",
157 					options->outFileName);
158 				handle_error(options);
159 			}
160 		}
161 		else {
162 			options->outFileStream = stdout;
163 		}
164 
165 		create_wave_header(&wavHeader, pcmBlock->pcmStreamLength);
166 		length = fwrite(&wavHeader, sizeof(wavHeader), 1,
167 			options->outFileStream);
168 		if(length != 1) {
169 			sprintf(options->errorString, "Error writing Header to %s!",
170 				options->outFileName);
171 			handle_error(options);
172 		}
173 	}
174 
175 	if(now == 0) {
176 		pcmBlock->data[pcmBlock->size] = data;
177 		pcmBlock->size++;
178 	}
179 
180 	if((pcmBlock->size == options->frameSize) || (now==1)) {
181 		length = fwrite(pcmBlock->data, sizeof(short), pcmBlock->size,
182 			options->outFileStream);
183 		if(length != pcmBlock->size) {
184 			 sprintf(options->errorString, "Error writing to %s!",
185 			 options->outFileName);
186 			 handle_error(options);
187 		}
188 		pcmBlock->size = 0;
189 		if(options->predictorVersion == FRAME_PREDICTOR) {
190 			pcmBlock->currentAve = bit_suck(kexisBlock, 3, pcmBlock, options);
191 			pcmBlock->currentMid = bit_suck(kexisBlock, 3, pcmBlock, options);
192 		}
193 	}
194 }
195