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