d3d51aed3077befc780f73ea78727d971218a26e
[xscreensaver] / hacks / analogtv.c
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 /*
13
14   This is the code for implementing something that looks like a conventional
15   analog TV set. It simulates the following characteristics of standard
16   televisions:
17
18   - Realistic rendering of a composite video signal
19   - Compression & brightening on the right, as the scan gets truncated
20     because of saturation in the flyback transformer
21   - Blooming of the picture dependent on brightness
22   - Overscan, cutting off a few pixels on the left side.
23   - Colored text in mixed graphics/text modes
24
25   It's amazing how much it makes your high-end monitor look like at large
26   late-70s TV. All you need is to put a big "Solid State" logo in curly script
27   on it and you'd be set.
28
29   In DirectColor or TrueColor modes, it generates pixel values
30   directly from RGB values it calculates across each scan line. In
31   PseudoColor mode, it consider each possible pattern of 5 preceding
32   bit values in each possible position modulo 4 and allocates a color
33   for each. A few things, like the brightening on the right side as
34   the horizontal trace slows down, aren't done in PseudoColor.
35
36   I originally wrote it for the Apple ][ emulator, and generalized it
37   here for use with a rewrite of xteevee and possibly others.
38
39   A maxim of technology is that failures reveal underlying mechanism.
40   A good way to learn how something works is to push it to failure.
41   The way it fails will usually tell you a lot about how it works. The
42   corollary for this piece of software is that in order to emulate
43   realistic failures of a TV set, it has to work just like a TV set.
44   So there is lots of DSP-style emulation of analog circuitry for
45   things like color decoding, H and V sync following, and more. In
46   2003, computers are just fast enough to do this at television signal
47   rates. We use a 14 MHz sample rate here, so we can do on the order
48   of a couple hundred instructions per sample and keep a good frame
49   rate.
50
51   Trevor Blackwell <tlb@tlb.org>
52 */
53
54 #include <X11/Xlib.h>
55 #include <X11/Xutil.h>
56 #include <X11/Intrinsic.h>
57 #include <assert.h>
58 #include "utils.h"
59 #include "resources.h"
60 #include "analogtv.h"
61 #include "yarandom.h"
62 #include "grabscreen.h"
63
64 /* #define DEBUG 1 */
65
66 #ifdef DEBUG
67 /* only works on linux + freebsd */
68 #include <machine/cpufunc.h>
69
70 #define DTIME_DECL u_int64_t dtimes[100]; int n_dtimes
71 #define DTIME_START do {n_dtimes=0; dtimes[n_dtimes++]=rdtsc(); } while (0)
72 #define DTIME dtimes[n_dtimes++]=rdtsc()
73 #define DTIME_SHOW(DIV) \
74 do { \
75   double _dtime_div=(DIV); \
76   printf("time/%.1f: ",_dtime_div); \
77   for (i=1; i<n_dtimes; i++) \
78     printf(" %0.9f",(dtimes[i]-dtimes[i-1])* 1e-9 / _dtime_div); \
79   printf("\n"); \
80 } while (0)
81
82 #else
83
84 #define DTIME_DECL
85 #define DTIME_START  do { } while (0)
86 #define DTIME  do { } while (0)
87 #define DTIME_SHOW(DIV)  do { } while (0)
88
89 #endif
90
91
92 #define FASTRND (fastrnd = fastrnd*1103515245+12345)
93
94 static void analogtv_ntsc_to_yiq(analogtv *it, int lineno, double *signal,
95                                  int start, int end);
96
97 static double puramp(analogtv *it, double tc, double start, double over)
98 {
99   double pt=it->powerup-start;
100   double ret;
101   if (pt<0.0) return 0.0;
102   if (pt>900.0 || pt/tc>8.0) return 1.0;
103
104   ret=(1.0-exp(-pt/tc))*over;
105   if (ret>1.0) return 1.0;
106   return ret*ret;
107 }
108
109 /*
110   There are actual standards for TV signals: NTSC and RS-170A describe the
111   system used in the US and Japan. Europe has slightly different systems, but
112   not different enough to make substantially different screensaver displays.
113   Sadly, the standards bodies don't do anything so useful as publish the spec on
114   the web. Best bets are:
115
116     http://www.ee.washington.edu/conselec/CE/kuhn/ntsc/95x4.htm
117     http://www.ntsc-tv.com/ntsc-index-02.htm
118
119   In DirectColor or TrueColor modes, it generates pixel values directly from RGB
120   values it calculates across each scan line. In PseudoColor mode, it consider
121   each possible pattern of 5 preceding bit values in each possible position
122   modulo 4 and allocates a color for each. A few things, like the brightening on
123   the right side as the horizontal trace slows down, aren't done in PseudoColor.
124
125   I'd like to add a bit of visible retrace, but it conflicts with being able to
126   bitcopy the image when fast scrolling. After another couple of CPU
127   generations, we could probably regenerate the whole image from scratch every
128   time. On a P4 2 GHz it can manage this fine for blinking text, but scrolling
129   looks too slow.
130 */
131
132 /* localbyteorder is MSBFirst or LSBFirst */
133 static int localbyteorder;
134 static const double float_low8_ofs=8388608.0;
135 static int float_extraction_works;
136
137 typedef union {
138   float f;
139   int i;
140 } float_extract_t;
141
142 static void
143 analogtv_init(void)
144 {
145   int i;
146   {
147     unsigned int localbyteorder_loc = (MSBFirst<<24) | (LSBFirst<<0);
148     localbyteorder=*(char *)&localbyteorder_loc;
149   }
150
151   if (1) {
152     float_extract_t fe;
153     int ans;
154
155     float_extraction_works=1;
156     for (i=0; i<256*4; i++) {
157       fe.f=float_low8_ofs+(double)i;
158       ans=fe.i&0x3ff;
159       if (ans != i) {
160 #ifdef DEBUG
161         printf("Float extraction failed for %d => %d\n",i,ans);
162 #endif
163         float_extraction_works=0;
164         break;
165       }
166     }
167   }
168
169 }
170
171 void
172 analogtv_set_defaults(analogtv *it, char *prefix)
173 {
174   char buf[256];
175
176   sprintf(buf,"%sTVTint",prefix);
177   it->tint_control = get_float_resource(buf,"TVTint");
178   sprintf(buf,"%sTVColor",prefix);
179   it->color_control = get_float_resource(buf,"TVColor")/100.0;
180   sprintf(buf,"%sTVBrightness",prefix);
181   it->brightness_control = get_float_resource(buf,"TVBrightness") / 100.0;
182   sprintf(buf,"%sTVContrast",prefix);
183   it->contrast_control = get_float_resource(buf,"TVContrast") / 100.0;
184   it->height_control = 1.0;
185   it->width_control = 1.0;
186   it->squish_control = 0.0;
187   it->powerup=1000.0;
188
189   it->hashnoise_rpm=0;
190   it->hashnoise_on=0;
191   it->hashnoise_enable=1;
192
193   it->horiz_desync=frand(10.0)-5.0;
194   it->squeezebottom=frand(5.0)-1.0;
195
196 #ifdef DEBUG
197   printf("analogtv: prefix=%s\n",prefix);
198   printf("  use: shm=%d cmap=%d color=%d\n",
199          it->use_shm,it->use_cmap,it->use_color);
200   printf("  controls: tint=%g color=%g brightness=%g contrast=%g\n",
201          it->tint_control, it->color_control, it->brightness_control,
202          it->contrast_control);
203   printf("  freq_error %g: %g %d\n",
204          it->freq_error, it->freq_error_inc, it->flutter_tint);
205   printf("  desync: %g %d\n",
206          it->horiz_desync, it->flutter_horiz_desync);
207   printf("  hashnoise rpm: %g\n",
208          it->hashnoise_rpm);
209   printf("  vis: %d %d %d\n",
210          it->visclass, it->visbits, it->visdepth);
211   printf("  shift: %d-%d %d-%d %d-%d\n",
212          it->red_invprec,it->red_shift,
213          it->green_invprec,it->green_shift,
214          it->blue_invprec,it->blue_shift);
215   printf("  size: %d %d  %d %d  xrepl=%d\n",
216          it->usewidth, it->useheight,
217          it->screen_xo, it->screen_yo, it->xrepl);
218
219   printf("    ANALOGTV_V=%d\n",ANALOGTV_V);
220   printf("    ANALOGTV_TOP=%d\n",ANALOGTV_TOP);
221   printf("    ANALOGTV_VISLINES=%d\n",ANALOGTV_VISLINES);
222   printf("    ANALOGTV_BOT=%d\n",ANALOGTV_BOT);
223   printf("    ANALOGTV_H=%d\n",ANALOGTV_H);
224   printf("    ANALOGTV_SYNC_START=%d\n",ANALOGTV_SYNC_START);
225   printf("    ANALOGTV_BP_START=%d\n",ANALOGTV_BP_START);
226   printf("    ANALOGTV_CB_START=%d\n",ANALOGTV_CB_START);
227   printf("    ANALOGTV_PIC_START=%d\n",ANALOGTV_PIC_START);
228   printf("    ANALOGTV_PIC_LEN=%d\n",ANALOGTV_PIC_LEN);
229   printf("    ANALOGTV_FP_START=%d\n",ANALOGTV_FP_START);
230   printf("    ANALOGTV_PIC_END=%d\n",ANALOGTV_PIC_END);
231   printf("    ANALOGTV_HASHNOISE_LEN=%d\n",ANALOGTV_HASHNOISE_LEN);
232
233 #endif
234
235 }
236
237 extern Bool mono_p; /* shoot me */
238
239 void
240 analogtv_free_image(analogtv *it)
241 {
242   if (it->image) {
243     if (it->use_shm) {
244 #ifdef HAVE_XSHM_EXTENSION
245       destroy_xshm_image(it->dpy, it->image, &it->shm_info);
246 #endif
247     } else {
248       XDestroyImage(it->image);
249     }
250     it->image=NULL;
251   }
252 }
253
254 void
255 analogtv_alloc_image(analogtv *it)
256 {
257   if (it->use_shm) {
258 #ifdef HAVE_XSHM_EXTENSION
259     it->image=create_xshm_image(it->dpy, it->xgwa.visual, it->xgwa.depth, ZPixmap, 0,
260                                 &it->shm_info, it->usewidth, it->useheight);
261 #endif
262     if (!it->image) it->use_shm=0;
263   }
264   if (!it->image) {
265     it->image = XCreateImage(it->dpy, it->xgwa.visual, it->xgwa.depth, ZPixmap, 0, 0,
266                              it->usewidth, it->useheight, 8, 0);
267     it->image->data = (char *)calloc(it->image->height, it->image->bytes_per_line);
268   }
269 }
270
271
272 void
273 analogtv_configure(analogtv *it)
274 {
275   int oldwidth=it->usewidth;
276   int oldheight=it->useheight;
277   int wlim,hlim,height_diff;
278
279   /* If the window is very small, don't let the image we draw get lower
280      than the actual TV resolution (266x200.)
281
282      If the aspect ratio of the window is within 20% of a 4:3 ratio,
283      then scale the image to exactly fill the window.
284
285      Otherwise, center the image either horizontally or vertically,
286      padding on the left+right, or top+bottom, but not both.
287
288      If it's very close (2.5%) to a multiple of VISLINES, make it exact
289      For example, it maps 1024 => 1000.
290    */
291   float percent = 0.20;
292   float min_ratio = 4.0 / 3.0 * (1 - percent);
293   float max_ratio = 4.0 / 3.0 * (1 + percent);
294   float ratio;
295   float height_snap=0.025;
296
297   hlim = it->xgwa.height;
298   wlim = it->xgwa.width;
299   ratio = wlim / (float) hlim;
300
301   if (wlim < 266 || hlim < 200)
302     {
303       wlim = 266;
304       hlim = 200;
305 # ifdef DEBUG
306       fprintf (stderr,
307                "size: minimal: %dx%d in %dx%d (%.3f < %.3f < %.3f)\n",
308                wlim, hlim, it->xgwa.width, it->xgwa.height,
309                min_ratio, ratio, max_ratio);
310 # endif
311     }
312   else if (ratio > min_ratio && ratio < max_ratio)
313     {
314 # ifdef DEBUG
315       fprintf (stderr,
316                "size: close enough: %dx%d (%.3f < %.3f < %.3f)\n",
317                wlim, hlim, min_ratio, ratio, max_ratio);
318 # endif
319     }
320   else if (ratio > max_ratio)
321     {
322       wlim = hlim*max_ratio;
323 # ifdef DEBUG
324       fprintf (stderr,
325                "size: center H: %dx%d in %dx%d (%.3f < %.3f < %.3f)\n",
326                wlim, hlim, it->xgwa.width, it->xgwa.height,
327                min_ratio, ratio, max_ratio);
328 # endif
329     }
330   else /* ratio < min_ratio */
331     {
332       hlim = wlim/min_ratio;
333 # ifdef DEBUG
334       fprintf (stderr,
335                "size: center V: %dx%d in %dx%d (%.3f < %.3f < %.3f)\n",
336                wlim, hlim, it->xgwa.width, it->xgwa.height,
337                min_ratio, ratio, max_ratio);
338 # endif
339     }
340
341
342   height_diff = ((hlim + ANALOGTV_VISLINES/2) % ANALOGTV_VISLINES) - ANALOGTV_VISLINES/2;
343   if (height_diff != 0 && fabs(height_diff) < hlim * height_snap)
344     {
345       hlim -= height_diff;
346     }
347
348
349   /* Most times this doesn't change */
350   if (wlim != oldwidth || hlim != oldheight) {
351
352     it->usewidth=wlim;
353     it->useheight=hlim;
354
355     it->xrepl=1+it->usewidth/640;
356     if (it->xrepl>2) it->xrepl=2;
357     it->subwidth=it->usewidth/it->xrepl;
358
359     analogtv_free_image(it);
360     analogtv_alloc_image(it);
361   }
362
363   it->screen_xo = (it->xgwa.width-it->usewidth)/2;
364   it->screen_yo = (it->xgwa.height-it->useheight)/2;
365   it->need_clear=1;
366 }
367
368 void
369 analogtv_reconfigure(analogtv *it)
370 {
371   XGetWindowAttributes (it->dpy, it->window, &it->xgwa);
372   analogtv_configure(it);
373 }
374
375 analogtv *
376 analogtv_allocate(Display *dpy, Window window)
377 {
378   XGCValues gcv;
379   analogtv *it=NULL;
380   int i;
381
382   analogtv_init();
383
384   it=(analogtv *)calloc(1,sizeof(analogtv));
385   it->dpy=dpy;
386   it->window=window;
387
388   it->shrinkpulse=-1;
389
390   it->n_colors=0;
391
392 #ifdef HAVE_XSHM_EXTENSION
393   it->use_shm=1;
394 #else
395   it->use_shm=0;
396 #endif
397
398   XGetWindowAttributes (it->dpy, it->window, &it->xgwa);
399
400   it->screen=it->xgwa.screen;
401   it->colormap=it->xgwa.colormap;
402   it->visclass=it->xgwa.visual->class;
403   it->visbits=it->xgwa.visual->bits_per_rgb;
404   it->visdepth=it->xgwa.depth;
405   if (it->visclass == TrueColor || it->visclass == DirectColor) {
406     if (get_integer_resource ("use_cmap", "Integer")) {
407       it->use_cmap=1;
408     } else {
409       it->use_cmap=0;
410     }
411     it->use_color=!mono_p;
412   }
413   else if (it->visclass == PseudoColor || it->visclass == StaticColor) {
414     it->use_cmap=1;
415     it->use_color=!mono_p;
416   }
417   else {
418     it->use_cmap=1;
419     it->use_color=0;
420   }
421
422   it->red_mask=it->xgwa.visual->red_mask;
423   it->green_mask=it->xgwa.visual->green_mask;
424   it->blue_mask=it->xgwa.visual->blue_mask;
425   it->red_shift=it->red_invprec=-1;
426   it->green_shift=it->green_invprec=-1;
427   it->blue_shift=it->blue_invprec=-1;
428   if (!it->use_cmap) {
429     /* Is there a standard way to do this? Does this handle all cases? */
430     int shift, prec;
431     for (shift=0; shift<32; shift++) {
432       for (prec=1; prec<16 && prec<32-shift; prec++) {
433         unsigned long mask=(0xffffUL>>(16-prec)) << shift;
434         if (it->red_shift<0 && mask==it->red_mask)
435           it->red_shift=shift, it->red_invprec=16-prec;
436         if (it->green_shift<0 && mask==it->green_mask)
437           it->green_shift=shift, it->green_invprec=16-prec;
438         if (it->blue_shift<0 && mask==it->blue_mask)
439           it->blue_shift=shift, it->blue_invprec=16-prec;
440       }
441     }
442     if (it->red_shift<0 || it->green_shift<0 || it->blue_shift<0) {
443       if (0) fprintf(stderr,"Can't figure out color space\n");
444       goto fail;
445     }
446
447     for (i=0; i<ANALOGTV_CV_MAX; i++) {
448       int intensity=pow(i/256.0, 0.8)*65535.0; /* gamma correction */
449       if (intensity>65535) intensity=65535;
450       it->red_values[i]=((intensity>>it->red_invprec)<<it->red_shift);
451       it->green_values[i]=((intensity>>it->green_invprec)<<it->green_shift);
452       it->blue_values[i]=((intensity>>it->blue_invprec)<<it->blue_shift);
453     }
454
455   }
456
457   gcv.background=get_pixel_resource("background", "Background",
458                                     it->dpy, it->colormap);
459
460   it->gc = XCreateGC(it->dpy, it->window, GCBackground, &gcv);
461   XSetWindowBackground(it->dpy, it->window, gcv.background);
462   XClearWindow(dpy,window);
463
464   analogtv_configure(it);
465
466   return it;
467
468  fail:
469   if (it) free(it);
470   return NULL;
471 }
472
473 void
474 analogtv_release(analogtv *it)
475 {
476   if (it->image) {
477     if (it->use_shm) {
478 #ifdef HAVE_XSHM_EXTENSION
479       destroy_xshm_image(it->dpy, it->image, &it->shm_info);
480 #endif
481     } else {
482       XDestroyImage(it->image);
483     }
484     it->image=NULL;
485   }
486   if (it->gc) XFreeGC(it->dpy, it->gc);
487   it->gc=NULL;
488   if (it->n_colors) XFreeColors(it->dpy, it->colormap, it->colors, it->n_colors, 0L);
489   it->n_colors=0;
490 }
491
492
493 /*
494   First generate the I and Q reference signals, which we'll multiply
495   the input signal by to accomplish the demodulation. Normally they
496   are shifted 33 degrees from the colorburst. I think this was convenient
497   for inductor-capacitor-vacuum tube implementation.
498
499   The tint control, FWIW, just adds a phase shift to the chroma signal,
500   and the color control controls the amplitude.
501
502   In text modes (colormode==0) the system disabled the color burst, and no
503   color was detected by the monitor.
504
505   freq_error gives a mismatch between the built-in oscillator and the
506   TV's colorbust. Some II Plus machines seemed to occasionally get
507   instability problems -- the crystal oscillator was a single
508   transistor if I remember correctly -- and the frequency would vary
509   enough that the tint would change across the width of the screen.
510   The left side would be in correct tint because it had just gotten
511   resynchronized with the color burst.
512
513   If we're using a colormap, set it up.
514 */
515 int
516 analogtv_set_demod(analogtv *it)
517 {
518   int y_levels=10,i_levels=5,q_levels=5;
519
520   /*
521     In principle, we might be able to figure out how to adjust the
522     color map frame-by-frame to get some nice color bummage. But I'm
523     terrified of changing the color map because we'll get flashing.
524
525     I can hardly believe we still have to deal with colormaps. They're
526     like having NEAR PTRs: an enormous hassle for the programmer just
527     to save on memory. They should have been deprecated by 1995 or
528     so. */
529
530  cmap_again:
531   if (it->use_cmap && !it->n_colors) {
532
533     if (it->n_colors) {
534       XFreeColors(it->dpy, it->colormap, it->colors, it->n_colors, 0L);
535       it->n_colors=0;
536     }
537
538     {
539       int yli,qli,ili;
540       for (yli=0; yli<y_levels; yli++) {
541         for (ili=0; ili<i_levels; ili++) {
542           for (qli=0; qli<q_levels; qli++) {
543             double interpy,interpi,interpq;
544             double levelmult=700.0;
545             int r,g,b;
546             XColor col;
547
548             interpy=100.0 * ((double)yli/y_levels);
549             interpi=50.0 * (((double)ili-(0.5*i_levels))/(double)i_levels);
550             interpq=50.0 * (((double)qli-(0.5*q_levels))/(double)q_levels);
551
552             r=(int)((interpy + 1.04*interpi + 0.624*interpq)*levelmult);
553             g=(int)((interpy - 0.276*interpi - 0.639*interpq)*levelmult);
554             b=(int)((interpy - 1.105*interpi + 1.729*interpq)*levelmult);
555             if (r<0) r=0;
556             if (r>65535) r=65535;
557             if (g<0) g=0;
558             if (g>65535) g=65535;
559             if (b<0) b=0;
560             if (b>65535) b=65535;
561
562 #ifdef DEBUG
563             printf("%0.2f %0.2f %0.2f => %02x%02x%02x\n",
564                    interpy, interpi, interpq,
565                    r/256,g/256,b/256);
566 #endif
567
568             col.red=r;
569             col.green=g;
570             col.blue=b;
571             col.pixel=0;
572             if (!XAllocColor(it->dpy, it->colormap, &col)) {
573               if (q_levels > y_levels*4/12)
574                 q_levels--;
575               else if (i_levels > y_levels*5/12)
576                 i_levels--;
577               else
578                 y_levels--;
579
580               if (y_levels<2)
581                 return -1;
582               goto cmap_again;
583             }
584             it->colors[it->n_colors++]=col.pixel;
585           }
586         }
587       }
588
589       it->cmap_y_levels=y_levels;
590       it->cmap_i_levels=i_levels;
591       it->cmap_q_levels=q_levels;
592     }
593   }
594
595   return 0;
596 }
597
598 #if 0
599 unsigned int
600 analogtv_line_signature(analogtv_input *input, int lineno)
601 {
602   int i;
603   char *origsignal=&input->signal[(lineno+input->vsync)
604                                   %ANALOGTV_V][input->line_hsync[lineno]];
605   unsigned int hash=0;
606
607   /* probably lame */
608   for (i=0; i<ANALOGTV_PIC_LEN; i++) {
609     int c=origsignal[i];
610     hash = hash + (hash<<17) + c;
611   }
612
613   hash += input->line_hsync[lineno];
614   hash ^= hash >> 2;
615   /*
616   hash += input->hashnoise_times[lineno];
617   hash ^= hash >> 2;
618   */
619
620   return hash;
621 }
622 #endif
623
624
625 /* Here we model the analog circuitry of an NTSC television.
626    Basically, it splits the signal into 3 signals: Y, I and Q. Y
627    corresponds to luminance, and you get it by low-pass filtering the
628    input signal to below 3.57 MHz.
629
630    I and Q are the in-phase and quadrature components of the 3.57 MHz
631    subcarrier. We get them by multiplying by cos(3.57 MHz*t) and
632    sin(3.57 MHz*t), and low-pass filtering. Because the eye has less
633    resolution in some colors than others, the I component gets
634    low-pass filtered at 1.5 MHz and the Q at 0.5 MHz. The I component
635    is approximately orange-blue, and Q is roughly purple-green. See
636    http://www.ntsc-tv.com for details.
637
638    We actually do an awful lot to the signal here. I suspect it would
639    make sense to wrap them all up together by calculating impulse
640    response and doing FFT convolutions.
641
642 */
643
644 static void
645 analogtv_ntsc_to_yiq(analogtv *it, int lineno, double *signal,
646                      int start, int end)
647 {
648   enum {MAXDELAY=32};
649   int i;
650   double *sp;
651   int phasecorr=(signal-it->rx_signal)&3;
652   struct analogtv_yiq_s *yiq;
653   int colormode;
654   double agclevel=it->agclevel;
655   double brightadd=it->brightness_control*100.0 - ANALOGTV_BLACK_LEVEL;
656   double delay[MAXDELAY+ANALOGTV_PIC_LEN], *dp;
657   double multiq2[4];
658
659   {
660
661     double cb_i=(it->line_cb_phase[lineno][(2+phasecorr)&3]-
662                  it->line_cb_phase[lineno][(0+phasecorr)&3])/16.0;
663     double cb_q=(it->line_cb_phase[lineno][(3+phasecorr)&3]-
664                  it->line_cb_phase[lineno][(1+phasecorr)&3])/16.0;
665
666     colormode = (cb_i * cb_i + cb_q * cb_q) > 2.8;
667
668     if (colormode) {
669       double tint_i = -cos((103 + it->color_control)*3.1415926/180);
670       double tint_q = sin((103 + it->color_control)*3.1415926/180);
671
672       multiq2[0] = (cb_i*tint_i - cb_q*tint_q) * it->color_control;
673       multiq2[1] = (cb_q*tint_i + cb_i*tint_q) * it->color_control;
674       multiq2[2]=-multiq2[0];
675       multiq2[3]=-multiq2[1];
676     }
677   }
678
679 #if 0
680   if (lineno==100) {
681     printf("multiq = [%0.3f %0.3f %0.3f %0.3f] ",
682            it->multiq[60],it->multiq[61],it->multiq[62],it->multiq[63]);
683     printf("it->line_cb_phase = [%0.3f %0.3f %0.3f %0.3f]\n",
684            it->line_cb_phase[lineno][0],it->line_cb_phase[lineno][1],
685            it->line_cb_phase[lineno][2],it->line_cb_phase[lineno][3]);
686     printf("multiq2 = [%0.3f %0.3f %0.3f %0.3f]\n",
687            multiq2[0],multiq2[1],multiq2[2],multiq2[3]);
688   }
689 #endif
690
691   dp=delay+ANALOGTV_PIC_LEN-MAXDELAY;
692   for (i=0; i<5; i++) dp[i]=0.0;
693
694   assert(start>=0);
695   assert(end < ANALOGTV_PIC_LEN+10);
696
697   dp=delay+ANALOGTV_PIC_LEN-MAXDELAY;
698   for (i=0; i<24; i++) dp[i]=0.0;
699   for (i=start, yiq=it->yiq+start, sp=signal+start;
700        i<end;
701        i++, dp--, yiq++, sp++) {
702
703     /* Now filter them. These are infinite impulse response filters
704        calculated by the script at
705        http://www-users.cs.york.ac.uk/~fisher/mkfilter. This is
706        fixed-point integer DSP, son. No place for wimps. We do it in
707        integer because you can count on integer being faster on most
708        CPUs. We care about speed because we need to recalculate every
709        time we blink text, and when we spew random bytes into screen
710        memory. This is roughly 16.16 fixed point arithmetic, but we
711        scale some filter values up by a few bits to avoid some nasty
712        precision errors. */
713
714     /* Filter Y with a 4-pole low-pass Butterworth filter at 3.5 MHz
715        with an extra zero at 3.5 MHz, from
716        mkfilter -Bu -Lp -o 4 -a 2.1428571429e-01 0 -Z 2.5e-01 -l
717        Delay about 2 */
718
719     dp[0] = sp[0] * 0.0469904257251935 * agclevel;
720     dp[8] = (+1.0*(dp[6]+dp[0])
721              +4.0*(dp[5]+dp[1])
722              +7.0*(dp[4]+dp[2])
723              +8.0*(dp[3])
724              -0.0176648*dp[12]
725              -0.4860288*dp[10]);
726     yiq->y = dp[8] + brightadd;
727   }
728
729   if (colormode) {
730     dp=delay+ANALOGTV_PIC_LEN-MAXDELAY;
731     for (i=0; i<27; i++) dp[i]=0.0;
732
733     for (i=start, yiq=it->yiq+start, sp=signal+start;
734          i<end;
735          i++, dp--, yiq++, sp++) {
736       double sig=*sp;
737
738       /* Filter I and Q with a 3-pole low-pass Butterworth filter at
739          1.5 MHz with an extra zero at 3.5 MHz, from
740          mkfilter -Bu -Lp -o 3 -a 1.0714285714e-01 0 -Z 2.5000000000e-01 -l
741          Delay about 3.
742       */
743
744       dp[0] = sig*multiq2[i&3] * 0.0833333333333;
745       yiq->i=dp[8] = (dp[5] + dp[0]
746                       +3.0*(dp[4] + dp[1])
747                       +4.0*(dp[3] + dp[2])
748                       -0.3333333333 * dp[10]);
749
750       dp[16] = sig*multiq2[(i+3)&3] * 0.0833333333333;
751       yiq->q=dp[24] = (dp[16+5] + dp[16+0]
752                        +3.0*(dp[16+4] + dp[16+1])
753                        +4.0*(dp[16+3] + dp[16+2])
754                        -0.3333333333 * dp[24+2]);
755     }
756   } else {
757     for (i=start, yiq=it->yiq+start; i<end; i++, yiq++) {
758       yiq->i = yiq->q = 0.0;
759     }
760   }
761 }
762
763 void
764 analogtv_setup_teletext(analogtv_input *input)
765 {
766   int x,y;
767   int teletext=ANALOGTV_BLACK_LEVEL;
768
769   /* Teletext goes in line 21. But I suspect there are other things
770      in the vertical retrace interval */
771
772   for (y=19; y<22; y++) {
773     for (x=ANALOGTV_PIC_START; x<ANALOGTV_PIC_END; x++) {
774       if ((x&7)==0) {
775         teletext=(random()&1) ? ANALOGTV_WHITE_LEVEL : ANALOGTV_BLACK_LEVEL;
776       }
777       input->signal[y][x]=teletext;
778     }
779   }
780 }
781
782 void
783 analogtv_setup_frame(analogtv *it)
784 {
785   int i,x,y;
786
787   it->redraw_all=0;
788
789   if (it->flutter_horiz_desync) {
790     /* Horizontal sync during vertical sync instability. */
791     it->horiz_desync += -0.10*(it->horiz_desync-3.0) +
792       ((int)(random()&0xff)-0x80) *
793       ((int)(random()&0xff)-0x80) *
794       ((int)(random()&0xff)-0x80) * 0.000001;
795   }
796
797   for (i=0; i<ANALOGTV_V; i++) {
798     it->hashnoise_times[i]=0;
799   }
800
801   if (it->hashnoise_enable && !it->hashnoise_on) {
802     if (random()%10000==0) {
803       it->hashnoise_on=1;
804       it->shrinkpulse=random()%ANALOGTV_V;
805     }
806   }
807   if (random()%1000==0) {
808     it->hashnoise_on=0;
809   }
810   if (it->hashnoise_on) {
811     it->hashnoise_rpm += (15000.0 - it->hashnoise_rpm)*0.05 +
812       ((int)(random()%2000)-1000)*0.1;
813   } else {
814     it->hashnoise_rpm -= 100 + 0.01*it->hashnoise_rpm;
815     if (it->hashnoise_rpm<0.0) it->hashnoise_rpm=0.0;
816   }
817   if (it->hashnoise_rpm > 0.0) {
818     int hni;
819     int hnc=it->hashnoise_counter; /* in 24.8 format */
820
821     /* Convert rpm of a 16-pole motor into dots in 24.8 format */
822     hni = (int)(ANALOGTV_V * ANALOGTV_H * 256.0 /
823                 (it->hashnoise_rpm * 16.0 / 60.0 / 60.0));
824
825     while (hnc < (ANALOGTV_V * ANALOGTV_H)<<8) {
826       y=(hnc>>8)/ANALOGTV_H;
827       x=(hnc>>8)%ANALOGTV_H;
828
829       if (x>0 && x<ANALOGTV_H - ANALOGTV_HASHNOISE_LEN) {
830         it->hashnoise_times[y]=x;
831       }
832       hnc += hni + (int)(random()%65536)-32768;
833     }
834     hnc -= (ANALOGTV_V * ANALOGTV_H)<<8;
835   }
836
837   if (it->rx_signal_level != 0.0)
838     it->agclevel = 1.0/it->rx_signal_level;
839
840
841 #ifdef DEBUG2
842   printf("filter: ");
843   for (i=0; i<ANALOGTV_GHOSTFIR_LEN; i++) {
844     printf(" %0.3f",it->ghostfir[i]);
845   }
846   printf(" siglevel=%g agc=%g\n", siglevel, it->agclevel);
847 #endif
848 }
849
850 void
851 analogtv_setup_sync(analogtv_input *input, int do_cb, int do_ssavi)
852 {
853   int i,lineno,vsync;
854   char *sig;
855
856   int synclevel = do_ssavi ? ANALOGTV_WHITE_LEVEL : ANALOGTV_SYNC_LEVEL;
857
858   for (lineno=0; lineno<ANALOGTV_V; lineno++) {
859     vsync=lineno>=3 && lineno<7;
860
861     sig=input->signal[lineno];
862
863     i=ANALOGTV_SYNC_START;
864     if (vsync) {
865       while (i<ANALOGTV_BP_START) sig[i++]=ANALOGTV_BLANK_LEVEL;
866       while (i<ANALOGTV_H) sig[i++]=synclevel;
867     } else {
868       while (i<ANALOGTV_BP_START) sig[i++]=synclevel;
869       while (i<ANALOGTV_PIC_START) sig[i++]=ANALOGTV_BLANK_LEVEL;
870       while (i<ANALOGTV_FP_START) sig[i++]=ANALOGTV_BLACK_LEVEL;
871     }
872     while (i<ANALOGTV_H) sig[i++]=ANALOGTV_BLANK_LEVEL;
873
874     if (do_cb) {
875       /* 9 cycles of colorburst */
876       for (i=ANALOGTV_CB_START; i<ANALOGTV_CB_START+36; i+=4) {
877         sig[i+1] += ANALOGTV_CB_LEVEL;
878         sig[i+3] -= ANALOGTV_CB_LEVEL;
879       }
880     }
881   }
882 }
883
884 void
885 analogtv_sync(analogtv *it)
886 {
887   int cur_hsync=it->cur_hsync;
888   int cur_vsync=it->cur_vsync;
889   int lineno;
890   int i,j;
891   double osc,filt;
892   double *sp;
893   double cbfc=1.0/128.0;
894
895   sp = it->rx_signal + lineno*ANALOGTV_H + cur_hsync;
896   for (i=-32; i<32; i++) {
897     lineno = (cur_vsync + i + ANALOGTV_V) % ANALOGTV_V;
898     sp = it->rx_signal + lineno*ANALOGTV_H;
899     filt=0.0;
900     for (j=0; j<ANALOGTV_H; j+=ANALOGTV_H/16) {
901       filt += sp[j];
902     }
903     filt *= it->agclevel;
904
905     osc = (double)(ANALOGTV_V+i)/(double)ANALOGTV_V;
906
907     if (osc >= 1.05+0.0002 * filt) break;
908   }
909   cur_vsync = (cur_vsync + i + ANALOGTV_V) % ANALOGTV_V;
910
911   for (lineno=0; lineno<ANALOGTV_V; lineno++) {
912
913     if (lineno>5 && lineno<ANALOGTV_V-3) { /* ignore vsync interval */
914
915       sp = it->rx_signal + ((lineno + cur_vsync + ANALOGTV_V)%ANALOGTV_V
916                             )*ANALOGTV_H + cur_hsync;
917       for (i=-8; i<8; i++) {
918         osc = (double)(ANALOGTV_H+i)/(double)ANALOGTV_H;
919         filt=(sp[i-3]+sp[i-2]+sp[i-1]+sp[i]) * it->agclevel;
920
921         if (osc >= 1.005 + 0.0001*filt) break;
922       }
923       cur_hsync = (cur_hsync + i + ANALOGTV_H) % ANALOGTV_H;
924     }
925
926     it->line_hsync[lineno]=(cur_hsync + ANALOGTV_PIC_START +
927                             ANALOGTV_H) % ANALOGTV_H;
928
929     /* Now look for the colorburst, which is a few cycles after the H
930        sync pulse, and store its phase.
931        The colorburst is 9 cycles long, and we look at the middle 5
932        cycles.
933     */
934
935     if (lineno>15) {
936       sp = it->rx_signal + lineno*ANALOGTV_H + (cur_hsync&~3);
937       for (i=ANALOGTV_CB_START+8; i<ANALOGTV_CB_START+36-8; i++) {
938         it->cb_phase[i&3] = it->cb_phase[i&3]*(1.0-cbfc) +
939           sp[i]*it->agclevel*cbfc;
940       }
941     }
942
943     {
944       double tot=0.1;
945       double cbgain;
946
947       for (i=0; i<4; i++) {
948         tot += it->cb_phase[i]*it->cb_phase[i];
949       }
950       cbgain = 32.0/sqrt(tot);
951
952       for (i=0; i<4; i++) {
953         it->line_cb_phase[lineno][i]=it->cb_phase[i]*cbgain;
954       }
955     }
956
957 #ifdef DEBUG
958     if (0) printf("hs=%d cb=[%0.3f %0.3f %0.3f %0.3f]\n",
959                   cur_hsync,
960                   it->cb_phase[0], it->cb_phase[1],
961                   it->cb_phase[2], it->cb_phase[3]);
962 #endif
963
964     /* if (random()%2000==0) cur_hsync=random()%ANALOGTV_H; */
965   }
966
967   it->cur_hsync = cur_hsync;
968   it->cur_vsync = cur_vsync;
969 }
970
971 static double
972 analogtv_levelmult(analogtv *it, int level)
973 {
974   static double levelfac[3]={-7.5, 5.5, 24.5};
975   return (40.0 + levelfac[level]*puramp(it, 3.0, 6.0, 1.0))/256.0;
976 }
977
978 static int
979 analogtv_level(analogtv *it, int y, int ytop, int ybot)
980 {
981   int level;
982   if (ybot-ytop>=7) {
983     if (y==ytop || y==ybot-1) level=0;
984     else if (y==ytop+1 || y==ybot-2) level=1;
985     else level=2;
986   }
987   else if (ybot-ytop>=5) {
988     if (y==ytop || y==ybot-1) level=0;
989     else level=2;
990   }
991   else if (ybot-ytop>=3) {
992     if (y==ytop) level=0;
993     else level=2;
994   }
995   else {
996     level=2;
997   }
998   return level;
999 }
1000
1001 /*
1002
1003   The point of this stuff is to ensure that when useheight is not a
1004   multiple of VISLINES so that TV scan lines map to different numbers
1005   of vertical screen pixels, the total brightness of each scan line
1006   remains the same.
1007   MAX_LINEHEIGHT corresponds to 2400 vertical pixels, beyond which
1008   it interpolates extra black lines.
1009  */
1010 enum {MAX_LINEHEIGHT=12};
1011 static struct {
1012   int index;
1013   double value;
1014 } leveltable[MAX_LINEHEIGHT+1][MAX_LINEHEIGHT+1];
1015
1016 static void
1017 analogtv_setup_levels(analogtv *it, double avgheight)
1018 {
1019   int i,height;
1020   static double levelfac[3]={-7.5, 5.5, 24.5};
1021
1022   for (height=0; height<avgheight+2.0 && height<=MAX_LINEHEIGHT; height++) {
1023
1024     for (i=0; i<height; i++) {
1025       leveltable[height][i].index = 2;
1026     }
1027     
1028     if (avgheight>=3) {
1029       leveltable[height][0].index=0;
1030     }
1031     if (avgheight>=5) {
1032       leveltable[height][height-1].index=0;
1033     }
1034     if (avgheight>=7) {
1035       leveltable[height][1].index=1;
1036       leveltable[height][height-2].index=1;
1037     }
1038
1039     for (i=0; i<height; i++) {
1040       leveltable[height][i].value = 
1041         (40.0 + levelfac[leveltable[height][i].index]*puramp(it, 3.0, 6.0, 1.0)) / 256.0;
1042     }
1043
1044   }
1045 }
1046
1047 static void
1048 analogtv_blast_imagerow(analogtv *it,
1049                         float *rgbf, float *rgbf_end,
1050                         int ytop, int ybot)
1051 {
1052   int i,j,x,y;
1053   float *rpf;
1054   char *level_copyfrom[3];
1055   int xrepl=it->xrepl;
1056   for (i=0; i<3; i++) level_copyfrom[i]=NULL;
1057
1058   for (y=ytop; y<ybot; y++) {
1059     int level=leveltable[ybot-ytop][y-ytop].index;
1060     double levelmult=leveltable[ybot-ytop][y-ytop].value;
1061     char *rowdata;
1062
1063     rowdata=it->image->data + y*it->image->bytes_per_line;
1064
1065     /* Fast special cases to avoid the slow XPutPixel. Ugh. It goes to show
1066        why standard graphics sw has to be fast, or else people will have to
1067        work around it and risk incompatibility. The quickdraw folks
1068        understood this. The other answer would be for X11 to have fewer
1069        formats for bitm.. oh, never mind. If neither of these cases work
1070        (they probably cover 99% of setups) it falls back on the Xlib
1071        routines. */
1072
1073     if (level_copyfrom[level]) {
1074       memcpy(rowdata, level_copyfrom[level], it->image->bytes_per_line);
1075     }
1076     else {
1077       level_copyfrom[level] = rowdata;
1078
1079       if (0) {
1080       }
1081       else if (it->image->format==ZPixmap &&
1082                it->image->bits_per_pixel==32 &&
1083                sizeof(unsigned int)==4 &&
1084                it->image->byte_order==localbyteorder) {
1085         /* int is more likely to be 32 bits than long */
1086         unsigned int *pixelptr=(unsigned int *)rowdata;
1087         unsigned int pix;
1088
1089         for (rpf=rgbf; rpf!=rgbf_end; rpf+=3) {
1090           int ntscri=rpf[0]*levelmult;
1091           int ntscgi=rpf[1]*levelmult;
1092           int ntscbi=rpf[2]*levelmult;
1093           if (ntscri>=ANALOGTV_CV_MAX) ntscri=ANALOGTV_CV_MAX-1;
1094           if (ntscgi>=ANALOGTV_CV_MAX) ntscgi=ANALOGTV_CV_MAX-1;
1095           if (ntscbi>=ANALOGTV_CV_MAX) ntscbi=ANALOGTV_CV_MAX-1;
1096           pix = (it->red_values[ntscri] |
1097                  it->green_values[ntscgi] |
1098                  it->blue_values[ntscbi]);
1099           pixelptr[0] = pix;
1100           if (xrepl>=2) {
1101             pixelptr[1] = pix;
1102             if (xrepl>=3) pixelptr[2] = pix;
1103           }
1104           pixelptr+=xrepl;
1105         }
1106       }
1107       else if (it->image->format==ZPixmap &&
1108                it->image->bits_per_pixel==16 &&
1109                sizeof(unsigned short)==2 &&
1110                float_extraction_works &&
1111                it->image->byte_order==localbyteorder) {
1112         unsigned short *pixelptr=(unsigned short *)rowdata;
1113         double r2,g2,b2;
1114         float_extract_t r1,g1,b1;
1115         unsigned short pix;
1116
1117         for (rpf=rgbf; rpf!=rgbf_end; rpf+=3) {
1118           r2=rpf[0]; g2=rpf[1]; b2=rpf[2];
1119           r1.f=r2 * levelmult+float_low8_ofs;
1120           g1.f=g2 * levelmult+float_low8_ofs;
1121           b1.f=b2 * levelmult+float_low8_ofs;
1122           pix = (it->red_values[r1.i & 0x3ff] |
1123                  it->green_values[g1.i & 0x3ff] |
1124                  it->blue_values[b1.i & 0x3ff]);
1125           pixelptr[0] = pix;
1126           if (xrepl>=2) {
1127             pixelptr[1] = pix;
1128             if (xrepl>=3) pixelptr[2] = pix;
1129           }
1130           pixelptr+=xrepl;
1131         }
1132       }
1133       else if (it->image->format==ZPixmap &&
1134                it->image->bits_per_pixel==16 &&
1135                sizeof(unsigned short)==2 &&
1136                it->image->byte_order==localbyteorder) {
1137         unsigned short *pixelptr=(unsigned short *)rowdata;
1138         unsigned short pix;
1139
1140         for (rpf=rgbf; rpf!=rgbf_end; rpf+=3) {
1141           int r1=rpf[0] * levelmult;
1142           int g1=rpf[1] * levelmult;
1143           int b1=rpf[2] * levelmult;
1144           if (r1>=ANALOGTV_CV_MAX) r1=ANALOGTV_CV_MAX-1;
1145           if (g1>=ANALOGTV_CV_MAX) g1=ANALOGTV_CV_MAX-1;
1146           if (b1>=ANALOGTV_CV_MAX) b1=ANALOGTV_CV_MAX-1;
1147           pix = it->red_values[r1] | it->green_values[g1] | it->blue_values[b1];
1148           pixelptr[0] = pix;
1149           if (xrepl>=2) {
1150             pixelptr[1] = pix;
1151             if (xrepl>=3) pixelptr[2] = pix;
1152           }
1153           pixelptr+=xrepl;
1154         }
1155       }
1156       else {
1157         for (x=0, rpf=rgbf; rpf!=rgbf_end ; x++, rpf+=3) {
1158           int ntscri=rpf[0]*levelmult;
1159           int ntscgi=rpf[1]*levelmult;
1160           int ntscbi=rpf[2]*levelmult;
1161           if (ntscri>=ANALOGTV_CV_MAX) ntscri=ANALOGTV_CV_MAX-1;
1162           if (ntscgi>=ANALOGTV_CV_MAX) ntscgi=ANALOGTV_CV_MAX-1;
1163           if (ntscbi>=ANALOGTV_CV_MAX) ntscbi=ANALOGTV_CV_MAX-1;
1164           for (j=0; j<xrepl; j++) {
1165             XPutPixel(it->image, x*xrepl + j, y,
1166                       it->red_values[ntscri] | it->green_values[ntscgi] |
1167                       it->blue_values[ntscbi]);
1168           }
1169         }
1170       }
1171     }
1172   }
1173 }
1174
1175 void
1176 analogtv_draw(analogtv *it)
1177 {
1178   int i,j,x,y,lineno;
1179   int scanstart_i,scanend_i,squishright_i,squishdiv,pixrate;
1180   float *rgb_start, *rgb_end;
1181   double pixbright;
1182   int pixmultinc;
1183   int bigloadchange,drawcount;
1184   double baseload;
1185   double puheight;
1186   int overall_top, overall_bot;
1187
1188   float *raw_rgb_start=(float *)calloc(it->subwidth*3, sizeof(float));
1189   float *raw_rgb_end=raw_rgb_start+3*it->subwidth;
1190   float *rrp;
1191
1192   analogtv_setup_frame(it);
1193   analogtv_set_demod(it);
1194
1195   /* rx_signal has an extra 2 lines at the end, where we copy the
1196      first 2 lines so we can index into it while only worrying about
1197      wraparound on a per-line level */
1198   memcpy(&it->rx_signal[ANALOGTV_SIGNAL_LEN],
1199          &it->rx_signal[0],
1200          2*ANALOGTV_H*sizeof(it->rx_signal[0]));
1201
1202   analogtv_sync(it);
1203
1204   baseload=0.5;
1205   /* if (it->hashnoise_on) baseload=0.5; */
1206
1207   bigloadchange=1;
1208   drawcount=0;
1209   it->crtload[ANALOGTV_TOP-1]=baseload;
1210   puheight = puramp(it, 2.0, 1.0, 1.3) * it->height_control *
1211     (1.125 - 0.125*puramp(it, 2.0, 2.0, 1.1));
1212
1213   analogtv_setup_levels(it, puheight * (double)it->useheight/(double)ANALOGTV_VISLINES);
1214
1215   overall_top=it->useheight;
1216   overall_bot=0;
1217
1218   for (lineno=ANALOGTV_TOP; lineno<ANALOGTV_BOT; lineno++) {
1219     int slineno=lineno-ANALOGTV_TOP;
1220     int ytop=(int)((slineno*it->useheight/ANALOGTV_VISLINES -
1221                     it->useheight/2)*puheight) + it->useheight/2;
1222     int ybot=(int)(((slineno+1)*it->useheight/ANALOGTV_VISLINES -
1223                     it->useheight/2)*puheight) + it->useheight/2;
1224 #if 0
1225     int linesig=analogtv_line_signature(input,lineno)
1226       + it->hashnoise_times[lineno];
1227 #endif
1228     double *signal=(it->rx_signal + ((lineno + it->cur_vsync +
1229                                       ANALOGTV_V)%ANALOGTV_V) * ANALOGTV_H +
1230                     it->line_hsync[lineno]);
1231
1232     if (ytop==ybot) continue;
1233     if (ybot<0 || ytop>it->useheight) continue;
1234     if (ytop<0) ytop=0;
1235     if (ybot>it->useheight) ybot=it->useheight;
1236
1237     if (ybot > ytop+MAX_LINEHEIGHT) ybot=ytop+MAX_LINEHEIGHT;
1238
1239     if (ytop < overall_top) overall_top=ytop;
1240     if (ybot > overall_bot) overall_bot=ybot;
1241
1242     if (lineno==it->shrinkpulse) {
1243       baseload += 0.4;
1244       bigloadchange=1;
1245       it->shrinkpulse=-1;
1246     }
1247
1248 #if 0
1249     if (it->hashnoise_rpm>0.0 &&
1250         !(bigloadchange ||
1251           it->redraw_all ||
1252           (slineno<20 && it->flutter_horiz_desync) ||
1253           it->gaussiannoise_level>30 ||
1254           ((it->gaussiannoise_level>2.0 ||
1255             it->multipath) && random()%4) ||
1256           linesig != it->onscreen_signature[lineno])) {
1257       continue;
1258     }
1259     it->onscreen_signature[lineno] = linesig;
1260 #endif
1261     drawcount++;
1262
1263     /*
1264       Interpolate the 600-dotclock line into however many horizontal
1265       screen pixels we're using, and convert to RGB.
1266
1267       We add some 'bloom', variations in the horizontal scan width with
1268       the amount of brightness, extremely common on period TV sets. They
1269       had a single oscillator which generated both the horizontal scan and
1270       (during the horizontal retrace interval) the high voltage for the
1271       electron beam. More brightness meant more load on the oscillator,
1272       which caused an decrease in horizontal deflection. Look for
1273       (bloomthisrow).
1274
1275       Also, the A2 did a bad job of generating horizontal sync pulses
1276       during the vertical blanking interval. This, and the fact that the
1277       horizontal frequency was a bit off meant that TVs usually went a bit
1278       out of sync during the vertical retrace, and the top of the screen
1279       would be bent a bit to the left or right. Look for (shiftthisrow).
1280
1281       We also add a teeny bit of left overscan, just enough to be
1282       annoying, but you can still read the left column of text.
1283
1284       We also simulate compression & brightening on the right side of the
1285       screen. Most TVs do this, but you don't notice because they overscan
1286       so it's off the right edge of the CRT. But the A2 video system used
1287       so much of the horizontal scan line that you had to crank the
1288       horizontal width down in order to not lose the right few characters,
1289       and you'd see the compression on the right edge. Associated with
1290       compression is brightening; since the electron beam was scanning
1291       slower, the same drive signal hit the phosphor harder. Look for
1292       (squishright_i) and (squishdiv).
1293     */
1294
1295     {
1296       int totsignal=0;
1297       double ncl,diff;
1298
1299       for (i=0; i<ANALOGTV_PIC_LEN; i++) {
1300         totsignal += signal[i];
1301       }
1302       totsignal *= it->agclevel;
1303       ncl = 0.95 * it->crtload[lineno-1] +
1304         0.05*(baseload +
1305               (totsignal-30000)/100000.0 +
1306               (slineno>184 ? (slineno-184)*(lineno-184)*0.001 * it->squeezebottom
1307                : 0.0));
1308       diff=ncl - it->crtload[lineno];
1309       bigloadchange = (diff>0.01 || diff<-0.01);
1310       it->crtload[lineno]=ncl;
1311     }
1312
1313     {
1314       double bloomthisrow,shiftthisrow;
1315       double viswidth,middle;
1316       double scanwidth;
1317       int scw,scl,scr;
1318
1319       bloomthisrow = -10.0 * it->crtload[lineno];
1320       if (bloomthisrow<-10.0) bloomthisrow=-10.0;
1321       if (bloomthisrow>2.0) bloomthisrow=2.0;
1322       if (slineno<16) {
1323         shiftthisrow=it->horiz_desync * (exp(-0.17*slineno) *
1324                                          (0.7+cos(slineno*0.6)));
1325       } else {
1326         shiftthisrow=0.0;
1327       }
1328
1329       viswidth=ANALOGTV_PIC_LEN * 0.79 - 5.0*bloomthisrow;
1330       middle=ANALOGTV_PIC_LEN/2 - shiftthisrow;
1331
1332       scanwidth=it->width_control * puramp(it, 0.5, 0.3, 1.0);
1333
1334       scw=it->subwidth*scanwidth;
1335       if (scw>it->subwidth) scw=it->usewidth;
1336       scl=it->subwidth/2 - scw/2;
1337       scr=it->subwidth/2 + scw/2;
1338
1339       pixrate=(int)((viswidth*65536.0*1.0)/it->subwidth)/scanwidth;
1340       scanstart_i=(int)((middle-viswidth*0.5)*65536.0);
1341       scanend_i=(ANALOGTV_PIC_LEN-1)*65536;
1342       squishright_i=(int)((middle+viswidth*(0.25 + 0.25*puramp(it, 2.0, 0.0, 1.1)
1343                                             - it->squish_control)) *65536.0);
1344       squishdiv=it->subwidth/15;
1345
1346       rgb_start=raw_rgb_start+scl*3;
1347       rgb_end=raw_rgb_start+scr*3;
1348
1349       assert(scanstart_i>=0);
1350
1351 #ifdef DEBUG
1352       if (0) printf("scan %d: %0.3f %0.3f %0.3f scl=%d scr=%d scw=%d\n",
1353                     lineno,
1354                     scanstart_i/65536.0,
1355                     squishright_i/65536.0,
1356                     scanend_i/65536.0,
1357                     scl,scr,scw);
1358 #endif
1359     }
1360
1361     if (it->use_cmap) {
1362       for (y=ytop; y<ybot; y++) {
1363         int level=analogtv_level(it, y, ytop, ybot);
1364         double levelmult=analogtv_levelmult(it, level);
1365         double levelmult_y = levelmult * it->contrast_control
1366           * puramp(it, 1.0, 0.0, 1.0) / (0.5+0.5*puheight) * 0.070;
1367         double levelmult_iq = levelmult * 0.090;
1368
1369         struct analogtv_yiq_s *yiq=it->yiq;
1370         analogtv_ntsc_to_yiq(it, lineno, signal,
1371                              (scanstart_i>>16)-10, (scanend_i>>16)+10);
1372         pixmultinc=pixrate;
1373
1374         x=0;
1375         i=scanstart_i;
1376         while (i<0 && x<it->usewidth) {
1377           XPutPixel(it->image, x, y, it->colors[0]);
1378           i+=pixmultinc;
1379           x++;
1380         }
1381
1382         while (i<scanend_i && x<it->usewidth) {
1383           double pixfrac=(i&0xffff)/65536.0;
1384           double invpixfrac=(1.0-pixfrac);
1385           int pati=i>>16;
1386           int yli,ili,qli,cmi;
1387
1388           double interpy=(yiq[pati].y*invpixfrac
1389                           + yiq[pati+1].y*pixfrac) * levelmult_y;
1390           double interpi=(yiq[pati].i*invpixfrac
1391                           + yiq[pati+1].i*pixfrac) * levelmult_iq;
1392           double interpq=(yiq[pati].q*invpixfrac
1393                           + yiq[pati+1].q*pixfrac) * levelmult_iq;
1394
1395           yli = (int)(interpy * it->cmap_y_levels);
1396           ili = (int)((interpi+0.5) * it->cmap_i_levels);
1397           qli = (int)((interpq+0.5) * it->cmap_q_levels);
1398           if (yli<0) yli=0;
1399           if (yli>=it->cmap_y_levels) yli=it->cmap_y_levels-1;
1400           if (ili<0) ili=0;
1401           if (ili>=it->cmap_i_levels) ili=it->cmap_i_levels-1;
1402           if (qli<0) qli=0;
1403           if (qli>=it->cmap_q_levels) qli=it->cmap_q_levels-1;
1404
1405           cmi=qli + it->cmap_i_levels*(ili + it->cmap_q_levels*yli);
1406
1407 #ifdef DEBUG
1408           if ((random()%65536)==0) {
1409             printf("%0.3f %0.3f %0.3f => %d %d %d => %d\n",
1410                    interpy, interpi, interpq,
1411                    yli, ili, qli,
1412                    cmi);
1413           }
1414 #endif
1415
1416           for (j=0; j<it->xrepl; j++) {
1417             XPutPixel(it->image, x, y,
1418                       it->colors[cmi]);
1419             x++;
1420           }
1421           if (i >= squishright_i) {
1422             pixmultinc += pixmultinc/squishdiv;
1423           }
1424           i+=pixmultinc;
1425         }
1426         while (x<it->usewidth) {
1427           XPutPixel(it->image, x, y, it->colors[0]);
1428           x++;
1429         }
1430       }
1431     }
1432     else {
1433       struct analogtv_yiq_s *yiq=it->yiq;
1434       analogtv_ntsc_to_yiq(it, lineno, signal,
1435                            (scanstart_i>>16)-10, (scanend_i>>16)+10);
1436
1437       pixbright=it->contrast_control * puramp(it, 1.0, 0.0, 1.0)
1438         / (0.5+0.5*puheight) * 1024.0/100.0;
1439       pixmultinc=pixrate;
1440       i=scanstart_i; rrp=rgb_start;
1441       while (i<0 && rrp!=rgb_end) {
1442         rrp[0]=rrp[1]=rrp[2]=0;
1443         i+=pixmultinc;
1444         rrp+=3;
1445       }
1446       while (i<scanend_i && rrp!=rgb_end) {
1447         double pixfrac=(i&0xffff)/65536.0;
1448         double invpixfrac=1.0-pixfrac;
1449         int pati=i>>16;
1450         double r,g,b;
1451
1452         double interpy=(yiq[pati].y*invpixfrac + yiq[pati+1].y*pixfrac);
1453         double interpi=(yiq[pati].i*invpixfrac + yiq[pati+1].i*pixfrac);
1454         double interpq=(yiq[pati].q*invpixfrac + yiq[pati+1].q*pixfrac);
1455
1456         /*
1457           According to the NTSC spec, Y,I,Q are generated as:
1458
1459           y=0.30 r + 0.59 g + 0.11 b
1460           i=0.60 r - 0.28 g - 0.32 b
1461           q=0.21 r - 0.52 g + 0.31 b
1462
1463           So if you invert the implied 3x3 matrix you get what standard
1464           televisions implement with a bunch of resistors (or directly in the
1465           CRT -- don't ask):
1466
1467           r = y + 0.948 i + 0.624 q
1468           g = y - 0.276 i - 0.639 q
1469           b = y - 1.105 i + 1.729 q
1470         */
1471
1472         r=(interpy + 0.948*interpi + 0.624*interpq) * pixbright;
1473         g=(interpy - 0.276*interpi - 0.639*interpq) * pixbright;
1474         b=(interpy - 1.105*interpi + 1.729*interpq) * pixbright;
1475         if (r<0.0) r=0.0;
1476         if (g<0.0) g=0.0;
1477         if (b<0.0) b=0.0;
1478         rrp[0]=r;
1479         rrp[1]=g;
1480         rrp[2]=b;
1481
1482         if (i>=squishright_i) {
1483           pixmultinc += pixmultinc/squishdiv;
1484           pixbright += pixbright/squishdiv/2;
1485         }
1486         i+=pixmultinc;
1487         rrp+=3;
1488       }
1489       while (rrp != rgb_end) {
1490         rrp[0]=rrp[1]=rrp[2]=0.0;
1491         rrp+=3;
1492       }
1493
1494       analogtv_blast_imagerow(it, raw_rgb_start, raw_rgb_end,
1495                               ytop,ybot);
1496     }
1497   }
1498   free(raw_rgb_start);
1499
1500 #if 0
1501   /* poor attempt at visible retrace */
1502   for (i=0; i<15; i++) {
1503     int ytop=(int)((i*it->useheight/15 -
1504                     it->useheight/2)*puheight) + it->useheight/2;
1505     int ybot=(int)(((i+1)*it->useheight/15 -
1506                     it->useheight/2)*puheight) + it->useheight/2;
1507     int div=it->usewidth*3/2;
1508
1509     for (x=0; x<it->usewidth; x++) {
1510       y = ytop + (ybot-ytop)*x / div;
1511       if (y<0 || y>=it->useheight) continue;
1512       XPutPixel(it->image, x, y, 0xffffff);
1513     }
1514   }
1515 #endif
1516
1517   if (it->need_clear) {
1518     XClearWindow(it->dpy, it->window);
1519     it->need_clear=0;
1520   }
1521
1522   if (overall_top>0) {
1523     XClearArea(it->dpy, it->window,
1524                it->screen_xo, it->screen_yo,
1525                it->usewidth, overall_top, 0);
1526   }
1527   if (it->useheight > overall_bot) {
1528     XClearArea(it->dpy, it->window,
1529                it->screen_xo, it->screen_yo+overall_bot,
1530                it->usewidth, it->useheight-overall_bot, 0);
1531   }
1532
1533   if (overall_bot > overall_top) {
1534     if (it->use_shm) {
1535 #ifdef HAVE_XSHM_EXTENSION
1536       XShmPutImage(it->dpy, it->window, it->gc, it->image,
1537                    0, overall_top,
1538                    it->screen_xo, it->screen_yo+overall_top,
1539                    it->usewidth, overall_bot - overall_top,
1540                    False);
1541 #endif
1542     } else {
1543       XPutImage(it->dpy, it->window, it->gc, it->image,
1544                 0, overall_top,
1545                 it->screen_xo, it->screen_yo+overall_top,
1546                 it->usewidth, overall_bot - overall_top);
1547     }
1548   }
1549
1550 #ifdef DEBUG
1551   if (0) {
1552     struct timeval tv;
1553     double fps;
1554     char buf[256];
1555     gettimeofday(&tv,NULL);
1556
1557     fps=1.0/((tv.tv_sec - it->last_display_time.tv_sec)
1558              + 0.000001*(tv.tv_usec - it->last_display_time.tv_usec));
1559     sprintf(buf, "FPS=%0.1f",fps);
1560     XDrawString(it->dpy, it->window, it->gc, 50, it->useheight*2/3,
1561                 buf, strlen(buf));
1562
1563     it->last_display_time=tv;
1564   }
1565 #endif
1566
1567   XSync(it->dpy,0);
1568 }
1569
1570 analogtv_input *
1571 analogtv_input_allocate()
1572 {
1573   analogtv_input *ret=(analogtv_input *)calloc(1,sizeof(analogtv_input));
1574
1575   return ret;
1576 }
1577
1578 /*
1579   This takes a screen image and encodes it as a video camera would,
1580   including all the bandlimiting and YIQ modulation.
1581   This isn't especially tuned for speed.
1582 */
1583
1584 int
1585 analogtv_load_ximage(analogtv *it, analogtv_input *input, XImage *pic_im)
1586 {
1587   int i,x,y;
1588   int img_w,img_h;
1589   int fyx[7],fyy[7];
1590   int fix[4],fiy[4];
1591   int fqx[4],fqy[4];
1592   XColor col1[ANALOGTV_PIC_LEN];
1593   XColor col2[ANALOGTV_PIC_LEN];
1594   int multiq[ANALOGTV_PIC_LEN+4];
1595   int y_overscan=5; /* overscan this much top and bottom */
1596   int y_scanlength=ANALOGTV_VISLINES+2*y_overscan;
1597
1598   img_w=pic_im->width;
1599   img_h=pic_im->height;
1600
1601   for (i=0; i<ANALOGTV_PIC_LEN+4; i++) {
1602     double phase=90.0-90.0*i;
1603     double ampl=1.0;
1604     multiq[i]=(int)(-cos(3.1415926/180.0*(phase-303)) * 4096.0 * ampl);
1605   }
1606
1607   for (y=0; y<y_scanlength; y++) {
1608     int picy1=(y*img_h)/y_scanlength;
1609     int picy2=(y*img_h + y_scanlength/2)/y_scanlength;
1610
1611     for (x=0; x<ANALOGTV_PIC_LEN; x++) {
1612       int picx=(x*img_w)/ANALOGTV_PIC_LEN;
1613       col1[x].pixel=XGetPixel(pic_im, picx, picy1);
1614       col2[x].pixel=XGetPixel(pic_im, picx, picy2);
1615     }
1616     XQueryColors(it->dpy, it->colormap, col1, ANALOGTV_PIC_LEN);
1617     XQueryColors(it->dpy, it->colormap, col2, ANALOGTV_PIC_LEN);
1618
1619     for (i=0; i<7; i++) fyx[i]=fyy[i]=0;
1620     for (i=0; i<4; i++) fix[i]=fiy[i]=fqx[i]=fqy[i]=0.0;
1621
1622     for (x=0; x<ANALOGTV_PIC_LEN; x++) {
1623       int rawy,rawi,rawq;
1624       int filty,filti,filtq;
1625       int composite;
1626       /* Compute YIQ as:
1627            y=0.30 r + 0.59 g + 0.11 b
1628            i=0.60 r - 0.28 g - 0.32 b
1629            q=0.21 r - 0.52 g + 0.31 b
1630           The coefficients below are in .4 format */
1631
1632       rawy=( 5*col1[x].red + 11*col1[x].green + 2*col1[x].blue +
1633              5*col2[x].red + 11*col2[x].green + 2*col2[x].blue)>>7;
1634       rawi=(10*col1[x].red -  4*col1[x].green - 5*col1[x].blue +
1635             10*col2[x].red -  4*col2[x].green - 5*col2[x].blue)>>7;
1636       rawq=( 3*col1[x].red -  8*col1[x].green + 5*col1[x].blue +
1637              3*col2[x].red -  8*col2[x].green + 5*col2[x].blue)>>7;
1638
1639       /* Filter y at with a 4-pole low-pass Butterworth filter at 3.5 MHz
1640          with an extra zero at 3.5 MHz, from
1641          mkfilter -Bu -Lp -o 4 -a 2.1428571429e-01 0 -Z 2.5e-01 -l */
1642
1643       fyx[0] = fyx[1]; fyx[1] = fyx[2]; fyx[2] = fyx[3];
1644       fyx[3] = fyx[4]; fyx[4] = fyx[5]; fyx[5] = fyx[6];
1645       fyx[6] = (rawy * 1897) >> 16;
1646       fyy[0] = fyy[1]; fyy[1] = fyy[2]; fyy[2] = fyy[3];
1647       fyy[3] = fyy[4]; fyy[4] = fyy[5]; fyy[5] = fyy[6];
1648       fyy[6] = (fyx[0]+fyx[6]) + 4*(fyx[1]+fyx[5]) + 7*(fyx[2]+fyx[4]) + 8*fyx[3]
1649         + ((-151*fyy[2] + 8115*fyy[3] - 38312*fyy[4] + 36586*fyy[5]) >> 16);
1650       filty = fyy[6];
1651
1652       /* Filter I at 1.5 MHz. 3 pole Butterworth from
1653          mkfilter -Bu -Lp -o 3 -a 1.0714285714e-01 0 */
1654
1655       fix[0] = fix[1]; fix[1] = fix[2]; fix[2] = fix[3];
1656       fix[3] = (rawi * 1413) >> 16;
1657       fiy[0] = fiy[1]; fiy[1] = fiy[2]; fiy[2] = fiy[3];
1658       fiy[3] = (fix[0]+fix[3]) + 3*(fix[1]+fix[2])
1659         + ((16559*fiy[0] - 72008*fiy[1] + 109682*fiy[2]) >> 16);
1660       filti = fiy[3];
1661
1662       /* Filter Q at 0.5 MHz. 3 pole Butterworth from
1663          mkfilter -Bu -Lp -o 3 -a 3.5714285714e-02 0 -l */
1664
1665       fqx[0] = fqx[1]; fqx[1] = fqx[2]; fqx[2] = fqx[3];
1666       fqx[3] = (rawq * 75) >> 16;
1667       fqy[0] = fqy[1]; fqy[1] = fqy[2]; fqy[2] = fqy[3];
1668       fqy[3] = (fqx[0]+fqx[3]) + 3 * (fqx[1]+fqx[2])
1669         + ((2612*fqy[0] - 9007*fqy[1] + 10453 * fqy[2]) >> 12);
1670       filtq = fqy[3];
1671
1672
1673       composite = filty + ((multiq[x] * filti + multiq[x+3] * filtq)>>12);
1674       composite = ((composite*100)>>14) + ANALOGTV_BLACK_LEVEL;
1675       if (composite>125) composite=125;
1676       if (composite<0) composite=0;
1677       input->signal[y-y_overscan+ANALOGTV_TOP][x+ANALOGTV_PIC_START] = composite;
1678     }
1679   }
1680
1681   return 1;
1682 }
1683
1684 #if 0
1685 void analogtv_channel_noise(analogtv_input *it, analogtv_input *s2)
1686 {
1687   int x,y,newsig;
1688   int change=random()%ANALOGTV_V;
1689   unsigned int fastrnd=random();
1690   double hso=(int)(random()%1000)-500;
1691   int yofs=random()%ANALOGTV_V;
1692   int noise;
1693
1694   for (y=change; y<ANALOGTV_V; y++) {
1695     int s2y=(y+yofs)%ANALOGTV_V;
1696     int filt=0;
1697     int noiselevel=60000 / (y-change+100);
1698
1699     it->line_hsync[y] = s2->line_hsync[y] + (int)hso;
1700     hso *= 0.9;
1701     for (x=0; x<ANALOGTV_H; x++) {
1702       FASTRND;
1703       filt+= (-filt/16) + (int)(fastrnd&0xfff)-0x800;
1704       noise=(filt*noiselevel)>>16;
1705       newsig=s2->signal[s2y][x] + noise;
1706       if (newsig>120) newsig=120;
1707       if (newsig<0) newsig=0;
1708       it->signal[y][x]=newsig;
1709     }
1710   }
1711   s2->vsync=yofs;
1712 }
1713 #endif
1714
1715
1716 void analogtv_add_signal(analogtv *it, analogtv_reception *rec)
1717 {
1718   analogtv_input *inp=rec->input;
1719   double *ps=it->rx_signal;
1720   double *pe=it->rx_signal + ANALOGTV_SIGNAL_LEN;
1721   double *p=ps;
1722   char *ss=&inp->signal[0][0];
1723   char *se=&inp->signal[0][0] + ANALOGTV_SIGNAL_LEN;
1724   char *s=ss + ((unsigned)rec->ofs % ANALOGTV_SIGNAL_LEN);
1725   int i;
1726   int ec=it->channel_change_cycles;
1727   double level=rec->level;
1728   double hfloss=rec->hfloss;
1729   unsigned int fastrnd=random();
1730   double dp[8];
1731
1732   /* assert((se-ss)%4==0 && (se-s)%4==0); */
1733
1734   /* duplicate the first line into the Nth line to ease wraparound computation */
1735   memcpy(inp->signal[ANALOGTV_V], inp->signal[0],
1736          ANALOGTV_H * sizeof(inp->signal[0][0]));
1737
1738   for (i=0; i<8; i++) dp[i]=0.0;
1739
1740   if (ec) {
1741     double noise_ampl;
1742
1743     /* Do a big noisy transition. We can make the transition noise of
1744        high constant strength regardless of signal strength.
1745
1746        There are two separate state machines. here, One is the noise
1747        process and the other is the
1748
1749        We don't bother with the FIR filter here
1750     */
1751
1752     noise_ampl = 1.3;
1753
1754     while (p!=pe && ec>0) {
1755
1756       double sig0=(double)s[0];
1757       double noise = ((int)fastrnd-(int)0x7fffffff) * (50.0/(double)0x7fffffff);
1758       fastrnd = (fastrnd*1103515245+12345) & 0xffffffffu;
1759
1760       p[0] += sig0 * level * (1.0 - noise_ampl) + noise * noise_ampl;
1761
1762       noise_ampl *= 0.99995;
1763
1764       p++;
1765       s++;
1766       if (s>=se) s=ss;
1767       ec--;
1768     }
1769
1770   }
1771
1772   while (p != pe) {
1773     double sig0,sig1,sig2,sig3,sigr;
1774
1775     sig0=(double)s[0];
1776     sig1=(double)s[1];
1777     sig2=(double)s[2];
1778     sig3=(double)s[3];
1779
1780     dp[0]=sig0+sig1+sig2+sig3;
1781
1782     /* Get the video out signal, and add some ghosting, typical of RF
1783        monitor cables. This corresponds to a pretty long cable, but
1784        looks right to me.
1785     */
1786
1787     sigr=(dp[1]*rec->ghostfir[0] + dp[2]*rec->ghostfir[1] +
1788           dp[3]*rec->ghostfir[2] + dp[4]*rec->ghostfir[3]);
1789     dp[4]=dp[3]; dp[3]=dp[2]; dp[2]=dp[1]; dp[1]=dp[0];
1790
1791     p[0] += (sig0+sigr + sig2*hfloss) * level;
1792     p[1] += (sig1+sigr + sig3*hfloss) * level;
1793     p[2] += (sig2+sigr + sig0*hfloss) * level;
1794     p[3] += (sig3+sigr + sig1*hfloss) * level;
1795
1796     p += 4;
1797     s += 4;
1798     if (s>=se) s = ss + (s-se);
1799   }
1800
1801   it->rx_signal_level =
1802     sqrt(it->rx_signal_level * it->rx_signal_level +
1803          (level * level * (1.0 + 4.0*(rec->ghostfir[0] + rec->ghostfir[1] +
1804                                       rec->ghostfir[2] + rec->ghostfir[3]))));
1805
1806
1807   it->channel_change_cycles=0;
1808
1809 }
1810
1811 #ifdef FIXME
1812 /* add hash */
1813   if (it->hashnoise_times[lineno]) {
1814     int hnt=it->hashnoise_times[lineno] - input->line_hsync[lineno];
1815
1816     if (hnt>=0 && hnt<ANALOGTV_PIC_LEN) {
1817       double maxampl=1.0;
1818       double cur=frand(150.0)-20.0;
1819       int len=random()%15+3;
1820       if (len > ANALOGTV_PIC_LEN-hnt) len=ANALOGTV_PIC_LEN-hnt;
1821       for (i=0; i<len; i++) {
1822         double sig=signal[hnt];
1823
1824         sig += cur*maxampl;
1825         cur += frand(5.0)-5.0;
1826         maxampl = maxampl*0.9;
1827
1828         signal[hnt]=sig;
1829         hnt++;
1830       }
1831     }
1832   }
1833 #endif
1834
1835
1836 void analogtv_init_signal(analogtv *it, double noiselevel)
1837 {
1838   double *ps=it->rx_signal;
1839   double *pe=it->rx_signal + ANALOGTV_SIGNAL_LEN;
1840   double *p=ps;
1841   unsigned int fastrnd=random();
1842   double nm1=0.0,nm2=0.0;
1843   double noisemul = sqrt(noiselevel*150)/(double)0x7fffffff;
1844
1845   while (p != pe) {
1846     nm2=nm1;
1847     nm1 = ((int)fastrnd-(int)0x7fffffff) * noisemul;
1848     *p++ = nm1*nm2;
1849     fastrnd = (fastrnd*1103515245+12345) & 0xffffffffu;
1850   }
1851
1852   it->rx_signal_level = noiselevel;
1853 }
1854
1855 void
1856 analogtv_reception_update(analogtv_reception *rec)
1857 {
1858   int i;
1859
1860   if (rec->multipath > 0.0) {
1861     for (i=0; i<ANALOGTV_GHOSTFIR_LEN; i++) {
1862       rec->ghostfir2[i] +=
1863         -(rec->ghostfir2[i]/16.0) + rec->multipath * (frand(0.02)-0.01);
1864     }
1865     if (random()%20==0) {
1866       rec->ghostfir2[random()%(ANALOGTV_GHOSTFIR_LEN)]
1867         = rec->multipath * (frand(0.08)-0.04);
1868     }
1869     for (i=0; i<ANALOGTV_GHOSTFIR_LEN; i++) {
1870       rec->ghostfir[i] = 0.8*rec->ghostfir[i] + 0.2*rec->ghostfir2[i];
1871     }
1872
1873     if (0) {
1874       rec->hfloss2 += -(rec->hfloss2/16.0) + rec->multipath * (frand(0.08)-0.04);
1875       rec->hfloss = 0.5*rec->hfloss + 0.5*rec->hfloss2;
1876     }
1877
1878   } else {
1879     for (i=0; i<ANALOGTV_GHOSTFIR_LEN; i++) {
1880       rec->ghostfir[i] = (i>=ANALOGTV_GHOSTFIR_LEN/2) ? ((i&1) ? +0.04 : -0.08) /ANALOGTV_GHOSTFIR_LEN
1881         : 0.0;
1882     }
1883   }
1884 }
1885
1886
1887 void
1888 analogtv_make_font(Display *dpy, Window window, analogtv_font *f,
1889                    int w, int h, char *fontname)
1890 {
1891   int i;
1892   XFontStruct *font;
1893   Pixmap text_pm;
1894   GC gc;
1895   XGCValues gcv;
1896   XWindowAttributes xgwa;
1897
1898   f->char_w = w;
1899   f->char_h = h;
1900
1901   XGetWindowAttributes (dpy, window, &xgwa);
1902
1903   if (fontname) {
1904
1905     font = XLoadQueryFont (dpy, fontname);
1906     if (!font) {
1907       fprintf(stderr, "analogtv: can't load font %s\n", fontname);
1908       abort();
1909     }
1910
1911     text_pm=XCreatePixmap(dpy, window, 128*f->char_w, f->char_h, xgwa.depth);
1912
1913     memset(&gcv, 0, sizeof(gcv));
1914     gcv.foreground=1;
1915     gcv.background=0;
1916     gcv.font=font->fid;
1917     gc=XCreateGC(dpy, text_pm, GCFont|GCBackground|GCForeground, &gcv);
1918
1919     XSetForeground(dpy, gc, 0);
1920     XFillRectangle(dpy, text_pm, gc, 0, 0, 128*f->char_w, f->char_h);
1921     XSetForeground(dpy, gc, 1);
1922     /* Just ASCII */
1923     for (i=0; i<128; i++) {
1924       char c=i;
1925       int x=f->char_w*i+1;
1926       int y=f->char_h*8/10;
1927       XDrawString(dpy, text_pm, gc, x, y, &c, 1);
1928     }
1929     f->text_im = XGetImage(dpy, text_pm, 0, 0, 128*f->char_w, f->char_h,
1930                            ~0L, ZPixmap);
1931     XFreeGC(dpy, gc);
1932     XFreePixmap(dpy, text_pm);
1933   } else {
1934     f->text_im = XCreateImage(dpy, xgwa.visual, xgwa.depth,
1935                               ZPixmap, 0, 0,
1936                               128*f->char_w, f->char_h, 8, 0);
1937     f->text_im->data = (char *)calloc(f->text_im->height,
1938                                       f->text_im->bytes_per_line);
1939
1940   }
1941   f->x_mult=4;
1942   f->y_mult=2;
1943 }
1944
1945 int
1946 analogtv_font_pixel(analogtv_font *f, int c, int x, int y)
1947 {
1948   if (x<0 || x>=f->char_w) return 0;
1949   if (y<0 || y>=f->char_h) return 0;
1950   if (c<0 || c>=128) return 0;
1951   return XGetPixel(f->text_im, c*f->char_w + x, y) ? 1 : 0;
1952 }
1953
1954 void
1955 analogtv_font_set_pixel(analogtv_font *f, int c, int x, int y, int value)
1956 {
1957   if (x<0 || x>=f->char_w) return;
1958   if (y<0 || y>=f->char_h) return;
1959   if (c<0 || c>=128) return;
1960
1961   XPutPixel(f->text_im, c*f->char_w + x, y, value);
1962 }
1963
1964 void
1965 analogtv_font_set_char(analogtv_font *f, int c, char *s)
1966 {
1967   int value,x,y;
1968
1969   if (c<0 || c>=128) return;
1970
1971   for (y=0; y<f->char_h; y++) {
1972     for (x=0; x<f->char_w; x++) {
1973       if (!*s) return;
1974       value=(*s==' ') ? 0 : 1;
1975       analogtv_font_set_pixel(f, c, x, y, value);
1976       s++;
1977     }
1978   }
1979 }
1980
1981 void
1982 analogtv_lcp_to_ntsc(double luma, double chroma, double phase, int ntsc[4])
1983 {
1984   int i;
1985   for (i=0; i<4; i++) {
1986     double w=90.0*i + phase;
1987     double val=luma + chroma * (cos(3.1415926/180.0*w));
1988     if (val<0.0) val=0.0;
1989     if (val>127.0) val=127.0;
1990     ntsc[i]=(int)val;
1991   }
1992 }
1993
1994 void
1995 analogtv_draw_solid(analogtv_input *input,
1996                     int left, int right, int top, int bot,
1997                     int ntsc[4])
1998 {
1999   int x,y;
2000
2001   if (right-left<4) right=left+4;
2002   if (bot-top<1) bot=top+1;
2003
2004   for (y=top; y<bot; y++) {
2005     for (x=left; x<right; x++) {
2006       input->signal[y][x] = ntsc[x&3];
2007     }
2008   }
2009 }
2010
2011
2012 void
2013 analogtv_draw_solid_rel_lcp(analogtv_input *input,
2014                             double left, double right, double top, double bot,
2015                             double luma, double chroma, double phase)
2016 {
2017   int ntsc[4];
2018
2019   int topi=(int)(ANALOGTV_TOP + ANALOGTV_VISLINES*top);
2020   int boti=(int)(ANALOGTV_TOP + ANALOGTV_VISLINES*bot);
2021   int lefti=(int)(ANALOGTV_VIS_START + ANALOGTV_VIS_LEN*left);
2022   int righti=(int)(ANALOGTV_VIS_START + ANALOGTV_VIS_LEN*right);
2023
2024   analogtv_lcp_to_ntsc(luma, chroma, phase, ntsc);
2025   analogtv_draw_solid(input, lefti, righti, topi, boti, ntsc);
2026 }
2027
2028
2029 void
2030 analogtv_draw_char(analogtv_input *input, analogtv_font *f,
2031                    int c, int x, int y, int ntsc[4])
2032 {
2033   int yc,xc,ys,xs,pix;
2034
2035   for (yc=0; yc<f->char_h; yc++) {
2036     for (ys=y + yc*f->y_mult; ys<y + (yc+1)*f->y_mult; ys++) {
2037       if (ys<0 || ys>=ANALOGTV_V) continue;
2038
2039       for (xc=0; xc<f->char_w; xc++) {
2040         pix=analogtv_font_pixel(f, c, xc, yc);
2041
2042         for (xs=x + xc*f->x_mult; xs<x + (xc+1)*f->x_mult; xs++) {
2043           if (xs<0 || xs>=ANALOGTV_H) continue;
2044           if (pix) {
2045             input->signal[ys][xs] = ntsc[xs&3];
2046           }
2047         }
2048       }
2049     }
2050   }
2051 }
2052
2053 void
2054 analogtv_draw_string(analogtv_input *input, analogtv_font *f,
2055                      char *s, int x, int y, int ntsc[4])
2056 {
2057   while (*s) {
2058     analogtv_draw_char(input, f, *s, x, y, ntsc);
2059     x += f->char_w * 4;
2060     s++;
2061   }
2062 }
2063
2064 void
2065 analogtv_draw_string_centered(analogtv_input *input, analogtv_font *f,
2066                               char *s, int x, int y, int ntsc[4])
2067 {
2068   int width=strlen(s) * f->char_w * 4;
2069   x -= width/2;
2070
2071   analogtv_draw_string(input, f, s, x, y, ntsc);
2072 }
2073
2074
2075 static const char hextonib[128] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2076                                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2077                                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2078                                    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0,
2079                                    0, 10,11,12,13,14,15,0, 0, 0, 0, 0, 0, 0, 0, 0,
2080                                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2081                                    0, 10,11,12,13,14,15,0, 0, 0, 0, 0, 0, 0, 0, 0,
2082                                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
2083
2084 /*
2085   Much of this function was adapted from logo.c
2086  */
2087 void
2088 analogtv_draw_xpm(analogtv *tv, analogtv_input *input,
2089                   const char * const *xpm, int left, int top)
2090 {
2091   int xpmw,xpmh;
2092   int x,y,tvx,tvy,i;
2093   int rawy,rawi,rawq;
2094   int ncolors, nbytes;
2095   char dummyc;
2096   struct {
2097     int r; int g; int b;
2098   } cmap[256];
2099
2100
2101   if (4 != sscanf ((const char *) *xpm,
2102                    "%d %d %d %d %c",
2103                    &xpmw, &xpmh, &ncolors, &nbytes, &dummyc))
2104     abort();
2105   if (ncolors < 1 || ncolors > 255)
2106     abort();
2107   if (nbytes != 1) /* a serious limitation */
2108     abort();
2109   xpm++;
2110
2111   for (i = 0; i < ncolors; i++) {
2112     const char *line = *xpm;
2113     int colori = ((unsigned char)*line++)&0xff;
2114     while (*line)
2115       {
2116         int r, g, b;
2117         char which;
2118         while (*line == ' ' || *line == '\t')
2119           line++;
2120         which = *line++;
2121         if (which != 'c' && which != 'm')
2122           abort();
2123         while (*line == ' ' || *line == '\t')
2124           line++;
2125         if (!strncasecmp(line, "None", 4))
2126           {
2127             r = g = b = -1;
2128             line += 4;
2129           }
2130         else
2131           {
2132             if (*line == '#')
2133               line++;
2134             r = (hextonib[(int) line[0]] << 4) | hextonib[(int) line[1]];
2135             line += 2;
2136             g = (hextonib[(int) line[0]] << 4) | hextonib[(int) line[1]];
2137             line += 2;
2138             b = (hextonib[(int) line[0]] << 4) | hextonib[(int) line[1]];
2139             line += 2;
2140           }
2141
2142         if (which == 'c')
2143           {
2144             cmap[colori].r = r;
2145             cmap[colori].g = g;
2146             cmap[colori].b = b;
2147           }
2148       }
2149
2150     xpm++;
2151   }
2152
2153   for (y=0; y<xpmh; y++) {
2154     const char *line = *xpm++;
2155     tvy=y+top;
2156     if (tvy<ANALOGTV_TOP || tvy>=ANALOGTV_BOT) continue;
2157
2158     for (x=0; x<xpmw; x++) {
2159       int cbyte=((unsigned char)line[x])&0xff;
2160       int ntsc[4];
2161       tvx=x*4+left;
2162       if (tvx<ANALOGTV_PIC_START || tvx+4>ANALOGTV_PIC_END) continue;
2163
2164       rawy=( 5*cmap[cbyte].r + 11*cmap[cbyte].g + 2*cmap[cbyte].b) / 64;
2165       rawi=(10*cmap[cbyte].r -  4*cmap[cbyte].g - 5*cmap[cbyte].b) / 64;
2166       rawq=( 3*cmap[cbyte].r -  8*cmap[cbyte].g + 5*cmap[cbyte].b) / 64;
2167
2168       ntsc[0]=rawy+rawq;
2169       ntsc[1]=rawy-rawi;
2170       ntsc[2]=rawy-rawq;
2171       ntsc[3]=rawy+rawi;
2172
2173       for (i=0; i<4; i++) {
2174         if (ntsc[i]>ANALOGTV_WHITE_LEVEL) ntsc[i]=ANALOGTV_WHITE_LEVEL;
2175         if (ntsc[i]<ANALOGTV_BLACK_LEVEL) ntsc[i]=ANALOGTV_BLACK_LEVEL;
2176       }
2177
2178       input->signal[tvy][tvx+0]= ntsc[(tvx+0)&3];
2179       input->signal[tvy][tvx+1]= ntsc[(tvx+1)&3];
2180       input->signal[tvy][tvx+2]= ntsc[(tvx+2)&3];
2181       input->signal[tvy][tvx+3]= ntsc[(tvx+3)&3];
2182     }
2183   }
2184 }
2185
2186 extern XtAppContext app;
2187
2188 int
2189 analogtv_handle_events (analogtv *it)
2190 {
2191   XSync(it->dpy, False);
2192   if (XtAppPending (app) & (XtIMTimer|XtIMAlternateInput))
2193     XtAppProcessEvent (app, XtIMTimer|XtIMAlternateInput);
2194
2195   while (XPending (it->dpy))
2196     {
2197       XEvent event;
2198       XNextEvent (it->dpy, &event);
2199       switch (event.xany.type)
2200         {
2201         case ButtonPress:
2202           return 1;
2203
2204         case KeyPress:
2205           {
2206             KeySym keysym;
2207             char c = 0;
2208
2209             if (it->key_handler) {
2210               if (it->key_handler (it->dpy, &event, it->key_data))
2211                 return 1;
2212             } else {
2213               XLookupString (&event.xkey, &c, 1, &keysym, 0);
2214               if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
2215                 return 1;
2216             }
2217           }
2218           break;
2219
2220           /* I don't seem to get an event when clicking the "full
2221              screen" window manager icon, at least when using
2222              metacity. Thus, it doesn't change the video size. Is this
2223              some separate WM_* message I have to deal with?
2224           */
2225         case ConfigureNotify:
2226           if (event.xconfigure.width  != it->xgwa.width ||
2227               event.xconfigure.height != it->xgwa.height)
2228             analogtv_reconfigure(it);
2229           break;
2230
2231         case Expose:
2232         case GraphicsExpose:
2233           it->need_clear=1;
2234           break;
2235
2236         default:
2237           break;
2238         }
2239       if (it->event_handler) {
2240         (*it->event_handler) (it->dpy, &event);
2241       }
2242     }
2243   return 0;
2244 }
2245