rate: add some sanity checking
[sox.git] / src / xa.c
blob9fc086eca2b278a63d0879fe9c81b8edb5e5513c
1 /* libSoX xa.c Support for Maxis .XA file format
3 * Copyright (C) 2006 Dwayne C. Litzenberger <dlitz@dlitz.net>
5 * This library is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU Lesser General Public License as published by
7 * the Free Software Foundation; either version 2.1 of the License, or (at
8 * your option) any later version.
10 * This library is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
13 * General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public License
16 * along with this library; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 /* Thanks to Valery V. Anisimovsky <samael@avn.mccme.ru> for the
21 * "Maxis XA Audio File Format Description", dated 5-01-2002. */
23 #include "sox_i.h"
25 #include <string.h>
26 #include <stdlib.h>
27 #include <stdio.h>
29 #define HNIBBLE(byte) (((byte) >> 4) & 0xf)
30 #define LNIBBLE(byte) ((byte) & 0xf)
32 /* .xa file header */
33 typedef struct {
34 char magic[4]; /* "XA\0\0", "XAI\0" (sound/speech), or "XAJ\0" (music) */
35 uint32_t outSize; /* decompressed size of the stream (in bytes) */
37 /* WAVEFORMATEX structure for the decompressed data */
38 uint16_t tag; /* 0x0001 - PCM data */
39 uint16_t channels; /* number of channels */
40 uint32_t sampleRate; /* sample rate (samples/sec) */
41 uint32_t avgByteRate; /* sampleRate * align */
42 uint16_t align; /* bits / 8 * channels */
43 uint16_t bits; /* 8 or 16 */
44 } xa_header_t;
46 typedef struct {
47 int32_t curSample; /* current sample */
48 int32_t prevSample; /* previous sample */
49 int32_t c1;
50 int32_t c2;
51 unsigned int shift;
52 } xa_state_t;
54 /* Private data for .xa file */
55 typedef struct {
56 xa_header_t header;
57 xa_state_t *state;
58 unsigned int blockSize;
59 unsigned int bufPos; /* position within the current block */
60 unsigned char *buf; /* buffer for the current block */
61 unsigned int bytesDecoded; /* number of decompressed bytes read */
62 } priv_t;
64 /* coefficients for EA ADPCM */
65 static const int32_t EA_ADPCM_Table[]= {
66 0, 240, 460, 392,
67 0, 0, -208, -220,
68 0, 1, 3, 4,
69 7, 8, 10, 11,
70 0, -1, -3, -4
73 /* Clip sample to 16 bits */
74 static inline int32_t clip16(int32_t sample)
76 if (sample > 32767) {
77 return 32767;
78 } else if (sample < -32768) {
79 return -32768;
80 } else {
81 return sample;
85 static int startread(sox_format_t * ft)
87 priv_t * xa = (priv_t *) ft->priv;
88 char *magic = xa->header.magic;
90 /* Check for the magic value */
91 if (lsx_readbuf(ft, xa->header.magic, (size_t)4) != 4 ||
92 (memcmp("XA\0\0", xa->header.magic, (size_t)4) != 0 &&
93 memcmp("XAI\0", xa->header.magic, (size_t)4) != 0 &&
94 memcmp("XAJ\0", xa->header.magic, (size_t)4) != 0))
96 lsx_fail_errno(ft, SOX_EHDR, "XA: Header not found");
97 return SOX_EOF;
100 /* Read the rest of the header */
101 if (lsx_readdw(ft, &xa->header.outSize) != SOX_SUCCESS) return SOX_EOF;
102 if (lsx_readw(ft, &xa->header.tag) != SOX_SUCCESS) return SOX_EOF;
103 if (lsx_readw(ft, &xa->header.channels) != SOX_SUCCESS) return SOX_EOF;
104 if (lsx_readdw(ft, &xa->header.sampleRate) != SOX_SUCCESS) return SOX_EOF;
105 if (lsx_readdw(ft, &xa->header.avgByteRate) != SOX_SUCCESS) return SOX_EOF;
106 if (lsx_readw(ft, &xa->header.align) != SOX_SUCCESS) return SOX_EOF;
107 if (lsx_readw(ft, &xa->header.bits) != SOX_SUCCESS) return SOX_EOF;
109 /* Output the data from the header */
110 lsx_debug("XA Header:");
111 lsx_debug(" szID: %02x %02x %02x %02x |%c%c%c%c|",
112 magic[0], magic[1], magic[2], magic[3],
113 (magic[0] >= 0x20 && magic[0] <= 0x7e) ? magic[0] : '.',
114 (magic[1] >= 0x20 && magic[1] <= 0x7e) ? magic[1] : '.',
115 (magic[2] >= 0x20 && magic[2] <= 0x7e) ? magic[2] : '.',
116 (magic[3] >= 0x20 && magic[3] <= 0x7e) ? magic[3] : '.');
117 lsx_debug(" dwOutSize: %u", xa->header.outSize);
118 lsx_debug(" wTag: 0x%04x", xa->header.tag);
119 lsx_debug(" wChannels: %u", xa->header.channels);
120 lsx_debug(" dwSampleRate: %u", xa->header.sampleRate);
121 lsx_debug(" dwAvgByteRate: %u", xa->header.avgByteRate);
122 lsx_debug(" wAlign: %u", xa->header.align);
123 lsx_debug(" wBits: %u", xa->header.bits);
125 /* Populate the sox_soundstream structure */
126 ft->encoding.encoding = SOX_ENCODING_SIGN2;
128 if (!ft->encoding.bits_per_sample || ft->encoding.bits_per_sample == xa->header.bits) {
129 ft->encoding.bits_per_sample = xa->header.bits;
130 } else {
131 lsx_report("User options overriding size read in .xa header");
134 if (ft->signal.channels == 0 || ft->signal.channels == xa->header.channels) {
135 ft->signal.channels = xa->header.channels;
136 } else {
137 lsx_report("User options overriding channels read in .xa header");
140 if (ft->signal.rate == 0 || ft->signal.rate == xa->header.sampleRate) {
141 ft->signal.rate = xa->header.sampleRate;
142 } else {
143 lsx_report("User options overriding rate read in .xa header");
146 if (ft->signal.channels == 0 || ft->signal.channels > UINT16_MAX) {
147 lsx_fail_errno(ft, SOX_EFMT, "invalid channel count %d",
148 ft->signal.channels);
149 return SOX_EOF;
152 /* Check for supported formats */
153 if (ft->encoding.bits_per_sample != 16) {
154 lsx_fail_errno(ft, SOX_EFMT, "%d-bit sample resolution not supported.",
155 ft->encoding.bits_per_sample);
156 return SOX_EOF;
159 /* Validate the header */
160 if (xa->header.bits != ft->encoding.bits_per_sample) {
161 lsx_report("Invalid sample resolution %d bits. Assuming %d bits.",
162 xa->header.bits, ft->encoding.bits_per_sample);
163 xa->header.bits = ft->encoding.bits_per_sample;
165 if (xa->header.align != (ft->encoding.bits_per_sample >> 3) * xa->header.channels) {
166 lsx_report("Invalid sample alignment value %d. Assuming %d.",
167 xa->header.align, (ft->encoding.bits_per_sample >> 3) * xa->header.channels);
168 xa->header.align = (ft->encoding.bits_per_sample >> 3) * xa->header.channels;
170 if (xa->header.avgByteRate != (xa->header.align * xa->header.sampleRate)) {
171 lsx_report("Invalid dwAvgByteRate value %d. Assuming %d.",
172 xa->header.avgByteRate, xa->header.align * xa->header.sampleRate);
173 xa->header.avgByteRate = xa->header.align * xa->header.sampleRate;
176 /* Set up the block buffer */
177 xa->blockSize = ft->signal.channels * 0xf;
178 xa->bufPos = xa->blockSize;
180 /* Allocate memory for the block buffer */
181 xa->buf = lsx_calloc(1, (size_t)xa->blockSize);
183 /* Allocate memory for the state */
184 xa->state = lsx_calloc(sizeof(xa_state_t), ft->signal.channels);
186 /* Final initialization */
187 xa->bytesDecoded = 0;
189 return SOX_SUCCESS;
193 * Read up to len samples from a file, converted to signed longs.
194 * Return the number of samples read.
196 static size_t read_samples(sox_format_t * ft, sox_sample_t *buf, size_t len)
198 priv_t * xa = (priv_t *) ft->priv;
199 int32_t sample;
200 unsigned char inByte;
201 size_t i, done, bytes;
203 ft->sox_errno = SOX_SUCCESS;
204 done = 0;
205 while (done < len) {
206 if (xa->bufPos >= xa->blockSize) {
207 /* Read the next block */
208 bytes = lsx_readbuf(ft, xa->buf, (size_t) xa->blockSize);
209 if (bytes < xa->blockSize) {
210 if (lsx_eof(ft)) {
211 if (done > 0) {
212 return done;
214 lsx_fail_errno(ft,SOX_EOF,"Premature EOF on .xa input file");
215 return 0;
216 } else {
217 /* error */
218 lsx_fail_errno(ft,SOX_EOF,"read error on input stream");
219 return 0;
222 xa->bufPos = 0;
224 for (i = 0; i < ft->signal.channels; i++) {
225 inByte = xa->buf[i];
226 xa->state[i].c1 = EA_ADPCM_Table[HNIBBLE(inByte)];
227 xa->state[i].c2 = EA_ADPCM_Table[HNIBBLE(inByte) + 4];
228 xa->state[i].shift = LNIBBLE(inByte) + 8;
230 xa->bufPos += ft->signal.channels;
231 } else {
232 /* Process the block */
233 for (i = 0; i < ft->signal.channels && done < len; i++) {
234 /* high nibble */
235 sample = HNIBBLE(xa->buf[xa->bufPos+i]);
236 sample = (sample << 28) >> xa->state[i].shift;
237 sample = (sample +
238 xa->state[i].curSample * xa->state[i].c1 +
239 xa->state[i].prevSample * xa->state[i].c2 + 0x80) >> 8;
240 sample = clip16(sample);
241 xa->state[i].prevSample = xa->state[i].curSample;
242 xa->state[i].curSample = sample;
244 buf[done++] = SOX_SIGNED_16BIT_TO_SAMPLE(sample,);
245 xa->bytesDecoded += (ft->encoding.bits_per_sample >> 3);
247 for (i = 0; i < ft->signal.channels && done < len; i++) {
248 /* low nibble */
249 sample = LNIBBLE(xa->buf[xa->bufPos+i]);
250 sample = (sample << 28) >> xa->state[i].shift;
251 sample = (sample +
252 xa->state[i].curSample * xa->state[i].c1 +
253 xa->state[i].prevSample * xa->state[i].c2 + 0x80) >> 8;
254 sample = clip16(sample);
255 xa->state[i].prevSample = xa->state[i].curSample;
256 xa->state[i].curSample = sample;
258 buf[done++] = SOX_SIGNED_16BIT_TO_SAMPLE(sample,);
259 xa->bytesDecoded += (ft->encoding.bits_per_sample >> 3);
262 xa->bufPos += ft->signal.channels;
265 if (done == 0) {
266 return 0;
268 return done;
271 static int stopread(sox_format_t * ft)
273 priv_t * xa = (priv_t *) ft->priv;
275 ft->sox_errno = SOX_SUCCESS;
277 /* Free memory */
278 free(xa->buf);
279 xa->buf = NULL;
280 free(xa->state);
281 xa->state = NULL;
283 return SOX_SUCCESS;
286 LSX_FORMAT_HANDLER(xa)
288 static char const * const names[] = {"xa", NULL };
289 static sox_format_handler_t const handler = {SOX_LIB_VERSION_CODE,
290 "16-bit ADPCM audio files used by Maxis games",
291 names, SOX_FILE_LIT_END,
292 startread, read_samples, stopread,
293 NULL, NULL, NULL,
294 NULL, NULL, NULL, sizeof(priv_t)
296 return &handler;