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