summaryrefslogtreecommitdiffstats
path: root/hacks/analogtv.h
diff options
context:
space:
mode:
Diffstat (limited to 'hacks/analogtv.h')
-rw-r--r--hacks/analogtv.h338
1 files changed, 338 insertions, 0 deletions
diff --git a/hacks/analogtv.h b/hacks/analogtv.h
new file mode 100644
index 0000000..e3170f1
--- /dev/null
+++ b/hacks/analogtv.h
@@ -0,0 +1,338 @@
+/* analogtv, Copyright (c) 2003-2018 Trevor Blackwell <tlb@tlb.org>
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation. No representations are made about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ */
+
+#ifndef _XSCREENSAVER_ANALOGTV_H
+#define _XSCREENSAVER_ANALOGTV_H
+
+#include "thread_util.h"
+#include "xshm.h"
+
+#if defined(USE_IPHONE) || defined(HAVE_ANDROID)
+# define HAVE_MOBILE
+#endif
+
+/*
+ You'll need these to generate standard NTSC TV signals
+ */
+enum {
+ /* We don't handle interlace here */
+ ANALOGTV_V=262,
+ ANALOGTV_TOP=30,
+ ANALOGTV_VISLINES=200,
+ ANALOGTV_BOT=ANALOGTV_TOP + ANALOGTV_VISLINES,
+
+ /* This really defines our sampling rate, 4x the colorburst
+ frequency. Handily equal to the Apple II's dot clock.
+ You could also make a case for using 3x the colorburst freq,
+ but 4x isn't hard to deal with. */
+ ANALOGTV_H=912,
+
+ /* Each line is 63500 nS long. The sync pulse is 4700 nS long, etc.
+ Define sync, back porch, colorburst, picture, and front porch
+ positions */
+ ANALOGTV_SYNC_START=0,
+ ANALOGTV_BP_START=4700*ANALOGTV_H/63500,
+ ANALOGTV_CB_START=5800*ANALOGTV_H/63500,
+ /* signal[row][ANALOGTV_PIC_START] is the first displayed pixel */
+ ANALOGTV_PIC_START=9400*ANALOGTV_H/63500,
+ ANALOGTV_PIC_LEN=52600*ANALOGTV_H/63500,
+ ANALOGTV_FP_START=62000*ANALOGTV_H/63500,
+ ANALOGTV_PIC_END=ANALOGTV_FP_START,
+
+ /* TVs scan past the edges of the picture tube, so normally you only
+ want to use about the middle 3/4 of the nominal scan line.
+ */
+ ANALOGTV_VIS_START=ANALOGTV_PIC_START + (ANALOGTV_PIC_LEN*1/8),
+ ANALOGTV_VIS_END=ANALOGTV_PIC_START + (ANALOGTV_PIC_LEN*7/8),
+ ANALOGTV_VIS_LEN=ANALOGTV_VIS_END-ANALOGTV_VIS_START,
+
+ ANALOGTV_HASHNOISE_LEN=6,
+
+ ANALOGTV_GHOSTFIR_LEN=4,
+
+ /* analogtv.signal is in IRE units, as defined below: */
+ ANALOGTV_WHITE_LEVEL=100,
+ ANALOGTV_GRAY50_LEVEL=55,
+ ANALOGTV_GRAY30_LEVEL=35,
+ ANALOGTV_BLACK_LEVEL=10,
+ ANALOGTV_BLANK_LEVEL=0,
+ ANALOGTV_SYNC_LEVEL=-40,
+ ANALOGTV_CB_LEVEL=20,
+
+ ANALOGTV_SIGNAL_LEN=ANALOGTV_V*ANALOGTV_H,
+
+ /* The number of intensity levels we deal with for gamma correction &c */
+ ANALOGTV_CV_MAX=1024,
+
+ /* MAX_LINEHEIGHT corresponds to 2400 vertical pixels, beyond which
+ it interpolates extra black lines. */
+ ANALOGTV_MAX_LINEHEIGHT=12
+
+};
+
+typedef struct analogtv_input_s {
+ signed char signal[ANALOGTV_V+1][ANALOGTV_H];
+
+ int do_teletext;
+
+ /* for client use */
+ void (*updater)(struct analogtv_input_s *inp);
+ void *client_data;
+ double next_update_time;
+
+} analogtv_input;
+
+typedef struct analogtv_font_s {
+ XImage *text_im;
+ int char_w, char_h;
+ int x_mult, y_mult;
+} analogtv_font;
+
+typedef struct analogtv_reception_s {
+
+ analogtv_input *input;
+ double ofs;
+ double level;
+ double multipath;
+ double freqerr;
+
+ double ghostfir[ANALOGTV_GHOSTFIR_LEN];
+ double ghostfir2[ANALOGTV_GHOSTFIR_LEN];
+
+ double hfloss;
+ double hfloss2;
+
+} analogtv_reception;
+
+/*
+ The rest of this should be considered mostly opaque to the analogtv module.
+ */
+
+struct analogtv_yiq_s {
+ float y,i,q;
+} /*yiq[ANALOGTV_PIC_LEN+10] */;
+
+typedef struct analogtv_s {
+
+ Display *dpy;
+ Window window;
+ Screen *screen;
+ XWindowAttributes xgwa;
+
+ struct threadpool threads;
+
+#if 0
+ unsigned int onscreen_signature[ANALOGTV_V];
+#endif
+
+ int n_colors;
+
+ int interlace;
+ int interlace_counter;
+
+ float agclevel;
+
+ /* If you change these, call analogtv_set_demod */
+ float tint_control,color_control,brightness_control,contrast_control;
+ float height_control, width_control, squish_control;
+ float horiz_desync;
+ float squeezebottom;
+ float powerup;
+
+ /* internal cache */
+ int blur_mult;
+
+ /* For fast display, set fakeit_top, fakeit_bot to
+ the scanlines (0..ANALOGTV_V) that can be preserved on screen.
+ fakeit_scroll is the number of scan lines to scroll it up,
+ or 0 to not scroll at all. It will DTRT if asked to scroll from
+ an offscreen region.
+ */
+ int fakeit_top;
+ int fakeit_bot;
+ int fakeit_scroll;
+ int redraw_all;
+
+ int use_cmap,use_color;
+ int bilevel_signal;
+
+ XShmSegmentInfo shm_info;
+ int visdepth,visclass,visbits;
+ int red_invprec, red_shift;
+ int green_invprec, green_shift;
+ int blue_invprec, blue_shift;
+ unsigned long red_mask, green_mask, blue_mask;
+
+ Colormap colormap;
+ int usewidth,useheight,xrepl,subwidth;
+ XImage *image; /* usewidth * useheight */
+ GC gc;
+ int screen_xo,screen_yo; /* centers image in window */
+
+ int flutter_horiz_desync;
+ int flutter_tint;
+
+ struct timeval last_display_time;
+ int need_clear;
+
+
+ /* Add hash (in the radio sense, not the programming sense.) These
+ are the small white streaks that appear in quasi-regular patterns
+ all over the screen when someone is running the vacuum cleaner or
+ the blender. We also set shrinkpulse for one period which
+ squishes the image horizontally to simulate the temporary line
+ voltate drop when someone turns on a big motor */
+ double hashnoise_rpm;
+ int hashnoise_counter;
+ int hashnoise_times[ANALOGTV_V];
+ int hashnoise_signal[ANALOGTV_V];
+ int hashnoise_on;
+ int hashnoise_enable;
+ int shrinkpulse;
+
+ float crtload[ANALOGTV_V];
+
+ unsigned int red_values[ANALOGTV_CV_MAX];
+ unsigned int green_values[ANALOGTV_CV_MAX];
+ unsigned int blue_values[ANALOGTV_CV_MAX];
+
+ unsigned long colors[256];
+ int cmap_y_levels;
+ int cmap_i_levels;
+ int cmap_q_levels;
+
+ float tint_i, tint_q;
+
+ int cur_hsync;
+ int line_hsync[ANALOGTV_V];
+ int cur_vsync;
+ double cb_phase[4];
+ double line_cb_phase[ANALOGTV_V][4];
+
+ int channel_change_cycles;
+ double rx_signal_level;
+ float *rx_signal;
+
+ struct {
+ int index;
+ double value;
+ } leveltable[ANALOGTV_MAX_LINEHEIGHT+1][ANALOGTV_MAX_LINEHEIGHT+1];
+
+ /* Only valid during draw. */
+ unsigned random0, random1;
+ double noiselevel;
+ const analogtv_reception *const *recs;
+ unsigned rec_count;
+
+ float *signal_subtotals;
+
+ float puheight;
+} analogtv;
+
+
+analogtv *analogtv_allocate(Display *dpy, Window window);
+analogtv_input *analogtv_input_allocate(void);
+
+/* call if window size changes */
+void analogtv_reconfigure(analogtv *it);
+
+void analogtv_set_defaults(analogtv *it, char *prefix);
+void analogtv_release(analogtv *it);
+int analogtv_set_demod(analogtv *it);
+void analogtv_setup_frame(analogtv *it);
+void analogtv_setup_sync(analogtv_input *input, int do_cb, int do_ssavi);
+void analogtv_draw(analogtv *it, double noiselevel,
+ const analogtv_reception *const *recs, unsigned rec_count);
+
+int analogtv_load_ximage(analogtv *it, analogtv_input *input,
+ XImage *pic_im, XImage *mask_im,
+ int xoff, int yoff, int width, int height);
+
+void analogtv_reception_update(analogtv_reception *inp);
+
+void analogtv_setup_teletext(analogtv_input *input);
+
+
+/* Functions for rendering content into an analogtv_input */
+
+void analogtv_make_font(Display *dpy, Window window,
+ analogtv_font *f, int w, int h, char *fontname);
+int analogtv_font_pixel(analogtv_font *f, int c, int x, int y);
+void analogtv_font_set_pixel(analogtv_font *f, int c, int x, int y, int value);
+void analogtv_font_set_char(analogtv_font *f, int c, char *s);
+void analogtv_lcp_to_ntsc(double luma, double chroma, double phase,
+ int ntsc[4]);
+
+
+void analogtv_draw_solid(analogtv_input *input,
+ int left, int right, int top, int bot,
+ int ntsc[4]);
+
+void analogtv_draw_solid_rel_lcp(analogtv_input *input,
+ double left, double right,
+ double top, double bot,
+ double luma, double chroma, double phase);
+
+void analogtv_draw_char(analogtv_input *input, analogtv_font *f,
+ int c, int x, int y, int ntsc[4]);
+void analogtv_draw_string(analogtv_input *input, analogtv_font *f,
+ char *s, int x, int y, int ntsc[4]);
+void analogtv_draw_string_centered(analogtv_input *input, analogtv_font *f,
+ char *s, int x, int y, int ntsc[4]);
+
+int analogtv_handle_events (analogtv *it);
+
+#ifdef HAVE_XSHM_EXTENSION
+#define ANALOGTV_DEFAULTS_SHM "*useSHM: True",
+#else
+#define ANALOGTV_DEFAULTS_SHM
+#endif
+
+#ifndef HAVE_MOBILE
+# define ANALOGTV_DEF_BRIGHTNESS "2"
+# define ANALOGTV_DEF_CONTRAST "150"
+#else
+ /* Need to really crank this up for it to look good on the iPhone screen. */
+# define ANALOGTV_DEF_BRIGHTNESS "3"
+# define ANALOGTV_DEF_CONTRAST "400"
+#endif
+
+/* Brightness: useful range is around -75 to 100.
+ Contrast: useful range is around 0 - 500.
+ Color: useful range is around +/- 500.
+ Tint: range is mod 360.
+
+ The values in the 'analogtv' struct are the resource divided by 100.0,
+ except for tint, which is exact.
+ */
+
+#define ANALOGTV_DEFAULTS \
+ "*TVColor: 70", \
+ "*TVTint: 5", \
+ "*TVBrightness: " ANALOGTV_DEF_BRIGHTNESS, \
+ "*TVContrast: " ANALOGTV_DEF_CONTRAST, \
+ "*Background: Black", \
+ "*use_cmap: 0", \
+ "*geometry: 800x600", \
+ "*fpsSolid: True", \
+ "*lowrez: True", \
+ THREAD_DEFAULTS \
+ ANALOGTV_DEFAULTS_SHM
+
+#define ANALOGTV_OPTIONS \
+ THREAD_OPTIONS \
+ { "-use-cmap", ".use_cmap", XrmoptionSepArg, 0 }, \
+ { "-tv-color", ".TVColor", XrmoptionSepArg, 0 }, \
+ { "-tv-tint", ".TVTint", XrmoptionSepArg, 0 }, \
+ { "-tv-brightness", ".TVBrightness", XrmoptionSepArg, 0 }, \
+ { "-tv-contrast", ".TVContrast", XrmoptionSepArg, 0 },
+
+#endif /* _XSCREENSAVER_ANALOGTV_H */