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