osmocom-analog/src/tv/convergence.c

110 lines
3.4 KiB
C

/* Color Convergence test image generator
*
* (C) 2019 by Andreas Eversberg <jolly@eversberg.eu>
* All Rights Reserved
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <math.h>
#include <stdlib.h>
#include <stdint.h>
#include "../libsample/sample.h"
#include "convergence.h"
#define GRID_LINES (4 * thick)
#define GRID_HEIGHT 40
#define GRID_HEIGHT2 20
#define CENTER_LINE (287 - 2)
#define GRID_WIDTH 0.0000027
#define GRID_WIDTH2 0.00000135
#define RAMP_WIDTH (0.0000002 * thick)
#define GRID_LEVEL 1.0
#define FIELD_LEVEL 0.00
/* create cosine ramp, so that the bandwidth is not higher than 2 * width of the ramp(0..1) */
static inline double ramp(double x)
{
return 0.5 - 0.5 * cos(x * M_PI);
}
int convergence_gen_line(sample_t *sample, double x, double samplerate, double line_start, double line_end, int line, double thick)
{
double step = 1.0 / samplerate;
int i = 0;
double render_start, render_end, center_x;
/* skip x to line_start */
while (x < line_start && x < line_end) {
i++;
x += step;
}
if (x >= line_end)
return i;
/* calculate phase for ramp start of center line */
center_x = (line_end - line_start) / 2.0 + line_start;
/* calculate position in grid:
* get the distance below the center line (line - CENTER_LINE)
* then be sure not to get negative value: add a multiple of the grid period
* then use modulo to get the distance below the grid line */
if (((line - CENTER_LINE + GRID_HEIGHT*40) % GRID_HEIGHT) < GRID_LINES) {
/* grid line after middle field */
while (x < line_end) {
sample[i++] = GRID_LEVEL;
x += step;
}
} else {
while (1) {
/* calculate position for next ramp:
* get the distance to center (center_x - x - RAMP_WIDTH)
* then be sure not to get negative value: add a multiple of the grid period
* then use fmod to get the next ramp start */
if (((line - CENTER_LINE + GRID_HEIGHT2*40) % GRID_HEIGHT2) < GRID_LINES)
render_start = fmod(center_x - x - RAMP_WIDTH + GRID_WIDTH2*40.0, GRID_WIDTH2) + x;
else
render_start = fmod(center_x - x - RAMP_WIDTH + GRID_WIDTH*40.0, GRID_WIDTH) + x;
/* draw background field up to grid start */
while (x < render_start && x < line_end) {
sample[i++] = FIELD_LEVEL;
x += step;
}
if (x >= line_end)
break;
/* ramp up to grid level */
render_end = render_start + RAMP_WIDTH;
while (x < render_end && x < line_end) {
sample[i++] = ramp((x - render_start) / RAMP_WIDTH) * (GRID_LEVEL - FIELD_LEVEL) + FIELD_LEVEL;
x += step;
}
if (x >= line_end)
break;
render_start = render_end;
/* ramp down to field level */
render_end = render_start + RAMP_WIDTH;
while (x < render_end && x < line_end) {
sample[i++] = ramp((x - render_start) / RAMP_WIDTH) * (FIELD_LEVEL - GRID_LEVEL) + GRID_LEVEL;
x += step;
}
if (x >= line_end)
break;
}
}
return i;
}