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