1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 #include "ultima/ultima8/misc/pent_include.h"
24 #include "ultima/ultima8/audio/sonarc_audio_sample.h"
25 
26 namespace Ultima {
27 namespace Ultima8 {
28 
29 bool SonarcAudioSample::_generatedOneTable = false;
30 int SonarcAudioSample::_oneTable[256];
31 
SonarcAudioSample(uint8 const * buffer,uint32 size)32 SonarcAudioSample::SonarcAudioSample(uint8 const *buffer, uint32 size) :
33 	AudioSample(buffer, size, 8, false, true), _srcOffset(0x20) {
34 	if (!_generatedOneTable) GenerateOneTable();
35 
36 	_length = *_buffer;
37 	_length |= *(_buffer + 1) << 8;
38 	_length |= *(_buffer + 2) << 16;
39 	_length |= *(_buffer + 3) << 24;
40 
41 	_sampleRate  = *(_buffer + 4);
42 	_sampleRate |= *(_buffer + 5) << 8;
43 
44 	// Get frame bytes... we need to compensate for 'large' files
45 	uint32 frame_bytes = *(_buffer + _srcOffset);
46 	frame_bytes |= (*(_buffer + _srcOffset + 1)) << 8;
47 
48 	if (frame_bytes == 0x20 && _length > 32767) {
49 		_srcOffset += 0x100;
50 	}
51 
52 	// Get Num Frame Samples
53 	_frameSize = *(_buffer + _srcOffset + 2);
54 	_frameSize |= (*(_buffer + _srcOffset + 3)) << 8;
55 
56 
57 	_decompressorSize = sizeof(SonarcDecompData);
58 }
59 
~SonarcAudioSample(void)60 SonarcAudioSample::~SonarcAudioSample(void) {
61 }
62 
63 //
64 // Sonarc Audio Decompressor
65 //
66 
GenerateOneTable()67 void SonarcAudioSample::GenerateOneTable() {
68 	// _oneTable[x] gives the number of consecutive 1's on the low side of x
69 	for (int i = 0; i < 256; ++i)
70 		_oneTable[i] = 0;
71 
72 	for (int power = 2; power < 32; power *= 2)
73 		for (int col = power - 1; col < 16; col += power)
74 			for (int row = 0; row < 16; ++row)
75 				_oneTable[row * 16 + col]++;
76 
77 	for (int i = 0; i < 16; ++i)
78 		_oneTable[i * 16 + 15] += _oneTable[i];
79 }
80 
decode_EC(int mode,int samplecount,const uint8 * source,int sourcesize,uint8 * dest)81 void SonarcAudioSample::decode_EC(int mode, int samplecount,
82 								  const uint8 *source, int sourcesize,
83 								  uint8 *dest) {
84 	bool zerospecial = false;
85 	uint32 data = 0;
86 	int inputbits = 0; // current 'fill rate' of data window
87 
88 	if (mode >= 7) {
89 		mode -= 7;
90 		zerospecial = true;
91 	}
92 
93 	while (samplecount) {
94 		// fill data window
95 		while (sourcesize && inputbits <= 24) {
96 			data |= (*source++) << inputbits;
97 			sourcesize--;
98 			inputbits += 8;
99 		}
100 
101 		if (zerospecial && !(data & 0x1)) {
102 			*dest++ = 0x80; // output zero
103 			data >>= 1;
104 			inputbits--;
105 		} else {
106 			if (zerospecial) {
107 				data >>= 1; // strip one
108 				inputbits--;
109 			}
110 
111 			uint8 lowByte = data & 0xFF;
112 			int ones = _oneTable[lowByte];
113 
114 			if (ones == 0) {
115 				data >>= 1; // strip zero
116 				// low byte contains (mode+1) _bits of the sample
117 				const uint8 usample = data & 0xFF;
118 				int8 sample = usample << (7 - mode);
119 				sample >>= (7 - mode); // sign extend
120 				*dest++ = (uint8)(sample + 0x80);
121 				data >>= mode + 1;
122 				inputbits -= mode + 2;
123 			} else if (ones < 7 - mode) {
124 				data >>= ones + 1; // strip ones and zero
125 				// low byte contains (mode+ones) _bits of the sample
126 				const uint8 usample = data & 0xFF;
127 				int8 sample = usample << (7 - mode - ones);
128 				sample &= 0x7F;
129 				if (!(sample & 0x40))
130 					sample |= 0x80; // reconstruct sign bit
131 				sample >>= (7 - mode - ones); // sign extend
132 				*dest++ = (uint8)(sample + 0x80);
133 				data >>= (mode + ones);
134 				inputbits -= mode + 2 * ones + 1;
135 			} else {
136 				data >>= (7 - mode); // strip ones
137 				// low byte contains 7 _bits of the sample
138 				int8 sample = data & 0xFF;
139 				sample &= 0x7F;
140 				if (!(sample & 0x40))
141 					sample |= 0x80; // reconstruct sign bit
142 				*dest++ = (uint8)(sample + 0x80);
143 				data >>= 7;
144 				inputbits -= 2 * 7 - mode;
145 			}
146 		}
147 		samplecount--;
148 	}
149 }
150 
decode_LPC(int order,int nsamples,uint8 * dest,const uint8 * factors)151 void SonarcAudioSample::decode_LPC(int order, int nsamples,
152 								   uint8 *dest, const uint8 *factors) {
153 	uint8 *startdest = dest;
154 	dest -= order;
155 
156 	// basic linear predictive (de)coding
157 	// the errors this produces are fixed by decode_EC
158 
159 	for (int i = 0; i < nsamples; ++i) {
160 		uint8 *loopdest = dest++;
161 		int accum = 0;
162 		for (int j = order - 1; j >= 0; --j) {
163 			int8 val1 = (loopdest < startdest) ? 0 : (*loopdest);
164 			loopdest++;
165 			val1 ^= 0x80;
166 			int16 val2 = factors[j * 2] + (factors[j * 2 + 1] << 8);
167 			accum += (int)val1 * val2;
168 		}
169 
170 		accum += 0x00000800;
171 		*loopdest -= (int8)((accum >> 12) & 0xFF);
172 	}
173 }
174 
audio_decode(const uint8 * source,uint8 * dest)175 int SonarcAudioSample::audio_decode(const uint8 *source, uint8 *dest) {
176 	int size = source[0] + (source[1] << 8);
177 	uint16 checksum = 0;
178 	for (int i = 0; i < size / 2; ++i) {
179 		uint16 val = source[2 * i] + (source[2 * i + 1] << 8);
180 		checksum ^= val;
181 	}
182 
183 	if (checksum != 0xACED) return -1;
184 
185 	int order = source[7];
186 	int mode = source[6] - 8;
187 	int samplecount = source[2] + (source[3] << 8);
188 
189 	decode_EC(mode, samplecount,
190 	          source + 8 + 2 * order, size - 8 - 2 * order,
191 	          dest);
192 	decode_LPC(order, samplecount, dest, source + 8);
193 
194 	// Try to fix a number of clipped samples
195 	for (int i = 1; i < samplecount; ++i)
196 		if (dest[i] == 0 && dest[i - 1] > 192) dest[i] = 0xFF;
197 
198 
199 	return 0;
200 }
201 
202 //
203 // AudioSample Interface
204 //
205 
initDecompressor(void * DecompData) const206 void SonarcAudioSample::initDecompressor(void *DecompData) const {
207 	SonarcDecompData *decomp = reinterpret_cast<SonarcDecompData *>(DecompData);
208 	decomp->_pos = _srcOffset;
209 	decomp->_samplePos = 0;
210 }
211 
decompressFrame(void * DecompData,void * samples) const212 uint32 SonarcAudioSample::decompressFrame(void *DecompData, void *samples) const {
213 	SonarcDecompData *decomp = reinterpret_cast<SonarcDecompData *>(DecompData);
214 
215 	if (decomp->_pos == _bufferSize) return 0;
216 	if (decomp->_samplePos == _length) return 0;
217 
218 	// Get Frame size
219 	uint32 frame_bytes  = *(_buffer + decomp->_pos);
220 	frame_bytes |= (*(_buffer + decomp->_pos + 1)) << 8;
221 
222 	// Get Num Frame Samples
223 	uint32 frame_samples  = *(_buffer + decomp->_pos + 2);
224 	frame_samples |= (*(_buffer + decomp->_pos + 3)) << 8;
225 
226 	audio_decode(_buffer + decomp->_pos, reinterpret_cast<uint8 *>(samples));
227 
228 	decomp->_pos += frame_bytes;
229 	decomp->_samplePos += frame_samples;
230 
231 	return frame_samples;
232 }
233 
rewind(void * DecompData) const234 void SonarcAudioSample::rewind(void *DecompData) const {
235 	SonarcDecompData *decomp = reinterpret_cast<SonarcDecompData *>(DecompData);
236 	decomp->_pos = _srcOffset;
237 	decomp->_samplePos = 0;
238 }
239 
240 } // End of namespace Ultima8
241 } // End of namespace Ultima
242