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