1 /*
2 wav.c: write wav/au/cdr files (and headerless raw
3
4 copyright ?-2015 by the mpg123 project - free software under the terms of the LGPL 2.1
5 see COPYING and AUTHORS files in distribution or http://mpg123.org
6 initially written by Samuel Audet
7
8 Geez, why are WAV RIFF headers are so secret? I got something together,
9 but wow... anyway, I hope someone will find this useful.
10 - Samuel Audet
11
12 minor simplifications and ugly AU/CDR format stuff by MH
13
14 It's not a very clean code ... Fix this!
15
16 ThOr: The usage of stdio streams means we loose control over what data is actually written. On a full disk, fwrite() happily suceeds for ages, only a fflush fails.
17 Now: Do we want to fflush() after every write? That defeats the purpose of buffered I/O. So, switching to good old write() is an option (kernel doing disk buffering anyway).
18
19 ThOr: Again reworked things for libout123, with non-static state.
20 This set of builtin "modules" is what we can use in automated tests
21 of libout123. Code still not very nice, but I tried to keep modification
22 of what stood the test of time minimal. One still can add a module to
23 libout123 that uses sndfile and similar libraries for more choice on writing
24 output files.
25 */
26
27 #include "out123_int.h"
28 #include "wav.h"
29
30 #include <errno.h>
31 #include "debug.h"
32
33 /* Create the two WAV headers. */
34
35 #define WAVE_FORMAT 1
36 #define RIFF_NAME riff_template
37 #define RIFF_STRUCT_NAME riff
38 #include "wavhead.h"
39
40 #undef WAVE_FORMAT
41 #undef RIFF_NAME
42 #undef RIFF_STRUCT_NAME
43 #define WAVE_FORMAT 3
44 #define RIFF_NAME riff_float_template
45 #define RIFF_STRUCT_NAME riff_float
46 #define FLOATOUT
47 #include "wavhead.h"
48
49 /* AU header struct... */
50
51 struct auhead {
52 byte magic[4];
53 byte headlen[4];
54 byte datalen[4];
55 byte encoding[4];
56 byte rate[4];
57 byte channels[4];
58 byte dummy[8];
59 } const auhead_template = {
60 { 0x2e,0x73,0x6e,0x64 } , { 0x00,0x00,0x00,0x20 } ,
61 { 0xff,0xff,0xff,0xff } , { 0,0,0,0 } , { 0,0,0,0 } , { 0,0,0,0 } ,
62 { 0,0,0,0,0,0,0,0 }};
63
64 struct wavdata
65 {
66 FILE *wavfp;
67 long datalen;
68 int flipendian;
69 int bytes_per_sample;
70 int floatwav; /* If we write a floating point WAV file. */
71 /*
72 Open routines only prepare a header, stored here and written on first
73 actual data write. If no data is written at all, proper files will
74 still get a header via the update at closing; non-seekable streams will
75 just have no no header if there is no data.
76 */
77 void *the_header;
78 size_t the_header_size;
79 };
80
wavdata_new(void)81 static struct wavdata* wavdata_new(void)
82 {
83 struct wavdata *wdat = malloc(sizeof(struct wavdata));
84 if(wdat)
85 {
86 wdat->wavfp = NULL;
87 wdat->datalen = 0;
88 wdat->flipendian = 0;
89 wdat->bytes_per_sample = -1;
90 wdat->floatwav = 0;
91 wdat->the_header = NULL;
92 wdat->the_header_size = 0;
93 }
94 return wdat;
95 }
96
wavdata_del(struct wavdata * wdat)97 static void wavdata_del(struct wavdata *wdat)
98 {
99 if(!wdat) return;
100 if(wdat->wavfp && wdat->wavfp != stdout)
101 compat_fclose(wdat->wavfp);
102 if(wdat->the_header)
103 free(wdat->the_header);
104 free(wdat);
105 }
106
107 /* Pointer types are for pussies;-) */
wavhead_new(void const * template,size_t size)108 static void* wavhead_new(void const *template, size_t size)
109 {
110 void *header = malloc(size);
111 if(header)
112 memcpy(header, template, size);
113 return header;
114 }
115
116 /* Convertfunctions: */
117 /* always little endian */
118
long2littleendian(long inval,byte * outval,int b)119 static void long2littleendian(long inval,byte *outval,int b)
120 {
121 int i;
122 for(i=0;i<b;i++) {
123 outval[i] = (inval>>(i*8)) & 0xff;
124 }
125 }
126
127 /* always big endian */
long2bigendian(long inval,byte * outval,int b)128 static void long2bigendian(long inval,byte *outval,int b)
129 {
130 int i;
131 for(i=0;i<b;i++) {
132 outval[i] = (inval>>((b-i-1)*8)) & 0xff;
133 }
134 }
135
from_little(byte * inval,int b)136 static long from_little(byte *inval, int b)
137 {
138 long ret = 0;
139 int i;
140 for(i=0;i<b;++i) ret += ((long)inval[i])<<(i*8);
141
142 return ret;
143 }
144
testEndian(void)145 static int testEndian(void)
146 {
147 long i,a=0,b=0,c=0;
148 int ret = 0;
149
150 for(i=0;i<sizeof(long);i++) {
151 ((byte *)&a)[i] = i;
152 b<<=8;
153 b |= i;
154 c |= i << (i*8);
155 }
156 if(a == b)
157 ret = 1;
158 else if(a != c) {
159 ret = -1;
160 }
161 return ret;
162 }
163
164 /* return: 0 is good, -1 is bad */
open_file(struct wavdata * wdat,char * filename)165 static int open_file(struct wavdata *wdat, char *filename)
166 {
167 debug2("open_file(%p, %s)", (void*)wdat, filename ? filename : "<nil>");
168 if(!wdat)
169 return -1;
170 #if defined(HAVE_SETUID) && defined(HAVE_GETUID)
171 /* TODO: get rid of that and settle that you rather not install mpg123
172 setuid-root. Why should you?
173 In case this program is setuid, create files owned by original user. */
174 setuid(getuid());
175 #endif
176 if(!filename || !strcmp("-",filename) || !strcmp("", filename))
177 {
178 wdat->wavfp = stdout;
179 #ifdef WIN32
180 _setmode(STDOUT_FILENO, _O_BINARY);
181 #endif
182 /* If stdout is redirected to a file, seeks suddenly can work.
183 Doing one here to ensure that such a file has the same output
184 it had when opening directly as such. */
185 fseek(wdat->wavfp, 0L, SEEK_SET);
186 return 0;
187 }
188 else
189 {
190 wdat->wavfp = compat_fopen(filename, "wb");
191 if(!wdat->wavfp)
192 return -1;
193 else
194 return 0;
195 }
196 }
197
198 /* return: 0 is good, -1 is bad
199 Works for any partial state of setup, especially should not complain if
200 ao->userptr == NULL. */
close_file(out123_handle * ao)201 static int close_file(out123_handle *ao)
202 {
203 struct wavdata *wdat = ao->userptr;
204 int ret = 0;
205
206 if(wdat->wavfp != NULL && wdat->wavfp != stdout)
207 {
208 if(compat_fclose(wdat->wavfp))
209 {
210 if(!AOQUIET)
211 error1("problem closing the audio file, probably because of flushing to disk: %s\n", strerror(errno));
212 ret = -1;
213 }
214 }
215
216 /* Always cleanup here. */
217 wdat->wavfp = NULL;
218 wavdata_del(wdat);
219 ao->userptr = NULL;
220 return ret;
221 }
222
223 /* return: 0 is good, -1 is bad */
write_header(out123_handle * ao)224 static int write_header(out123_handle *ao)
225 {
226 struct wavdata *wdat = ao->userptr;
227
228 if(!wdat)
229 return 0;
230
231 if(
232 wdat->the_header_size > 0
233 && (
234 fwrite(wdat->the_header, wdat->the_header_size, 1, wdat->wavfp) != 1
235 || fflush(wdat->wavfp)
236 )
237 )
238 {
239 if(!AOQUIET)
240 error1("cannot write header: %s", strerror(errno));
241 return -1;
242 }
243 else return 0;
244 }
245
au_open(out123_handle * ao)246 int au_open(out123_handle *ao)
247 {
248 struct wavdata *wdat = NULL;
249 struct auhead *auhead = NULL;
250
251 if(ao->format < 0)
252 {
253 ao->rate = 44100;
254 ao->channels = 2;
255 ao->format = MPG123_ENC_SIGNED_16;
256 return 0;
257 }
258
259 if(ao->format & MPG123_ENC_FLOAT)
260 {
261 if(!AOQUIET)
262 error("AU file support for float values not there yet");
263 goto au_open_bad;
264 }
265
266 if(
267 !(wdat = wavdata_new())
268 || !(auhead = wavhead_new(&auhead_template, sizeof(auhead_template)))
269 )
270 {
271 ao->errcode = OUT123_DOOM;
272 goto au_open_bad;
273 }
274
275 wdat->the_header = auhead;
276 wdat->the_header_size = sizeof(*auhead);
277
278 wdat->flipendian = 0;
279
280 switch(ao->format)
281 {
282 case MPG123_ENC_SIGNED_16:
283 {
284 int endiantest = testEndian();
285 if(endiantest == -1)
286 goto au_open_bad;
287 wdat->flipendian = !endiantest; /* big end */
288 long2bigendian(3,auhead->encoding,sizeof(auhead->encoding));
289 }
290 break;
291 case MPG123_ENC_UNSIGNED_8:
292 ao->format = MPG123_ENC_ULAW_8;
293 case MPG123_ENC_ULAW_8:
294 long2bigendian(1,auhead->encoding,sizeof(auhead->encoding));
295 break;
296 default:
297 if(!AOQUIET)
298 error("AU output is only a hack. This audio mode isn't supported yet.");
299 goto au_open_bad;
300 }
301
302 long2bigendian(0xffffffff,auhead->datalen,sizeof(auhead->datalen));
303 long2bigendian(ao->rate,auhead->rate,sizeof(auhead->rate));
304 long2bigendian(ao->channels,auhead->channels,sizeof(auhead->channels));
305
306 if(open_file(wdat, ao->device) < 0)
307 goto au_open_bad;
308
309 wdat->datalen = 0;
310
311 ao->userptr = wdat;
312 return 0;
313
314 au_open_bad:
315 if(auhead)
316 free(auhead);
317 if(wdat)
318 {
319 wdat->the_header = NULL;
320 wavdata_del(wdat);
321 }
322 return -1;
323 }
324
cdr_open(out123_handle * ao)325 int cdr_open(out123_handle *ao)
326 {
327 struct wavdata *wdat = NULL;
328
329 if(ao->format < 0)
330 {
331 ao->rate = 44100;
332 ao->channels = 2;
333 ao->format = MPG123_ENC_SIGNED_16;
334 return 0;
335 }
336
337 if(
338 ao->format != MPG123_ENC_SIGNED_16
339 || ao->rate != 44100
340 || ao->channels != 2
341 )
342 {
343 if(!AOQUIET)
344 error("Oops .. not forced to 16 bit, 44 kHz, stereo?");
345 goto cdr_open_bad;
346 }
347
348 if(!(wdat = wavdata_new()))
349 {
350 ao->errcode = OUT123_DOOM;
351 goto cdr_open_bad;
352 }
353
354 wdat->flipendian = !testEndian(); /* big end */
355
356 if(open_file(wdat, ao->device) < 0)
357 {
358 if(!AOQUIET)
359 error("cannot open file for writing");
360 goto cdr_open_bad;
361 }
362
363 ao->userptr = wdat;
364 return 0;
365 cdr_open_bad:
366 if(wdat)
367 wavdata_del(wdat);
368 return -1;
369 }
370
371 /* RAW files are headerless WAVs where the format does not matter. */
raw_open(out123_handle * ao)372 int raw_open(out123_handle *ao)
373 {
374 struct wavdata *wdat;
375
376 if(ao->format < 0)
377 {
378 ao->rate = 44100;
379 ao->channels = 2;
380 ao->format = MPG123_ENC_SIGNED_16;
381 return 0;
382 }
383
384 if(!(wdat = wavdata_new()))
385 {
386 ao->errcode = OUT123_DOOM;
387 goto raw_open_bad;
388 }
389
390 if(open_file(wdat, ao->device) < 0)
391 goto raw_open_bad;
392
393 ao->userptr = wdat;
394 return 1;
395 raw_open_bad:
396 if(wdat)
397 wavdata_del(wdat);
398 return -1;
399 }
400
wav_open(out123_handle * ao)401 int wav_open(out123_handle *ao)
402 {
403 int bps;
404 struct wavdata *wdat = NULL;
405 struct riff *inthead = NULL;
406 struct riff_float *floathead = NULL;
407
408 if(ao->format < 0)
409 {
410 ao->rate = 44100;
411 ao->channels = 2;
412 ao->format = MPG123_ENC_SIGNED_16;
413 return 0;
414 }
415
416 if(!(wdat = wavdata_new()))
417 {
418 ao->errcode = OUT123_DOOM;
419 goto wav_open_bad;
420 }
421
422 wdat->floatwav = (ao->format & MPG123_ENC_FLOAT);
423 if(wdat->floatwav)
424 {
425 if(!(floathead = wavhead_new( &riff_float_template
426 , sizeof(riff_float_template)) ))
427 {
428 ao->errcode = OUT123_DOOM;
429 goto wav_open_bad;
430 }
431 wdat->the_header = floathead;
432 wdat->the_header_size = sizeof(*floathead);
433 }
434 else
435 {
436 if(!(inthead = wavhead_new( &riff_template
437 , sizeof(riff_template)) ))
438 {
439 ao->errcode = OUT123_DOOM;
440 goto wav_open_bad;
441 }
442 wdat->the_header = inthead;
443 wdat->the_header_size = sizeof(*inthead);
444
445 /* standard MS PCM, and its format specific is BitsPerSample */
446 long2littleendian(1, inthead->WAVE.fmt.FormatTag
447 , sizeof(inthead->WAVE.fmt.FormatTag));
448 }
449
450 if(ao->format == MPG123_ENC_FLOAT_32)
451 {
452 long2littleendian(3, floathead->WAVE.fmt.FormatTag
453 , sizeof(floathead->WAVE.fmt.FormatTag));
454 long2littleendian(bps=32, floathead->WAVE.fmt.BitsPerSample
455 , sizeof(floathead->WAVE.fmt.BitsPerSample));
456 wdat->flipendian = testEndian();
457 }
458 else if(ao->format == MPG123_ENC_SIGNED_32)
459 {
460 long2littleendian(bps=32, inthead->WAVE.fmt.BitsPerSample
461 , sizeof(inthead->WAVE.fmt.BitsPerSample));
462 wdat->flipendian = testEndian();
463 }
464 else if(ao->format == MPG123_ENC_SIGNED_24)
465 {
466 long2littleendian(bps=24, inthead->WAVE.fmt.BitsPerSample
467 , sizeof(inthead->WAVE.fmt.BitsPerSample));
468 wdat->flipendian = testEndian();
469 }
470 else if(ao->format == MPG123_ENC_SIGNED_16)
471 {
472 long2littleendian(bps=16, inthead->WAVE.fmt.BitsPerSample
473 , sizeof(inthead->WAVE.fmt.BitsPerSample));
474 wdat->flipendian = testEndian();
475 }
476 else if(ao->format == MPG123_ENC_UNSIGNED_8)
477 long2littleendian(bps=8, inthead->WAVE.fmt.BitsPerSample
478 , sizeof(inthead->WAVE.fmt.BitsPerSample));
479 else
480 {
481 if(!AOQUIET)
482 error("Format not supported.");
483 goto wav_open_bad;
484 }
485
486 if(wdat->floatwav)
487 {
488 long2littleendian(ao->channels, floathead->WAVE.fmt.Channels
489 , sizeof(floathead->WAVE.fmt.Channels));
490 long2littleendian(ao->rate, floathead->WAVE.fmt.SamplesPerSec
491 , sizeof(floathead->WAVE.fmt.SamplesPerSec));
492 long2littleendian( (int)(ao->channels * ao->rate * bps)>>3
493 , floathead->WAVE.fmt.AvgBytesPerSec
494 , sizeof(floathead->WAVE.fmt.AvgBytesPerSec) );
495 long2littleendian( (int)(ao->channels * bps)>>3
496 , floathead->WAVE.fmt.BlockAlign
497 , sizeof(floathead->WAVE.fmt.BlockAlign) );
498 }
499 else
500 {
501 long2littleendian(ao->channels, inthead->WAVE.fmt.Channels
502 , sizeof(inthead->WAVE.fmt.Channels));
503 long2littleendian(ao->rate, inthead->WAVE.fmt.SamplesPerSec
504 , sizeof(inthead->WAVE.fmt.SamplesPerSec));
505 long2littleendian( (int)(ao->channels * ao->rate * bps)>>3
506 , inthead->WAVE.fmt.AvgBytesPerSec
507 ,sizeof(inthead->WAVE.fmt.AvgBytesPerSec) );
508 long2littleendian( (int)(ao->channels * bps)>>3
509 , inthead->WAVE.fmt.BlockAlign
510 , sizeof(inthead->WAVE.fmt.BlockAlign) );
511 }
512
513 if(open_file(wdat, ao->device) < 0)
514 goto wav_open_bad;
515
516 if(wdat->floatwav)
517 {
518 long2littleendian(wdat->datalen, floathead->WAVE.data.datalen
519 , sizeof(floathead->WAVE.data.datalen));
520 long2littleendian(wdat->datalen+sizeof(floathead->WAVE)
521 , floathead->WAVElen, sizeof(floathead->WAVElen));
522 }
523 else
524 {
525 long2littleendian(wdat->datalen, inthead->WAVE.data.datalen
526 , sizeof(inthead->WAVE.data.datalen));
527 long2littleendian( wdat->datalen+sizeof(inthead->WAVE)
528 , inthead->WAVElen
529 , sizeof(inthead->WAVElen) );
530 }
531
532 wdat->bytes_per_sample = bps>>3;
533
534 ao->userptr = wdat;
535 return 0;
536
537 wav_open_bad:
538 if(inthead)
539 free(inthead);
540 if(floathead)
541 free(floathead);
542 if(wdat)
543 {
544 wdat->the_header = NULL;
545 wavdata_del(wdat);
546 }
547 return -1;
548 }
549
wav_write(out123_handle * ao,unsigned char * buf,int len)550 int wav_write(out123_handle *ao, unsigned char *buf, int len)
551 {
552 struct wavdata *wdat = ao->userptr;
553 int temp;
554 int i;
555
556 if(!wdat || !wdat->wavfp)
557 return 0; /* Really? Zero? */
558
559 if(wdat->datalen == 0 && write_header(ao) < 0)
560 return -1;
561
562 /* Endianess conversion. Not fancy / optimized. */
563 if(wdat->flipendian)
564 {
565 if(wdat->bytes_per_sample == 4) /* 32 bit */
566 {
567 if(len & 3)
568 {
569 if(!AOQUIET)
570 error("Number of bytes no multiple of 4 (32bit)!");
571 return -1;
572 }
573 for(i=0;i<len;i+=4)
574 {
575 int j;
576 unsigned char tmp[4];
577 for(j = 0; j<=3; ++j) tmp[j] = buf[i+j];
578 for(j = 0; j<=3; ++j) buf[i+j] = tmp[3-j];
579 }
580 }
581 else /* 16 bit */
582 {
583 if(len & 1)
584 {
585 error("Odd number of bytes!");
586 return -1;
587 }
588 for(i=0;i<len;i+=2)
589 {
590 unsigned char tmp;
591 tmp = buf[i+0];
592 buf[i+0] = buf[i+1];
593 buf[i+1] = tmp;
594 }
595 }
596 }
597
598 temp = fwrite(buf, 1, len, wdat->wavfp);
599 if(temp <= 0) return temp;
600 /* That would kill it of early when running out of disk space. */
601 #if 0
602 if(fflush(wdat->wavfp))
603 {
604 if(!AOQUIET)
605 error1("flushing failed: %s\n", strerror(errno));
606 return -1;
607 }
608 #endif
609 wdat->datalen += temp;
610
611 return temp;
612 }
613
wav_close(out123_handle * ao)614 int wav_close(out123_handle *ao)
615 {
616 struct wavdata *wdat = ao->userptr;
617
618 if(!wdat) /* Special case: Opened only for format query. */
619 return 0;
620
621 if(!wdat || !wdat->wavfp)
622 return -1;
623
624 /* flush before seeking to catch out-of-disk explicitly at least at the end */
625 if(fflush(wdat->wavfp))
626 {
627 if(!AOQUIET)
628 error1("cannot flush WAV stream: %s", strerror(errno));
629 return close_file(ao);
630 }
631 if(fseek(wdat->wavfp, 0L, SEEK_SET) >= 0)
632 {
633 if(wdat->floatwav)
634 {
635 struct riff_float *floathead = wdat->the_header;
636 long2littleendian(wdat->datalen
637 , floathead->WAVE.data.datalen
638 , sizeof(floathead->WAVE.data.datalen));
639 long2littleendian(wdat->datalen+sizeof(floathead->WAVE)
640 , floathead->WAVElen
641 , sizeof(floathead->WAVElen));
642 long2littleendian( wdat->datalen
643 / (
644 from_little(floathead->WAVE.fmt.Channels,2)
645 * from_little(floathead->WAVE.fmt.BitsPerSample,2)/8
646 )
647 , floathead->WAVE.fact.samplelen
648 , sizeof(floathead->WAVE.fact.samplelen) );
649 }
650 else
651 {
652 struct riff *inthead = wdat->the_header;
653 long2littleendian(wdat->datalen, inthead->WAVE.data.datalen
654 , sizeof(inthead->WAVE.data.datalen));
655 long2littleendian(wdat->datalen+sizeof(inthead->WAVE), inthead->WAVElen
656 , sizeof(inthead->WAVElen));
657 }
658 /* Always (over)writing the header here; also for stdout, when
659 fseek worked, this overwrite works. */
660 write_header(ao);
661 }
662 else if(!AOQUIET)
663 warning("Cannot rewind WAV file. File-format isn't fully conform now.");
664
665 return close_file(ao);
666 }
667
au_close(out123_handle * ao)668 int au_close(out123_handle *ao)
669 {
670 struct wavdata *wdat = ao->userptr;
671
672 if(!wdat) /* Special case: Opened only for format query. */
673 return 0;
674
675 if(!wdat->wavfp)
676 return -1;
677
678 /* flush before seeking to catch out-of-disk explicitly at least at the end */
679 if(fflush(wdat->wavfp))
680 {
681 if(!AOQUIET)
682 error1("cannot flush WAV stream: %s", strerror(errno));
683 return close_file(ao);
684 }
685 if(fseek(wdat->wavfp, 0L, SEEK_SET) >= 0)
686 {
687 struct auhead *auhead = wdat->the_header;
688 long2bigendian(wdat->datalen, auhead->datalen, sizeof(auhead->datalen));
689 /* Always (over)writing the header here; also for stdout, when
690 fseek worked, this overwrite works. */
691 write_header(ao);
692 }
693 else if(!AOQUIET)
694 warning("Cannot rewind AU file. File-format isn't fully conform now.");
695
696 return close_file(ao);
697 }
698
699 /* CDR data also uses that. */
raw_close(out123_handle * ao)700 int raw_close(out123_handle *ao)
701 {
702 struct wavdata *wdat = ao->userptr;
703
704 if(!wdat) /* Special case: Opened only for format query. */
705 return 0;
706
707 if(!wdat->wavfp)
708 return -1;
709
710 return close_file(ao);
711 }
712
713 /* Some trivial functions to interface with out123's module architecture. */
714
cdr_formats(out123_handle * ao)715 int cdr_formats(out123_handle *ao)
716 {
717 if(ao->rate == 44100 && ao->channels == 2)
718 return MPG123_ENC_SIGNED_16;
719 else
720 return 0;
721 }
722
au_formats(out123_handle * ao)723 int au_formats(out123_handle *ao)
724 {
725 return MPG123_ENC_SIGNED_16|MPG123_ENC_UNSIGNED_8|MPG123_ENC_ULAW_8;
726 }
727
raw_formats(out123_handle * ao)728 int raw_formats(out123_handle *ao)
729 {
730 return MPG123_ENC_ANY;
731 }
732
wav_formats(out123_handle * ao)733 int wav_formats(out123_handle *ao)
734 {
735 return
736 MPG123_ENC_SIGNED_16
737 | MPG123_ENC_UNSIGNED_8
738 | MPG123_ENC_FLOAT_32
739 | MPG123_ENC_SIGNED_24
740 | MPG123_ENC_SIGNED_32;
741 }
742
743 /* Draining is flushing to disk. Words do suck at times.
744 One could call fsync(), too, but to be safe, that would need to
745 be called on the directory, too. Also, apps randomly calling
746 fsync() can cause annoying issues in a system. */
wav_drain(out123_handle * ao)747 void wav_drain(out123_handle *ao)
748 {
749 struct wavdata *wdat = ao->userptr;
750
751 if(!wdat)
752 return;
753
754 if(fflush(wdat->wavfp) && !AOQUIET)
755 error1("flushing failed: %s\n", strerror(errno));
756 }
757