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