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