121 lines
2.8 KiB
Python
121 lines
2.8 KiB
Python
|
#/usr/bin/env python3
|
||
|
import numpy as np
|
||
|
|
||
|
|
||
|
from scipy.io import wavfile
|
||
|
from scipy.misc import imread
|
||
|
from matplotlib import pyplot as plt
|
||
|
|
||
|
|
||
|
WIDTH = 640
|
||
|
HEIGHT = 496
|
||
|
|
||
|
OUTPUT_RATE = 48000
|
||
|
|
||
|
VIS_START_FREQ = 1900
|
||
|
VIS_START_DUR = 300
|
||
|
VIS_PAUSE = 10
|
||
|
VIS_ONE_FREQ = 1100
|
||
|
VIS_ZERO_FREQ = 1300
|
||
|
VIS_BIT_DUR = 30
|
||
|
# Code 97 + even parity, lsb first
|
||
|
VIS_BITS = [True, False, False, False, False, True, True, True]
|
||
|
|
||
|
SYNC_FREQ = 1200
|
||
|
SYNC_DUR = 20
|
||
|
|
||
|
PORCH_DUR = 2.080
|
||
|
|
||
|
PIXEL_DUR = 0.382
|
||
|
|
||
|
COLOR_LOW_FREQ = 1500
|
||
|
COLOR_HIGH_FREG = 2300
|
||
|
|
||
|
phase_acc = 0
|
||
|
|
||
|
|
||
|
def sine_gen(freq):
|
||
|
global phase_acc
|
||
|
phase_inc = (2 * np.pi / OUTPUT_RATE) * freq
|
||
|
phase_acc += phase_inc
|
||
|
if phase_acc > 2 * np.pi:
|
||
|
phase_acc = phase_acc - 2 * np.pi
|
||
|
|
||
|
return np.sin(phase_acc)
|
||
|
|
||
|
|
||
|
samples_left = 0
|
||
|
def make_tone(freq, duration, data):
|
||
|
global samples_left
|
||
|
samples = duration / 1000 * OUTPUT_RATE + samples_left
|
||
|
sample_count = int(samples)
|
||
|
samples_left = samples - sample_count
|
||
|
|
||
|
for i in range(0, sample_count):
|
||
|
data += [sine_gen(freq)]
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
def make_vis(samples):
|
||
|
make_tone(VIS_START_FREQ, VIS_START_DUR, samples)
|
||
|
make_tone(SYNC_FREQ, VIS_PAUSE, samples)
|
||
|
make_tone(VIS_START_FREQ, VIS_START_DUR, samples)
|
||
|
|
||
|
make_tone(SYNC_FREQ, VIS_BIT_DUR, samples)
|
||
|
for bit in VIS_BITS:
|
||
|
if bit:
|
||
|
make_tone(VIS_ONE_FREQ, VIS_BIT_DUR, samples)
|
||
|
else:
|
||
|
make_tone(VIS_ZERO_FREQ, VIS_BIT_DUR, samples)
|
||
|
|
||
|
make_tone(SYNC_FREQ, VIS_BIT_DUR, samples)
|
||
|
|
||
|
|
||
|
def main():
|
||
|
|
||
|
image = imread('testcard.png', mode='YCbCr')
|
||
|
|
||
|
samples = []
|
||
|
|
||
|
make_vis(samples)
|
||
|
|
||
|
for y in range(0, int(HEIGHT/2)):
|
||
|
make_tone(SYNC_FREQ, SYNC_DUR, samples)
|
||
|
make_tone(COLOR_LOW_FREQ, PORCH_DUR, samples)
|
||
|
|
||
|
for x in range(0, WIDTH):
|
||
|
lum = image[y*2, x, 0] / 255.0
|
||
|
freq = COLOR_LOW_FREQ + lum * (COLOR_HIGH_FREG - COLOR_LOW_FREQ)
|
||
|
make_tone(freq, PIXEL_DUR, samples)
|
||
|
|
||
|
for x in range(0, WIDTH):
|
||
|
cr0 = image[y*2, x, 2] / 255.0
|
||
|
cr1 = image[y*2 + 1, x, 2] / 255.0
|
||
|
cr = (cr0 + cr1) / 2
|
||
|
freq = COLOR_LOW_FREQ + cr * (COLOR_HIGH_FREG - COLOR_LOW_FREQ)
|
||
|
make_tone(freq, PIXEL_DUR, samples)
|
||
|
|
||
|
for x in range(0, WIDTH):
|
||
|
cb0 = image[y*2, x, 1] / 255.0
|
||
|
cb1 = image[y*2 + 1, x, 1] / 255.0
|
||
|
cb = (cb0 + cb1) / 2
|
||
|
freq = COLOR_LOW_FREQ + cb * (COLOR_HIGH_FREG - COLOR_LOW_FREQ)
|
||
|
make_tone(freq, PIXEL_DUR, samples)
|
||
|
|
||
|
for x in range(0, WIDTH):
|
||
|
lum = image[y*2 + 1, x, 0] / 255.0
|
||
|
freq = COLOR_LOW_FREQ + lum * (COLOR_HIGH_FREG - COLOR_LOW_FREQ)
|
||
|
make_tone(freq, PIXEL_DUR, samples)
|
||
|
|
||
|
|
||
|
samples = np.array(samples)
|
||
|
|
||
|
samples = samples * 0.75 * 32767
|
||
|
samples = np.int16(samples)
|
||
|
|
||
|
wavfile.write("output.wav", OUTPUT_RATE, samples)
|
||
|
|
||
|
if __name__ == '__main__':
|
||
|
main()
|