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