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.
24 /* This project is a small, tightly tailored application. it is not
25 designed to be nigh-infinitely extensible, nor is it designed to be
26 reusable code. It's monolithic, inflexible, and designed that way
29 /* sound playback code is OSS-specific for now */
33 #include <fenv.h> // Thank you C99!
41 #include "multicompand.h"
42 #include "singlecomp.h"
49 #include "mainpanel.h"
52 sig_atomic_t main_looping
;
53 char *configfile
="postfish-staterc";
56 void clean_exit(int sig
){
60 "\nTrapped signal %d; saving state and exiting!\n"
61 "This signal almost certainly indicates a bug in the Postfish;\n"
62 "If this version of Postfish is newer than a few months old,\n"
63 "please email a detailed report of the crash along with\n"
64 "processor type, OS version, FFTW3 version, and as much\n"
65 "information as possible about what caused the crash. The best\n"
66 "possible report will outline the exact steps needed to\n"
67 "reproduce the error, ensuring that we at Xiph can fix the\n"
68 "bug as quickly as possible.\n\n"
69 "-- monty@xiph.org, Postfish revision %s\n\n",sig
,version
);
70 configfile
="postfish-staterc-crashsave";
82 /* otherwise inform the UI thread that we've requested shutdown */
83 write(eventpipe
[1],"\001",1);
87 const char *optstring
= "-c:gh";
89 struct option options
[] = {
90 {"configuration-file",required_argument
,NULL
,'c'},
91 {"group",no_argument
,NULL
,'g'},
92 {"help",no_argument
,NULL
,'h'},
97 static void usage(FILE *f
){
99 "\nthe Postfish, revision %s\n\n"
102 " postfish [options] infile [infile]+ [-g infile [infile]+]+ > output\n\n"
105 " -c --configuration-file : load state from alternate configuration file\n"
106 " -g --group : place following input files in a new channel\n"
108 " -h --help : print this help\n\n"
111 " Postfish takes WAV/AIFF input either from stdin or from a list of files\n"
112 " specified on the command line. A list of input files is handled as\n"
113 " time-continguous entries, each holding audio data that continues at\n"
114 " the instant the previous file ends. Files may also be arranged into\n"
115 " groups with -g; each group represents additional input channels\n"
116 " parallel to preceeding groups. All input files must be the same\n"
117 " sampling rate. Files in a group must have the same number of\n"
121 " Files a.wav, b.wav, c.wav and d.wav are all four channels and\n"
122 " ten minutes each.\n\n"
124 " postfish a.wav b.wav c.wav d.wav \n"
125 " This command line treats the input as forty minutes of four channel\n"
126 " audio in the order a.wav, b.wav, c.wav, d.wav.\n\n"
128 " postfish a.wav b.wav -g c.wav d.wav \n"
129 " This command line treats the input as twenty minutes of eight channel\n"
130 " audio. Channels 1-4 are taken from files a.wav and b.wav while channels\n"
131 " 5-8 are taken from files c.wav and d.wav.\n\n"
133 " cat a.wav | postfish \n"
134 " This command line sends a.wav to Postfish as a non-seekable stream\n"
135 " of four-channel data. If the WAV (or AIFF) header is complete, Postfish\n"
136 " obeys the length encoded in the header and halts after processing to\n"
137 " that length. If the data length in the header is unset (0 or -1),\n"
138 " Postfish will continue processing data until EOF on stdin.\n\n"
142 " Postfish writes output to stdout.\n\n"
144 " If stdout is piped, the output is nonseekable and Postfish marks the\n"
145 " produced header incomplete (length of -1). Stopping and re-starting\n"
146 " processing writes a fresh stream to stdout.\n\n"
148 " If stdout is redirected to a file, Postfish will write a complete header\n"
149 " upon processing halt or program exit. If processing halts and restarts,\n"
150 " the file is re-written from scratch.\n\n"
152 " If stdout is a pipe or redirected to a file, the user may specify\n"
153 " parallel audio monitor through the audio device using the 'mOn' activator\n"
154 " button in the main panel's 'master' section, or on the output config\n"
155 " panel. The audio device selected for playback is configurable on the\n"
156 " output config panel.\n\n"
158 " If stdout is redirected to an audio device, output is sent to that audio\n"
159 " device exclusively and the 'mOn' activator on the main panel will not\n"
164 " By default, persistent panel state is loaded from the file \n"
165 " 'postfish-staterc' in the current working directory. Postfish rewrites\n"
166 " this file with all current panel state upon exit. -c specifies loading\n"
167 " from and saving to an alternate configuration file name.\n\n",version
);
171 void parse_command_line(int argc
, char **argv
){
172 int c
,long_option_index
;
175 while((c
=getopt_long(argc
,argv
,optstring
,options
,&long_option_index
))!=EOF
){
178 /* file name that belongs to current group */
179 input_parse(optarg
,newgroup
);
183 /* alternate configuration file */
184 configfile
=strdup(optarg
);
187 /* start a new file/channel group */
200 int look_for_wisdom(char *filename
){
202 FILE *f
=fopen(filename
,"r");
204 ret
=fftwf_import_wisdom_from_file(f
);
208 fprintf(stderr
,"Found valid postfish-wisdomrc file at %s\n",filename
);
210 fprintf(stderr
,"WARNING: corrupt, invalid or obsolete postfish-wisdomrc file at %s\n",filename
);
215 void sigill_handler(int sig
){
217 if(sig
==SIGILL
)sigill
=1;
220 int main(int argc
, char **argv
){
223 version
=strstr(VERSION
,"version.h");
225 char *versionend
=strchr(version
,' ');
226 if(versionend
)versionend
=strchr(versionend
+1,' ');
227 if(versionend
)versionend
=strchr(versionend
+1,' ');
228 if(versionend
)versionend
=strchr(versionend
+1,' ');
230 int len
=versionend
-version
-9;
231 version
=strdup(version
+10);
238 /* parse command line and open all the input files */
239 parse_command_line(argc
, argv
);
241 /* We do not care about FPEs; rather, underflow is nominal case, and
242 its better to ignore other traps in production than to crash the
243 app. Please inform the FPU of this. */
246 fedisableexcept(FE_INVALID
);
247 fedisableexcept(FE_INEXACT
);
248 fedisableexcept(FE_UNDERFLOW
);
249 fedisableexcept(FE_OVERFLOW
);
251 feenableexcept(FE_INVALID
);
252 feenableexcept(FE_INEXACT
);
253 feenableexcept(FE_UNDERFLOW
);
254 feenableexcept(FE_OVERFLOW
);
257 /* Linux Altivec support has a very annoying problem; by default,
258 math on denormalized floats will simply crash the program. FFTW3
259 uses Altivec, so boom, but only random booms.
261 By the C99 spec, the above exception configuration is also
262 supposed to handle Altivec config, but doesn't. So we use the
263 below ugliness to both handle altivec and non-alitvec PPC. */
267 signal(SIGILL
,sigill_handler
);
269 #if (defined __GNUC__) && (__GNUC__ == 3) && ! (defined __APPLE_CC__)
270 __vector
unsigned short noTrap
=
271 (__vector
unsigned short){0,0,0,0,0,0,0x1,0};
273 vector
unsigned short noTrap
=
274 (vector
unsigned short)(0,0,0,0,0,0,0x1,0);
280 /* check for fftw wisdom file in order:
282 $(POSTFISHDIR)/postfish-wisdomrc
283 ~/.postfish/postfish-wisdomrc
284 ETCDIR/postfish-wisdomrc
288 wisdom
=look_for_wisdom("./postfish-wisdomrc");
290 char *rcdir
=getenv("POSTFISH_RCDIR");
292 char *rcfile
="/postfish-wisdomrc";
293 char *homerc
=calloc(1,strlen(rcdir
)+strlen(rcfile
)+1);
294 strcat(homerc
,rcdir
);
295 strcat(homerc
,rcfile
);
296 wisdom
=look_for_wisdom(homerc
);
300 char *rcdir
=getenv("HOME");
302 char *rcfile
="/.postfish/postfish-wisdomrc";
303 char *homerc
=calloc(1,strlen(rcdir
)+strlen(rcfile
)+1);
304 strcat(homerc
,rcdir
);
305 strcat(homerc
,rcfile
);
306 wisdom
=look_for_wisdom(homerc
);
309 if(!wisdom
)wisdom
=look_for_wisdom(ETCDIR
"/postfish-wisdomrc");
311 fftwf_import_system_wisdom();
313 fprintf(stderr
,"Postfish could not find the postfish-wisdom configuration file normally built\n"
314 "or installed with Postfish and located in one of the following places:\n"
316 "\t./postfish-wisdomrc\n"
317 "\t$(POSTFISHDIR)/postfish-wisdomrc\n"
318 "\t~/.postfish/postfish-wisdomrc\n\t"
319 ETCDIR
"/postfish-wisdomrc\n"
320 "This configuration file is used to reduce the startup time Postfish uses to \n"
321 "pre-calculate Fourier transform tables for the FFTW3 library. Postfish will start\n"
322 "and operate normally, but it will take additional time before popping the main\n"
323 "window because this information must be regenerated each time Postfish runs.\n");
327 if(setvbuf(stdout
, NULL
, _IONBF
, 0))
328 fprintf(stderr
,"Unable to remove block buffering on stdout; continuing\n");
330 output_probe_stdout(STDOUT_FILENO
);
331 output_probe_monitor();
333 /* open all the input files */
334 if(input_load())exit(1);
336 /* load config file */
337 if(config_load(configfile
))exit(1);
339 /* set up filter chains */
340 if(declip_load())exit(1);
341 if(eq_load(OUTPUT_CHANNELS
))exit(1);
342 if(deverb_load())exit(1);
343 if(multicompand_load(OUTPUT_CHANNELS
))exit(1);
344 if(singlecomp_load(OUTPUT_CHANNELS
))exit(1);
345 if(limit_load(OUTPUT_CHANNELS
))exit(1);
346 if(mute_load())exit(1);
347 if(mix_load(OUTPUT_CHANNELS
))exit(1);
348 if(p_reverb_load())exit(1);
350 /* easiest way to inform gtk of changes and not deal with locking
351 issues around the UI */
353 fprintf(stderr
,"Unable to open event pipe:\n"
354 " %s\n",strerror(errno
));
363 signal(SIGINT
,clean_exit
);
364 signal(SIGSEGV
,clean_exit
);
366 mainpanel_go(argc
,argv
,input_ch
);