1 /*
2 channel for Bt848 frame grabber driver
3
4 Copyright (C) 1996,97 Marcus Metzler (mocm@thp.uni-koeln.de)
5 (c) 1998-2003 Gerd Knorr <kraxel@bytesex.org>
6
7 This program 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 of the License, or
10 (at your option) any later version.
11
12 This program 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.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "config.h"
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <unistd.h>
27 #include <string.h>
28 #include <ctype.h>
29 #include <math.h>
30 #include <pthread.h>
31
32 #ifndef NO_X11
33 # include <X11/Xlib.h>
34 # include <X11/Intrinsic.h>
35 # include <X11/StringDefs.h>
36 # include <X11/Xaw/XawInit.h>
37 # include <X11/Xaw/Command.h>
38 # include <X11/Xaw/Paned.h>
39 #endif
40
41 #include "grab-ng.h"
42 #include "channel.h"
43 #include "commands.h"
44 #include "frequencies.h"
45 #include "sound.h"
46 #include "parseconfig.h"
47 #include "event.h"
48
49 /* ----------------------------------------------------------------------- */
50 /* misc common stuff, not only channel related */
51
52 struct CHANNEL defaults = {
53 .name = "defaults",
54 .group = "main",
55 .capture = CAPTURE_ON,
56 .channel = -1,
57 .audio = -1,
58 .color = -1,
59 .bright = -1,
60 .hue = -1,
61 .contrast = -1,
62 };
63
64 struct CHANNEL **channels = NULL;
65 int count = 0;
66 int alloc_count = 0;
67
68 int last_sender = -1, cur_sender = -1, cur_channel = -1, cur_fine = 0;
69 int cur_freq;
70 struct ng_filter *cur_filter;
71
72 int cur_capture = CAPTURE_OFF;
73 int have_config;
74 int keypad_ntsc = 0;
75 int keypad_partial = 1;
76 int use_wm_fullscreen = 1;
77 int use_osd = 1;
78 int osd_x = 30;
79 int osd_y = 20;
80 int fs_width,fs_height,fs_xoff,fs_yoff;
81 int pix_width=128, pix_height=96, pix_cols=1;
82
83 char *mov_driver = NULL;
84 char *mov_video = NULL;
85 char *mov_fps = NULL;
86 char *mov_audio = NULL;
87 char *mov_rate = NULL;
88
89 #ifndef NO_X11
90 extern Widget chan_box, chan_viewport, tv, opt_paned, launch_paned;
91 #endif
92
93 static char *mixer = NULL;
94 char mixerdev[32],mixerctl[16];
95 char *midi = NULL;
96
97 struct LAUNCH *launch = NULL;
98 int nlaunch = 0;
99
100 /* ----------------------------------------------------------------------- */
101
lookup_channel(char * channel)102 int lookup_channel(char *channel)
103 {
104 #if 0
105 /* Hmm, why the heck that used to be that complex?
106 * Any good reason I forgot ? */
107 int i,nr1,nr2;
108 char tag1[5],tag2[5];
109
110 if (NULL == channel)
111 return -1;
112
113 if (isdigit(channel[0])) {
114 tag1[0] = 0;
115 nr1 = atoi(channel);
116 } else {
117 sscanf(channel,"%4[A-Za-z]%d",tag1,&nr1);
118 }
119
120 for (i = 0; i < chancount; i++) {
121 if (isdigit(chanlist[i].name[0])) {
122 tag2[0] = 0;
123 nr2 = atoi(chanlist[i].name);
124 } else {
125 sscanf(chanlist[i].name,"%4[A-Za-z]%d",tag2,&nr2);
126 }
127 if (tag1[0] && tag2[0])
128 if (nr1 == nr2 && 0 == strcmp(tag1,tag2))
129 break;
130 if (!tag1[0] && !tag2[0])
131 if (nr1 == nr2)
132 break;
133 }
134 if (i == chancount)
135 return -1;
136
137 return i;
138 #else
139 int i;
140
141 if (NULL == channel)
142 return -1;
143 for (i = 0; i < chancount; i++)
144 if (0 == strcasecmp(chanlist[i].name,channel))
145 break;
146 if (i == chancount)
147 return -1;
148 return i;
149 #endif
150 }
151
get_freq(int i)152 int get_freq(int i)
153 {
154 if (i < 0 || i >= chancount)
155 return -1;
156 return chanlist[i].freq*16/1000;
157 }
158
cf2freq(char * name,int fine)159 int cf2freq(char *name, int fine)
160 {
161 int i;
162
163 if (-1 == (i = lookup_channel(name)))
164 return -1;
165 return get_freq(i)+fine;
166 }
167
168 /* ----------------------------------------------------------------------- */
169
170 struct STRTAB captab[] = {
171 { CAPTURE_ON, "on" },
172 { CAPTURE_ON, "yes" },
173 { CAPTURE_ON, "true" },
174 { CAPTURE_OFF, "off" },
175 { CAPTURE_OFF, "no" },
176 { CAPTURE_OFF, "false" },
177 { CAPTURE_OVERLAY, "over" },
178 { CAPTURE_OVERLAY, "overlay" },
179 { CAPTURE_GRABDISPLAY, "grab" },
180 { CAPTURE_GRABDISPLAY, "grabdisplay" },
181 { -1, NULL, },
182 };
183
184 /* just malloc memory for a new channel ... */
185 struct CHANNEL*
add_channel(char * name)186 add_channel(char *name)
187 {
188 struct CHANNEL *channel;
189
190 if (alloc_count == count) {
191 alloc_count += 16;
192 if (alloc_count == 16)
193 channels = malloc(sizeof(struct CHANNEL*)*alloc_count);
194 else
195 channels = realloc(channels,sizeof(struct CHANNEL*)*alloc_count);
196 }
197 channel = channels[count++] = malloc(sizeof(struct CHANNEL));
198 memcpy(channel,&defaults,sizeof(struct CHANNEL));
199 channel->name = strdup(name);
200 return channel;
201 }
202
203 #ifndef NO_X11
204
205 #define PANED_FIX \
206 XtNallowResize, False, \
207 XtNshowGrip, False, \
208 XtNskipAdjust, True
209
hotkey_channel(struct CHANNEL * channel)210 void hotkey_channel(struct CHANNEL *channel)
211 {
212 char str[100],key[32],ctrl[16];
213
214 if (NULL == channel->key)
215 return;
216 if (2 == sscanf(channel->key,"%15[A-Za-z0-9_]+%31[A-Za-z0-9_]",
217 ctrl,key))
218 sprintf(str,"%s<Key>%s: Command(setstation,\"%s\")",
219 ctrl,key,channel->name);
220 else
221 sprintf(str,"<Key>%s: Command(setstation,\"%s\")",
222 channel->key,channel->name);
223 XtOverrideTranslations(tv,XtParseTranslationTable(str));
224 XtOverrideTranslations(opt_paned,XtParseTranslationTable(str));
225 XtOverrideTranslations(chan_viewport,XtParseTranslationTable(str));
226 }
227
228 static void
launch_cb(Widget widget,XtPointer clientdata,XtPointer call_data)229 launch_cb(Widget widget, XtPointer clientdata, XtPointer call_data)
230 {
231 char *argv[2];
232
233 argv[0] = (char*)clientdata;
234 argv[1] = NULL;
235 XtCallActionProc(widget,"Launch",NULL,argv,1);
236 }
237
238 static void
hotkey_launch(struct LAUNCH * launch)239 hotkey_launch(struct LAUNCH *launch)
240 {
241 Widget c;
242 char str[100],key[32],ctrl[16],label[64];
243
244 if (NULL == launch->key)
245 return;
246 if (2 == sscanf(launch->key,"%15[A-Za-z0-9_]+%31[A-Za-z0-9_]",
247 ctrl,key))
248 sprintf(str,"%s<Key>%s: Launch(\"%s\")",ctrl,key,launch->name);
249 else
250 sprintf(str,"<Key>%s: Launch(\"%s\")",launch->key,launch->name);
251 XtOverrideTranslations(tv,XtParseTranslationTable(str));
252 XtOverrideTranslations(opt_paned,XtParseTranslationTable(str));
253 XtOverrideTranslations(chan_viewport,XtParseTranslationTable(str));
254
255 sprintf(label,"%-20s %s",launch->name,launch->key);
256 c = XtVaCreateManagedWidget(launch->name, commandWidgetClass,
257 launch_paned,
258 PANED_FIX,
259 XtNlabel,label,
260 NULL);
261 XtAddCallback(c,XtNcallback,launch_cb,(XtPointer)(launch->name));
262 }
263
264 static void
button_cb(Widget widget,XtPointer clientdata,XtPointer call_data)265 button_cb(Widget widget, XtPointer clientdata, XtPointer call_data)
266 {
267 struct CHANNEL *channel = clientdata;
268 do_va_cmd(2,"setstation",channel->name);
269 }
270
271 /* ... and initalize later */
configure_channel(struct CHANNEL * channel)272 void configure_channel(struct CHANNEL *channel)
273 {
274 channel->button =
275 XtVaCreateManagedWidget(channel->name,
276 commandWidgetClass, chan_box,
277 XtNwidth,pix_width,
278 XtNheight,pix_height,
279 NULL);
280 XtAddCallback(channel->button,XtNcallback,button_cb,(XtPointer*)channel);
281 hotkey_channel(channel);
282 }
283 #endif
284
285 /* delete channel */
286 void
del_channel(int i)287 del_channel(int i)
288 {
289 free(channels[i]->name);
290 if (channels[i]->key)
291 free(channels[i]->key);
292 free(channels[i]);
293 count--;
294 if (i < count)
295 memmove(channels+i,channels+i+1,(count-i)*sizeof(struct CHANNEL*));
296 }
297
298 void
calc_frequencies()299 calc_frequencies()
300 {
301 int i;
302
303 for (i = 0; i < count; i++) {
304 if (NULL == channels[i]->cname)
305 continue;
306 channels[i]->channel = lookup_channel(channels[i]->cname);
307 if (-1 == channels[i]->channel)
308 channels[i]->freq = -1;
309 else
310 channels[i]->freq = get_freq(channels[i]->channel)
311 + channels[i]->fine;
312 }
313 }
314
315 /* ----------------------------------------------------------------------- */
316
317 static void
init_channel(char * name,struct CHANNEL * c)318 init_channel(char *name, struct CHANNEL *c)
319 {
320 struct ng_attribute *attr;
321 char *val; int n,i;
322
323 if (NULL != (val = cfg_get_str(name,"capture"))) {
324 if (-1 != (i = str_to_int(val,captab)))
325 c->capture = i;
326 else
327 fprintf(stderr,"config: invalid value for capture: %s\n",val);
328 }
329 if (NULL != (attr = ng_attr_byid(attrs,ATTR_ID_INPUT)) &&
330 (NULL != (val = cfg_get_str(name,"input")) ||
331 NULL != (val = cfg_get_str(name,"source")))) { /* obsolete */
332 if (-1 != (i = ng_attr_getint(attr,val)))
333 c->input = i;
334 else {
335 fprintf(stderr,"config: invalid value for input: %s\n",val);
336 ng_attr_listchoices(attr);
337 }
338 }
339 if (NULL != (attr = ng_attr_byid(attrs,ATTR_ID_NORM)) &&
340 NULL != (val = cfg_get_str(name,"norm"))) {
341 if (-1 != (i = ng_attr_getint(attr,val)))
342 c->norm = i;
343 else {
344 fprintf(stderr,"config: invalid value for norm: %s\n",val);
345 ng_attr_listchoices(attr);
346 }
347 }
348 if (NULL != (attr = ng_attr_byid(attrs,ATTR_ID_AUDIO_MODE)) &&
349 NULL != (val = cfg_get_str(name,"audio"))) {
350 if (-1 != (i = ng_attr_getint(attr,val)))
351 c->audio = i;
352 else {
353 fprintf(stderr,"config: invalid value for audio: %s\n",val);
354 ng_attr_listchoices(attr);
355 }
356 }
357
358 if (NULL != (val = cfg_get_str(name,"channel")))
359 c->cname = strdup(val);
360 if (NULL != (val = cfg_get_str(name,"freq")))
361 c->freq = (int)(atof(val)*16);
362 if (0 != (n = cfg_get_signed_int(name,"fine")))
363 c->fine = n;
364
365 if (NULL != (val = cfg_get_str(name,"key")))
366 c->key = strdup(val);
367 if (NULL != (val = cfg_get_str(name,"group")))
368 c->group = strdup(val);
369 if (NULL != (val = cfg_get_str(name,"midi")))
370 c->midi = atoi(val);
371
372 attr = ng_attr_byid(attrs,ATTR_ID_COLOR);
373 if (attr && NULL != (val = cfg_get_str(name,"color")))
374 c->color = ng_attr_parse_int(attr,val);
375 attr = ng_attr_byid(attrs,ATTR_ID_BRIGHT);
376 if (attr && NULL != (val = cfg_get_str(name,"bright")))
377 c->bright = ng_attr_parse_int(attr,val);
378 attr = ng_attr_byid(attrs,ATTR_ID_HUE);
379 if (attr && NULL != (val = cfg_get_str(name,"hue")))
380 c->hue = ng_attr_parse_int(attr,val);
381 attr = ng_attr_byid(attrs,ATTR_ID_CONTRAST);
382 if (attr && NULL != (val = cfg_get_str(name,"contrast")))
383 c->contrast = ng_attr_parse_int(attr,val);
384 }
385
386 void
read_config(char * conffile,int * argc,char ** argv)387 read_config(char *conffile, int *argc, char **argv)
388 {
389 struct list_head *item;
390 char filename[100];
391 char *val;
392 int i;
393
394 if (conffile) {
395 if (0 == cfg_parse_file(conffile))
396 have_config = 1;
397 } else {
398 sprintf(filename,"%.*s/%s",(int)sizeof(filename)-8,
399 getenv("HOME"),".xawtv");
400 if (0 == cfg_parse_file(CONFIGFILE))
401 have_config = 1;
402 if (0 == cfg_parse_file(filename))
403 have_config = 1;
404 }
405 if (argc)
406 cfg_parse_options(argc,argv);
407
408 /* misc global settings */
409 if (NULL != (val = cfg_get_str("global","mixer"))) {
410 mixer = strdup(val);
411 if (2 != sscanf(mixer,"%31[^:]:%15s",mixerdev,mixerctl)) {
412 strcpy(mixerdev,ng_dev.mixer);
413 strncpy(mixerctl,val,15);
414 mixerctl[15] = 0;
415 }
416 }
417
418 if (NULL != (val = cfg_get_str("global","midi")))
419 midi = strdup(val);
420
421 if (NULL != (val = cfg_get_str("global","freqtab"))) {
422 for (i = 0; chanlists[i].name != NULL; i++)
423 if (0 == strcasecmp(val,chanlists[i].name))
424 break;
425 if (chanlists[i].name != NULL) {
426 freq_newtab(i);
427 } else
428 fprintf(stderr,"invalid value for freqtab: %s\n",val);
429 }
430
431 if (NULL != (val = cfg_get_str("global","fullscreen"))) {
432 if (2 != sscanf(val,"%d x %d",&fs_width,&fs_height)) {
433 fprintf(stderr,"invalid value for fullscreen: %s\n",val);
434 fs_width = fs_height = 0;
435 }
436 }
437
438 if (NULL != (val = cfg_get_str("global","pixsize"))) {
439 if (2 != sscanf(val,"%d x %d",&pix_width,&pix_height)) {
440 fprintf(stderr,"invalid value for pixsize: %s\n",val);
441 pix_width = 128;
442 pix_height = 96;
443 }
444 }
445 if (-1 != (i = cfg_get_int("global","pixcols")))
446 pix_cols = i;
447
448 if (NULL != (val = cfg_get_str("global","wm-off-by"))) {
449 if (2 != sscanf(val,"%d %d",&fs_xoff,&fs_yoff)) {
450 fprintf(stderr,"invalid value for wm-off-by: %s\n",val);
451 fs_xoff = fs_yoff = 0;
452 }
453 }
454 if (NULL != (val = cfg_get_str("global","ratio"))) {
455 if (2 != sscanf(val,"%d:%d",&ng_ratio_x,&ng_ratio_y)) {
456 fprintf(stderr,"invalid value for ratio: %s\n",val);
457 ng_ratio_x = ng_ratio_y = 0;
458 }
459 }
460
461 if (-1 != (i = cfg_get_int("global","jpeg-quality")))
462 ng_jpeg_quality = i;
463
464 if (NULL != (val = cfg_get_str("global","keypad-ntsc")))
465 if (-1 != (i = str_to_int(val,booltab)))
466 keypad_ntsc = i;
467 if (NULL != (val = cfg_get_str("global","keypad-partial")))
468 if (-1 != (i = str_to_int(val,booltab)))
469 keypad_partial = i;
470 if (NULL != (val = cfg_get_str("global","osd")))
471 if (-1 != (i = str_to_int(val,booltab)))
472 use_osd = i;
473 if (NULL != (val = cfg_get_str("global","osd-position")))
474 if (2 != sscanf(val,"%d , %d",&osd_x,&osd_y))
475 fprintf(stderr,"invalid values for osd-position: %s\n",val);
476 if (NULL != (val = cfg_get_str("global","use-wm-fullscreen")))
477 if (-1 != (i = str_to_int(val,booltab)))
478 use_wm_fullscreen = i;
479
480 if (NULL != (val = cfg_get_str("global","mov-driver")))
481 mov_driver = val;
482 if (NULL != (val = cfg_get_str("global","mov-video")))
483 mov_video = val;
484 if (NULL != (val = cfg_get_str("global","mov-fps")))
485 mov_fps = val;
486 if (NULL != (val = cfg_get_str("global","mov-audio")))
487 mov_audio = val;
488 if (NULL != (val = cfg_get_str("global","mov-rate")))
489 mov_rate = val;
490
491 if (NULL != (val = cfg_get_str("global","filter"))) {
492 list_for_each(item,&ng_filters) {
493 struct ng_filter *f = list_entry(item, struct ng_filter, list);
494 if (0 == strcasecmp(f->name, val))
495 cur_filter = f;
496 }
497 }
498 }
499
500 void
parse_config(int parse_channels)501 parse_config(int parse_channels)
502 {
503 char key[16], cmdline[128];
504 char **list,*val;
505 #ifndef NO_X11
506 int i;
507 #endif
508
509 /* launch */
510 list = cfg_list_entries("launch");
511 if (NULL != list) {
512 for (; *list != NULL; list++) {
513 if (NULL != (val = cfg_get_str("launch",*list)) &&
514 2 == sscanf(val,"%15[^,], %127[^\n]",
515 key,cmdline)) {
516 launch = realloc(launch,sizeof(struct LAUNCH)*(nlaunch+1));
517 launch[nlaunch].name = strdup(*list);
518 launch[nlaunch].key = strdup(key);
519 launch[nlaunch].cmdline = strdup(cmdline);
520 #ifndef NO_X11
521 hotkey_launch(launch+nlaunch);
522 #endif
523 nlaunch++;
524 } else {
525 fprintf(stderr,"invalid value in section [launch]: %s\n",val);
526 }
527 }
528 }
529
530 /* events */
531 event_readconfig();
532
533 if (!parse_channels)
534 return;
535
536 /* channels */
537 init_channel("defaults",&defaults);
538 for (list = cfg_list_sections(); *list != NULL; list++) {
539 if (0 == strcmp(*list,"defaults")) continue;
540 if (0 == strcmp(*list,"global")) continue;
541 if (0 == strcmp(*list,"launch")) continue;
542 if (0 == strcmp(*list,"eventmap")) continue;
543 init_channel(*list,add_channel(*list));
544 }
545
546 /* calculate channel frequencies */
547 defaults.channel = lookup_channel(defaults.cname);
548 defaults.freq = get_freq(defaults.channel) + defaults.fine;
549 calc_frequencies();
550 #ifndef NO_X11
551 for (i = 0; i < count; i++)
552 configure_channel(channels[i]);
553 #endif
554 }
555
556 /* ----------------------------------------------------------------------- */
557
558 void
save_config()559 save_config()
560 {
561 struct ng_attribute *attr;
562 char filename1[100], filename2[100];
563 FILE *fp;
564 int i;
565
566 sprintf(filename1,"%s/%s",getenv("HOME"),".xawtv");
567 sprintf(filename2,"%s/%s",getenv("HOME"),".xawtv~");
568
569 /* delete old backup */
570 unlink(filename2);
571
572 /* current becomes backup */
573 if (0 == link(filename1,filename2))
574 unlink(filename1);
575
576 /* write new one... */
577 fp = fopen(filename1,"w");
578 if (NULL == fp) {
579 fprintf(stderr,"can't open config file %s\n",filename1);
580 return;
581 }
582
583 fprintf(fp,"[global]\n");
584 if (fs_width && fs_height)
585 fprintf(fp,"fullscreen = %d x %d\n",fs_width,fs_height);
586 if (fs_xoff || fs_yoff)
587 fprintf(fp,"wm-off-by = %+d%+d\n",fs_xoff,fs_yoff);
588 if (ng_ratio_x || ng_ratio_y)
589 fprintf(fp,"ratio = %d:%d\n",ng_ratio_x,ng_ratio_y);
590 fprintf(fp,"freqtab = %s\n",chanlists[chantab].name);
591 fprintf(fp,"pixsize = %d x %d\n",pix_width,pix_height);
592 fprintf(fp,"pixcols = %d\n",pix_cols);
593 fprintf(fp,"jpeg-quality = %d\n",ng_jpeg_quality);
594 fprintf(fp,"keypad-ntsc = %s\n",int_to_str(keypad_ntsc,booltab));
595 fprintf(fp,"keypad-partial = %s\n",int_to_str(keypad_partial,booltab));
596 fprintf(fp,"osd = %s\n",int_to_str(use_osd,booltab));
597 fprintf(fp,"osd-position = %d , %d\n",osd_x,osd_y);
598 fprintf(fp,"use-wm-fullscreen = %s\n",
599 int_to_str(use_wm_fullscreen,booltab));
600 if (mixer)
601 fprintf(fp,"mixer = %s\n",mixer);
602 if (midi)
603 fprintf(fp,"midi = %s\n",midi);
604
605 if (mov_driver)
606 fprintf(fp,"mov-driver = %s\n",mov_driver);
607 if (mov_video)
608 fprintf(fp,"mov-video = %s\n",mov_video);
609 if (mov_fps)
610 fprintf(fp,"mov-fps = %s\n",mov_fps);
611 if (mov_audio)
612 fprintf(fp,"mov-audio = %s\n",mov_audio);
613 if (mov_rate)
614 fprintf(fp,"mov-rate = %s\n",mov_rate);
615
616 fprintf(fp,"\n");
617
618 if (nlaunch > 0) {
619 fprintf(fp,"[launch]\n");
620 for (i = 0; i < nlaunch; i++) {
621 fprintf(fp,"%s = %s, %s\n",
622 launch[i].name,launch[i].key,launch[i].cmdline);
623 }
624 fprintf(fp,"\n");
625 }
626
627 /* events */
628 event_writeconfig(fp);
629
630 /* write help */
631 fprintf(fp,"# [Station name]\n");
632 fprintf(fp,"# capture = overlay | grabdisplay | on | off\n");
633 fprintf(fp,"# input = Television | Composite1 | S-Video | ...\n");
634 fprintf(fp,"# norm = PAL | NTSC | SECAM | ... \n");
635 fprintf(fp,"# channel = #\n");
636 fprintf(fp,"# fine = # (-128..+127)\n");
637 fprintf(fp,"# key = keysym | modifier+keysym\n");
638 fprintf(fp,"# color = #\n");
639 fprintf(fp,"# bright = #\n");
640 fprintf(fp,"# hue = #\n");
641 fprintf(fp,"# contrast = #\n");
642 fprintf(fp,"\n");
643
644 /* write defaults */
645 fprintf(fp,"[defaults]\n");
646 fprintf(fp,"group = %s\n",defaults.group);
647
648 fprintf(fp,"norm = %s\n",
649 ng_attr_getstr(ng_attr_byid(attrs,ATTR_ID_NORM),
650 cur_attrs[ATTR_ID_NORM]));
651 fprintf(fp,"input = %s\n",
652 ng_attr_getstr(ng_attr_byid(attrs,ATTR_ID_INPUT),
653 cur_attrs[ATTR_ID_INPUT]));
654 fprintf(fp,"capture = %s\n",int_to_str(cur_capture,captab));
655
656 attr = ng_attr_byid(attrs,ATTR_ID_COLOR);
657 if (attr && attr->defval != cur_attrs[ATTR_ID_COLOR])
658 fprintf(fp,"color = %d%%\n",
659 ng_attr_int2percent(attr,cur_attrs[ATTR_ID_COLOR]));
660 attr = ng_attr_byid(attrs,ATTR_ID_BRIGHT);
661 if (attr && attr->defval != cur_attrs[ATTR_ID_BRIGHT])
662 fprintf(fp,"bright = %d%%\n",
663 ng_attr_int2percent(attr,cur_attrs[ATTR_ID_BRIGHT]));
664 attr = ng_attr_byid(attrs,ATTR_ID_HUE);
665 if (attr && attr->defval != cur_attrs[ATTR_ID_HUE])
666 fprintf(fp,"hue = %d%%\n",
667 ng_attr_int2percent(attr,cur_attrs[ATTR_ID_HUE]));
668 attr = ng_attr_byid(attrs,ATTR_ID_CONTRAST);
669 if (attr && attr->defval != cur_attrs[ATTR_ID_CONTRAST])
670 fprintf(fp,"contrast = %d%%\n",
671 ng_attr_int2percent(attr,cur_attrs[ATTR_ID_CONTRAST]));
672 fprintf(fp,"\n");
673
674 /* write channels */
675 for (i = 0; i < count; i++) {
676 fprintf(fp,"[%s]\n",channels[i]->name);
677 if (NULL != channels[i]->cname) {
678 fprintf(fp,"channel = %s\n",chanlist[channels[i]->channel].name);
679 if (0 != channels[i]->fine)
680 fprintf(fp,"fine = %+d\n", channels[i]->fine);
681 } else {
682 fprintf(fp,"freq = %.2f\n",(float)(channels[i]->freq)/16);
683 }
684
685 if ( channels[i]->norm != cur_attrs[ATTR_ID_NORM])
686 fprintf(fp,"norm = %s\n",
687 ng_attr_getstr(ng_attr_byid(attrs,ATTR_ID_NORM),
688 channels[i]->norm));
689 if (channels[i]->input != cur_attrs[ATTR_ID_INPUT])
690 fprintf(fp,"input = %s\n",
691 ng_attr_getstr(ng_attr_byid(attrs,ATTR_ID_INPUT),
692 channels[i]->input));
693
694 if (channels[i]->key != NULL)
695 fprintf(fp,"key = %s\n",channels[i]->key);
696 if (0 != strcmp(channels[i]->group,defaults.group))
697 fprintf(fp,"group = %s\n",channels[i]->group);
698 if (channels[i]->midi != 0)
699 fprintf(fp,"midi = %d\n",channels[i]->midi);
700 if (channels[i]->capture != cur_capture)
701 fprintf(fp,"capture = %s\n",
702 int_to_str(channels[i]->capture,captab));
703
704 attr = ng_attr_byid(attrs,ATTR_ID_COLOR);
705 if (attr && cur_attrs[ATTR_ID_COLOR] != channels[i]->color)
706 fprintf(fp,"color = %d%%\n",
707 ng_attr_int2percent(attr,channels[i]->color));
708 attr = ng_attr_byid(attrs,ATTR_ID_BRIGHT);
709 if (attr && cur_attrs[ATTR_ID_BRIGHT] != channels[i]->bright)
710 fprintf(fp,"bright = %d%%\n",
711 ng_attr_int2percent(attr,channels[i]->bright));
712 attr = ng_attr_byid(attrs,ATTR_ID_HUE);
713 if (attr && cur_attrs[ATTR_ID_HUE] != channels[i]->hue)
714 fprintf(fp,"hue = %d%%\n",
715 ng_attr_int2percent(attr,channels[i]->hue));
716 attr = ng_attr_byid(attrs,ATTR_ID_CONTRAST);
717 if (attr && cur_attrs[ATTR_ID_CONTRAST] != channels[i]->contrast)
718 fprintf(fp,"contrast = %d%%\n",
719 ng_attr_int2percent(attr,channels[i]->contrast));
720
721 fprintf(fp,"\n");
722 }
723 fclose(fp);
724 }
725
726 /* ----------------------------------------------------------------------- */
727
728 struct STRTAB booltab[] = {
729 { 0, "no" },
730 { 0, "false" },
731 { 0, "off" },
732 { 1, "yes" },
733 { 1, "true" },
734 { 1, "on" },
735 { -1, NULL }
736 };
737
738 int
str_to_int(char * str,struct STRTAB * tab)739 str_to_int(char *str, struct STRTAB *tab)
740 {
741 int i;
742
743 if (str[0] >= '0' && str[0] <= '9')
744 return atoi(str);
745 for (i = 0; tab[i].str != NULL; i++)
746 if (0 == strcasecmp(str,tab[i].str))
747 return(tab[i].nr);
748 return -1;
749 }
750
751 const char*
int_to_str(int n,struct STRTAB * tab)752 int_to_str(int n, struct STRTAB *tab)
753 {
754 int i;
755
756 for (i = 0; tab[i].str != NULL; i++)
757 if (tab[i].nr == n)
758 return tab[i].str;
759 return NULL;
760 }
761