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