http://slackware.bholcomb.com/slackware/slackware-11.0/source/xap/xscreensaver/xscree...
[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 #ifdef HAVE_COCOA
55 # include "jwxyz.h"
56 #else /* !HAVE_COCOA */
57 # include <X11/Xlib.h>
58 # include <X11/Xutil.h>
59 #endif
60
61 #include <assert.h>
62 #include "utils.h"
63 #include "resources.h"
64 #include "analogtv.h"
65 #include "yarandom.h"
66 #include "grabscreen.h"
67
68 /* #define DEBUG 1 */
69
70 #ifdef DEBUG
71 /* only works on linux + freebsd */
72 #include <machine/cpufunc.h>
73
74 #define DTIME_DECL u_int64_t dtimes[100]; int n_dtimes
75 #define DTIME_START do {n_dtimes=0; dtimes[n_dtimes++]=rdtsc(); } while (0)
76 #define DTIME dtimes[n_dtimes++]=rdtsc()
77 #define DTIME_SHOW(DIV) \
78 do { \
79   double _dtime_div=(DIV); \
80   printf("time/%.1f: ",_dtime_div); \
81   for (i=1; i<n_dtimes; i++) \
82     printf(" %0.9f",(dtimes[i]-dtimes[i-1])* 1e-9 / _dtime_div); \
83   printf("\n"); \
84 } while (0)
85
86 #else
87
88 #define DTIME_DECL
89 #define DTIME_START  do { } while (0)
90 #define DTIME  do { } while (0)
91 #define DTIME_SHOW(DIV)  do { } while (0)
92
93 #endif
94
95
96 #define FASTRND (fastrnd = fastrnd*1103515245+12345)
97
98 static void analogtv_ntsc_to_yiq(analogtv *it, int lineno, double *signal,
99                                  int start, int end);
100
101 static double puramp(analogtv *it, double tc, double start, double over)
102 {
103   double pt=it->powerup-start;
104   double ret;
105   if (pt<0.0) return 0.0;
106   if (pt>900.0 || pt/tc>8.0) return 1.0;
107
108   ret=(1.0-exp(-pt/tc))*over;
109   if (ret>1.0) return 1.0;
110   return ret*ret;
111 }
112
113 /*
114   There are actual standards for TV signals: NTSC and RS-170A describe the
115   system used in the US and Japan. Europe has slightly different systems, but
116   not different enough to make substantially different screensaver displays.
117   Sadly, the standards bodies don't do anything so useful as publish the spec on
118   the web. Best bets are:
119
120     http://www.ee.washington.edu/conselec/CE/kuhn/ntsc/95x4.htm
121     http://www.ntsc-tv.com/ntsc-index-02.htm
122
123   In DirectColor or TrueColor modes, it generates pixel values directly from RGB
124   values it calculates across each scan line. In PseudoColor mode, it consider
125   each possible pattern of 5 preceding bit values in each possible position
126   modulo 4 and allocates a color for each. A few things, like the brightening on
127   the right side as the horizontal trace slows down, aren't done in PseudoColor.
128
129   I'd like to add a bit of visible retrace, but it conflicts with being able to
130   bitcopy the image when fast scrolling. After another couple of CPU
131   generations, we could probably regenerate the whole image from scratch every
132   time. On a P4 2 GHz it can manage this fine for blinking text, but scrolling
133   looks too slow.
134 */
135
136 /* localbyteorder is MSBFirst or LSBFirst */
137 static int localbyteorder;
138 static const double float_low8_ofs=8388608.0;
139 static int float_extraction_works;
140
141 typedef union {
142   float f;
143   int i;
144 } float_extract_t;
145
146 static void
147 analogtv_init(void)
148 {
149   int i;
150   {
151     unsigned int localbyteorder_loc = (MSBFirst<<24) | (LSBFirst<<0);
152     localbyteorder=*(char *)&localbyteorder_loc;
153   }
154
155   if (1) {
156     float_extract_t fe;
157     int ans;
158
159     float_extraction_works=1;
160     for (i=0; i<256*4; i++) {
161       fe.f=float_low8_ofs+(double)i;
162       ans=fe.i&0x3ff;
163       if (ans != i) {
164 #ifdef DEBUG
165         printf("Float extraction failed for %d => %d\n",i,ans);
166 #endif
167         float_extraction_works=0;
168         break;
169       }
170     }
171   }
172
173 }
174
175 void
176 analogtv_set_defaults(analogtv *it, char *prefix)
177 {
178   char buf[256];
179
180   sprintf(buf,"%sTVTint",prefix);
181   it->tint_control = get_float_resource(it->dpy, buf,"TVTint");
182   sprintf(buf,"%sTVColor",prefix);
183   it->color_control = get_float_resource(it->dpy, buf,"TVColor")/100.0;
184   sprintf(buf,"%sTVBrightness",prefix);
185   it->brightness_control = get_float_resource(it->dpy, buf,"TVBrightness") / 100.0;
186   sprintf(buf,"%sTVContrast",prefix);
187   it->contrast_control = get_float_resource(it->dpy, buf,"TVContrast") / 100.0;
188   it->height_control = 1.0;
189   it->width_control = 1.0;
190   it->squish_control = 0.0;
191   it->powerup=1000.0;
192
193   it->hashnoise_rpm=0;
194   it->hashnoise_on=0;
195   it->hashnoise_enable=1;
196
197   it->horiz_desync=frand(10.0)-5.0;
198   it->squeezebottom=frand(5.0)-1.0;
199
200 #ifdef DEBUG
201   printf("analogtv: prefix=%s\n",prefix);
202   printf("  use: shm=%d cmap=%d color=%d\n",
203          it->use_shm,it->use_cmap,it->use_color);
204   printf("  controls: tint=%g color=%g brightness=%g contrast=%g\n",
205          it->tint_control, it->color_control, it->brightness_control,
206          it->contrast_control);
207   printf("  freq_error %g: %g %d\n",
208          it->freq_error, it->freq_error_inc, it->flutter_tint);
209   printf("  desync: %g %d\n",
210          it->horiz_desync, it->flutter_horiz_desync);
211   printf("  hashnoise rpm: %g\n",
212          it->hashnoise_rpm);
213   printf("  vis: %d %d %d\n",
214          it->visclass, it->visbits, it->visdepth);
215   printf("  shift: %d-%d %d-%d %d-%d\n",
216          it->red_invprec,it->red_shift,
217          it->green_invprec,it->green_shift,
218          it->blue_invprec,it->blue_shift);
219   printf("  size: %d %d  %d %d  xrepl=%d\n",
220          it->usewidth, it->useheight,
221          it->screen_xo, it->screen_yo, it->xrepl);
222
223   printf("    ANALOGTV_V=%d\n",ANALOGTV_V);
224   printf("    ANALOGTV_TOP=%d\n",ANALOGTV_TOP);
225   printf("    ANALOGTV_VISLINES=%d\n",ANALOGTV_VISLINES);
226   printf("    ANALOGTV_BOT=%d\n",ANALOGTV_BOT);
227   printf("    ANALOGTV_H=%d\n",ANALOGTV_H);
228   printf("    ANALOGTV_SYNC_START=%d\n",ANALOGTV_SYNC_START);
229   printf("    ANALOGTV_BP_START=%d\n",ANALOGTV_BP_START);
230   printf("    ANALOGTV_CB_START=%d\n",ANALOGTV_CB_START);
231   printf("    ANALOGTV_PIC_START=%d\n",ANALOGTV_PIC_START);
232   printf("    ANALOGTV_PIC_LEN=%d\n",ANALOGTV_PIC_LEN);
233   printf("    ANALOGTV_FP_START=%d\n",ANALOGTV_FP_START);
234   printf("    ANALOGTV_PIC_END=%d\n",ANALOGTV_PIC_END);
235   printf("    ANALOGTV_HASHNOISE_LEN=%d\n",ANALOGTV_HASHNOISE_LEN);
236
237 #endif
238
239 }
240
241 extern Bool mono_p; /* shoot me */
242
243 static void
244 analogtv_free_image(analogtv *it)
245 {
246   if (it->image) {
247     if (it->use_shm) {
248 #ifdef HAVE_XSHM_EXTENSION
249       destroy_xshm_image(it->dpy, it->image, &it->shm_info);
250 #endif
251     } else {
252       XDestroyImage(it->image);
253     }
254     it->image=NULL;
255   }
256 }
257
258 static void
259 analogtv_alloc_image(analogtv *it)
260 {
261   if (it->use_shm) {
262 #ifdef HAVE_XSHM_EXTENSION
263     it->image=create_xshm_image(it->dpy, it->xgwa.visual, it->xgwa.depth, ZPixmap, 0,
264                                 &it->shm_info, it->usewidth, it->useheight);
265 #endif
266     if (!it->image) it->use_shm=0;
267   }
268   if (!it->image) {
269     it->image = XCreateImage(it->dpy, it->xgwa.visual, it->xgwa.depth, ZPixmap, 0, 0,
270                              it->usewidth, it->useheight, 8, 0);
271     it->image->data = (char *)malloc(it->image->height * it->image->bytes_per_line);
272   }
273   memset (it->image->data, 0, it->image->height * it->image->bytes_per_line);
274 }
275
276
277 static void
278 analogtv_configure(analogtv *it)
279 {
280   int oldwidth=it->usewidth;
281   int oldheight=it->useheight;
282   int wlim,hlim,height_diff;
283
284   /* If the window is very small, don't let the image we draw get lower
285      than the actual TV resolution (266x200.)
286
287      If the aspect ratio of the window is within 15% of a 4:3 ratio,
288      then scale the image to exactly fill the window.
289
290      Otherwise, center the image either horizontally or vertically,
291      padding on the left+right, or top+bottom, but not both.
292
293      If it's very close (2.5%) to a multiple of VISLINES, make it exact
294      For example, it maps 1024 => 1000.
295    */
296   float percent = 0.15;  /* jwz: 20% caused severe top/bottom clipping
297                                  in Pong on 1680x1050 iMac screen. */
298   float min_ratio = 4.0 / 3.0 * (1 - percent);
299   float max_ratio = 4.0 / 3.0 * (1 + percent);
300   float ratio;
301   float height_snap=0.025;
302
303   hlim = it->xgwa.height;
304   wlim = it->xgwa.width;
305   ratio = wlim / (float) hlim;
306
307   if (wlim < 266 || hlim < 200)
308     {
309       wlim = 266;
310       hlim = 200;
311 # ifdef DEBUG
312       fprintf (stderr,
313                "size: minimal: %dx%d in %dx%d (%.3f < %.3f < %.3f)\n",
314                wlim, hlim, it->xgwa.width, it->xgwa.height,
315                min_ratio, ratio, max_ratio);
316 # endif
317     }
318   else if (ratio > min_ratio && ratio < max_ratio)
319     {
320 # ifdef DEBUG
321       fprintf (stderr,
322                "size: close enough: %dx%d (%.3f < %.3f < %.3f)\n",
323                wlim, hlim, min_ratio, ratio, max_ratio);
324 # endif
325     }
326   else if (ratio > max_ratio)
327     {
328       wlim = hlim*max_ratio;
329 # ifdef DEBUG
330       fprintf (stderr,
331                "size: center H: %dx%d in %dx%d (%.3f < %.3f < %.3f)\n",
332                wlim, hlim, it->xgwa.width, it->xgwa.height,
333                min_ratio, ratio, max_ratio);
334 # endif
335     }
336   else /* ratio < min_ratio */
337     {
338       hlim = wlim/min_ratio;
339 # ifdef DEBUG
340       fprintf (stderr,
341                "size: center V: %dx%d in %dx%d (%.3f < %.3f < %.3f)\n",
342                wlim, hlim, it->xgwa.width, it->xgwa.height,
343                min_ratio, ratio, max_ratio);
344 # endif
345     }
346
347
348   height_diff = ((hlim + ANALOGTV_VISLINES/2) % ANALOGTV_VISLINES) - ANALOGTV_VISLINES/2;
349   if (height_diff != 0 && fabs(height_diff) < hlim * height_snap)
350     {
351       hlim -= height_diff;
352     }
353
354
355   /* Most times this doesn't change */
356   if (wlim != oldwidth || hlim != oldheight) {
357
358     it->usewidth=wlim;
359     it->useheight=hlim;
360
361     it->xrepl=1+it->usewidth/640;
362     if (it->xrepl>2) it->xrepl=2;
363     it->subwidth=it->usewidth/it->xrepl;
364
365     analogtv_free_image(it);
366     analogtv_alloc_image(it);
367   }
368
369   it->screen_xo = (it->xgwa.width-it->usewidth)/2;
370   it->screen_yo = (it->xgwa.height-it->useheight)/2;
371   it->need_clear=1;
372 }
373
374 void
375 analogtv_reconfigure(analogtv *it)
376 {
377   XGetWindowAttributes (it->dpy, it->window, &it->xgwa);
378   analogtv_configure(it);
379 }
380
381 analogtv *
382 analogtv_allocate(Display *dpy, Window window)
383 {
384   XGCValues gcv;
385   analogtv *it=NULL;
386   int i;
387
388   analogtv_init();
389
390   it=(analogtv *)calloc(1,sizeof(analogtv));
391   it->dpy=dpy;
392   it->window=window;
393
394   it->shrinkpulse=-1;
395
396   it->n_colors=0;
397
398 #ifdef HAVE_XSHM_EXTENSION
399   it->use_shm=1;
400 #else
401   it->use_shm=0;
402 #endif
403
404   XGetWindowAttributes (it->dpy, it->window, &it->xgwa);
405
406   it->screen=it->xgwa.screen;
407   it->colormap=it->xgwa.colormap;
408   it->visclass=it->xgwa.visual->class;
409   it->visbits=it->xgwa.visual->bits_per_rgb;
410   it->visdepth=it->xgwa.depth;
411   if (it->visclass == TrueColor || it->visclass == DirectColor) {
412     if (get_integer_resource (it->dpy, "use_cmap", "Integer")) {
413       it->use_cmap=1;
414     } else {
415       it->use_cmap=0;
416     }
417     it->use_color=!mono_p;
418   }
419   else if (it->visclass == PseudoColor || it->visclass == StaticColor) {
420     it->use_cmap=1;
421     it->use_color=!mono_p;
422   }
423   else {
424     it->use_cmap=1;
425     it->use_color=0;
426   }
427
428   it->red_mask=it->xgwa.visual->red_mask;
429   it->green_mask=it->xgwa.visual->green_mask;
430   it->blue_mask=it->xgwa.visual->blue_mask;
431   it->red_shift=it->red_invprec=-1;
432   it->green_shift=it->green_invprec=-1;
433   it->blue_shift=it->blue_invprec=-1;
434   if (!it->use_cmap) {
435     /* Is there a standard way to do this? Does this handle all cases? */
436     int shift, prec;
437     for (shift=0; shift<32; shift++) {
438       for (prec=1; prec<16 && prec<40-shift; prec++) {
439         unsigned long mask=(0xffffUL>>(16-prec)) << shift;
440         if (it->red_shift<0 && mask==it->red_mask)
441           it->red_shift=shift, it->red_invprec=16-prec;
442         if (it->green_shift<0 && mask==it->green_mask)
443           it->green_shift=shift, it->green_invprec=16-prec;
444         if (it->blue_shift<0 && mask==it->blue_mask)
445           it->blue_shift=shift, it->blue_invprec=16-prec;
446       }
447     }
448     if (it->red_shift<0 || it->green_shift<0 || it->blue_shift<0) {
449       if (0) fprintf(stderr,"Can't figure out color space\n");
450       goto fail;
451     }
452
453     for (i=0; i<ANALOGTV_CV_MAX; i++) {
454       int intensity=pow(i/256.0, 0.8)*65535.0; /* gamma correction */
455       if (intensity>65535) intensity=65535;
456       it->red_values[i]=((intensity>>it->red_invprec)<<it->red_shift);
457       it->green_values[i]=((intensity>>it->green_invprec)<<it->green_shift);
458       it->blue_values[i]=((intensity>>it->blue_invprec)<<it->blue_shift);
459     }
460
461   }
462
463   gcv.background=get_pixel_resource(it->dpy, it->colormap,
464                                     "background", "Background");
465
466   it->gc = XCreateGC(it->dpy, it->window, GCBackground, &gcv);
467   XSetWindowBackground(it->dpy, it->window, gcv.background);
468   XClearWindow(dpy,window);
469
470   analogtv_configure(it);
471
472   return it;
473
474  fail:
475   if (it) free(it);
476   return NULL;
477 }
478
479 void
480 analogtv_release(analogtv *it)
481 {
482   if (it->image) {
483     if (it->use_shm) {
484 #ifdef HAVE_XSHM_EXTENSION
485       destroy_xshm_image(it->dpy, it->image, &it->shm_info);
486 #endif
487     } else {
488       XDestroyImage(it->image);
489     }
490     it->image=NULL;
491   }
492   if (it->gc) XFreeGC(it->dpy, it->gc);
493   it->gc=NULL;
494   if (it->n_colors) XFreeColors(it->dpy, it->colormap, it->colors, it->n_colors, 0L);
495   it->n_colors=0;
496 }
497
498
499 /*
500   First generate the I and Q reference signals, which we'll multiply
501   the input signal by to accomplish the demodulation. Normally they
502   are shifted 33 degrees from the colorburst. I think this was convenient
503   for inductor-capacitor-vacuum tube implementation.
504
505   The tint control, FWIW, just adds a phase shift to the chroma signal,
506   and the color control controls the amplitude.
507
508   In text modes (colormode==0) the system disabled the color burst, and no
509   color was detected by the monitor.
510
511   freq_error gives a mismatch between the built-in oscillator and the
512   TV's colorbust. Some II Plus machines seemed to occasionally get
513   instability problems -- the crystal oscillator was a single
514   transistor if I remember correctly -- and the frequency would vary
515   enough that the tint would change across the width of the screen.
516   The left side would be in correct tint because it had just gotten
517   resynchronized with the color burst.
518
519   If we're using a colormap, set it up.
520 */
521 int
522 analogtv_set_demod(analogtv *it)
523 {
524   int y_levels=10,i_levels=5,q_levels=5;
525
526   /*
527     In principle, we might be able to figure out how to adjust the
528     color map frame-by-frame to get some nice color bummage. But I'm
529     terrified of changing the color map because we'll get flashing.
530
531     I can hardly believe we still have to deal with colormaps. They're
532     like having NEAR PTRs: an enormous hassle for the programmer just
533     to save on memory. They should have been deprecated by 1995 or
534     so. */
535
536  cmap_again:
537   if (it->use_cmap && !it->n_colors) {
538
539     if (it->n_colors) {
540       XFreeColors(it->dpy, it->colormap, it->colors, it->n_colors, 0L);
541       it->n_colors=0;
542     }
543
544     {
545       int yli,qli,ili;
546       for (yli=0; yli<y_levels; yli++) {
547         for (ili=0; ili<i_levels; ili++) {
548           for (qli=0; qli<q_levels; qli++) {
549             double interpy,interpi,interpq;
550             double levelmult=700.0;
551             int r,g,b;
552             XColor col;
553
554             interpy=100.0 * ((double)yli/y_levels);
555             interpi=50.0 * (((double)ili-(0.5*i_levels))/(double)i_levels);
556             interpq=50.0 * (((double)qli-(0.5*q_levels))/(double)q_levels);
557
558             r=(int)((interpy + 1.04*interpi + 0.624*interpq)*levelmult);
559             g=(int)((interpy - 0.276*interpi - 0.639*interpq)*levelmult);
560             b=(int)((interpy - 1.105*interpi + 1.729*interpq)*levelmult);
561             if (r<0) r=0;
562             if (r>65535) r=65535;
563             if (g<0) g=0;
564             if (g>65535) g=65535;
565             if (b<0) b=0;
566             if (b>65535) b=65535;
567
568 #ifdef DEBUG
569             printf("%0.2f %0.2f %0.2f => %02x%02x%02x\n",
570                    interpy, interpi, interpq,
571                    r/256,g/256,b/256);
572 #endif
573
574             col.red=r;
575             col.green=g;
576             col.blue=b;
577             col.pixel=0;
578             if (!XAllocColor(it->dpy, it->colormap, &col)) {
579               if (q_levels > y_levels*4/12)
580                 q_levels--;
581               else if (i_levels > y_levels*5/12)
582                 i_levels--;
583               else
584                 y_levels--;
585
586               if (y_levels<2)
587                 return -1;
588               goto cmap_again;
589             }
590             it->colors[it->n_colors++]=col.pixel;
591           }
592         }
593       }
594
595       it->cmap_y_levels=y_levels;
596       it->cmap_i_levels=i_levels;
597       it->cmap_q_levels=q_levels;
598     }
599   }
600
601   return 0;
602 }
603
604 #if 0
605 unsigned int
606 analogtv_line_signature(analogtv_input *input, int lineno)
607 {
608   int i;
609   char *origsignal=&input->signal[(lineno+input->vsync)
610                                   %ANALOGTV_V][input->line_hsync[lineno]];
611   unsigned int hash=0;
612
613   /* probably lame */
614   for (i=0; i<ANALOGTV_PIC_LEN; i++) {
615     int c=origsignal[i];
616     hash = hash + (hash<<17) + c;
617   }
618
619   hash += input->line_hsync[lineno];
620   hash ^= hash >> 2;
621   /*
622   hash += input->hashnoise_times[lineno];
623   hash ^= hash >> 2;
624   */
625
626   return hash;
627 }
628 #endif
629
630
631 /* Here we model the analog circuitry of an NTSC television.
632    Basically, it splits the signal into 3 signals: Y, I and Q. Y
633    corresponds to luminance, and you get it by low-pass filtering the
634    input signal to below 3.57 MHz.
635
636    I and Q are the in-phase and quadrature components of the 3.57 MHz
637    subcarrier. We get them by multiplying by cos(3.57 MHz*t) and
638    sin(3.57 MHz*t), and low-pass filtering. Because the eye has less
639    resolution in some colors than others, the I component gets
640    low-pass filtered at 1.5 MHz and the Q at 0.5 MHz. The I component
641    is approximately orange-blue, and Q is roughly purple-green. See
642    http://www.ntsc-tv.com for details.
643
644    We actually do an awful lot to the signal here. I suspect it would
645    make sense to wrap them all up together by calculating impulse
646    response and doing FFT convolutions.
647
648 */
649
650 static void
651 analogtv_ntsc_to_yiq(analogtv *it, int lineno, double *signal,
652                      int start, int end)
653 {
654   enum {MAXDELAY=32};
655   int i;
656   double *sp;
657   int phasecorr=(signal-it->rx_signal)&3;
658   struct analogtv_yiq_s *yiq;
659   int colormode;
660   double agclevel=it->agclevel;
661   double brightadd=it->brightness_control*100.0 - ANALOGTV_BLACK_LEVEL;
662   double delay[MAXDELAY+ANALOGTV_PIC_LEN], *dp;
663   double multiq2[4];
664
665   {
666
667     double cb_i=(it->line_cb_phase[lineno][(2+phasecorr)&3]-
668                  it->line_cb_phase[lineno][(0+phasecorr)&3])/16.0;
669     double cb_q=(it->line_cb_phase[lineno][(3+phasecorr)&3]-
670                  it->line_cb_phase[lineno][(1+phasecorr)&3])/16.0;
671
672     colormode = (cb_i * cb_i + cb_q * cb_q) > 2.8;
673
674     if (colormode) {
675       double tint_i = -cos((103 + it->color_control)*3.1415926/180);
676       double tint_q = sin((103 + it->color_control)*3.1415926/180);
677
678       multiq2[0] = (cb_i*tint_i - cb_q*tint_q) * it->color_control;
679       multiq2[1] = (cb_q*tint_i + cb_i*tint_q) * it->color_control;
680       multiq2[2]=-multiq2[0];
681       multiq2[3]=-multiq2[1];
682     }
683   }
684
685 #if 0
686   if (lineno==100) {
687     printf("multiq = [%0.3f %0.3f %0.3f %0.3f] ",
688            it->multiq[60],it->multiq[61],it->multiq[62],it->multiq[63]);
689     printf("it->line_cb_phase = [%0.3f %0.3f %0.3f %0.3f]\n",
690            it->line_cb_phase[lineno][0],it->line_cb_phase[lineno][1],
691            it->line_cb_phase[lineno][2],it->line_cb_phase[lineno][3]);
692     printf("multiq2 = [%0.3f %0.3f %0.3f %0.3f]\n",
693            multiq2[0],multiq2[1],multiq2[2],multiq2[3]);
694   }
695 #endif
696
697   dp=delay+ANALOGTV_PIC_LEN-MAXDELAY;
698   for (i=0; i<5; i++) dp[i]=0.0;
699
700   assert(start>=0);
701   assert(end < ANALOGTV_PIC_LEN+10);
702
703   dp=delay+ANALOGTV_PIC_LEN-MAXDELAY;
704   for (i=0; i<24; i++) dp[i]=0.0;
705   for (i=start, yiq=it->yiq+start, sp=signal+start;
706        i<end;
707        i++, dp--, yiq++, sp++) {
708
709     /* Now filter them. These are infinite impulse response filters
710        calculated by the script at
711        http://www-users.cs.york.ac.uk/~fisher/mkfilter. This is
712        fixed-point integer DSP, son. No place for wimps. We do it in
713        integer because you can count on integer being faster on most
714        CPUs. We care about speed because we need to recalculate every
715        time we blink text, and when we spew random bytes into screen
716        memory. This is roughly 16.16 fixed point arithmetic, but we
717        scale some filter values up by a few bits to avoid some nasty
718        precision errors. */
719
720     /* Filter Y with a 4-pole low-pass Butterworth filter at 3.5 MHz
721        with an extra zero at 3.5 MHz, from
722        mkfilter -Bu -Lp -o 4 -a 2.1428571429e-01 0 -Z 2.5e-01 -l
723        Delay about 2 */
724
725     dp[0] = sp[0] * 0.0469904257251935 * agclevel;
726     dp[8] = (+1.0*(dp[6]+dp[0])
727              +4.0*(dp[5]+dp[1])
728              +7.0*(dp[4]+dp[2])
729              +8.0*(dp[3])
730              -0.0176648*dp[12]
731              -0.4860288*dp[10]);
732     yiq->y = dp[8] + brightadd;
733   }
734
735   if (colormode) {
736     dp=delay+ANALOGTV_PIC_LEN-MAXDELAY;
737     for (i=0; i<27; i++) dp[i]=0.0;
738
739     for (i=start, yiq=it->yiq+start, sp=signal+start;
740          i<end;
741          i++, dp--, yiq++, sp++) {
742       double sig=*sp;
743
744       /* Filter I and Q with a 3-pole low-pass Butterworth filter at
745          1.5 MHz with an extra zero at 3.5 MHz, from
746          mkfilter -Bu -Lp -o 3 -a 1.0714285714e-01 0 -Z 2.5000000000e-01 -l
747          Delay about 3.
748       */
749
750       dp[0] = sig*multiq2[i&3] * 0.0833333333333;
751       yiq->i=dp[8] = (dp[5] + dp[0]
752                       +3.0*(dp[4] + dp[1])
753                       +4.0*(dp[3] + dp[2])
754                       -0.3333333333 * dp[10]);
755
756       dp[16] = sig*multiq2[(i+3)&3] * 0.0833333333333;
757       yiq->q=dp[24] = (dp[16+5] + dp[16+0]
758                        +3.0*(dp[16+4] + dp[16+1])
759                        +4.0*(dp[16+3] + dp[16+2])
760                        -0.3333333333 * dp[24+2]);
761     }
762   } else {
763     for (i=start, yiq=it->yiq+start; i<end; i++, yiq++) {
764       yiq->i = yiq->q = 0.0;
765     }
766   }
767 }
768
769 void
770 analogtv_setup_teletext(analogtv_input *input)
771 {
772   int x,y;
773   int teletext=ANALOGTV_BLACK_LEVEL;
774
775   /* Teletext goes in line 21. But I suspect there are other things
776      in the vertical retrace interval */
777
778   for (y=19; y<22; y++) {
779     for (x=ANALOGTV_PIC_START; x<ANALOGTV_PIC_END; x++) {
780       if ((x&7)==0) {
781         teletext=(random()&1) ? ANALOGTV_WHITE_LEVEL : ANALOGTV_BLACK_LEVEL;
782       }
783       input->signal[y][x]=teletext;
784     }
785   }
786 }
787
788 void
789 analogtv_setup_frame(analogtv *it)
790 {
791   int i,x,y;
792
793   it->redraw_all=0;
794
795   if (it->flutter_horiz_desync) {
796     /* Horizontal sync during vertical sync instability. */
797     it->horiz_desync += -0.10*(it->horiz_desync-3.0) +
798       ((int)(random()&0xff)-0x80) *
799       ((int)(random()&0xff)-0x80) *
800       ((int)(random()&0xff)-0x80) * 0.000001;
801   }
802
803   for (i=0; i<ANALOGTV_V; i++) {
804     it->hashnoise_times[i]=0;
805   }
806
807   if (it->hashnoise_enable && !it->hashnoise_on) {
808     if (random()%10000==0) {
809       it->hashnoise_on=1;
810       it->shrinkpulse=random()%ANALOGTV_V;
811     }
812   }
813   if (random()%1000==0) {
814     it->hashnoise_on=0;
815   }
816   if (it->hashnoise_on) {
817     it->hashnoise_rpm += (15000.0 - it->hashnoise_rpm)*0.05 +
818       ((int)(random()%2000)-1000)*0.1;
819   } else {
820     it->hashnoise_rpm -= 100 + 0.01*it->hashnoise_rpm;
821     if (it->hashnoise_rpm<0.0) it->hashnoise_rpm=0.0;
822   }
823   if (it->hashnoise_rpm > 0.0) {
824     int hni;
825     int hnc=it->hashnoise_counter; /* in 24.8 format */
826
827     /* Convert rpm of a 16-pole motor into dots in 24.8 format */
828     hni = (int)(ANALOGTV_V * ANALOGTV_H * 256.0 /
829                 (it->hashnoise_rpm * 16.0 / 60.0 / 60.0));
830
831     while (hnc < (ANALOGTV_V * ANALOGTV_H)<<8) {
832       y=(hnc>>8)/ANALOGTV_H;
833       x=(hnc>>8)%ANALOGTV_H;
834
835       if (x>0 && x<ANALOGTV_H - ANALOGTV_HASHNOISE_LEN) {
836         it->hashnoise_times[y]=x;
837       }
838       hnc += hni + (int)(random()%65536)-32768;
839     }
840     hnc -= (ANALOGTV_V * ANALOGTV_H)<<8;
841   }
842
843   if (it->rx_signal_level != 0.0)
844     it->agclevel = 1.0/it->rx_signal_level;
845
846
847 #ifdef DEBUG2
848   printf("filter: ");
849   for (i=0; i<ANALOGTV_GHOSTFIR_LEN; i++) {
850     printf(" %0.3f",it->ghostfir[i]);
851   }
852   printf(" siglevel=%g agc=%g\n", siglevel, it->agclevel);
853 #endif
854 }
855
856 void
857 analogtv_setup_sync(analogtv_input *input, int do_cb, int do_ssavi)
858 {
859   int i,lineno,vsync;
860   signed char *sig;
861
862   int synclevel = do_ssavi ? ANALOGTV_WHITE_LEVEL : ANALOGTV_SYNC_LEVEL;
863
864   for (lineno=0; lineno<ANALOGTV_V; lineno++) {
865     vsync=lineno>=3 && lineno<7;
866
867     sig=input->signal[lineno];
868
869     i=ANALOGTV_SYNC_START;
870     if (vsync) {
871       while (i<ANALOGTV_BP_START) sig[i++]=ANALOGTV_BLANK_LEVEL;
872       while (i<ANALOGTV_H) sig[i++]=synclevel;
873     } else {
874       while (i<ANALOGTV_BP_START) sig[i++]=synclevel;
875       while (i<ANALOGTV_PIC_START) sig[i++]=ANALOGTV_BLANK_LEVEL;
876       while (i<ANALOGTV_FP_START) sig[i++]=ANALOGTV_BLACK_LEVEL;
877     }
878     while (i<ANALOGTV_H) sig[i++]=ANALOGTV_BLANK_LEVEL;
879
880     if (do_cb) {
881       /* 9 cycles of colorburst */
882       for (i=ANALOGTV_CB_START; i<ANALOGTV_CB_START+36; i+=4) {
883         sig[i+1] += ANALOGTV_CB_LEVEL;
884         sig[i+3] -= ANALOGTV_CB_LEVEL;
885       }
886     }
887   }
888 }
889
890 static void
891 analogtv_sync(analogtv *it)
892 {
893   int cur_hsync=it->cur_hsync;
894   int cur_vsync=it->cur_vsync;
895   int lineno = 0;
896   int i,j;
897   double osc,filt;
898   double *sp;
899   double cbfc=1.0/128.0;
900
901   sp = it->rx_signal + lineno*ANALOGTV_H + cur_hsync;
902   for (i=-32; i<32; i++) {
903     lineno = (cur_vsync + i + ANALOGTV_V) % ANALOGTV_V;
904     sp = it->rx_signal + lineno*ANALOGTV_H;
905     filt=0.0;
906     for (j=0; j<ANALOGTV_H; j+=ANALOGTV_H/16) {
907       filt += sp[j];
908     }
909     filt *= it->agclevel;
910
911     osc = (double)(ANALOGTV_V+i)/(double)ANALOGTV_V;
912
913     if (osc >= 1.05+0.0002 * filt) break;
914   }
915   cur_vsync = (cur_vsync + i + ANALOGTV_V) % ANALOGTV_V;
916
917   for (lineno=0; lineno<ANALOGTV_V; lineno++) {
918
919     if (lineno>5 && lineno<ANALOGTV_V-3) { /* ignore vsync interval */
920
921       sp = it->rx_signal + ((lineno + cur_vsync + ANALOGTV_V)%ANALOGTV_V
922                             )*ANALOGTV_H + cur_hsync;
923       for (i=-8; i<8; i++) {
924         osc = (double)(ANALOGTV_H+i)/(double)ANALOGTV_H;
925         filt=(sp[i-3]+sp[i-2]+sp[i-1]+sp[i]) * it->agclevel;
926
927         if (osc >= 1.005 + 0.0001*filt) break;
928       }
929       cur_hsync = (cur_hsync + i + ANALOGTV_H) % ANALOGTV_H;
930     }
931
932     it->line_hsync[lineno]=(cur_hsync + ANALOGTV_PIC_START +
933                             ANALOGTV_H) % ANALOGTV_H;
934
935     /* Now look for the colorburst, which is a few cycles after the H
936        sync pulse, and store its phase.
937        The colorburst is 9 cycles long, and we look at the middle 5
938        cycles.
939     */
940
941     if (lineno>15) {
942       sp = it->rx_signal + lineno*ANALOGTV_H + (cur_hsync&~3);
943       for (i=ANALOGTV_CB_START+8; i<ANALOGTV_CB_START+36-8; i++) {
944         it->cb_phase[i&3] = it->cb_phase[i&3]*(1.0-cbfc) +
945           sp[i]*it->agclevel*cbfc;
946       }
947     }
948
949     {
950       double tot=0.1;
951       double cbgain;
952
953       for (i=0; i<4; i++) {
954         tot += it->cb_phase[i]*it->cb_phase[i];
955       }
956       cbgain = 32.0/sqrt(tot);
957
958       for (i=0; i<4; i++) {
959         it->line_cb_phase[lineno][i]=it->cb_phase[i]*cbgain;
960       }
961     }
962
963 #ifdef DEBUG
964     if (0) printf("hs=%d cb=[%0.3f %0.3f %0.3f %0.3f]\n",
965                   cur_hsync,
966                   it->cb_phase[0], it->cb_phase[1],
967                   it->cb_phase[2], it->cb_phase[3]);
968 #endif
969
970     /* if (random()%2000==0) cur_hsync=random()%ANALOGTV_H; */
971   }
972
973   it->cur_hsync = cur_hsync;
974   it->cur_vsync = cur_vsync;
975 }
976
977 static double
978 analogtv_levelmult(analogtv *it, int level)
979 {
980   static const double levelfac[3]={-7.5, 5.5, 24.5};
981   return (40.0 + levelfac[level]*puramp(it, 3.0, 6.0, 1.0))/256.0;
982 }
983
984 static int
985 analogtv_level(analogtv *it, int y, int ytop, int ybot)
986 {
987   int level;
988   if (ybot-ytop>=7) {
989     if (y==ytop || y==ybot-1) level=0;
990     else if (y==ytop+1 || y==ybot-2) level=1;
991     else level=2;
992   }
993   else if (ybot-ytop>=5) {
994     if (y==ytop || y==ybot-1) level=0;
995     else level=2;
996   }
997   else if (ybot-ytop>=3) {
998     if (y==ytop) level=0;
999     else level=2;
1000   }
1001   else {
1002     level=2;
1003   }
1004   return level;
1005 }
1006
1007 /*
1008   The point of this stuff is to ensure that when useheight is not a
1009   multiple of VISLINES so that TV scan lines map to different numbers
1010   of vertical screen pixels, the total brightness of each scan line
1011   remains the same.
1012   ANALOGTV_MAX_LINEHEIGHT corresponds to 2400 vertical pixels, beyond which
1013   it interpolates extra black lines.
1014  */
1015
1016 static void
1017 analogtv_setup_levels(analogtv *it, double avgheight)
1018 {
1019   int i,height;
1020   static const double levelfac[3]={-7.5, 5.5, 24.5};
1021
1022   for (height=0; height<avgheight+2.0 && height<=ANALOGTV_MAX_LINEHEIGHT; height++) {
1023
1024     for (i=0; i<height; i++) {
1025       it->leveltable[height][i].index = 2;
1026     }
1027     
1028     if (avgheight>=3) {
1029       it->leveltable[height][0].index=0;
1030     }
1031     if (avgheight>=5) {
1032       it->leveltable[height][height-1].index=0;
1033     }
1034     if (avgheight>=7) {
1035       it->leveltable[height][1].index=1;
1036       it->leveltable[height][height-2].index=1;
1037     }
1038
1039     for (i=0; i<height; i++) {
1040       it->leveltable[height][i].value = 
1041         (40.0 + levelfac[it->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=it->leveltable[ybot-ytop][y-ytop].index;
1060     double levelmult=it->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+ANALOGTV_MAX_LINEHEIGHT) ybot=ytop+ANALOGTV_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
1568 analogtv_input *
1569 analogtv_input_allocate()
1570 {
1571   analogtv_input *ret=(analogtv_input *)calloc(1,sizeof(analogtv_input));
1572
1573   return ret;
1574 }
1575
1576 /*
1577   This takes a screen image and encodes it as a video camera would,
1578   including all the bandlimiting and YIQ modulation.
1579   This isn't especially tuned for speed.
1580 */
1581
1582 int
1583 analogtv_load_ximage(analogtv *it, analogtv_input *input, XImage *pic_im)
1584 {
1585   int i,x,y;
1586   int img_w,img_h;
1587   int fyx[7],fyy[7];
1588   int fix[4],fiy[4];
1589   int fqx[4],fqy[4];
1590   XColor col1[ANALOGTV_PIC_LEN];
1591   XColor col2[ANALOGTV_PIC_LEN];
1592   int multiq[ANALOGTV_PIC_LEN+4];
1593   int y_overscan=5; /* overscan this much top and bottom */
1594   int y_scanlength=ANALOGTV_VISLINES+2*y_overscan;
1595
1596   img_w=pic_im->width;
1597   img_h=pic_im->height;
1598   
1599   for (i=0; i<ANALOGTV_PIC_LEN+4; i++) {
1600     double phase=90.0-90.0*i;
1601     double ampl=1.0;
1602     multiq[i]=(int)(-cos(3.1415926/180.0*(phase-303)) * 4096.0 * ampl);
1603   }
1604
1605   for (y=0; y<y_scanlength; y++) {
1606     int picy1=(y*img_h)/y_scanlength;
1607     int picy2=(y*img_h + y_scanlength/2)/y_scanlength;
1608
1609     for (x=0; x<ANALOGTV_PIC_LEN; x++) {
1610       int picx=(x*img_w)/ANALOGTV_PIC_LEN;
1611       col1[x].pixel=XGetPixel(pic_im, picx, picy1);
1612       col2[x].pixel=XGetPixel(pic_im, picx, picy2);
1613     }
1614     XQueryColors(it->dpy, it->colormap, col1, ANALOGTV_PIC_LEN);
1615     XQueryColors(it->dpy, it->colormap, col2, ANALOGTV_PIC_LEN);
1616
1617     for (i=0; i<7; i++) fyx[i]=fyy[i]=0;
1618     for (i=0; i<4; i++) fix[i]=fiy[i]=fqx[i]=fqy[i]=0.0;
1619
1620     for (x=0; x<ANALOGTV_PIC_LEN; x++) {
1621       int rawy,rawi,rawq;
1622       int filty,filti,filtq;
1623       int composite;
1624       /* Compute YIQ as:
1625            y=0.30 r + 0.59 g + 0.11 b
1626            i=0.60 r - 0.28 g - 0.32 b
1627            q=0.21 r - 0.52 g + 0.31 b
1628           The coefficients below are in .4 format */
1629
1630       rawy=( 5*col1[x].red + 11*col1[x].green + 2*col1[x].blue +
1631              5*col2[x].red + 11*col2[x].green + 2*col2[x].blue)>>7;
1632       rawi=(10*col1[x].red -  4*col1[x].green - 5*col1[x].blue +
1633             10*col2[x].red -  4*col2[x].green - 5*col2[x].blue)>>7;
1634       rawq=( 3*col1[x].red -  8*col1[x].green + 5*col1[x].blue +
1635              3*col2[x].red -  8*col2[x].green + 5*col2[x].blue)>>7;
1636
1637       /* Filter y at with a 4-pole low-pass Butterworth filter at 3.5 MHz
1638          with an extra zero at 3.5 MHz, from
1639          mkfilter -Bu -Lp -o 4 -a 2.1428571429e-01 0 -Z 2.5e-01 -l */
1640
1641       fyx[0] = fyx[1]; fyx[1] = fyx[2]; fyx[2] = fyx[3];
1642       fyx[3] = fyx[4]; fyx[4] = fyx[5]; fyx[5] = fyx[6];
1643       fyx[6] = (rawy * 1897) >> 16;
1644       fyy[0] = fyy[1]; fyy[1] = fyy[2]; fyy[2] = fyy[3];
1645       fyy[3] = fyy[4]; fyy[4] = fyy[5]; fyy[5] = fyy[6];
1646       fyy[6] = (fyx[0]+fyx[6]) + 4*(fyx[1]+fyx[5]) + 7*(fyx[2]+fyx[4]) + 8*fyx[3]
1647         + ((-151*fyy[2] + 8115*fyy[3] - 38312*fyy[4] + 36586*fyy[5]) >> 16);
1648       filty = fyy[6];
1649
1650       /* Filter I at 1.5 MHz. 3 pole Butterworth from
1651          mkfilter -Bu -Lp -o 3 -a 1.0714285714e-01 0 */
1652
1653       fix[0] = fix[1]; fix[1] = fix[2]; fix[2] = fix[3];
1654       fix[3] = (rawi * 1413) >> 16;
1655       fiy[0] = fiy[1]; fiy[1] = fiy[2]; fiy[2] = fiy[3];
1656       fiy[3] = (fix[0]+fix[3]) + 3*(fix[1]+fix[2])
1657         + ((16559*fiy[0] - 72008*fiy[1] + 109682*fiy[2]) >> 16);
1658       filti = fiy[3];
1659
1660       /* Filter Q at 0.5 MHz. 3 pole Butterworth from
1661          mkfilter -Bu -Lp -o 3 -a 3.5714285714e-02 0 -l */
1662
1663       fqx[0] = fqx[1]; fqx[1] = fqx[2]; fqx[2] = fqx[3];
1664       fqx[3] = (rawq * 75) >> 16;
1665       fqy[0] = fqy[1]; fqy[1] = fqy[2]; fqy[2] = fqy[3];
1666       fqy[3] = (fqx[0]+fqx[3]) + 3 * (fqx[1]+fqx[2])
1667         + ((2612*fqy[0] - 9007*fqy[1] + 10453 * fqy[2]) >> 12);
1668       filtq = fqy[3];
1669
1670
1671       composite = filty + ((multiq[x] * filti + multiq[x+3] * filtq)>>12);
1672       composite = ((composite*100)>>14) + ANALOGTV_BLACK_LEVEL;
1673       if (composite>125) composite=125;
1674       if (composite<0) composite=0;
1675       input->signal[y-y_overscan+ANALOGTV_TOP][x+ANALOGTV_PIC_START] = composite;
1676     }
1677   }
1678
1679   return 1;
1680 }
1681
1682 #if 0
1683 void analogtv_channel_noise(analogtv_input *it, analogtv_input *s2)
1684 {
1685   int x,y,newsig;
1686   int change=random()%ANALOGTV_V;
1687   unsigned int fastrnd=random();
1688   double hso=(int)(random()%1000)-500;
1689   int yofs=random()%ANALOGTV_V;
1690   int noise;
1691
1692   for (y=change; y<ANALOGTV_V; y++) {
1693     int s2y=(y+yofs)%ANALOGTV_V;
1694     int filt=0;
1695     int noiselevel=60000 / (y-change+100);
1696
1697     it->line_hsync[y] = s2->line_hsync[y] + (int)hso;
1698     hso *= 0.9;
1699     for (x=0; x<ANALOGTV_H; x++) {
1700       FASTRND;
1701       filt+= (-filt/16) + (int)(fastrnd&0xfff)-0x800;
1702       noise=(filt*noiselevel)>>16;
1703       newsig=s2->signal[s2y][x] + noise;
1704       if (newsig>120) newsig=120;
1705       if (newsig<0) newsig=0;
1706       it->signal[y][x]=newsig;
1707     }
1708   }
1709   s2->vsync=yofs;
1710 }
1711 #endif
1712
1713
1714 void analogtv_add_signal(analogtv *it, analogtv_reception *rec)
1715 {
1716   analogtv_input *inp=rec->input;
1717   double *ps=it->rx_signal;
1718   double *pe=it->rx_signal + ANALOGTV_SIGNAL_LEN;
1719   double *p=ps;
1720   signed char *ss=&inp->signal[0][0];
1721   signed char *se=&inp->signal[0][0] + ANALOGTV_SIGNAL_LEN;
1722   signed char *s=ss + ((unsigned)rec->ofs % ANALOGTV_SIGNAL_LEN);
1723   int i;
1724   int ec=it->channel_change_cycles;
1725   double level=rec->level;
1726   double hfloss=rec->hfloss;
1727   unsigned int fastrnd=random();
1728   double dp[8];
1729
1730   /* assert((se-ss)%4==0 && (se-s)%4==0); */
1731
1732   /* duplicate the first line into the Nth line to ease wraparound computation */
1733   memcpy(inp->signal[ANALOGTV_V], inp->signal[0],
1734          ANALOGTV_H * sizeof(inp->signal[0][0]));
1735
1736   for (i=0; i<8; i++) dp[i]=0.0;
1737
1738   if (ec) {
1739     double noise_ampl;
1740
1741     /* Do a big noisy transition. We can make the transition noise of
1742        high constant strength regardless of signal strength.
1743
1744        There are two separate state machines. here, One is the noise
1745        process and the other is the
1746
1747        We don't bother with the FIR filter here
1748     */
1749
1750     noise_ampl = 1.3;
1751
1752     while (p!=pe && ec>0) {
1753
1754       double sig0=(double)s[0];
1755       double noise = ((int)fastrnd-(int)0x7fffffff) * (50.0/(double)0x7fffffff);
1756       fastrnd = (fastrnd*1103515245+12345) & 0xffffffffu;
1757
1758       p[0] += sig0 * level * (1.0 - noise_ampl) + noise * noise_ampl;
1759
1760       noise_ampl *= 0.99995;
1761
1762       p++;
1763       s++;
1764       if (s>=se) s=ss;
1765       ec--;
1766     }
1767
1768   }
1769
1770   while (p != pe) {
1771     double sig0,sig1,sig2,sig3,sigr;
1772
1773     sig0=(double)s[0];
1774     sig1=(double)s[1];
1775     sig2=(double)s[2];
1776     sig3=(double)s[3];
1777
1778     dp[0]=sig0+sig1+sig2+sig3;
1779
1780     /* Get the video out signal, and add some ghosting, typical of RF
1781        monitor cables. This corresponds to a pretty long cable, but
1782        looks right to me.
1783     */
1784
1785     sigr=(dp[1]*rec->ghostfir[0] + dp[2]*rec->ghostfir[1] +
1786           dp[3]*rec->ghostfir[2] + dp[4]*rec->ghostfir[3]);
1787     dp[4]=dp[3]; dp[3]=dp[2]; dp[2]=dp[1]; dp[1]=dp[0];
1788
1789     p[0] += (sig0+sigr + sig2*hfloss) * level;
1790     p[1] += (sig1+sigr + sig3*hfloss) * level;
1791     p[2] += (sig2+sigr + sig0*hfloss) * level;
1792     p[3] += (sig3+sigr + sig1*hfloss) * level;
1793
1794     p += 4;
1795     s += 4;
1796     if (s>=se) s = ss + (s-se);
1797   }
1798
1799   it->rx_signal_level =
1800     sqrt(it->rx_signal_level * it->rx_signal_level +
1801          (level * level * (1.0 + 4.0*(rec->ghostfir[0] + rec->ghostfir[1] +
1802                                       rec->ghostfir[2] + rec->ghostfir[3]))));
1803
1804
1805   it->channel_change_cycles=0;
1806
1807 }
1808
1809 #ifdef FIXME
1810 /* add hash */
1811   if (it->hashnoise_times[lineno]) {
1812     int hnt=it->hashnoise_times[lineno] - input->line_hsync[lineno];
1813
1814     if (hnt>=0 && hnt<ANALOGTV_PIC_LEN) {
1815       double maxampl=1.0;
1816       double cur=frand(150.0)-20.0;
1817       int len=random()%15+3;
1818       if (len > ANALOGTV_PIC_LEN-hnt) len=ANALOGTV_PIC_LEN-hnt;
1819       for (i=0; i<len; i++) {
1820         double sig=signal[hnt];
1821
1822         sig += cur*maxampl;
1823         cur += frand(5.0)-5.0;
1824         maxampl = maxampl*0.9;
1825
1826         signal[hnt]=sig;
1827         hnt++;
1828       }
1829     }
1830   }
1831 #endif
1832
1833
1834 void analogtv_init_signal(analogtv *it, double noiselevel)
1835 {
1836   double *ps=it->rx_signal;
1837   double *pe=it->rx_signal + ANALOGTV_SIGNAL_LEN;
1838   double *p=ps;
1839   unsigned int fastrnd=random();
1840   double nm1=0.0,nm2=0.0;
1841   double noisemul = sqrt(noiselevel*150)/(double)0x7fffffff;
1842
1843   while (p != pe) {
1844     nm2=nm1;
1845     nm1 = ((int)fastrnd-(int)0x7fffffff) * noisemul;
1846     *p++ = nm1*nm2;
1847     fastrnd = (fastrnd*1103515245+12345) & 0xffffffffu;
1848   }
1849
1850   it->rx_signal_level = noiselevel;
1851 }
1852
1853 void
1854 analogtv_reception_update(analogtv_reception *rec)
1855 {
1856   int i;
1857
1858   if (rec->multipath > 0.0) {
1859     for (i=0; i<ANALOGTV_GHOSTFIR_LEN; i++) {
1860       rec->ghostfir2[i] +=
1861         -(rec->ghostfir2[i]/16.0) + rec->multipath * (frand(0.02)-0.01);
1862     }
1863     if (random()%20==0) {
1864       rec->ghostfir2[random()%(ANALOGTV_GHOSTFIR_LEN)]
1865         = rec->multipath * (frand(0.08)-0.04);
1866     }
1867     for (i=0; i<ANALOGTV_GHOSTFIR_LEN; i++) {
1868       rec->ghostfir[i] = 0.8*rec->ghostfir[i] + 0.2*rec->ghostfir2[i];
1869     }
1870
1871     if (0) {
1872       rec->hfloss2 += -(rec->hfloss2/16.0) + rec->multipath * (frand(0.08)-0.04);
1873       rec->hfloss = 0.5*rec->hfloss + 0.5*rec->hfloss2;
1874     }
1875
1876   } else {
1877     for (i=0; i<ANALOGTV_GHOSTFIR_LEN; i++) {
1878       rec->ghostfir[i] = (i>=ANALOGTV_GHOSTFIR_LEN/2) ? ((i&1) ? +0.04 : -0.08) /ANALOGTV_GHOSTFIR_LEN
1879         : 0.0;
1880     }
1881   }
1882 }
1883
1884
1885 /* jwz: since MacOS doesn't have "6x10", I dumped this font to an XBM...
1886  */
1887
1888 #include "images/6x10font.xbm"
1889
1890 void
1891 analogtv_make_font(Display *dpy, Window window, analogtv_font *f,
1892                    int w, int h, char *fontname)
1893 {
1894   int i;
1895   XFontStruct *font;
1896   Pixmap text_pm;
1897   GC gc;
1898   XGCValues gcv;
1899   XWindowAttributes xgwa;
1900
1901   f->char_w = w;
1902   f->char_h = h;
1903
1904   XGetWindowAttributes (dpy, window, &xgwa);
1905
1906   if (fontname && !strcmp (fontname, "6x10")) {
1907
1908     text_pm = XCreatePixmapFromBitmapData (dpy, window,
1909                                            (char *) font6x10_bits,
1910                                            font6x10_width,
1911                                            font6x10_height,
1912                                            1, 0, 1);
1913     f->text_im = XGetImage(dpy, text_pm, 0, 0, font6x10_width, font6x10_height,
1914                            1, XYPixmap);
1915     XFreePixmap(dpy, text_pm);
1916
1917   } else if (fontname) {
1918
1919     font = XLoadQueryFont (dpy, fontname);
1920     if (!font) {
1921       fprintf(stderr, "analogtv: can't load font %s\n", fontname);
1922       abort();
1923     }
1924
1925     text_pm=XCreatePixmap(dpy, window, 256*f->char_w, f->char_h, 1);
1926
1927     memset(&gcv, 0, sizeof(gcv));
1928     gcv.foreground=1;
1929     gcv.background=0;
1930     gcv.font=font->fid;
1931     gc=XCreateGC(dpy, text_pm, GCFont|GCBackground|GCForeground, &gcv);
1932
1933     XSetForeground(dpy, gc, 0);
1934     XFillRectangle(dpy, text_pm, gc, 0, 0, 256*f->char_w, f->char_h);
1935     XSetForeground(dpy, gc, 1);
1936     for (i=0; i<256; i++) {
1937       char c=i;
1938       int x=f->char_w*i+1;
1939       int y=f->char_h*8/10;
1940       XDrawString(dpy, text_pm, gc, x, y, &c, 1);
1941     }
1942     f->text_im = XGetImage(dpy, text_pm, 0, 0, 256*f->char_w, f->char_h,
1943                            1, XYPixmap);
1944 # if 0
1945     XWriteBitmapFile(dpy, "/tmp/tvfont.xbm", text_pm, 
1946                      256*f->char_w, f->char_h, -1, -1);
1947 # endif
1948     XFreeGC(dpy, gc);
1949     XFreePixmap(dpy, text_pm);
1950   } else {
1951     f->text_im = XCreateImage(dpy, xgwa.visual, 1, XYPixmap, 0, 0,
1952                               256*f->char_w, f->char_h, 8, 0);
1953     f->text_im->data = (char *)calloc(f->text_im->height,
1954                                       f->text_im->bytes_per_line);
1955
1956   }
1957   f->x_mult=4;
1958   f->y_mult=2;
1959 }
1960
1961 int
1962 analogtv_font_pixel(analogtv_font *f, int c, int x, int y)
1963 {
1964   if (x<0 || x>=f->char_w) return 0;
1965   if (y<0 || y>=f->char_h) return 0;
1966   if (c<0 || c>=256) return 0;
1967   return XGetPixel(f->text_im, c*f->char_w + x, y) ? 1 : 0;
1968 }
1969
1970 void
1971 analogtv_font_set_pixel(analogtv_font *f, int c, int x, int y, int value)
1972 {
1973   if (x<0 || x>=f->char_w) return;
1974   if (y<0 || y>=f->char_h) return;
1975   if (c<0 || c>=256) return;
1976
1977   XPutPixel(f->text_im, c*f->char_w + x, y, value);
1978 }
1979
1980 void
1981 analogtv_font_set_char(analogtv_font *f, int c, char *s)
1982 {
1983   int value,x,y;
1984
1985   if (c<0 || c>=256) return;
1986
1987   for (y=0; y<f->char_h; y++) {
1988     for (x=0; x<f->char_w; x++) {
1989       if (!*s) return;
1990       value=(*s==' ') ? 0 : 1;
1991       analogtv_font_set_pixel(f, c, x, y, value);
1992       s++;
1993     }
1994   }
1995 }
1996
1997 void
1998 analogtv_lcp_to_ntsc(double luma, double chroma, double phase, int ntsc[4])
1999 {
2000   int i;
2001   for (i=0; i<4; i++) {
2002     double w=90.0*i + phase;
2003     double val=luma + chroma * (cos(3.1415926/180.0*w));
2004     if (val<0.0) val=0.0;
2005     if (val>127.0) val=127.0;
2006     ntsc[i]=(int)val;
2007   }
2008 }
2009
2010 void
2011 analogtv_draw_solid(analogtv_input *input,
2012                     int left, int right, int top, int bot,
2013                     int ntsc[4])
2014 {
2015   int x,y;
2016
2017   if (right-left<4) right=left+4;
2018   if (bot-top<1) bot=top+1;
2019
2020   for (y=top; y<bot; y++) {
2021     for (x=left; x<right; x++) {
2022       input->signal[y][x] = ntsc[x&3];
2023     }
2024   }
2025 }
2026
2027
2028 void
2029 analogtv_draw_solid_rel_lcp(analogtv_input *input,
2030                             double left, double right, double top, double bot,
2031                             double luma, double chroma, double phase)
2032 {
2033   int ntsc[4];
2034
2035   int topi=(int)(ANALOGTV_TOP + ANALOGTV_VISLINES*top);
2036   int boti=(int)(ANALOGTV_TOP + ANALOGTV_VISLINES*bot);
2037   int lefti=(int)(ANALOGTV_VIS_START + ANALOGTV_VIS_LEN*left);
2038   int righti=(int)(ANALOGTV_VIS_START + ANALOGTV_VIS_LEN*right);
2039
2040   analogtv_lcp_to_ntsc(luma, chroma, phase, ntsc);
2041   analogtv_draw_solid(input, lefti, righti, topi, boti, ntsc);
2042 }
2043
2044
2045 void
2046 analogtv_draw_char(analogtv_input *input, analogtv_font *f,
2047                    int c, int x, int y, int ntsc[4])
2048 {
2049   int yc,xc,ys,xs,pix;
2050
2051   for (yc=0; yc<f->char_h; yc++) {
2052     for (ys=y + yc*f->y_mult; ys<y + (yc+1)*f->y_mult; ys++) {
2053       if (ys<0 || ys>=ANALOGTV_V) continue;
2054
2055       for (xc=0; xc<f->char_w; xc++) {
2056         pix=analogtv_font_pixel(f, c, xc, yc);
2057
2058         for (xs=x + xc*f->x_mult; xs<x + (xc+1)*f->x_mult; xs++) {
2059           if (xs<0 || xs>=ANALOGTV_H) continue;
2060           if (pix) {
2061             input->signal[ys][xs] = ntsc[xs&3];
2062           }
2063         }
2064       }
2065     }
2066   }
2067 }
2068
2069 void
2070 analogtv_draw_string(analogtv_input *input, analogtv_font *f,
2071                      char *s, int x, int y, int ntsc[4])
2072 {
2073   while (*s) {
2074     analogtv_draw_char(input, f, *s, x, y, ntsc);
2075     x += f->char_w * 4;
2076     s++;
2077   }
2078 }
2079
2080 void
2081 analogtv_draw_string_centered(analogtv_input *input, analogtv_font *f,
2082                               char *s, int x, int y, int ntsc[4])
2083 {
2084   int width=strlen(s) * f->char_w * 4;
2085   x -= width/2;
2086
2087   analogtv_draw_string(input, f, s, x, y, ntsc);
2088 }
2089
2090
2091 static const char hextonib[128] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2092                                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2093                                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2094                                    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0,
2095                                    0, 10,11,12,13,14,15,0, 0, 0, 0, 0, 0, 0, 0, 0,
2096                                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2097                                    0, 10,11,12,13,14,15,0, 0, 0, 0, 0, 0, 0, 0, 0,
2098                                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
2099
2100 /*
2101   Much of this function was adapted from logo.c
2102  */
2103 void
2104 analogtv_draw_xpm(analogtv *tv, analogtv_input *input,
2105                   const char * const *xpm, int left, int top)
2106 {
2107   int xpmw,xpmh;
2108   int x,y,tvx,tvy,i;
2109   int rawy,rawi,rawq;
2110   int ncolors, nbytes;
2111   char dummyc;
2112   struct {
2113     int r; int g; int b;
2114   } cmap[256];
2115
2116
2117   if (4 != sscanf ((const char *) *xpm,
2118                    "%d %d %d %d %c",
2119                    &xpmw, &xpmh, &ncolors, &nbytes, &dummyc))
2120     abort();
2121   if (ncolors < 1 || ncolors > 255)
2122     abort();
2123   if (nbytes != 1) /* a serious limitation */
2124     abort();
2125   xpm++;
2126
2127   for (i = 0; i < ncolors; i++) {
2128     const char *line = *xpm;
2129     int colori = ((unsigned char)*line++)&0xff;
2130     while (*line)
2131       {
2132         int r, g, b;
2133         char which;
2134         while (*line == ' ' || *line == '\t')
2135           line++;
2136         which = *line++;
2137         if (which != 'c' && which != 'm')
2138           abort();
2139         while (*line == ' ' || *line == '\t')
2140           line++;
2141         if (!strncasecmp(line, "None", 4))
2142           {
2143             r = g = b = -1;
2144             line += 4;
2145           }
2146         else
2147           {
2148             if (*line == '#')
2149               line++;
2150             r = (hextonib[(int) line[0]] << 4) | hextonib[(int) line[1]];
2151             line += 2;
2152             g = (hextonib[(int) line[0]] << 4) | hextonib[(int) line[1]];
2153             line += 2;
2154             b = (hextonib[(int) line[0]] << 4) | hextonib[(int) line[1]];
2155             line += 2;
2156           }
2157
2158         if (which == 'c')
2159           {
2160             cmap[colori].r = r;
2161             cmap[colori].g = g;
2162             cmap[colori].b = b;
2163           }
2164       }
2165
2166     xpm++;
2167   }
2168
2169   for (y=0; y<xpmh; y++) {
2170     const char *line = *xpm++;
2171     tvy=y+top;
2172     if (tvy<ANALOGTV_TOP || tvy>=ANALOGTV_BOT) continue;
2173
2174     for (x=0; x<xpmw; x++) {
2175       int cbyte=((unsigned char)line[x])&0xff;
2176       int ntsc[4];
2177       tvx=x*4+left;
2178       if (tvx<ANALOGTV_PIC_START || tvx+4>ANALOGTV_PIC_END) continue;
2179
2180       rawy=( 5*cmap[cbyte].r + 11*cmap[cbyte].g + 2*cmap[cbyte].b) / 64;
2181       rawi=(10*cmap[cbyte].r -  4*cmap[cbyte].g - 5*cmap[cbyte].b) / 64;
2182       rawq=( 3*cmap[cbyte].r -  8*cmap[cbyte].g + 5*cmap[cbyte].b) / 64;
2183
2184       ntsc[0]=rawy+rawq;
2185       ntsc[1]=rawy-rawi;
2186       ntsc[2]=rawy-rawq;
2187       ntsc[3]=rawy+rawi;
2188
2189       for (i=0; i<4; i++) {
2190         if (ntsc[i]>ANALOGTV_WHITE_LEVEL) ntsc[i]=ANALOGTV_WHITE_LEVEL;
2191         if (ntsc[i]<ANALOGTV_BLACK_LEVEL) ntsc[i]=ANALOGTV_BLACK_LEVEL;
2192       }
2193
2194       input->signal[tvy][tvx+0]= ntsc[(tvx+0)&3];
2195       input->signal[tvy][tvx+1]= ntsc[(tvx+1)&3];
2196       input->signal[tvy][tvx+2]= ntsc[(tvx+2)&3];
2197       input->signal[tvy][tvx+3]= ntsc[(tvx+3)&3];
2198     }
2199   }
2200 }