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