Add Russian translation provided by Валерий Крувялис <valkru@mail.ru>
[xiph-mirror.git] / spectrum / spectrum.c
blob34597b4d4a0b765e0baf000ec676f23fc4d67299
1 /*
3 * gtk2 spectrum analyzer
5 * Copyright (C) 2004-2012 Monty
7 * This analyzer 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)
10 * any later version.
12 * The analyzer 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 #include "analyzer.h"
25 #include "io.h"
26 #include <signal.h>
27 #include <getopt.h>
28 #include <fenv.h> // Thank you C99!
29 #include <fftw3.h>
30 #include <gtk/gtk.h>
31 #include "version.h"
33 int eventpipe[2];
34 char *version;
35 char *inputname[MAX_FILES];
36 int inputs=0;
37 int blocksize = 32768;
38 extern int plot_bold;
40 void handler(int sig){
41 signal(sig,SIG_IGN);
42 if(sig!=SIGINT){
43 fprintf(stderr,
44 "\nTrapped signal %d; exiting!\n"
45 "This signal almost certainly indicates a bug in the analyzer;\n"
46 "If this version of the analyzer is newer than a few months old,\n"
47 "please email a detailed report of the crash along with\n"
48 "processor type, OS version, FFTW3 version, and as much\n"
49 "information as possible about what caused the crash. The best\n"
50 "possible report will outline the exact steps needed to\n"
51 "reproduce the error, ensuring that I can fix the bug as\n"
52 "quickly as possible.\n\n"
53 "-- monty@xiph.org, spectrum revision %s\n\n",sig,version);
56 gtk_main_quit();
59 const char *optstring = "-r:c:EeBlb:suhF:T";
61 struct option options [] = {
62 {"bold",no_argument,NULL,'T'},
63 {"rate",required_argument,NULL,'r'},
64 {"channels",required_argument,NULL,'c'},
65 {"big-endian",no_argument,NULL,'E'},
66 {"little-endian",no_argument,NULL,'e'},
67 {"bits",required_argument,NULL,'b'},
68 {"signed",no_argument,NULL,'s'},
69 {"unsigned",no_argument,NULL,'u'},
70 {"help",no_argument,NULL,'h'},
71 {"fft-size",required_argument,NULL,'F'},
73 {NULL,0,NULL,0}
76 static void usage(FILE *f){
77 fprintf( f,
78 "\ngtk2 spectrum analyzer, revision %s\n\n"
80 "USAGE:\n\n"
81 " spectrum [options] [file]\n\n"
83 "OPTIONS:\n\n"
84 " -b --bits <bits> : Force input to be read as 8, 16, 24 or 32 bit\n"
85 " PCM. Default bit depth is normally read from\n"
86 " the file/stream header or set to 16 bits\n"
87 " for raw input.\n"
88 " -B -E --big-endian : Force input to be read as big endian.\n"
89 " Default endianness is normally read from the\n"
90 " file/stream header or set to host"
91 " endianness for raw input.\n"
92 " -c --channels <channels> : Input channel number override; use to\n"
93 " specify the number of channels in a raw\n"
94 " input. default: 1\n"
95 " -e -l --little-endian : Force input to be read as little endian.\n"
96 " Default endianness is normally read from the\n"
97 " file/stream header or set to host"
98 " endianness for raw input.\n"
99 " -F --fft-size : Set the size of the fft transform used. Valid\n"
100 " range 8192 to 262144, 131072 default.\n"
101 " -h --help : print this help\n"
102 " -r --rate <Hz> : Input sample rate override in Hz; use to\n"
103 " specify the rate of a raw input.\n"
104 " default: 44100\n"
105 " -s --signed : Force input to be read as signed PCM.\n"
106 " Signedness is normally read from the \n"
107 " file/stream header or set to signed for raw\n"
108 " input.\n"
109 " -T --bold : plot spectrum with thicker/bolder lines.\n"
110 " -u --unsigned : Force input to be read as unsigned PCM.\n"
111 " Signedness is normally read from the \n"
112 " file/stream header or set to signed for raw\n"
113 " input.\n\n"
115 "INPUT:\n\n"
117 " Spectrum takes raw, WAV or AIFF input either from stdin or from \n"
118 " file[s]/stream[s] specified on the command line.\n\n",version);
122 void parse_command_line(int argc, char **argv){
123 int c,long_option_index;
125 while((c=getopt_long(argc,argv,optstring,options,&long_option_index))!=EOF){
126 switch(c){
127 case 1:
128 /* file name that belongs to current group */
129 if(inputs>=MAX_FILES){
130 fprintf(stderr,"Maximum of MAX_FILES input files exceeded. Oops. Programmer was lazy.\n\n");
131 exit(1);
133 inputname[inputs++]=strdup(optarg);
134 break;
135 case 'T':
136 plot_bold = 1;
137 break;
138 case 'b':
139 /* force bit width */
141 int a=atoi(optarg);
142 bits[inputs]=a;
143 bits_force[inputs]=1;
144 if(a!=8 && a!=16 && a!=24 && a!=32){
145 usage(stderr);
146 exit(1);
149 break;
150 case 'F':
151 blocksize = atoi(optarg);
152 if(blocksize<8192 || blocksize>262144){
153 usage(stderr);
154 exit(1);
156 break;
157 case 'B':case 'E':
158 /* force big endian */
159 bigendian[inputs]=1;
160 bigendian_force[inputs]=1;
161 break;
162 case 'c':
163 /* force channels */
165 int a=atoi(optarg);
166 channels[inputs]=a;
167 channels_force[inputs]=1;
168 if(a<1 || a>32){
169 usage(stderr);
170 exit(1);
173 break;
174 case 'l':case 'e':
175 /* force little endian */
176 bigendian[inputs]=0;
177 bigendian_force[inputs]=1;
178 break;
179 case 'h':
180 usage(stdout);
181 exit(0);
182 case 'r':
183 /* force rate */
185 int a=atoi(optarg);
186 rate[inputs]=a;
187 rate_force[inputs]=1;
188 if(a<4000 || a>200000){
189 usage(stderr);
190 exit(1);
193 break;
194 case 's':
195 /* force signed */
196 signedp[inputs]=1;
197 signed_force[inputs]=1;
198 break;
199 case 'u':
200 /* force unsigned */
201 signedp[inputs]=0;
202 signed_force[inputs]=1;
203 break;
204 default:
205 usage(stderr);
206 exit(0);
211 static int sigill=0;
212 void sigill_handler(int sig){
213 /* make sure */
214 if(sig==SIGILL)sigill=1;
217 int main(int argc, char **argv){
219 version=strstr(VERSION,"version.h");
220 if(version){
221 char *versionend=strchr(version,' ');
222 if(versionend)versionend=strchr(versionend+1,' ');
223 if(versionend)versionend=strchr(versionend+1,' ');
224 if(versionend)versionend=strchr(versionend+1,' ');
225 if(versionend){
226 int len=versionend-version-9;
227 version=strdup(version+10);
228 version[len-1]=0;
230 }else{
231 version="";
234 /* parse command line and open all the input files */
235 parse_command_line(argc, argv);
237 /* We do not care about FPEs; rather, underflow is nominal case, and
238 its better to ignore other traps in production than to crash the
239 app. Please inform the FPU of this. */
241 #ifndef DEBUG
242 fedisableexcept(FE_INVALID);
243 fedisableexcept(FE_INEXACT);
244 fedisableexcept(FE_UNDERFLOW);
245 fedisableexcept(FE_OVERFLOW);
246 #else
247 feenableexcept(FE_INVALID);
248 feenableexcept(FE_INEXACT);
249 feenableexcept(FE_UNDERFLOW);
250 feenableexcept(FE_OVERFLOW);
251 #endif
253 /* Linux Altivec support has a very annoying problem; by default,
254 math on denormalized floats will simply crash the program. FFTW3
255 uses Altivec, so boom, but only random booms.
257 By the C99 spec, the above exception configuration is also
258 supposed to handle Altivec config, but doesn't. So we use the
259 below ugliness to both handle altivec and non-alitvec PPC. */
261 #ifdef __PPC
262 #include <altivec.h>
263 signal(SIGILL,sigill_handler);
265 #if (defined __GNUC__) && (__GNUC__ == 3) && ! (defined __APPLE_CC__)
266 __vector unsigned short noTrap =
267 (__vector unsigned short){0,0,0,0,0,0,0x1,0};
268 #else
269 vector unsigned short noTrap =
270 (vector unsigned short)(0,0,0,0,0,0,0x1,0);
271 #endif
273 vec_mtvscr(noTrap);
274 #endif
276 /* easiest way to inform gtk of changes and not deal with locking
277 issues around the UI */
278 if(pipe(eventpipe)){
279 fprintf(stderr,"Unable to open event pipe:\n"
280 " %s\n",strerror(errno));
282 exit(1);
285 /* Allows event compression on the read side */
286 if(fcntl(eventpipe[0], F_SETFL, O_NONBLOCK)){
287 fprintf(stderr,"Unable to set O_NONBLOCK on event pipe:\n"
288 " %s\n",strerror(errno));
290 exit(1);
293 //signal(SIGINT,handler);
294 signal(SIGSEGV,handler);
296 blockslice_frac=10;
297 if(input_load())exit(1);
299 /* go */
300 panel_go(argc,argv);
302 return(0);