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