1 /*
2  * Schism Tracker - a cross-platform Impulse Tracker clone
3  * copyright (c) 2003-2005 Storlek <storlek@rigelseven.com>
4  * copyright (c) 2005-2008 Mrs. Brisby <mrs.brisby@nimh.org>
5  * copyright (c) 2009 Storlek & Mrs. Brisby
6  * copyright (c) 2010-2012 Storlek
7  * URL: http://schismtracker.org/
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  */
23 
24 #define NEED_BYTESWAP
25 #include "headers.h"
26 #include "fmt.h"
27 #include "it.h"
28 #include "disko.h"
29 #include "sndfile.h"
30 #include "log.h"
31 #include <stdint.h>
32 
33 #define WAVE_FORMAT_PCM             0x0001
34 #define WAVE_FORMAT_IEEE_FLOAT      0x0003 // IEEE float
35 #define WAVE_FORMAT_ALAW            0x0006 // 8-bit ITU-T G.711 A-law
36 #define WAVE_FORMAT_MULAW           0x0007 // 8-bit ITU-T G.711 µ-law
37 #define WAVE_FORMAT_EXTENSIBLE      0xFFFE
38 
39 // Standard IFF chunks IDs
40 #define IFFID_FORM              0x4d524f46
41 #define IFFID_RIFF              0x46464952
42 #define IFFID_WAVE              0x45564157
43 #define IFFID_LIST              0x5453494C
44 #define IFFID_INFO              0x4F464E49
45 
46 // IFF Info fields
47 #define IFFID_ICOP              0x504F4349
48 #define IFFID_IART              0x54524149
49 #define IFFID_IPRD              0x44525049
50 #define IFFID_INAM              0x4D414E49
51 #define IFFID_ICMT              0x544D4349
52 #define IFFID_IENG              0x474E4549
53 #define IFFID_ISFT              0x54465349
54 #define IFFID_ISBJ              0x4A425349
55 #define IFFID_IGNR              0x524E4749
56 #define IFFID_ICRD              0x44524349
57 
58 // Wave IFF chunks IDs
59 #define IFFID_wave              0x65766177
60 #define IFFID_fmt               0x20746D66
61 #define IFFID_wsmp              0x706D7377
62 #define IFFID_pcm               0x206d6370
63 #define IFFID_data              0x61746164
64 #define IFFID_smpl              0x6C706D73
65 #define IFFID_xtra              0x61727478
66 
67 
68 #pragma pack(push, 1)
69 typedef struct {
70     uint32_t id_RIFF;           // "RIFF"
71     uint32_t filesize;          // file length-8
72     uint32_t id_WAVE;
73 } wave_file_header_t;
74 
75 
76 
77 typedef struct {
78     uint16_t format;          // 1
79     uint16_t channels;        // 1:mono, 2:stereo
80     uint32_t freqHz;          // sampling freq
81     uint32_t bytessec;        // bytes/sec=freqHz*samplesize
82     uint16_t samplesize;      // sizeof(sample)
83     uint16_t bitspersample;   // bits per sample (8/16)
84 } wave_format_t;
85 
86 
87 typedef struct {
88     uint32_t id;
89     uint32_t length;
90 } wave_chunk_prefix_t;
91 
92 
93 typedef struct {
94     wave_format_t fmt;        // Format
95     wave_chunk_prefix_t data; // Data header
96     uint8_t *buf;
97 } wave_file_t;
98 #pragma pack(pop)
99 
100 /* --------------------------------------------------------------------------------------------------------- */
101 
102 static int wav_load(wave_file_t *f, const uint8_t *data, size_t len)
103 {
104 	wave_file_header_t phdr;
105 	size_t offset;
106 	int have_format = 0;
107 
108 	if (len < sizeof(wave_file_header_t)) {
109 		return 0;
110 	}
111 
112 	memcpy(&phdr, data, sizeof(wave_file_header_t));
113 #if WORDS_BIGENDIAN
114 	phdr.id_RIFF  = bswapLE32(phdr.id_RIFF);
115 	phdr.filesize = bswapLE32(phdr.filesize);
116 	phdr.id_WAVE  = bswapLE32(phdr.id_WAVE);
117 #endif
118 
119 	if (phdr.id_RIFF != IFFID_RIFF ||
120 	    phdr.id_WAVE != IFFID_WAVE) {
121 		return 0;
122 	}
123 
124 	offset = sizeof(wave_file_header_t);
125 
126 	while (1) {
127 		wave_chunk_prefix_t c;
128 		memcpy(&c, data + offset, sizeof(wave_chunk_prefix_t));
129 
130 #if WORDS_BIGENDIAN
131 		c.id     = bswapLE32(c.id);
132 		c.length = bswapLE32(c.length);
133 #endif
134 		offset  += sizeof(wave_chunk_prefix_t);
135 
136 		if (offset + c.length > len) {
137 			log_appendf(4, "Corrupt WAV file. Chunk points outside of WAV file [%lu + %u > %lu]\n",
138 			    (unsigned long) offset, c.length, (unsigned long) len);
139 			return 0;
140 		}
141 
142 		switch (c.id) {
143 		case IFFID_fmt: {
144 			if (have_format) {
145 				log_appendf(4, "Corrupt WAV file. Found multiple format headers.\n");
146 				return 0;
147 			}
148 
149 			have_format = 1;
150 			memcpy(&f->fmt, data + offset, sizeof(wave_format_t));
151 #if WORDS_BIGENDIAN
152 			f->fmt.format        = bswapLE16(f->fmt.format);
153 			f->fmt.channels      = bswapLE16(f->fmt.channels);
154 			f->fmt.freqHz        = bswapLE32(f->fmt.freqHz);
155 			f->fmt.bytessec      = bswapLE32(f->fmt.bytessec);
156 			f->fmt.samplesize    = bswapLE16(f->fmt.samplesize);
157 			f->fmt.bitspersample = bswapLE16(f->fmt.bitspersample);
158 #endif
159 			break;
160 		}
161 
162 		case IFFID_data:
163 			if (!have_format) {
164 				log_appendf(4, "WAV file did not specify format before data\n");
165 				return 0;
166 			}
167 
168 			memcpy(&f->data, &c, sizeof(wave_chunk_prefix_t));
169 			f->buf = (uint8_t *)(data + offset);
170 			return 1;
171 		}
172 
173 	    offset += c.length;
174 
175 	    if (offset == len)
176 		    break;
177 	}
178 
179 	return 1;
180 }
181 
182 /* --------------------------------------------------------------------------------------------------------- */
183 
184 int fmt_wav_load_sample(const uint8_t *data, size_t len, song_sample_t *smp)
185 {
186 	wave_file_t f;
187 	uint32_t flags;
188 
189 	if (!wav_load(&f, data, len))
190 		return 0;
191 
192 	if (f.fmt.format != WAVE_FORMAT_PCM ||
193 	    !f.fmt.freqHz ||
194 	    (f.fmt.channels != 1 && f.fmt.channels != 2))
195 		return 0;
196 
197 	smp->flags = 0; // flags are set by csf_read_sample
198 	flags      = 0;
199 
200 	// endianness
201 	flags = SF_LE;
202 	// channels
203 	flags |= (f.fmt.channels == 2) ? SF_SI : SF_M; // interleaved stereo
204 	// bit width
205 	switch (f.fmt.bitspersample) {
206 	case 8:  flags |= SF_8;  break;
207 	case 16: flags |= SF_16; break;
208 	case 24: flags |= SF_24; break;
209 	case 32: flags |= SF_32; break;
210 	default: return 0; // unsupported
211 	}
212 	// encoding (8-bit wav is unsigned, everything else is signed -- yeah, it's stupid)
213 	flags |= (f.fmt.bitspersample == 8) ? SF_PCMU : SF_PCMS;
214 
215 	smp->volume        = 64 * 4;
216 	smp->global_volume = 64;
217 	smp->c5speed         = f.fmt.freqHz;
218 	smp->length        = f.data.length / ((f.fmt.bitspersample / 8) * f.fmt.channels);
219 
220 	return csf_read_sample((song_sample_t *)smp, flags, (const char *) f.buf, f.data.length);
221 }
222 
223 int fmt_wav_read_info(dmoz_file_t *file, const uint8_t *data, size_t length)
224 {
225 	wave_file_t f;
226 
227 	if (!wav_load(&f, data, length))
228 		return 0;
229 	else if (f.fmt.format != WAVE_FORMAT_PCM ||
230 		!f.fmt.freqHz ||
231 		(f.fmt.channels != 1 && f.fmt.channels != 2) ||
232 		(f.fmt.bitspersample != 8 && f.fmt.bitspersample != 16 &&
233 		 f.fmt.bitspersample != 24 && f.fmt.bitspersample != 32))
234 		return 0;
235 
236 	file->smp_flags  = 0;
237 
238 	if (f.fmt.channels == 2)
239 		file->smp_flags |= CHN_STEREO;
240 
241 	if (f.fmt.bitspersample == 16)
242 		file->smp_flags |= CHN_16BIT;
243 
244 	file->smp_speed  = f.fmt.freqHz;
245 	file->smp_length = f.data.length / ((f.fmt.bitspersample / 8) * f.fmt.channels);
246 
247 	file->description  = "IBM/Microsoft RIFF Audio";
248 	file->type         = TYPE_SAMPLE_PLAIN;
249 	file->smp_filename = file->base;
250 	return 1;
251 }
252 
253 /* --------------------------------------------------------------------------------------------------------- */
254 /* wav is like aiff's retarded cousin */
255 
256 struct wav_writedata {
257 	long data_size; // seek position for writing data size (in bytes)
258 	size_t numbytes; // how many bytes have been written
259 	int bps; // bytes per sample
260 	int swap; // should be byteswapped?
261 };
262 
263 static int wav_header(disko_t *fp, int bits, int channels, int rate, size_t length,
264 	struct wav_writedata *wwd /* out */)
265 {
266 	int16_t s;
267 	uint32_t ul;
268 	int bps = 1;
269 
270 	bps *= ((bits + 7) / 8) * channels;
271 
272 	/* write a very large size for now */
273 	disko_write(fp, "RIFF\377\377\377\377WAVEfmt ", 16);
274 	ul = bswapLE32(16); // fmt chunk size
275 	disko_write(fp, &ul, 4);
276 	s = bswapLE16(1); // linear pcm
277 	disko_write(fp, &s, 2);
278 	s = bswapLE16(channels); // number of channels
279 	disko_write(fp, &s, 2);
280 	ul = bswapLE32(rate); // sample rate
281 	disko_write(fp, &ul, 4);
282 	ul = bswapLE32(bps * rate); // "byte rate" (why?! I have no idea)
283 	disko_write(fp, &ul, 4);
284 	s = bswapLE16(bps); // (oh, come on! the format already stores everything needed to calculate this!)
285 	disko_write(fp, &s, 2);
286 	s = bswapLE16(bits); // bits per sample
287 	disko_write(fp, &s, 2);
288 
289 	disko_write(fp, "data", 4);
290 	if (wwd)
291 		wwd->data_size = disko_tell(fp);
292 	ul = bswapLE32(bps * length);
293 	disko_write(fp, &ul, 4);
294 
295 	return bps;
296 }
297 
298 int fmt_wav_save_sample(disko_t *fp, song_sample_t *smp)
299 {
300 	int bps;
301 	uint32_t ul;
302 	uint32_t flags = SF_LE;
303 	flags |= (smp->flags & CHN_16BIT) ? (SF_16 | SF_PCMS) : (SF_8 | SF_PCMU);
304 	flags |= (smp->flags & CHN_STEREO) ? SF_SI : SF_M;
305 
306 	bps = wav_header(fp, (smp->flags & CHN_16BIT) ? 16 : 8, (smp->flags & CHN_STEREO) ? 2 : 1,
307 		smp->c5speed, smp->length, NULL);
308 
309 	if (csf_write_sample(fp, smp, flags, UINT32_MAX) != smp->length * bps) {
310 		log_appendf(4, "WAV: unexpected data size written");
311 		return SAVE_INTERNAL_ERROR;
312 	}
313 
314 	/* fix the length in the file header */
315 	ul = disko_tell(fp) - 8;
316 	ul = bswapLE32(ul);
317 	disko_seek(fp, 4, SEEK_SET);
318 	disko_write(fp, &ul, 4);
319 
320 	return SAVE_SUCCESS;
321 }
322 
323 
324 int fmt_wav_export_head(disko_t *fp, int bits, int channels, int rate)
325 {
326 	struct wav_writedata *wwd = malloc(sizeof(struct wav_writedata));
327 	if (!wwd)
328 		return DW_ERROR;
329 	fp->userdata = wwd;
330 	wwd->bps = wav_header(fp, bits, channels, rate, ~0, wwd);
331 	wwd->numbytes = 0;
332 #if WORDS_BIGENDIAN
333 	wwd->swap = (bits > 8);
334 #else
335 	wwd->swap = 0;
336 #endif
337 
338 	return DW_OK;
339 }
340 
341 int fmt_wav_export_body(disko_t *fp, const uint8_t *data, size_t length)
342 {
343 	struct wav_writedata *wwd = fp->userdata;
344 
345 	if (length % wwd->bps) {
346 		log_appendf(4, "WAV export: received uneven length");
347 		return DW_ERROR;
348 	}
349 
350 	wwd->numbytes += length;
351 
352 	if (wwd->swap) {
353 		const int16_t *ptr = (const int16_t *) data;
354 		uint16_t v;
355 
356 		length /= 2;
357 		while (length--) {
358 			v = *ptr;
359 			v = bswapLE16(v);
360 			disko_write(fp, &v, 2);
361 			ptr++;
362 		}
363 	} else {
364 		disko_write(fp, data, length);
365 	}
366 
367 	return DW_OK;
368 }
369 
370 int fmt_wav_export_silence(disko_t *fp, long bytes)
371 {
372 	struct wav_writedata *wwd = fp->userdata;
373 	wwd->numbytes += bytes;
374 
375 	disko_seek(fp, bytes, SEEK_CUR);
376 	return DW_OK;
377 }
378 
379 int fmt_wav_export_tail(disko_t *fp)
380 {
381 	struct wav_writedata *wwd = fp->userdata;
382 	uint32_t ul;
383 
384 	/* fix the length in the file header */
385 	ul = disko_tell(fp) - 8;
386 	ul= bswapLE32(ul);
387 	disko_seek(fp, 4, SEEK_SET);
388 	disko_write(fp, &ul, 4);
389 
390 	/* write the other lengths */
391 	disko_seek(fp, wwd->data_size, SEEK_SET);
392 	ul = bswapLE32(wwd->numbytes);
393 	disko_write(fp, &ul, 4);
394 
395 	free(wwd);
396 
397 	return DW_OK;
398 }
399 
400