5 * Copyright (C) 2002-2005 Monty
7 * Postfish is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2, or (at your option)
12 * Postfish is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Postfish; see the file COPYING. If not, write to the
19 * Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
28 static off_t Acursor
=0;
29 static off_t Bcursor
=-1;
30 static off_t cursor
=0;
32 sig_atomic_t loop_active
;
39 pthread_mutex_t input_mutex
=PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
;
59 file_entry
*file_list
;
61 int current_file_entry_number
;
62 file_entry
*current_file_entry
;
67 static group_entry
*group_list
=0;
69 typedef struct input_feedback
{
70 feedback_generic parent_class
;
76 static feedback_generic_pool feedpool
;
78 static time_linkage out
;
80 void input_Acursor_set(off_t c
){
81 pthread_mutex_lock(&input_mutex
);
83 pthread_mutex_unlock(&input_mutex
);
86 void input_Bcursor_set(off_t c
){
87 pthread_mutex_lock(&input_mutex
);
89 pthread_mutex_unlock(&input_mutex
);
92 off_t
input_time_to_cursor(const char *t
){
142 return ((off_t
)hd
+ (off_t
)s
*100 + (off_t
)m
*60*100 + (off_t
)h
*60*60*100) *
146 void time_fix(char *buffer
){
147 if(buffer
[0]=='0')buffer
[0]=' ';
148 if(!strncmp(buffer
," 0",2))buffer
[1]=' ';
149 if(!strncmp(buffer
," 0",3))buffer
[2]=' ';
150 if(!strncmp(buffer
," 0",4))buffer
[3]=' ';
151 if(!strncmp(buffer
," :0",6))buffer
[5]=' ';
152 if(!strncmp(buffer
," : 0",7))buffer
[6]=' ';
154 if(buffer
[0]!=' ' && buffer
[1]==' ')buffer
[1]='0';
155 if(buffer
[1]!=' ' && buffer
[2]==' ')buffer
[2]='0';
156 if(buffer
[2]!=' ' && buffer
[3]==' ')buffer
[3]='0';
157 if(buffer
[3]!=' ' && buffer
[5]==' ')buffer
[5]='0';
158 if(buffer
[5]!=' ' && buffer
[6]==' ')buffer
[6]='0';
161 void input_cursor_to_time(off_t cursor
,char *t
){
164 h
=cursor
/60/60/input_rate
;
165 cursor
%=(off_t
)60*60*input_rate
;
166 m
=cursor
/60/input_rate
;
167 cursor
%=(off_t
)60*input_rate
;
169 hd
=cursor
%input_rate
*100/input_rate
;
172 sprintf(t
,"%04d:%02d:%02d.%02d",h
,m
,s
,hd
);
176 void input_parse(char *filename
,int newgroup
){
181 group_list
=calloc(1,sizeof(*group_list
));
183 group_list
=realloc(group_list
,sizeof(*group_list
)*(groups
+1));
184 memset(group_list
+groups
,0,sizeof(*group_list
));
190 group_entry
*g
=group_list
+groups
-1;
194 g
->file_list
=calloc(1,sizeof(*g
->file_list
));
196 g
->file_list
=realloc(g
->file_list
,
197 sizeof(*g
->file_list
)*(g
->files
+1));
198 memset(g
->file_list
+g
->files
,0,sizeof(*g
->file_list
));
200 fe
=g
->file_list
+g
->files
;
203 fe
->name
=strdup(filename
);
207 /* Macros to read header data */
208 #define READ_U32_LE(buf) \
209 (((buf)[3]<<24)|((buf)[2]<<16)|((buf)[1]<<8)|((buf)[0]&0xff))
211 #define READ_U16_LE(buf) \
212 (((buf)[1]<<8)|((buf)[0]&0xff))
214 #define READ_U32_BE(buf) \
215 (((buf)[0]<<24)|((buf)[1]<<16)|((buf)[2]<<8)|((buf)[3]&0xff))
217 #define READ_U16_BE(buf) \
218 (((buf)[0]<<8)|((buf)[1]&0xff))
220 double read_IEEE80(unsigned char *buf
){
222 int e
=((buf
[0]&0x7f)<<8)|(buf
[1]&0xff);
223 double f
=((unsigned long)(buf
[2]&0xff)<<24)|
230 return HUGE_VAL
; /* Really NaN, but this won't happen in reality */
240 f
+= ((buf
[6]&0xff)<<24)|
245 return ldexp(f
, e
-16446);
248 static int find_chunk(FILE *in
, char *type
, unsigned int *len
, int endian
){
250 unsigned char buf
[8];
253 if(fread(buf
,1,8,in
) <8)return 0;
256 *len
= READ_U32_BE(buf
+4);
258 *len
= READ_U32_LE(buf
+4);
260 if(memcmp(buf
,type
,4)){
262 if((*len
) & 0x1)(*len
)++;
265 if(fgetc(in
)==EOF
)return 0;
271 int input_load(void){
278 /* look at stdin... is it a file, pipe, tty...? */
279 if(isatty(STDIN_FILENO
)){
281 "Postfish requires input either as a list of contiguous WAV\n"
282 "files on the command line, or WAV data piped|redirected to\n"
283 "stdin. postfish -h will give more details.\n");
286 stdinp
=1; /* file coming in via stdin */
288 group_list
=calloc(1,sizeof(*group_list
));
289 group_list
[0].file_list
=calloc(1,sizeof(*group_list
[0].file_list
));
292 group_list
[0].files
=1;
293 group_list
[0].file_list
[0].name
="stdin";
296 for(k
=0;k
<groups
;k
++){
297 group_entry
*g
=group_list
+k
;
300 for(i
=0;i
<g
->files
;i
++){
301 file_entry
*fe
=g
->file_list
+i
;
306 int newfd
=dup(STDIN_FILENO
);
307 f
=fdopen(newfd
,"rb");
309 fname
=g
->file_list
[i
].name
;
313 /* Crappy! Use a lib to do this for pete's sake! */
319 /* parse header (well, sort of) and get file size */
320 input_seekable
=(fseek(f
,0,SEEK_CUR
)?0:1);
325 filelength
=ftello(f
);
329 fread(headerid
,1,12,f
);
330 if(!strncmp(headerid
,"RIFF",4) && !strncmp(headerid
+8,"WAVE",4)){
331 unsigned int chunklen
;
333 if(find_chunk(f
,"fmt ",&chunklen
,0)){
338 unsigned char *buf
=alloca(chunklen
);
340 fread(buf
,1,chunklen
,f
);
342 ltype
= READ_U16_LE(buf
);
343 lch
= READ_U16_LE(buf
+2);
344 lrate
= READ_U32_LE(buf
+4);
345 lbits
= READ_U16_LE(buf
+14);
348 fprintf(stderr
,"%s:\n\tWAVE file not PCM.\n",fname
);
352 fe
->bytes
=(lbits
+7)/8;
355 if(fe
->bytes
>1)fe
->signp
=1;
357 if(lrate
<4000 || lrate
>192000){
358 fprintf(stderr
,"%s:\n\tSampling rate out of bounds\n",fname
);
364 }else if(input_rate
!=lrate
){
365 fprintf(stderr
,"%s:\n\tInput files must all be same sampling rate.\n",fname
);
374 fprintf(stderr
,"%s:\n\tInput files must all have same number of channels.\n",fname
);
379 if(find_chunk(f
,"data",&chunklen
,0)){
386 (g
->ch
*fe
->bytes
)+pos
;
389 chunklen
==0x7fffffffUL
||
390 chunklen
==0xffffffffUL
){
394 fprintf(stderr
,"%s: Incomplete header; assuming stream.\n",fname
);
397 total
=fe
->end
=total
+(filelength
-pos
)/(g
->ch
*fe
->bytes
);
398 fprintf(stderr
,"%s: Incomplete header; using actual file size.\n",fname
);
400 }else if(filelength
==-1 || chunklen
+pos
<=filelength
){
402 total
=fe
->end
=total
+ (chunklen
/(g
->ch
*fe
->bytes
));
403 fprintf(stderr
,"%s: Using declared file size.\n",fname
);
407 total
=fe
->end
=total
+(filelength
-pos
)/(g
->ch
*fe
->bytes
);
408 fprintf(stderr
,"%s: File truncated; Using actual file size.\n",fname
);
412 fprintf(stderr
,"%s: WAVE file has no \"data\" chunk following \"fmt \".\n",fname
);
416 fprintf(stderr
,"%s: WAVE file has no \"fmt \" chunk.\n",fname
);
420 }else if(!strncmp(headerid
,"FORM",4) && !strncmp(headerid
+8,"AIF",3)){
423 if(headerid
[11]=='C')aifc
=1;
424 unsigned char *buffer
;
432 if(!find_chunk(f
, "COMM", &len
,1)){
433 fprintf(stderr
,"%s: AIFF file has no \"COMM\" chunk.\n",fname
);
437 if(len
< 18 || (aifc
&& len
<22)) {
438 fprintf(stderr
,"%s: AIFF COMM chunk is truncated.\n",fname
);
442 buffer
= alloca(len
);
444 if(fread(buffer
,1,len
,f
) < len
){
445 fprintf(stderr
, "%s: Unexpected EOF in reading AIFF header\n",fname
);
449 lch
= READ_U16_BE(buffer
);
450 lbits
= READ_U16_BE(buffer
+6);
451 lrate
= (int)read_IEEE80(buffer
+8);
453 fe
->endian
= 1; // default
455 fe
->bytes
=(lbits
+7)/8;
458 if(lrate
<4000 || lrate
>192000){
459 fprintf(stderr
,"%s:\n\tSampling rate out of bounds\n",fname
);
465 }else if(input_rate
!=lrate
){
466 fprintf(stderr
,"%s:\n\tInput files must all be same sampling rate.\n",fname
);
475 fprintf(stderr
,"%s:\n\tInput files must all have same number of channels.\n",fname
);
481 if(!memcmp(buffer
+18, "NONE", 4)) {
483 }else if(!memcmp(buffer
+18, "sowt", 4)) {
486 fprintf(stderr
, "%s: Postfish supports only linear PCM AIFF-C files.\n",fname
);
491 if(!find_chunk(f
, "SSND", &len
, 1)){
492 fprintf(stderr
,"%s: AIFF file has no \"SSND\" chunk.\n",fname
);
496 if(fread(buf2
,1,8,f
) < 8){
497 fprintf(stderr
,"%s: Unexpected EOF reading AIFF header\n",fname
);
502 int loffset
= READ_U32_BE(buf2
);
503 int lblocksize
= READ_U32_BE(buf2
+4);
505 /* swallow some data */
506 for(i
=0;i
<loffset
;i
++)
507 if(fgetc(f
)==EOF
)break;
509 if( lblocksize
== 0 && (lbits
== 32 || lbits
== 24 || lbits
== 16 || lbits
== 8)){
517 (g
->ch
*fe
->bytes
)+pos
;
525 fprintf(stderr
,"%s: Incomplete header; assuming stream.\n",fname
);
528 total
=fe
->end
=total
+(filelength
-pos
)/(g
->ch
*fe
->bytes
);
529 fprintf(stderr
,"%s: Incomplete header; using actual file size.\n",fname
);
531 }else if(filelength
==-1 || (len
+pos
-loffset
-8)<=filelength
){
533 total
=fe
->end
=total
+ ((len
-loffset
-8)/(g
->ch
*fe
->bytes
));
534 fprintf(stderr
,"%s: Using declared file size.\n",fname
);
538 total
=fe
->end
=total
+(filelength
-pos
)/(g
->ch
*fe
->bytes
);
539 fprintf(stderr
,"%s: File truncated; Using actual file size.\n",fname
);
543 fprintf(stderr
, "%s: Postfish supports only linear PCM AIFF-C files.\n",fname
);
550 fprintf(stderr
,"%s: Postfish supports only linear PCM WAV and AIFF[-C] files.\n",fname
);
555 fprintf(stderr
,"%s: Unable to open file.\n",fname
);
582 }else if(input_rate
<15000){
584 }else if(input_rate
<25000){
586 }else if(input_rate
<50000){
588 }else if(input_rate
<100000){
593 out
.channels
=input_ch
;
595 out
.data
=malloc(sizeof(*out
.data
)*input_ch
);
596 for(i
=0;i
<input_ch
;i
++)
597 out
.data
[i
]=malloc(sizeof(**out
.data
)*input_size
);
602 static off_t
input_seek_i(off_t pos
,int ps
){
609 for(i
=0;i
<groups
;i
++){
610 group_list
[i
].current_file_entry
=group_list
[i
].file_list
;
611 group_list
[i
].current_file_entry_number
=0;
616 pthread_mutex_lock(&input_mutex
);
617 if(ps
)playback_seeking
=1;
619 /* seek has to happen correctly in all groups */
620 for(k
=0;k
<groups
;k
++){
621 group_entry
*g
=group_list
+k
;
623 for(i
=0;i
<g
->files
;i
++){
624 file_entry
*fe
=g
->current_file_entry
=g
->file_list
+i
;
625 g
->current_file_entry_number
=i
;
627 if(fe
->begin
<=pos
&& fe
->end
>pos
){
630 (pos
-fe
->begin
)*(g
->ch
*fe
->bytes
)+fe
->data
,
637 /* this group isn't that long; seek to the end of it */
638 file_entry
*fe
=g
->current_file_entry
;
640 fseeko(fe
->f
,(fe
->end
-fe
->begin
)*(g
->ch
*fe
->bytes
)+fe
->data
,SEEK_SET
);
642 if(fe
->end
>maxpos
)maxpos
=fe
->end
;
648 pthread_mutex_unlock(&input_mutex
);
651 pthread_mutex_unlock(&input_mutex
);
657 off_t
input_seek(off_t pos
){
658 return input_seek_i(pos
,1);
661 off_t
input_time_seek_rel(float s
){
662 return input_seek(cursor
+input_rate
*s
);
665 static feedback_generic
*new_input_feedback(void){
666 input_feedback
*ret
=malloc(sizeof(*ret
));
667 ret
->rms
=malloc(input_ch
*sizeof(*ret
->rms
));
668 ret
->peak
=malloc(input_ch
*sizeof(*ret
->peak
));
669 return (feedback_generic
*)ret
;
672 static void push_input_feedback(float *peak
,float *rms
, off_t cursor
){
673 input_feedback
*f
=(input_feedback
*)
674 feedback_new(&feedpool
,new_input_feedback
);
676 memcpy(f
->rms
,rms
,input_ch
*sizeof(*rms
));
677 memcpy(f
->peak
,peak
,input_ch
*sizeof(*peak
));
678 feedback_push(&feedpool
,(feedback_generic
*)f
);
681 int pull_input_feedback(float *peak
,float *rms
,off_t
*cursor
){
682 input_feedback
*f
=(input_feedback
*)feedback_pull(&feedpool
);
684 if(rms
)memcpy(rms
,f
->rms
,sizeof(*rms
)*input_ch
);
685 if(peak
)memcpy(peak
,f
->peak
,sizeof(*peak
)*input_ch
);
686 if(cursor
)*cursor
=f
->cursor
;
687 feedback_old(&feedpool
,(feedback_generic
*)f
);
691 static void LEconvert(float **data
,
692 unsigned char *readbuf
, int dataoff
,
693 int ch
,int bytes
, int signp
, int n
){
695 int32_t xor=(signp
?0:0x80000000UL
);
696 float scale
=1./2147483648.;
702 for(i
=dataoff
;i
<dataoff
+n
;i
++)
704 data
[j
][i
]=((readbuf
[k
]<<24)^xor)*scale
;
711 for(i
=dataoff
;i
<dataoff
+n
;i
++)
713 data
[j
][i
]=(((readbuf
[k
]<<16)|(readbuf
[k
+1]<<24))^xor)*scale
;
720 for(i
=dataoff
;i
<dataoff
+n
;i
++)
722 data
[j
][i
]=(((readbuf
[k
]<<8)|(readbuf
[k
+1]<<16)|(readbuf
[k
+2]<<24))^xor)*scale
;
729 for(i
=dataoff
;i
<dataoff
+n
;i
++)
731 data
[j
][i
]=(((readbuf
[k
])|(readbuf
[k
+1]<<8)|(readbuf
[k
+2]<<16)|(readbuf
[k
+3]<<24))^xor)*scale
;
738 static void BEconvert(float **data
,
739 unsigned char *readbuf
, int dataoff
,
740 int ch
,int bytes
, int signp
, int n
){
742 int32_t xor=(signp
?0:0x80000000UL
);
743 float scale
=1./2147483648.;
749 for(i
=dataoff
;i
<dataoff
+n
;i
++)
751 data
[j
][i
]=((readbuf
[k
]<<24)^xor)*scale
;
758 for(i
=dataoff
;i
<dataoff
+n
;i
++)
760 data
[j
][i
]=(((readbuf
[k
+1]<<16)|(readbuf
[k
]<<24))^xor)*scale
;
767 for(i
=dataoff
;i
<dataoff
+n
;i
++)
769 data
[j
][i
]=(((readbuf
[k
+2]<<8)|(readbuf
[k
+1]<<16)|(readbuf
[k
]<<24))^xor)*scale
;
776 for(i
=dataoff
;i
<dataoff
+n
;i
++)
778 data
[j
][i
]=(((readbuf
[k
+3])|(readbuf
[k
+2]<<8)|(readbuf
[k
+1]<<16)|(readbuf
[k
]<<24))^xor)*scale
;
785 static void zero(float **data
, int dataoff
, int ch
, int n
){
788 for(i
=dataoff
;i
<dataoff
+n
;i
++)
793 /* no locking within as the only use of input_read is locked in the
794 playback thread (must be locked there because the real lock needs
795 to avoid a seeking race) */
797 time_linkage
*input_read(void){
801 float *rms
=alloca(sizeof(*rms
)*(out
.channels
));
802 float *peak
=alloca(sizeof(*peak
)*(out
.channels
));
804 memset(rms
,0,sizeof(*rms
)*(out
.channels
));
805 memset(peak
,0,sizeof(*peak
)*(out
.channels
));
809 /* the non-streaming case */
810 if(!loop_active
&& input_seekable
){
811 for(i
=0;i
<groups
;i
++)
812 if(cursor
<group_list
[i
].file_list
[group_list
[i
].files
-1].end
)
814 if(i
==groups
)goto tidy_up
;
817 /* the streaming case */
818 if(!input_seekable
&& feof(group_list
[0].current_file_entry
->f
)){
822 /* If we're A-B looping, we might need several loops/seeks */
823 while(groupread_s
<input_size
){
827 if(loop_active
&& cursor
>=Bcursor
){
828 input_seek_i(Acursor
,0);
831 /* each read section is by group */
832 for(h
=0;h
<groups
;h
++){
833 group_entry
*g
=group_list
+h
;
834 int toread_s
=input_size
-groupread_s
;
837 if(input_seekable
&& loop_active
&& toread_s
>Bcursor
-cursor
)
838 toread_s
= Bcursor
-cursor
;
840 /* inner loop in case the read spans multiple files within the group */
842 file_entry
*fe
=g
->current_file_entry
;
845 /* span forward to next file entry in the group? */
846 if(cursor
+fileread_s
>=fe
->end
&&
847 g
->current_file_entry_number
+1<g
->files
){
848 fe
=++g
->current_file_entry
;
849 g
->current_file_entry_number
++;
850 fseeko(fe
->f
,fe
->data
,SEEK_SET
);
853 /* perform read/conversion of this file entry */
855 off_t read_this_loop
=(fe
->end
<0?input_size
:fe
->end
-cursor
-fileread_s
);
856 unsigned char readbuf
[input_size
*(g
->ch
*fe
->bytes
)];
857 if(read_this_loop
>toread_s
)read_this_loop
=toread_s
;
859 ret
=fread(readbuf
,1,read_this_loop
*(g
->ch
*fe
->bytes
),fe
->f
);
862 ret
/=(g
->ch
*fe
->bytes
);
865 BEconvert(out
.data
+chcount
,readbuf
,
866 fileread_s
+groupread_s
,g
->ch
,fe
->bytes
,fe
->signp
,ret
);
868 LEconvert(out
.data
+chcount
,readbuf
,
869 fileread_s
+groupread_s
,g
->ch
,fe
->bytes
,fe
->signp
,ret
);
875 if(g
->current_file_entry_number
+1>=g
->files
){
877 /* end of group before full frame */
878 zero(out
.data
+chcount
,fileread_s
+groupread_s
,g
->ch
,toread_s
);
885 if(max_read_s
<fileread_s
)max_read_s
=fileread_s
;
889 groupread_s
+=max_read_s
;
892 if(!loop_active
|| cursor
<Bcursor
) break;
896 out
.samples
=groupread_s
;
898 for(i
=0;i
<groupread_s
;i
++)
899 for(j
=0;j
<out
.channels
;j
++){
900 float dval
=out
.data
[j
][i
];
902 if(dval
>peak
[j
])peak
[j
]=dval
;
906 for(j
=0;j
<out
.channels
;j
++)
909 push_input_feedback(peak
,rms
,cursor
);
914 int tozero
=input_size
-out
.samples
;
916 for(j
=0;j
<out
.channels
;j
++)
917 memset(out
.data
[j
]+out
.samples
,0,sizeof(**out
.data
)*tozero
);
923 void input_reset(void){
924 while(pull_input_feedback(NULL
,NULL
,NULL
));