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