01dca14d95f130ad097447a7e670f73e83c93aa4
[xscreensaver] / hacks / analogtv.h
1 /* analogtv, Copyright (c) 2003, 2004 Trevor Blackwell <tlb@tlb.org>
2  *
3  * Permission to use, copy, modify, distribute, and sell this software and its
4  * documentation for any purpose is hereby granted without fee, provided that
5  * the above copyright notice appear in all copies and that both that
6  * copyright notice and this permission notice appear in supporting
7  * documentation.  No representations are made about the suitability of this
8  * software for any purpose.  It is provided "as is" without express or
9  * implied warranty.
10  */
11
12 #ifndef _XSCREENSAVER_ANALOGTV_H
13 #define _XSCREENSAVER_ANALOGTV_H
14
15 #include "xshm.h"
16
17 /*
18   You'll need these to generate standard NTSC TV signals
19  */
20 enum {
21   /* We don't handle interlace here */
22   ANALOGTV_V=262,
23   ANALOGTV_TOP=30,
24   ANALOGTV_VISLINES=200,
25   ANALOGTV_BOT=ANALOGTV_TOP + ANALOGTV_VISLINES,
26
27   /* This really defines our sampling rate, 4x the colorburst
28      frequency. Handily equal to the Apple II's dot clock.
29      You could also make a case for using 3x the colorburst freq,
30      but 4x isn't hard to deal with. */
31   ANALOGTV_H=912,
32
33   /* Each line is 63500 nS long. The sync pulse is 4700 nS long, etc.
34      Define sync, back porch, colorburst, picture, and front porch
35      positions */
36   ANALOGTV_SYNC_START=0,
37   ANALOGTV_BP_START=4700*ANALOGTV_H/63500,
38   ANALOGTV_CB_START=5800*ANALOGTV_H/63500,
39   /* signal[row][ANALOGTV_PIC_START] is the first displayed pixel */
40   ANALOGTV_PIC_START=9400*ANALOGTV_H/63500,
41   ANALOGTV_PIC_LEN=52600*ANALOGTV_H/63500,
42   ANALOGTV_FP_START=62000*ANALOGTV_H/63500,
43   ANALOGTV_PIC_END=ANALOGTV_FP_START,
44
45   /* TVs scan past the edges of the picture tube, so normally you only
46      want to use about the middle 3/4 of the nominal scan line.
47   */
48   ANALOGTV_VIS_START=ANALOGTV_PIC_START + (ANALOGTV_PIC_LEN*1/8),
49   ANALOGTV_VIS_END=ANALOGTV_PIC_START + (ANALOGTV_PIC_LEN*7/8),
50   ANALOGTV_VIS_LEN=ANALOGTV_VIS_END-ANALOGTV_VIS_START,
51
52   ANALOGTV_HASHNOISE_LEN=6,
53
54   ANALOGTV_GHOSTFIR_LEN=4,
55
56   /* analogtv.signal is in IRE units, as defined below: */
57   ANALOGTV_WHITE_LEVEL=100,
58   ANALOGTV_GRAY50_LEVEL=55,
59   ANALOGTV_GRAY30_LEVEL=35,
60   ANALOGTV_BLACK_LEVEL=10,
61   ANALOGTV_BLANK_LEVEL=0,
62   ANALOGTV_SYNC_LEVEL=-40,
63   ANALOGTV_CB_LEVEL=20,
64
65   ANALOGTV_SIGNAL_LEN=ANALOGTV_V*ANALOGTV_H,
66
67   /* The number of intensity levels we deal with for gamma correction &c */
68   ANALOGTV_CV_MAX=1024,
69
70   /* MAX_LINEHEIGHT corresponds to 2400 vertical pixels, beyond which
71      it interpolates extra black lines. */
72   ANALOGTV_MAX_LINEHEIGHT=12
73
74 };
75
76 typedef struct analogtv_input_s {
77   signed char signal[ANALOGTV_V+1][ANALOGTV_H];
78
79   int do_teletext;
80
81   /* for client use */
82   void (*updater)(struct analogtv_input_s *inp);
83   void *client_data;
84   double next_update_time;
85
86 } analogtv_input;
87
88 typedef struct analogtv_font_s {
89   XImage *text_im;
90   int char_w, char_h;
91   int x_mult, y_mult;
92 } analogtv_font;
93
94 typedef struct analogtv_reception_s {
95
96   analogtv_input *input;
97   double ofs;
98   double level;
99   double multipath;
100   double freqerr;
101
102   double ghostfir[ANALOGTV_GHOSTFIR_LEN];
103   double ghostfir2[ANALOGTV_GHOSTFIR_LEN];
104
105   double hfloss;
106   double hfloss2;
107
108 } analogtv_reception;
109
110 /*
111   The rest of this should be considered mostly opaque to the analogtv module.
112  */
113
114 typedef struct analogtv_s {
115
116   Display *dpy;
117   Window window;
118   Screen *screen;
119   XWindowAttributes xgwa;
120
121 #if 0
122   unsigned int onscreen_signature[ANALOGTV_V];
123 #endif
124
125   int n_colors;
126
127   int interlace;
128   int interlace_counter;
129
130   double agclevel;
131
132   /* If you change these, call analogtv_set_demod */
133   double tint_control,color_control,brightness_control,contrast_control;
134   double height_control, width_control, squish_control;
135   double horiz_desync;
136   double squeezebottom;
137   double powerup;
138
139   /* internal cache */
140   int blur_mult;
141
142   /* For fast display, set fakeit_top, fakeit_bot to
143      the scanlines (0..ANALOGTV_V) that can be preserved on screen.
144      fakeit_scroll is the number of scan lines to scroll it up,
145      or 0 to not scroll at all. It will DTRT if asked to scroll from
146      an offscreen region.
147   */
148   int fakeit_top;
149   int fakeit_bot;
150   int fakeit_scroll;
151   int redraw_all;
152
153   int use_shm,use_cmap,use_color;
154   int bilevel_signal;
155
156 #ifdef HAVE_XSHM_EXTENSION
157   XShmSegmentInfo shm_info;
158 #endif
159   int visdepth,visclass,visbits;
160   int red_invprec, red_shift;
161   int green_invprec, green_shift;
162   int blue_invprec, blue_shift;
163   unsigned int red_mask, green_mask, blue_mask;
164
165   Colormap colormap;
166   int usewidth,useheight,xrepl,subwidth;
167   XImage *image; /* usewidth * useheight */
168   GC gc;
169   int screen_xo,screen_yo; /* centers image in window */
170
171   int flutter_horiz_desync;
172   int flutter_tint;
173
174   struct timeval last_display_time;
175   int need_clear;
176
177
178   /* Add hash (in the radio sense, not the programming sense.) These
179      are the small white streaks that appear in quasi-regular patterns
180      all over the screen when someone is running the vacuum cleaner or
181      the blender. We also set shrinkpulse for one period which
182      squishes the image horizontally to simulate the temporary line
183      voltate drop when someone turns on a big motor */
184   double hashnoise_rpm;
185   int hashnoise_counter;
186   int hashnoise_times[ANALOGTV_V];
187   int hashnoise_signal[ANALOGTV_V];
188   int hashnoise_on;
189   int hashnoise_enable;
190   int shrinkpulse;
191
192   double crtload[ANALOGTV_V];
193
194   unsigned int red_values[ANALOGTV_CV_MAX];
195   unsigned int green_values[ANALOGTV_CV_MAX];
196   unsigned int blue_values[ANALOGTV_CV_MAX];
197
198   struct analogtv_yiq_s {
199     float y,i,q;
200   } yiq[ANALOGTV_PIC_LEN+10];
201
202   unsigned long colors[256];
203   int cmap_y_levels;
204   int cmap_i_levels;
205   int cmap_q_levels;
206
207   int cur_hsync;
208   int line_hsync[ANALOGTV_V];
209   int cur_vsync;
210   double cb_phase[4];
211   double line_cb_phase[ANALOGTV_V][4];
212
213   int channel_change_cycles;
214   double rx_signal_level;
215   double rx_signal[ANALOGTV_SIGNAL_LEN + 2*ANALOGTV_H];
216
217   struct {
218     int index;
219     double value;
220   } leveltable[ANALOGTV_MAX_LINEHEIGHT+1][ANALOGTV_MAX_LINEHEIGHT+1];
221
222 } analogtv;
223
224
225 analogtv *analogtv_allocate(Display *dpy, Window window);
226 analogtv_input *analogtv_input_allocate(void);
227
228 /* call if window size changes */
229 void analogtv_reconfigure(analogtv *it);
230
231 void analogtv_set_defaults(analogtv *it, char *prefix);
232 void analogtv_release(analogtv *it);
233 int analogtv_set_demod(analogtv *it);
234 void analogtv_setup_frame(analogtv *it);
235 void analogtv_setup_sync(analogtv_input *input, int do_cb, int do_ssavi);
236 void analogtv_draw(analogtv *it);
237
238 int analogtv_load_ximage(analogtv *it, analogtv_input *input, XImage *pic_im);
239
240 void analogtv_reception_update(analogtv_reception *inp);
241
242 void analogtv_init_signal(analogtv *it, double noiselevel);
243 void analogtv_add_signal(analogtv *it, analogtv_reception *rec);
244
245 void analogtv_setup_teletext(analogtv_input *input);
246
247
248 /* Functions for rendering content into an analogtv_input */
249
250 void analogtv_make_font(Display *dpy, Window window,
251                         analogtv_font *f, int w, int h, char *fontname);
252 int analogtv_font_pixel(analogtv_font *f, int c, int x, int y);
253 void analogtv_font_set_pixel(analogtv_font *f, int c, int x, int y, int value);
254 void analogtv_font_set_char(analogtv_font *f, int c, char *s);
255 void analogtv_lcp_to_ntsc(double luma, double chroma, double phase,
256                           int ntsc[4]);
257
258
259 void analogtv_draw_solid(analogtv_input *input,
260                          int left, int right, int top, int bot,
261                          int ntsc[4]);
262
263 void analogtv_draw_solid_rel_lcp(analogtv_input *input,
264                                  double left, double right,
265                                  double top, double bot,
266                                  double luma, double chroma, double phase);
267
268 void analogtv_draw_char(analogtv_input *input, analogtv_font *f,
269                         int c, int x, int y, int ntsc[4]);
270 void analogtv_draw_string(analogtv_input *input, analogtv_font *f,
271                           char *s, int x, int y, int ntsc[4]);
272 void analogtv_draw_string_centered(analogtv_input *input, analogtv_font *f,
273                                    char *s, int x, int y, int ntsc[4]);
274 void analogtv_draw_xpm(analogtv *tv, analogtv_input *input,
275                        const char * const *xpm, int left, int top);
276
277 int analogtv_handle_events (analogtv *it);
278
279 #ifdef HAVE_XSHM_EXTENSION
280 #define ANALOGTV_DEFAULTS_SHM "*useSHM:           True",
281 #else
282 #define ANALOGTV_DEFAULTS_SHM
283 #endif
284
285 #ifndef USE_IPHONE
286 # define ANALOGTV_DEF_BRIGHTNESS "2"
287 # define ANALOGTV_DEF_CONTRAST "150"
288 #else
289   /* Need to really crank this up for it to look good on the iPhone screen. */
290 # define ANALOGTV_DEF_BRIGHTNESS "3"
291 # define ANALOGTV_DEF_CONTRAST "1000"
292 #endif
293
294 #define ANALOGTV_DEFAULTS \
295   "*TVColor:         70", \
296   "*TVTint:          5",  \
297   "*TVBrightness:  " ANALOGTV_DEF_BRIGHTNESS,  \
298   "*TVContrast:    " ANALOGTV_DEF_CONTRAST, \
299   "*Background:      Black", \
300   "*use_cmap:        0",  \
301   "*geometry:        800x600", \
302   "*fpsSolid:        True", \
303   ANALOGTV_DEFAULTS_SHM
304
305 #define ANALOGTV_OPTIONS \
306   { "-use-cmap",        ".use_cmap",     XrmoptionSepArg, 0 }, \
307   { "-tv-color",        ".TVColor",      XrmoptionSepArg, 0 }, \
308   { "-tv-tint",         ".TVTint",       XrmoptionSepArg, 0 }, \
309   { "-tv-brightness",   ".TVBrightness", XrmoptionSepArg, 0 }, \
310   { "-tv-contrast",     ".TVContrast",   XrmoptionSepArg, 0 },
311
312 #endif /* _XSCREENSAVER_ANALOGTV_H */