cannam@154
|
1 /********************************************************************
|
cannam@154
|
2 * *
|
cannam@154
|
3 * THIS FILE IS PART OF THE libopusfile SOFTWARE CODEC SOURCE CODE. *
|
cannam@154
|
4 * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
cannam@154
|
5 * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
|
cannam@154
|
6 * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
cannam@154
|
7 * *
|
cannam@154
|
8 * THE libopusfile SOURCE CODE IS (C) COPYRIGHT 1994-2012 *
|
cannam@154
|
9 * by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
cannam@154
|
10 * *
|
cannam@154
|
11 ********************************************************************/
|
cannam@154
|
12 #ifdef HAVE_CONFIG_H
|
cannam@154
|
13 #include "config.h"
|
cannam@154
|
14 #endif
|
cannam@154
|
15
|
cannam@154
|
16 /*For fileno()*/
|
cannam@154
|
17 #if !defined(_POSIX_SOURCE)
|
cannam@154
|
18 # define _POSIX_SOURCE 1
|
cannam@154
|
19 #endif
|
cannam@154
|
20 #include <stdio.h>
|
cannam@154
|
21 #include <stdlib.h>
|
cannam@154
|
22 #include <errno.h>
|
cannam@154
|
23 #include <string.h>
|
cannam@154
|
24 #include <opusfile.h>
|
cannam@154
|
25 #if defined(_WIN32)
|
cannam@154
|
26 # include "win32utf8.h"
|
cannam@154
|
27 # undef fileno
|
cannam@154
|
28 # define fileno _fileno
|
cannam@154
|
29 #endif
|
cannam@154
|
30
|
cannam@154
|
31 static void print_duration(FILE *_fp,ogg_int64_t _nsamples,int _frac){
|
cannam@154
|
32 ogg_int64_t seconds;
|
cannam@154
|
33 ogg_int64_t minutes;
|
cannam@154
|
34 ogg_int64_t hours;
|
cannam@154
|
35 ogg_int64_t days;
|
cannam@154
|
36 ogg_int64_t weeks;
|
cannam@154
|
37 _nsamples+=_frac?24:24000;
|
cannam@154
|
38 seconds=_nsamples/48000;
|
cannam@154
|
39 _nsamples-=seconds*48000;
|
cannam@154
|
40 minutes=seconds/60;
|
cannam@154
|
41 seconds-=minutes*60;
|
cannam@154
|
42 hours=minutes/60;
|
cannam@154
|
43 minutes-=hours*60;
|
cannam@154
|
44 days=hours/24;
|
cannam@154
|
45 hours-=days*24;
|
cannam@154
|
46 weeks=days/7;
|
cannam@154
|
47 days-=weeks*7;
|
cannam@154
|
48 if(weeks)fprintf(_fp,"%liw",(long)weeks);
|
cannam@154
|
49 if(weeks||days)fprintf(_fp,"%id",(int)days);
|
cannam@154
|
50 if(weeks||days||hours){
|
cannam@154
|
51 if(weeks||days)fprintf(_fp,"%02ih",(int)hours);
|
cannam@154
|
52 else fprintf(_fp,"%ih",(int)hours);
|
cannam@154
|
53 }
|
cannam@154
|
54 if(weeks||days||hours||minutes){
|
cannam@154
|
55 if(weeks||days||hours)fprintf(_fp,"%02im",(int)minutes);
|
cannam@154
|
56 else fprintf(_fp,"%im",(int)minutes);
|
cannam@154
|
57 fprintf(_fp,"%02i",(int)seconds);
|
cannam@154
|
58 }
|
cannam@154
|
59 else fprintf(_fp,"%i",(int)seconds);
|
cannam@154
|
60 if(_frac)fprintf(_fp,".%03i",(int)(_nsamples/48));
|
cannam@154
|
61 fprintf(_fp,"s");
|
cannam@154
|
62 }
|
cannam@154
|
63
|
cannam@154
|
64 static void print_size(FILE *_fp,opus_int64 _nbytes,int _metric,
|
cannam@154
|
65 const char *_spacer){
|
cannam@154
|
66 static const char SUFFIXES[7]={' ','k','M','G','T','P','E'};
|
cannam@154
|
67 opus_int64 val;
|
cannam@154
|
68 opus_int64 den;
|
cannam@154
|
69 opus_int64 round;
|
cannam@154
|
70 int base;
|
cannam@154
|
71 int shift;
|
cannam@154
|
72 base=_metric?1000:1024;
|
cannam@154
|
73 round=0;
|
cannam@154
|
74 den=1;
|
cannam@154
|
75 for(shift=0;shift<6;shift++){
|
cannam@154
|
76 if(_nbytes<den*base-round)break;
|
cannam@154
|
77 den*=base;
|
cannam@154
|
78 round=den>>1;
|
cannam@154
|
79 }
|
cannam@154
|
80 val=(_nbytes+round)/den;
|
cannam@154
|
81 if(den>1&&val<10){
|
cannam@154
|
82 if(den>=1000000000)val=(_nbytes+(round/100))/(den/100);
|
cannam@154
|
83 else val=(_nbytes*100+round)/den;
|
cannam@154
|
84 fprintf(_fp,"%li.%02i%s%c",(long)(val/100),(int)(val%100),
|
cannam@154
|
85 _spacer,SUFFIXES[shift]);
|
cannam@154
|
86 }
|
cannam@154
|
87 else if(den>1&&val<100){
|
cannam@154
|
88 if(den>=1000000000)val=(_nbytes+(round/10))/(den/10);
|
cannam@154
|
89 else val=(_nbytes*10+round)/den;
|
cannam@154
|
90 fprintf(_fp,"%li.%i%s%c",(long)(val/10),(int)(val%10),
|
cannam@154
|
91 _spacer,SUFFIXES[shift]);
|
cannam@154
|
92 }
|
cannam@154
|
93 else fprintf(_fp,"%li%s%c",(long)val,_spacer,SUFFIXES[shift]);
|
cannam@154
|
94 }
|
cannam@154
|
95
|
cannam@154
|
96 static void put_le32(unsigned char *_dst,opus_uint32 _x){
|
cannam@154
|
97 _dst[0]=(unsigned char)(_x&0xFF);
|
cannam@154
|
98 _dst[1]=(unsigned char)(_x>>8&0xFF);
|
cannam@154
|
99 _dst[2]=(unsigned char)(_x>>16&0xFF);
|
cannam@154
|
100 _dst[3]=(unsigned char)(_x>>24&0xFF);
|
cannam@154
|
101 }
|
cannam@154
|
102
|
cannam@154
|
103 /*Make a header for a 48 kHz, stereo, signed, 16-bit little-endian PCM WAV.*/
|
cannam@154
|
104 static void make_wav_header(unsigned char _dst[44],ogg_int64_t _duration){
|
cannam@154
|
105 /*The chunk sizes are set to 0x7FFFFFFF by default.
|
cannam@154
|
106 Many, though not all, programs will interpret this to mean the duration is
|
cannam@154
|
107 "undefined", and continue to read from the file so long as there is actual
|
cannam@154
|
108 data.*/
|
cannam@154
|
109 static const unsigned char WAV_HEADER_TEMPLATE[44]={
|
cannam@154
|
110 'R','I','F','F',0xFF,0xFF,0xFF,0x7F,
|
cannam@154
|
111 'W','A','V','E','f','m','t',' ',
|
cannam@154
|
112 0x10,0x00,0x00,0x00,0x01,0x00,0x02,0x00,
|
cannam@154
|
113 0x80,0xBB,0x00,0x00,0x00,0xEE,0x02,0x00,
|
cannam@154
|
114 0x04,0x00,0x10,0x00,'d','a','t','a',
|
cannam@154
|
115 0xFF,0xFF,0xFF,0x7F
|
cannam@154
|
116 };
|
cannam@154
|
117 memcpy(_dst,WAV_HEADER_TEMPLATE,sizeof(WAV_HEADER_TEMPLATE));
|
cannam@154
|
118 if(_duration>0){
|
cannam@154
|
119 if(_duration>0x1FFFFFF6){
|
cannam@154
|
120 fprintf(stderr,"WARNING: WAV output would be larger than 2 GB.\n");
|
cannam@154
|
121 fprintf(stderr,
|
cannam@154
|
122 "Writing non-standard WAV header with invalid chunk sizes.\n");
|
cannam@154
|
123 }
|
cannam@154
|
124 else{
|
cannam@154
|
125 opus_uint32 audio_size;
|
cannam@154
|
126 audio_size=(opus_uint32)(_duration*4);
|
cannam@154
|
127 put_le32(_dst+4,audio_size+36);
|
cannam@154
|
128 put_le32(_dst+40,audio_size);
|
cannam@154
|
129 }
|
cannam@154
|
130 }
|
cannam@154
|
131 }
|
cannam@154
|
132
|
cannam@154
|
133 int main(int _argc,const char **_argv){
|
cannam@154
|
134 OggOpusFile *of;
|
cannam@154
|
135 ogg_int64_t duration;
|
cannam@154
|
136 unsigned char wav_header[44];
|
cannam@154
|
137 int ret;
|
cannam@154
|
138 int is_ssl;
|
cannam@154
|
139 int output_seekable;
|
cannam@154
|
140 #if defined(_WIN32)
|
cannam@154
|
141 win32_utf8_setup(&_argc,&_argv);
|
cannam@154
|
142 #endif
|
cannam@154
|
143 if(_argc!=2){
|
cannam@154
|
144 fprintf(stderr,"Usage: %s <file.opus>\n",_argv[0]);
|
cannam@154
|
145 return EXIT_FAILURE;
|
cannam@154
|
146 }
|
cannam@154
|
147 is_ssl=0;
|
cannam@154
|
148 if(strcmp(_argv[1],"-")==0){
|
cannam@154
|
149 OpusFileCallbacks cb={NULL,NULL,NULL,NULL};
|
cannam@154
|
150 of=op_open_callbacks(op_fdopen(&cb,fileno(stdin),"rb"),&cb,NULL,0,&ret);
|
cannam@154
|
151 }
|
cannam@154
|
152 else{
|
cannam@154
|
153 OpusServerInfo info;
|
cannam@154
|
154 /*Try to treat the argument as a URL.*/
|
cannam@154
|
155 of=op_open_url(_argv[1],&ret,OP_GET_SERVER_INFO(&info),NULL);
|
cannam@154
|
156 #if 0
|
cannam@154
|
157 if(of==NULL){
|
cannam@154
|
158 OpusFileCallbacks cb={NULL,NULL,NULL,NULL};
|
cannam@154
|
159 void *fp;
|
cannam@154
|
160 /*For debugging: force a file to not be seekable.*/
|
cannam@154
|
161 fp=op_fopen(&cb,_argv[1],"rb");
|
cannam@154
|
162 cb.seek=NULL;
|
cannam@154
|
163 cb.tell=NULL;
|
cannam@154
|
164 of=op_open_callbacks(fp,&cb,NULL,0,NULL);
|
cannam@154
|
165 }
|
cannam@154
|
166 #else
|
cannam@154
|
167 if(of==NULL)of=op_open_file(_argv[1],&ret);
|
cannam@154
|
168 #endif
|
cannam@154
|
169 else{
|
cannam@154
|
170 if(info.name!=NULL){
|
cannam@154
|
171 fprintf(stderr,"Station name: %s\n",info.name);
|
cannam@154
|
172 }
|
cannam@154
|
173 if(info.description!=NULL){
|
cannam@154
|
174 fprintf(stderr,"Station description: %s\n",info.description);
|
cannam@154
|
175 }
|
cannam@154
|
176 if(info.genre!=NULL){
|
cannam@154
|
177 fprintf(stderr,"Station genre: %s\n",info.genre);
|
cannam@154
|
178 }
|
cannam@154
|
179 if(info.url!=NULL){
|
cannam@154
|
180 fprintf(stderr,"Station homepage: %s\n",info.url);
|
cannam@154
|
181 }
|
cannam@154
|
182 if(info.bitrate_kbps>=0){
|
cannam@154
|
183 fprintf(stderr,"Station bitrate: %u kbps\n",
|
cannam@154
|
184 (unsigned)info.bitrate_kbps);
|
cannam@154
|
185 }
|
cannam@154
|
186 if(info.is_public>=0){
|
cannam@154
|
187 fprintf(stderr,"%s\n",
|
cannam@154
|
188 info.is_public?"Station is public.":"Station is private.");
|
cannam@154
|
189 }
|
cannam@154
|
190 if(info.server!=NULL){
|
cannam@154
|
191 fprintf(stderr,"Server software: %s\n",info.server);
|
cannam@154
|
192 }
|
cannam@154
|
193 if(info.content_type!=NULL){
|
cannam@154
|
194 fprintf(stderr,"Content-Type: %s\n",info.content_type);
|
cannam@154
|
195 }
|
cannam@154
|
196 is_ssl=info.is_ssl;
|
cannam@154
|
197 opus_server_info_clear(&info);
|
cannam@154
|
198 }
|
cannam@154
|
199 }
|
cannam@154
|
200 if(of==NULL){
|
cannam@154
|
201 fprintf(stderr,"Failed to open file '%s': %i\n",_argv[1],ret);
|
cannam@154
|
202 return EXIT_FAILURE;
|
cannam@154
|
203 }
|
cannam@154
|
204 duration=0;
|
cannam@154
|
205 output_seekable=fseek(stdout,0,SEEK_CUR)!=-1;
|
cannam@154
|
206 if(op_seekable(of)){
|
cannam@154
|
207 opus_int64 size;
|
cannam@154
|
208 fprintf(stderr,"Total number of links: %i\n",op_link_count(of));
|
cannam@154
|
209 duration=op_pcm_total(of,-1);
|
cannam@154
|
210 fprintf(stderr,"Total duration: ");
|
cannam@154
|
211 print_duration(stderr,duration,3);
|
cannam@154
|
212 fprintf(stderr," (%li samples @ 48 kHz)\n",(long)duration);
|
cannam@154
|
213 size=op_raw_total(of,-1);
|
cannam@154
|
214 fprintf(stderr,"Total size: ");
|
cannam@154
|
215 print_size(stderr,size,0,"");
|
cannam@154
|
216 fprintf(stderr,"\n");
|
cannam@154
|
217 }
|
cannam@154
|
218 else if(!output_seekable){
|
cannam@154
|
219 fprintf(stderr,"WARNING: Neither input nor output are seekable.\n");
|
cannam@154
|
220 fprintf(stderr,
|
cannam@154
|
221 "Writing non-standard WAV header with invalid chunk sizes.\n");
|
cannam@154
|
222 }
|
cannam@154
|
223 make_wav_header(wav_header,duration);
|
cannam@154
|
224 if(!fwrite(wav_header,sizeof(wav_header),1,stdout)){
|
cannam@154
|
225 fprintf(stderr,"Error writing WAV header: %s\n",strerror(errno));
|
cannam@154
|
226 ret=EXIT_FAILURE;
|
cannam@154
|
227 }
|
cannam@154
|
228 else{
|
cannam@154
|
229 ogg_int64_t pcm_offset;
|
cannam@154
|
230 ogg_int64_t pcm_print_offset;
|
cannam@154
|
231 ogg_int64_t nsamples;
|
cannam@154
|
232 opus_int32 bitrate;
|
cannam@154
|
233 int prev_li;
|
cannam@154
|
234 prev_li=-1;
|
cannam@154
|
235 nsamples=0;
|
cannam@154
|
236 pcm_offset=op_pcm_tell(of);
|
cannam@154
|
237 if(pcm_offset!=0){
|
cannam@154
|
238 fprintf(stderr,"Non-zero starting PCM offset: %li\n",(long)pcm_offset);
|
cannam@154
|
239 }
|
cannam@154
|
240 pcm_print_offset=pcm_offset-48000;
|
cannam@154
|
241 bitrate=0;
|
cannam@154
|
242 for(;;){
|
cannam@154
|
243 ogg_int64_t next_pcm_offset;
|
cannam@154
|
244 opus_int16 pcm[120*48*2];
|
cannam@154
|
245 unsigned char out[120*48*2*2];
|
cannam@154
|
246 int li;
|
cannam@154
|
247 int si;
|
cannam@154
|
248 /*Although we would generally prefer to use the float interface, WAV
|
cannam@154
|
249 files with signed, 16-bit little-endian samples are far more
|
cannam@154
|
250 universally supported, so that's what we output.*/
|
cannam@154
|
251 ret=op_read_stereo(of,pcm,sizeof(pcm)/sizeof(*pcm));
|
cannam@154
|
252 if(ret==OP_HOLE){
|
cannam@154
|
253 fprintf(stderr,"\nHole detected! Corrupt file segment?\n");
|
cannam@154
|
254 continue;
|
cannam@154
|
255 }
|
cannam@154
|
256 else if(ret<0){
|
cannam@154
|
257 fprintf(stderr,"\nError decoding '%s': %i\n",_argv[1],ret);
|
cannam@154
|
258 if(is_ssl)fprintf(stderr,"Possible truncation attack?\n");
|
cannam@154
|
259 ret=EXIT_FAILURE;
|
cannam@154
|
260 break;
|
cannam@154
|
261 }
|
cannam@154
|
262 li=op_current_link(of);
|
cannam@154
|
263 if(li!=prev_li){
|
cannam@154
|
264 const OpusHead *head;
|
cannam@154
|
265 const OpusTags *tags;
|
cannam@154
|
266 int binary_suffix_len;
|
cannam@154
|
267 int ci;
|
cannam@154
|
268 /*We found a new link.
|
cannam@154
|
269 Print out some information.*/
|
cannam@154
|
270 fprintf(stderr,"Decoding link %i: \n",li);
|
cannam@154
|
271 head=op_head(of,li);
|
cannam@154
|
272 fprintf(stderr," Channels: %i\n",head->channel_count);
|
cannam@154
|
273 if(op_seekable(of)){
|
cannam@154
|
274 ogg_int64_t duration;
|
cannam@154
|
275 opus_int64 size;
|
cannam@154
|
276 duration=op_pcm_total(of,li);
|
cannam@154
|
277 fprintf(stderr," Duration: ");
|
cannam@154
|
278 print_duration(stderr,duration,3);
|
cannam@154
|
279 fprintf(stderr," (%li samples @ 48 kHz)\n",(long)duration);
|
cannam@154
|
280 size=op_raw_total(of,li);
|
cannam@154
|
281 fprintf(stderr," Size: ");
|
cannam@154
|
282 print_size(stderr,size,0,"");
|
cannam@154
|
283 fprintf(stderr,"\n");
|
cannam@154
|
284 }
|
cannam@154
|
285 if(head->input_sample_rate){
|
cannam@154
|
286 fprintf(stderr," Original sampling rate: %lu Hz\n",
|
cannam@154
|
287 (unsigned long)head->input_sample_rate);
|
cannam@154
|
288 }
|
cannam@154
|
289 tags=op_tags(of,li);
|
cannam@154
|
290 fprintf(stderr," Encoded by: %s\n",tags->vendor);
|
cannam@154
|
291 for(ci=0;ci<tags->comments;ci++){
|
cannam@154
|
292 const char *comment;
|
cannam@154
|
293 comment=tags->user_comments[ci];
|
cannam@154
|
294 if(opus_tagncompare("METADATA_BLOCK_PICTURE",22,comment)==0){
|
cannam@154
|
295 OpusPictureTag pic;
|
cannam@154
|
296 int err;
|
cannam@154
|
297 err=opus_picture_tag_parse(&pic,comment);
|
cannam@154
|
298 fprintf(stderr," %.23s",comment);
|
cannam@154
|
299 if(err>=0){
|
cannam@154
|
300 fprintf(stderr,"%u|%s|%s|%ux%ux%u",pic.type,pic.mime_type,
|
cannam@154
|
301 pic.description,pic.width,pic.height,pic.depth);
|
cannam@154
|
302 if(pic.colors!=0)fprintf(stderr,"/%u",pic.colors);
|
cannam@154
|
303 if(pic.format==OP_PIC_FORMAT_URL){
|
cannam@154
|
304 fprintf(stderr,"|%s\n",pic.data);
|
cannam@154
|
305 }
|
cannam@154
|
306 else{
|
cannam@154
|
307 fprintf(stderr,"|<%u bytes of image data>\n",pic.data_length);
|
cannam@154
|
308 }
|
cannam@154
|
309 opus_picture_tag_clear(&pic);
|
cannam@154
|
310 }
|
cannam@154
|
311 else fprintf(stderr,"<error parsing picture tag>\n");
|
cannam@154
|
312 }
|
cannam@154
|
313 else fprintf(stderr," %s\n",tags->user_comments[ci]);
|
cannam@154
|
314 }
|
cannam@154
|
315 if(opus_tags_get_binary_suffix(tags,&binary_suffix_len)!=NULL){
|
cannam@154
|
316 fprintf(stderr,"<%u bytes of unknown binary metadata>\n",
|
cannam@154
|
317 binary_suffix_len);
|
cannam@154
|
318 }
|
cannam@154
|
319 fprintf(stderr,"\n");
|
cannam@154
|
320 if(!op_seekable(of)){
|
cannam@154
|
321 pcm_offset=op_pcm_tell(of)-ret;
|
cannam@154
|
322 if(pcm_offset!=0){
|
cannam@154
|
323 fprintf(stderr,"Non-zero starting PCM offset in link %i: %li\n",
|
cannam@154
|
324 li,(long)pcm_offset);
|
cannam@154
|
325 }
|
cannam@154
|
326 }
|
cannam@154
|
327 }
|
cannam@154
|
328 if(li!=prev_li||pcm_offset>=pcm_print_offset+48000){
|
cannam@154
|
329 opus_int32 next_bitrate;
|
cannam@154
|
330 opus_int64 raw_offset;
|
cannam@154
|
331 next_bitrate=op_bitrate_instant(of);
|
cannam@154
|
332 if(next_bitrate>=0)bitrate=next_bitrate;
|
cannam@154
|
333 raw_offset=op_raw_tell(of);
|
cannam@154
|
334 fprintf(stderr,"\r ");
|
cannam@154
|
335 print_size(stderr,raw_offset,0,"");
|
cannam@154
|
336 fprintf(stderr," ");
|
cannam@154
|
337 print_duration(stderr,pcm_offset,0);
|
cannam@154
|
338 fprintf(stderr," (");
|
cannam@154
|
339 print_size(stderr,bitrate,1," ");
|
cannam@154
|
340 fprintf(stderr,"bps) \r");
|
cannam@154
|
341 pcm_print_offset=pcm_offset;
|
cannam@154
|
342 fflush(stderr);
|
cannam@154
|
343 }
|
cannam@154
|
344 next_pcm_offset=op_pcm_tell(of);
|
cannam@154
|
345 if(pcm_offset+ret!=next_pcm_offset){
|
cannam@154
|
346 fprintf(stderr,"\nPCM offset gap! %li+%i!=%li\n",
|
cannam@154
|
347 (long)pcm_offset,ret,(long)next_pcm_offset);
|
cannam@154
|
348 }
|
cannam@154
|
349 pcm_offset=next_pcm_offset;
|
cannam@154
|
350 if(ret<=0){
|
cannam@154
|
351 ret=EXIT_SUCCESS;
|
cannam@154
|
352 break;
|
cannam@154
|
353 }
|
cannam@154
|
354 /*Ensure the data is little-endian before writing it out.*/
|
cannam@154
|
355 for(si=0;si<2*ret;si++){
|
cannam@154
|
356 out[2*si+0]=(unsigned char)(pcm[si]&0xFF);
|
cannam@154
|
357 out[2*si+1]=(unsigned char)(pcm[si]>>8&0xFF);
|
cannam@154
|
358 }
|
cannam@154
|
359 if(!fwrite(out,sizeof(*out)*4*ret,1,stdout)){
|
cannam@154
|
360 fprintf(stderr,"\nError writing decoded audio data: %s\n",
|
cannam@154
|
361 strerror(errno));
|
cannam@154
|
362 ret=EXIT_FAILURE;
|
cannam@154
|
363 break;
|
cannam@154
|
364 }
|
cannam@154
|
365 nsamples+=ret;
|
cannam@154
|
366 prev_li=li;
|
cannam@154
|
367 }
|
cannam@154
|
368 if(ret==EXIT_SUCCESS){
|
cannam@154
|
369 fprintf(stderr,"\nDone: played ");
|
cannam@154
|
370 print_duration(stderr,nsamples,3);
|
cannam@154
|
371 fprintf(stderr," (%li samples @ 48 kHz).\n",(long)nsamples);
|
cannam@154
|
372 }
|
cannam@154
|
373 if(op_seekable(of)&&nsamples!=duration){
|
cannam@154
|
374 fprintf(stderr,"\nWARNING: "
|
cannam@154
|
375 "Number of output samples does not match declared file duration.\n");
|
cannam@154
|
376 if(!output_seekable)fprintf(stderr,"Output WAV file will be corrupt.\n");
|
cannam@154
|
377 }
|
cannam@154
|
378 if(output_seekable&&nsamples!=duration){
|
cannam@154
|
379 make_wav_header(wav_header,nsamples);
|
cannam@154
|
380 if(fseek(stdout,0,SEEK_SET)||
|
cannam@154
|
381 !fwrite(wav_header,sizeof(wav_header),1,stdout)){
|
cannam@154
|
382 fprintf(stderr,"Error rewriting WAV header: %s\n",strerror(errno));
|
cannam@154
|
383 ret=EXIT_FAILURE;
|
cannam@154
|
384 }
|
cannam@154
|
385 }
|
cannam@154
|
386 }
|
cannam@154
|
387 op_free(of);
|
cannam@154
|
388 return ret;
|
cannam@154
|
389 }
|