#!/usr/bin/env python3

import matplotlib.pyplot as plt
import struct

from PIL import Image

IMG_WIDTH = 640

SYNC_LENGTH = 105
SYNC_THRESH = 100
PORCH_LENGTH = 10

LINE_LENGTH = SYNC_LENGTH + PORCH_LENGTH + 4 * IMG_WIDTH

MAX_DEV = 600
CENTER = 1750
MIN_FREQ = 1200
MAX_FREQ = 2300

COLOR_LOW = 1500
COLOR_HIGH = MAX_FREQ

def to_freq(sample):
    freq = CENTER + sample * MAX_DEV
    freq = max(MIN_FREQ, freq)
    freq = min(MAX_FREQ, freq)
    return freq

def to_color(sample):
    sample = (sample - 1500) / (COLOR_HIGH - COLOR_LOW)
    sample = int(sample * 255)
    sample = max(sample, 0)
    sample = min(sample, 255)
    return sample

def ycbcr_to_rgb(y, cb, cr):
    #https://stackoverflow.com/questions/4041840/function-to-convert-ycbcr-to-rgb/15333019#15333019
    cr = cr - 128 ;
    cb = cb - 128 ;
    r = y + 45 * cr / 32 ;
    g = y - (11 * cb + 23 * cr) / 32 ;
    b = y + 113 * cb / 64 ;

    return (int(r), int(g), int(b))

last_sync = False
def is_sync(backlog):
    global last_sync
    count = 0
    for sample in backlog:
        if sample < COLOR_LOW:
            count += 1

    res = False
    if count > SYNC_THRESH and not last_sync:
        res = True

    last_sync = count > SYNC_THRESH
    return res


def render_lines(line):
    pixels = [[(0,0,0)] * IMG_WIDTH,  [(0,0,0)] * IMG_WIDTH]

    # Strip porch
    porch = len(line) - SYNC_LENGTH - 4 * IMG_WIDTH
    if porch < 0:
        return pixels
    line = line[PORCH_LENGTH:]

    for i in range(0, IMG_WIDTH):
        y0 = to_color(line[i])
        cr = to_color(line[IMG_WIDTH + i])
        cb = to_color(line[2 * IMG_WIDTH + i])
        y1 = to_color(line[3 * IMG_WIDTH + i])

        pixels[0][i] = ycbcr_to_rgb(y0, cb, cr)
        pixels[1][i] = ycbcr_to_rgb(y1, cb, cr)

    return pixels

def main():
    data_file = open("demod.dat", 'rb')

    samples = []
    syncs = []

    pixels = []

    backlog = [0.0] * SYNC_LENGTH
    line = []

    bytes = data_file.read(4)
    while len(bytes) == 4:
        sample = struct.unpack('f', bytes)[0]
        sample = to_freq(sample)
        samples += [sample]

        backlog = backlog[1:] + [sample]

        line += [sample]

        if is_sync(backlog) or len(line) > LINE_LENGTH:
            if len(line) > SYNC_LENGTH + 4 * IMG_WIDTH:
                syncs += [1000]
                print("%d \t %d" % (len(line), len(line) - LINE_LENGTH))
                pixels += render_lines(line)
            else:
                print("Short line dropped")
            line = []
        else:
            syncs += [0]

        bytes = data_file.read(4)


    plt.plot(samples)
    plt.plot(syncs)
    plt.show()

    img = Image.new('RGB', (IMG_WIDTH, len(pixels)))
    img_pix = img.load()
    for x in range(0, IMG_WIDTH):
        for y in range(0, len(pixels)):
            img_pix[x,y] = pixels[y][x]

    img.save('output.png')


if __name__ == '__main__':
    main()
