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