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