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