1 /*
2 This file is Copyright © 1994-1995 Olivier Montanuy,
3 Copyright © 1999-2005 André Majorel,
4 Copyright © 2006-2019 contributors to the DeuTex project.
5
6 DeuTex incorporates code derived from DEU 5.21 that was put in the
7 public domain in 1994 by Raphaël Quinet and Brendon Wyber.
8
9 SPDX-License-Identifier: GPL-2.0-or-later
10 */
11
12 #include "deutex.h"
13 #include <errno.h>
14 #include "tools.h"
15 #include "endianm.h"
16 #include "mkwad.h"
17 #include "sound.h"
18 #include "text.h"
19
20 static struct RIFFHEAD {
21 char riff[4];
22 int32_t length;
23 char wave[4];
24 } headr;
25 static struct CHUNK {
26 char name[4];
27 int32_t size;
28 } headc;
29 static struct WAVEFMT { /*format */
30 char fmt[4]; /* "fmt " */
31 int32_t fmtsize; /*0x10 */
32 int16_t tag; /*format tag. 1=PCM */
33 int16_t channel; /*1 */
34 int32_t smplrate;
35 int32_t bytescnd; /*average bytes per second */
36 int16_t align; /*block alignment, in bytes */
37 int16_t nbits; /*specific to PCM format */
38 } headf;
39 static struct WAVEDATA { /*data */
40 char data[4]; /* "data" */
41 int32_t datasize;
42 } headw;
43
SNDsaveWave(char * file,char * buffer,int32_t size,int32_t speed)44 static void SNDsaveWave(char *file, char *buffer, int32_t size,
45 int32_t speed)
46 {
47 FILE *fp;
48 int32_t wsize, sz = 0;
49 fp = fopen(file, FOPEN_WB);
50 if (fp == NULL) {
51 ProgError("RW10", "%s: %s", fname(file), strerror(errno));
52 }
53 /*header */
54 strncpy(headr.riff, "RIFF", 4);
55 write_i32_le(&headr.length,
56 4 + sizeof(struct WAVEFMT) + sizeof(struct WAVEDATA) +
57 size);
58 strncpy(headr.wave, "WAVE", 4);
59 fwrite(&headr, sizeof(struct RIFFHEAD), 1, fp);
60 strncpy(headf.fmt, "fmt ", 4);
61 write_i32_le(&headf.fmtsize, sizeof(struct WAVEFMT) - 8);
62 write_i16_le(&headf.tag, 1);
63 write_i16_le(&headf.channel, 1);
64 write_i32_le(&headf.smplrate, speed);
65 write_i32_le(&headf.bytescnd, speed);
66 write_i16_le(&headf.align, 1);
67 write_i16_le(&headf.nbits, 8);
68 fwrite(&headf, sizeof(struct WAVEFMT), 1, fp);
69 strncpy(headw.data, "data", 4);
70 write_i32_le(&headw.datasize, size);
71 fwrite(&headw, sizeof(struct WAVEDATA), 1, fp);
72 for (wsize = 0; wsize < size; wsize += sz) {
73 sz = (size - wsize > MEMORYCACHE) ? MEMORYCACHE : (size - wsize);
74 if (fwrite((buffer + (wsize)), (size_t) sz, 1, fp) != 1)
75 ProgError("RW11", "%s: write error", fname(file));
76 }
77 fclose(fp);
78 }
79
SNDloadWaveFile(char * file,int32_t * psize,int32_t * pspeed)80 char *SNDloadWaveFile(char *file, int32_t * psize, int32_t * pspeed)
81 {
82 FILE *fp;
83 int32_t wsize, sz = 0, smplrate, datasize;
84 int32_t chunk;
85 char *data;
86 fp = fopen(file, FOPEN_RB);
87 if (fp == NULL)
88 ProgError("RR10", "%s: %s", fname(file), strerror(errno));
89 /*read RIFF HEADER */
90 if (fread(&headr, sizeof(struct RIFFHEAD), 1, fp) != 1)
91 ProgError("RR11", "%s: read error in header", fname(file));
92 /*check RIFF header */
93 if (strncmp(headr.riff, "RIFF", 4) != 0)
94 ProgError("RR12", "%s: bad RIFF magic in header (%s)", fname(file),
95 short_dump(headr.riff, 4));
96 if (strncmp(headr.wave, "WAVE", 4) != 0)
97 ProgError("RR13", "%s: bad WAVE magic in header (%s)", fname(file),
98 short_dump(headr.wave, 4));
99 chunk = sizeof(struct RIFFHEAD);
100 for (sz = 0;; sz++) {
101 if (sz > 256)
102 ProgError("RR14", "%s: no fmt", fname(file));
103 fseek(fp, chunk, SEEK_SET);
104 if (fread(&headc, sizeof(struct CHUNK), 1, fp) != 1)
105 ProgError("RR15", "%s: no fmt", fname(file));
106 if (strncmp(headc.name, "fmt ", 4) == 0)
107 break;
108 /* There used to be a bug here; sizeof (struct CHUNK) had
109 its bytes swapped too. Reading .wav files on big endian
110 machines must have been broken. -- AYM 1999-07-04 */
111 chunk += sizeof(struct CHUNK) + peek_i32_le(&headc.size);
112 }
113 fseek(fp, chunk, SEEK_SET);
114 if (fread(&headf, sizeof(struct WAVEFMT), 1, fp) == 1) {
115 Detail("RR01", "%s is a WAVE file", fname(file));
116 } else {
117 ProgError("RR02", "%s is not a WAVE file", fname(file));
118 }
119 if (peek_i16_le(&headf.tag) != 1)
120 ProgError("RR16", "%s: not raw data", fname(file));
121 if (peek_i16_le(&headf.channel) != 1)
122 ProgError("RR17", "%s: not one channel", fname(file));
123 smplrate = peek_i32_le(&headf.smplrate);
124
125 for (sz = 0;; sz++) {
126 if (sz > 256)
127 ProgError("RR18", "%s: no data", fname(file));
128 fseek(fp, chunk, SEEK_SET);
129 if (fread(&headc, sizeof(struct CHUNK), 1, fp) != 1)
130 ProgError("RR19", "%s: no data", fname(file));
131 if (strncmp(headc.name, "data", 4) == 0)
132 break;
133 /* Same endianness bug as above. */
134 chunk += sizeof(struct CHUNK) + peek_i32_le(&headc.size);
135 }
136 fseek(fp, chunk, SEEK_SET);
137 if (fread(&headw, sizeof(struct WAVEDATA), 1, fp) != 1)
138 ProgError("RR20", "%s: no data", fname(file));
139 datasize = peek_i32_le(&headw.datasize);
140 /*check WAVE header */
141 if (datasize > 0x1000000L) /* AYM 2000-04-22 */
142 ProgError("RR21", "%s: sample too long (%ld)", fname(file),
143 (long) datasize);
144 /*read data */
145 data = (char *) Malloc(datasize);
146 for (wsize = 0; wsize < datasize; wsize += sz) {
147 sz = (datasize - wsize >
148 MEMORYCACHE) ? MEMORYCACHE : (datasize - wsize);
149 if (fread((data + (wsize)), (size_t) sz, 1, fp) != 1)
150 ProgError("RR22", "%s: read error in data", fname(file));
151 }
152 fclose(fp);
153 *psize = datasize;
154 *pspeed = smplrate & 0xFFFFL;
155 return data;
156 }
157
SNDsaveSound(char * file,char * buffer,int32_t size,SNDTYPE format,const char * name)158 void SNDsaveSound(char *file, char *buffer, int32_t size, SNDTYPE format,
159 const char *name)
160 {
161 char *data;
162 int32_t datasize;
163 int32_t phys_size;
164 int16_t type;
165 int16_t headsize;
166 uint16_t rate;
167
168 headsize = sizeof(int16_t) + sizeof(int16_t) + sizeof(int32_t);
169 if (size < headsize) {
170 Warning("SD10", "Sound %s: lump has no header, skipping",
171 lump_name(name));
172 return;
173 }
174 type = peek_i16_le(buffer);
175 rate = peek_u16_le(buffer + 2);
176 datasize = peek_i32_le(buffer + 4);
177 data = buffer + headsize;
178 if (type != 3)
179 Warning("SD11", "Sound %s: weird type %d, extracting anyway",
180 lump_name(name), type);
181
182 phys_size = size - headsize;
183 if (datasize > phys_size) {
184 Warning("SD12",
185 "Sound %s: declared length %lu > lump size %lu, truncating",
186 lump_name(name), (unsigned long) datasize,
187 (unsigned long) phys_size);
188 datasize = phys_size;
189 } else if (datasize < phys_size) {
190 datasize = phys_size;
191 }
192
193 switch (format) {
194 case SNDWAV:
195 SNDsaveWave(file, data, datasize, rate);
196 break;
197 default:
198 Bug("SD14", "sndsv %d", (int) format);
199 }
200 }
201
SNDcopyInWAD(struct WADINFO * info,char * file,SNDTYPE format)202 int32_t SNDcopyInWAD(struct WADINFO *info, char *file, SNDTYPE format)
203 {
204 int32_t size = 0;
205 int32_t datasize;
206 int32_t rate;
207 char *data = NULL;
208 long wadrate;
209
210 switch (format) {
211 case SNDWAV:
212 data = SNDloadWaveFile(file, &datasize, &rate);
213 break;
214 default:
215 Bug("SC10", "sndcw %d", (int) format);
216 }
217 wadrate = rate;
218 switch (rate_policy) {
219 case RP_REJECT:
220 if (rate != 11025)
221 ProgError("SC11", "%s: sample rate not 11025 Hz", fname(file));
222 break;
223
224 case RP_FORCE:
225 if (rate > 11025) {
226 Warning("SC12", "%s: resampling down from %ld Hz to 11025 Hz",
227 fname(file), rate);
228 wadrate = 11025;
229 {
230 double ratio = 11025.0 / rate;
231 long s;
232
233 datasize = (int32_t) (ratio * datasize) + 1;
234 for (s = 0; s < datasize; s++)
235 data[s] = data[(size_t) (s / ratio + 0.5)];
236 }
237 data = (char *) Realloc(data, datasize);
238 } else if (rate < 11025) {
239 Warning("SC13", "%s: resampling up from %ld Hz to 11025 Hz",
240 fname(file), rate);
241 wadrate = 11025;
242 {
243 double ratio = 11025.0 / rate;
244 long s;
245
246 datasize = (int32_t) (ratio * datasize) + 1;
247 data = (char *) Realloc(data, datasize);
248 for (s = datasize - 1; s >= 0; s--)
249 data[s] = data[(size_t) (s / ratio + 0.5)];
250 }
251 }
252 break;
253
254 case RP_WARN:
255 if (rate != 11025)
256 Warning("SC14",
257 "%s: sample rate != 11025 Hz, won't work on Doom < 1.4",
258 fname(file));
259 break;
260
261 case RP_ACCEPT:
262 break;
263
264 default:
265 Bug("SC15", "SNDcopyInWAD: rate_policy %d", (int) rate_policy);
266 }
267
268 if (datasize > 0) {
269 size = WADRwriteShort(info, 3);
270 size += WADRwriteShort(info, wadrate);
271 size += WADRwriteLong(info, datasize);
272 size += WADRwriteBytes(info, data, datasize);
273 }
274 free(data);
275 return size;
276 }
277
SNDsavePCSound(const char * lumpname,const char * file,const char * buffer,int32_t size)278 void SNDsavePCSound(const char *lumpname, const char *file,
279 const char *buffer, int32_t size)
280 {
281 FILE *fp;
282 const char *data;
283 int16_t datasize, type, headsize;
284 int16_t i;
285 headsize = sizeof(int16_t) + sizeof(int16_t);
286 if (size < headsize)
287 ProgError("KW10", "FIXME: wrong size", fname(file));
288 type = peek_i16_le(buffer);
289 datasize = peek_i16_le(buffer + 2);
290 data = buffer + (sizeof(int16_t) + sizeof(int16_t));
291 if (type != 0)
292 Bug("KW11", "FIXME: not a PC sound", fname(file));
293 if (size < datasize + headsize)
294 ProgError("KW12", "FIXME: wrong size", fname(file));
295 fp = fopen(file, FOPEN_WT); /*text file */
296 if (fp == NULL)
297 ProgError("KW13", "%s: %s", fname(file), strerror(errno));
298 for (i = 0; i < datasize; i++) {
299 fprintf(fp, "%d\n", ((int) data[i]) & 0xFF);
300 }
301 if (fclose(fp) != 0)
302 ProgError("KW14", "%s: %s", fname(file), strerror(errno));
303 }
304
SNDcopyPCSoundInWAD(struct WADINFO * info,char * file)305 int32_t SNDcopyPCSoundInWAD(struct WADINFO *info, char *file)
306 {
307 struct TXTFILE *Txt;
308 int32_t size, datasizepos;
309 int16_t datasize, s;
310 char c;
311 Txt = TXTopenR(file, 1);
312 if (Txt == NULL)
313 ProgError("KR10", "%s: %s", fname(file), strerror(errno));
314 size = WADRwriteShort(info, 0);
315 datasizepos = WADRposition(info);
316 size += WADRwriteShort(info, -1);
317 datasize = 0;
318 while (TXTskipComment(Txt)) {
319 s = TXTreadShort(Txt);
320 if ((s < 0) || (s > 255))
321 ProgError("KR11", "%s: number out of bounds [0-255]",
322 fname(file));
323 datasize += sizeof(char);
324 c = (char) (s & 0xFF);
325 size += WADRwriteBytes(info, &c, sizeof(c));
326 }
327 WADRsetShort(info, datasizepos, datasize);
328 TXTcloseR(Txt);
329 return size;
330 }
331