let's be a bit more consistent with variable names
This commit is contained in:
parent
3a9fa29ca2
commit
726a89abb0
9 changed files with 115 additions and 107 deletions
BIN
.gitignore
(Stored with Git LFS)
vendored
Normal file
BIN
.gitignore
(Stored with Git LFS)
vendored
Normal file
Binary file not shown.
100
src/Encoder.gd
100
src/Encoder.gd
|
@ -12,6 +12,7 @@ const HEADER_PULSE_LENGTH = 0.3 # 300 ms
|
||||||
const HEADER_BREAK_LENGTH = 0.01 # 10 ms
|
const HEADER_BREAK_LENGTH = 0.01 # 10 ms
|
||||||
const VIS_BIT_LENGTH = 0.03 # 30 ms
|
const VIS_BIT_LENGTH = 0.03 # 30 ms
|
||||||
const SYNC_PULSE_FREQ = 1200.0
|
const SYNC_PULSE_FREQ = 1200.0
|
||||||
|
const BLANKING_PULSE_FREQ = 1500.0
|
||||||
|
|
||||||
var outputFloats = PackedFloat32Array()
|
var outputFloats = PackedFloat32Array()
|
||||||
|
|
||||||
|
@ -36,21 +37,21 @@ func EncodeHeader(vis: Array):
|
||||||
var parity = 0
|
var parity = 0
|
||||||
vis.reverse()
|
vis.reverse()
|
||||||
for bit in vis:
|
for bit in vis:
|
||||||
var bit_freq = VIS_BIT_FREQ["ONE"] if bit else VIS_BIT_FREQ["ZERO"]
|
var bitFreq = VIS_BIT_FREQ["ONE"] if bit else VIS_BIT_FREQ["ZERO"]
|
||||||
if bit:
|
if bit:
|
||||||
parity += 1
|
parity += 1
|
||||||
outputFloats.append_array(GenerateTone(bit_freq, VIS_BIT_LENGTH))
|
outputFloats.append_array(GenerateTone(bitFreq, VIS_BIT_LENGTH))
|
||||||
|
|
||||||
var parity_freq = VIS_BIT_FREQ["ZERO"] if parity % 2 == 0 else VIS_BIT_FREQ["ONE"]
|
var parityFreq = VIS_BIT_FREQ["ZERO"] if parity % 2 == 0 else VIS_BIT_FREQ["ONE"]
|
||||||
outputFloats.append_array(GenerateTone(parity_freq, VIS_BIT_LENGTH))
|
outputFloats.append_array(GenerateTone(parityFreq, VIS_BIT_LENGTH))
|
||||||
|
|
||||||
outputFloats.append_array(GenerateTone(SYNC_PULSE_FREQ, VIS_BIT_LENGTH))
|
outputFloats.append_array(GenerateTone(SYNC_PULSE_FREQ, VIS_BIT_LENGTH))
|
||||||
|
|
||||||
func GenerateTone(frequency: float, duration: float) -> PackedFloat32Array:
|
func GenerateTone(frequency: float, duration: float) -> PackedFloat32Array:
|
||||||
var samples = PackedFloat32Array()
|
var samples = PackedFloat32Array()
|
||||||
var total_samples = int(duration * SAMPLE_RATE)
|
var totalSamples = int(duration * SAMPLE_RATE)
|
||||||
|
|
||||||
for i in range(total_samples):
|
for i in range(totalSamples):
|
||||||
var time = float(i) / SAMPLE_RATE
|
var time = float(i) / SAMPLE_RATE
|
||||||
var sample = sin(TWO_PI * frequency * time)
|
var sample = sin(TWO_PI * frequency * time)
|
||||||
samples.append(sample)
|
samples.append(sample)
|
||||||
|
@ -60,21 +61,21 @@ func GenerateTone(frequency: float, duration: float) -> PackedFloat32Array:
|
||||||
func GenerateToneFromCurve(frequencies: Array, duration: float) -> PackedFloat32Array:
|
func GenerateToneFromCurve(frequencies: Array, duration: float) -> PackedFloat32Array:
|
||||||
var samples = PackedFloat32Array()
|
var samples = PackedFloat32Array()
|
||||||
var totalSamples = int(duration * SAMPLE_RATE)
|
var totalSamples = int(duration * SAMPLE_RATE)
|
||||||
var num_points = frequencies.size()
|
var points = frequencies.size()
|
||||||
|
|
||||||
var phase = 0.0
|
var phase = 0.0
|
||||||
var timeStep = 1.0 / SAMPLE_RATE
|
var timeStep = 1.0 / SAMPLE_RATE
|
||||||
|
|
||||||
for i in range(totalSamples):
|
for i in range(totalSamples):
|
||||||
var time = float(i) * timeStep
|
var time = float(i) * timeStep
|
||||||
var normalized_time = time / duration
|
var normalizedTime = time / duration
|
||||||
var index_f = normalized_time * (num_points - 1)
|
var indexx = normalizedTime * (points - 1)
|
||||||
var index = int(index_f)
|
var index = int(indexx)
|
||||||
var frac = index_f - index
|
var frac = indexx - index
|
||||||
var freq: float
|
var freq: float
|
||||||
|
|
||||||
if index >= num_points - 1:
|
if index >= points - 1:
|
||||||
freq = frequencies[num_points - 1]
|
freq = frequencies[points - 1]
|
||||||
else:
|
else:
|
||||||
freq = lerp(frequencies[index], frequencies[index + 1], frac)
|
freq = lerp(frequencies[index], frequencies[index + 1], frac)
|
||||||
|
|
||||||
|
@ -85,38 +86,41 @@ func GenerateToneFromCurve(frequencies: Array, duration: float) -> PackedFloat32
|
||||||
|
|
||||||
return samples
|
return samples
|
||||||
|
|
||||||
#func save_wav(path: String, samples: PackedFloat32Array) -> void:
|
func EncodeSSTV(image: Image, skipHeader: bool = false):
|
||||||
#var file = FileAccess.open(path, FileAccess.WRITE)
|
pass
|
||||||
#var byte_data = PackedByteArray()
|
|
||||||
#
|
func SaveAsWav(path: String):
|
||||||
#var num_samples = samples.size()
|
var file = FileAccess.open(path, FileAccess.WRITE)
|
||||||
#var data_chunk_size = num_samples * 2
|
var outputData = PackedByteArray()
|
||||||
#var file_size = 44 + data_chunk_size - 8
|
|
||||||
#
|
var samples = outputFloats.size()
|
||||||
## WAV Header
|
var chunkSize = samples * 2
|
||||||
#byte_data.append_array("RIFF".to_ascii_buffer())
|
var fileSize = 44 + chunkSize - 8
|
||||||
#byte_data.append_array(to_little_endian(file_size, 4))
|
|
||||||
#byte_data.append_array("WAVEfmt ".to_ascii_buffer())
|
# WAV Header
|
||||||
#byte_data.append_array(to_little_endian(16, 4)) # PCM header size
|
outputData.append_array("RIFF".to_ascii_buffer())
|
||||||
#byte_data.append_array(to_little_endian(1, 2)) # PCM format
|
outputData.append_array(ConvertEndian(fileSize, 4))
|
||||||
#byte_data.append_array(to_little_endian(1, 2))
|
outputData.append_array("WAVEfmt ".to_ascii_buffer())
|
||||||
#byte_data.append_array(to_little_endian(SAMPLE_RATE, 4))
|
outputData.append_array(ConvertEndian(16, 4)) # PCM header size
|
||||||
#byte_data.append_array(to_little_endian(SAMPLE_RATE * 1 * 16 / 8, 4)) # Byte rate
|
outputData.append_array(ConvertEndian(1, 2)) # PCM format
|
||||||
#byte_data.append_array(to_little_endian(1 * 16 / 8, 2)) # Block align
|
outputData.append_array(ConvertEndian(1, 2))
|
||||||
#byte_data.append_array(to_little_endian(16, 2))
|
outputData.append_array(ConvertEndian(SAMPLE_RATE, 4))
|
||||||
#byte_data.append_array("data".to_ascii_buffer())
|
outputData.append_array(ConvertEndian(SAMPLE_RATE * 1 * 16 / 8, 4)) # Byte rate
|
||||||
#byte_data.append_array(to_little_endian(data_chunk_size, 4))
|
outputData.append_array(ConvertEndian(1 * 16 / 8, 2)) # Block align
|
||||||
#
|
outputData.append_array(ConvertEndian(16, 2))
|
||||||
## Sample data
|
outputData.append_array("data".to_ascii_buffer())
|
||||||
#for sample in samples:
|
outputData.append_array(ConvertEndian(chunkSize, 4))
|
||||||
#var int_sample = int(clamp(sample * 32767, -32767, 32767))
|
|
||||||
#byte_data.append_array(to_little_endian(int_sample, 2))
|
# Sample data
|
||||||
#
|
for sample in outputFloats:
|
||||||
#file.store_buffer(byte_data)
|
var signed16Sample = int(clamp(sample * 32767, -32767, 32767))
|
||||||
#file.close()
|
outputData.append_array(ConvertEndian(signed16Sample, 2))
|
||||||
#
|
|
||||||
#func to_little_endian(value: int, byte_count: int) -> PackedByteArray:
|
file.store_buffer(outputData)
|
||||||
#var ba = PackedByteArray()
|
file.close()
|
||||||
#for i in range(byte_count):
|
|
||||||
#ba.append((value >> (8 * i)) & 0xFF)
|
func ConvertEndian(value: int, bytes: int) -> PackedByteArray:
|
||||||
#return ba
|
var reversedBytes = PackedByteArray()
|
||||||
|
for i in range(bytes):
|
||||||
|
reversedBytes.append((value >> (8 * i)) & 0xFF)
|
||||||
|
return reversedBytes
|
||||||
|
|
|
@ -1,50 +1,50 @@
|
||||||
extends SSTVEncoder
|
extends SSTVEncoder
|
||||||
class_name Martin1
|
class_name Martin1
|
||||||
|
|
||||||
const BLANKING_PULSE_FREQ = 1500.0
|
|
||||||
const COLOR_FREQ_MULT = 3.1372549
|
const COLOR_FREQ_MULT = 3.1372549
|
||||||
|
|
||||||
func get_rgb_value_as_freq(image: Image, scan_line: int, vert_pos: int) -> Array:
|
func PixelRGBAsFrequencies(image: Image, scanLine: int, scanLinePos: int) -> Array:
|
||||||
#var index = scan_line * (vertResolution * 4) + vert_pos * 4
|
var color = image.get_pixel(scanLinePos, scanLine)
|
||||||
var color = image.get_pixel(vert_pos, scan_line)
|
var redFreq = float(color.r8) * COLOR_FREQ_MULT + 1500.0
|
||||||
var red = float(color.r8) * COLOR_FREQ_MULT + 1500.0
|
var greenFreq = float(color.g8) * COLOR_FREQ_MULT + 1500.0
|
||||||
var green = float(color.g8) * COLOR_FREQ_MULT + 1500.0
|
var blueFreq = float(color.b8) * COLOR_FREQ_MULT + 1500.0
|
||||||
var blue = float(color.b8) * COLOR_FREQ_MULT + 1500.0
|
return [redFreq, greenFreq, blueFreq]
|
||||||
return [red, green, blue]
|
|
||||||
|
const IMAGE_WIDTH = 320.0
|
||||||
|
const IMAGE_HEIGHT = 256.0
|
||||||
|
const BLANKING_INTERVAL = 0.000572
|
||||||
|
const SCAN_LINE_LENGTH = 0.146432
|
||||||
|
const SYNC_PULSE_LENGTH = 0.004862
|
||||||
|
|
||||||
var numScanLines = 256.0
|
|
||||||
var vertResolution = 320.0
|
|
||||||
var blankingInterval = 0.000572
|
|
||||||
var scanLineLength = 0.146432
|
|
||||||
var syncPulseLength = 0.004862
|
|
||||||
var preparedImage = []
|
var preparedImage = []
|
||||||
|
|
||||||
func PrepareImage(image: Image):
|
func PrepareImage(image: Image):
|
||||||
image.resize(vertResolution, numScanLines)
|
image.resize(IMAGE_WIDTH, IMAGE_HEIGHT)
|
||||||
image.convert(Image.FORMAT_RGB8)
|
image.convert(Image.FORMAT_RGB8)
|
||||||
|
|
||||||
for scanLine in range(0, numScanLines):
|
for scanLine in range(0, IMAGE_HEIGHT):
|
||||||
var red = []
|
var red = []
|
||||||
var green = []
|
var green = []
|
||||||
var blue = []
|
var blue = []
|
||||||
for vertPos in range(0, vertResolution):
|
for vertPos in range(0, IMAGE_WIDTH):
|
||||||
var freqs = get_rgb_value_as_freq(image, scanLine, vertPos)
|
var freqs = PixelRGBAsFrequencies(image, scanLine, vertPos)
|
||||||
red.push_back(freqs[0]);
|
red.push_back(freqs[0])
|
||||||
green.push_back(freqs[1]);
|
green.push_back(freqs[1])
|
||||||
blue.push_back(freqs[2]);
|
blue.push_back(freqs[2])
|
||||||
preparedImage.push_back([green, blue, red]);
|
preparedImage.push_back([green, blue, red])
|
||||||
|
|
||||||
func EncodeSSTV(image: Image):
|
func EncodeSSTV(image: Image, skipHeader: bool = false):
|
||||||
PrepareImage(image)
|
PrepareImage(image)
|
||||||
|
|
||||||
EncodePrefix()
|
if not skipHeader:
|
||||||
EncodeHeader([false, true, false, true, true, false, false])
|
EncodePrefix()
|
||||||
|
EncodeHeader([false, true, false, true, true, false, false])
|
||||||
|
|
||||||
for scanLine in range(0, numScanLines):
|
for scanLine in range(0, IMAGE_HEIGHT):
|
||||||
outputFloats.append_array(GenerateTone(SYNC_PULSE_FREQ, syncPulseLength))
|
outputFloats.append_array(GenerateTone(SYNC_PULSE_FREQ, SYNC_PULSE_LENGTH))
|
||||||
outputFloats.append_array(GenerateTone(BLANKING_PULSE_FREQ, blankingInterval))
|
outputFloats.append_array(GenerateTone(BLANKING_PULSE_FREQ, BLANKING_INTERVAL))
|
||||||
for dataLine in range(0, 3):
|
for dataLine in range(0, 3):
|
||||||
outputFloats.append_array(GenerateToneFromCurve(preparedImage[scanLine][dataLine], scanLineLength))
|
outputFloats.append_array(GenerateToneFromCurve(preparedImage[scanLine][dataLine], SCAN_LINE_LENGTH))
|
||||||
outputFloats.append_array(GenerateTone(BLANKING_PULSE_FREQ, blankingInterval))
|
outputFloats.append_array(GenerateTone(BLANKING_PULSE_FREQ, BLANKING_INTERVAL))
|
||||||
|
|
||||||
return outputFloats
|
return outputFloats
|
||||||
|
|
|
@ -6,17 +6,16 @@ var preparedImage: Array
|
||||||
const BLACK = 1500.0
|
const BLACK = 1500.0
|
||||||
const WHITE = 2300.0
|
const WHITE = 2300.0
|
||||||
const COLOR_FREQ_MULT = 3.1372549
|
const COLOR_FREQ_MULT = 3.1372549
|
||||||
const BLANKING_PULSE_FREQ = 1500.0
|
|
||||||
|
|
||||||
const SYNC_PULSE = 1200.0
|
const SCAN_LINE_LENGTH = 0.056
|
||||||
|
const SYNC_PULSE_LENGTH = 0.01
|
||||||
|
const BLANKING_INTERVAL = 0.000572
|
||||||
|
|
||||||
var scanLineLength = 0.056
|
const IMAGE_WIDTH = 160
|
||||||
var syncPulseLength = 0.01
|
const IMAGE_HEIGHT = 120
|
||||||
var blankingInterval = 0.000572
|
|
||||||
var numScanLines = 120
|
|
||||||
|
|
||||||
func PrepareImage(image: Image):
|
func PrepareImage(image: Image):
|
||||||
image.resize(160, numScanLines)
|
image.resize(IMAGE_WIDTH, IMAGE_HEIGHT)
|
||||||
image.convert(Image.FORMAT_RGB8)
|
image.convert(Image.FORMAT_RGB8)
|
||||||
|
|
||||||
for h in range(image.get_height()):
|
for h in range(image.get_height()):
|
||||||
|
@ -26,16 +25,17 @@ func PrepareImage(image: Image):
|
||||||
line.push_back(round((color.r8 + color.g8 + color.b8) / 3) * COLOR_FREQ_MULT + BLACK)
|
line.push_back(round((color.r8 + color.g8 + color.b8) / 3) * COLOR_FREQ_MULT + BLACK)
|
||||||
preparedImage.push_back(line)
|
preparedImage.push_back(line)
|
||||||
|
|
||||||
func EncodeSSTV(image: Image):
|
func EncodeSSTV(image: Image, skipHeader: bool = false):
|
||||||
PrepareImage(image)
|
PrepareImage(image)
|
||||||
|
|
||||||
EncodePrefix()
|
if not skipHeader:
|
||||||
EncodeHeader([false, false, false, false, false, true, false])
|
EncodePrefix()
|
||||||
|
EncodeHeader([false, false, false, false, false, true, false])
|
||||||
|
|
||||||
for scanLine in range(0, numScanLines):
|
for scanLine in range(0, IMAGE_HEIGHT):
|
||||||
outputFloats.append_array(GenerateTone(SYNC_PULSE_FREQ, syncPulseLength))
|
outputFloats.append_array(GenerateTone(SYNC_PULSE_FREQ, SYNC_PULSE_LENGTH))
|
||||||
outputFloats.append_array(GenerateTone(BLANKING_PULSE_FREQ, blankingInterval))
|
outputFloats.append_array(GenerateTone(BLANKING_PULSE_FREQ, BLANKING_INTERVAL))
|
||||||
outputFloats.append_array(GenerateToneFromCurve(preparedImage[scanLine], scanLineLength))
|
outputFloats.append_array(GenerateToneFromCurve(preparedImage[scanLine], SCAN_LINE_LENGTH))
|
||||||
outputFloats.append_array(GenerateTone(BLANKING_PULSE_FREQ, blankingInterval))
|
outputFloats.append_array(GenerateTone(BLANKING_PULSE_FREQ, BLANKING_INTERVAL))
|
||||||
|
|
||||||
return outputFloats
|
return outputFloats
|
||||||
|
|
|
@ -3,15 +3,15 @@
|
||||||
importer="texture"
|
importer="texture"
|
||||||
type="CompressedTexture2D"
|
type="CompressedTexture2D"
|
||||||
uid="uid://doprjuugw7ga7"
|
uid="uid://doprjuugw7ga7"
|
||||||
path="res://.godot/imported/checker.png-6bb199bedbd039461e4248c1d0b9691d.ctex"
|
path="res://.godot/imported/checker.png-92fa9be0ae7ebdef80a2df49e06c564e.ctex"
|
||||||
metadata={
|
metadata={
|
||||||
"vram_texture": false
|
"vram_texture": false
|
||||||
}
|
}
|
||||||
|
|
||||||
[deps]
|
[deps]
|
||||||
|
|
||||||
source_file="res://checker.png"
|
source_file="res://tests/checker.png"
|
||||||
dest_files=["res://.godot/imported/checker.png-6bb199bedbd039461e4248c1d0b9691d.ctex"]
|
dest_files=["res://.godot/imported/checker.png-92fa9be0ae7ebdef80a2df49e06c564e.ctex"]
|
||||||
|
|
||||||
[params]
|
[params]
|
||||||
|
|
||||||
|
|
|
@ -3,15 +3,15 @@
|
||||||
importer="texture"
|
importer="texture"
|
||||||
type="CompressedTexture2D"
|
type="CompressedTexture2D"
|
||||||
uid="uid://c7ayqic8e3l60"
|
uid="uid://c7ayqic8e3l60"
|
||||||
path="res://.godot/imported/spiral.png-4b65a5988dfd3c48a98523c1603a55da.ctex"
|
path="res://.godot/imported/spiral.png-22b5746c0fb32849d6990602fdefbcc8.ctex"
|
||||||
metadata={
|
metadata={
|
||||||
"vram_texture": false
|
"vram_texture": false
|
||||||
}
|
}
|
||||||
|
|
||||||
[deps]
|
[deps]
|
||||||
|
|
||||||
source_file="res://spiral.png"
|
source_file="res://tests/spiral.png"
|
||||||
dest_files=["res://.godot/imported/spiral.png-4b65a5988dfd3c48a98523c1603a55da.ctex"]
|
dest_files=["res://.godot/imported/spiral.png-22b5746c0fb32849d6990602fdefbcc8.ctex"]
|
||||||
|
|
||||||
[params]
|
[params]
|
||||||
|
|
||||||
|
|
|
@ -3,15 +3,15 @@
|
||||||
importer="texture"
|
importer="texture"
|
||||||
type="CompressedTexture2D"
|
type="CompressedTexture2D"
|
||||||
uid="uid://b44c511u6oile"
|
uid="uid://b44c511u6oile"
|
||||||
path="res://.godot/imported/testtest.png-3138b9f8c3bb6f85feeb295d99c6a7a2.ctex"
|
path="res://.godot/imported/testtest.png-5867611cf1f138e6707d303cad402dab.ctex"
|
||||||
metadata={
|
metadata={
|
||||||
"vram_texture": false
|
"vram_texture": false
|
||||||
}
|
}
|
||||||
|
|
||||||
[deps]
|
[deps]
|
||||||
|
|
||||||
source_file="res://testtest.png"
|
source_file="res://tests/testtest.png"
|
||||||
dest_files=["res://.godot/imported/testtest.png-3138b9f8c3bb6f85feeb295d99c6a7a2.ctex"]
|
dest_files=["res://.godot/imported/testtest.png-5867611cf1f138e6707d303cad402dab.ctex"]
|
||||||
|
|
||||||
[params]
|
[params]
|
||||||
|
|
||||||
|
|
|
@ -3,15 +3,15 @@
|
||||||
importer="texture"
|
importer="texture"
|
||||||
type="CompressedTexture2D"
|
type="CompressedTexture2D"
|
||||||
uid="uid://t5rtcbk8u7yo"
|
uid="uid://t5rtcbk8u7yo"
|
||||||
path="res://.godot/imported/testtest2.png-939c8d08bcfd841ad5a1a682e0766d88.ctex"
|
path="res://.godot/imported/testtest2.png-e9060202f6a513b94a63dcc46f5ebdaf.ctex"
|
||||||
metadata={
|
metadata={
|
||||||
"vram_texture": false
|
"vram_texture": false
|
||||||
}
|
}
|
||||||
|
|
||||||
[deps]
|
[deps]
|
||||||
|
|
||||||
source_file="res://testtest2.png"
|
source_file="res://tests/testtest2.png"
|
||||||
dest_files=["res://.godot/imported/testtest2.png-939c8d08bcfd841ad5a1a682e0766d88.ctex"]
|
dest_files=["res://.godot/imported/testtest2.png-e9060202f6a513b94a63dcc46f5ebdaf.ctex"]
|
||||||
|
|
||||||
[params]
|
[params]
|
||||||
|
|
||||||
|
|
|
@ -3,15 +3,15 @@
|
||||||
importer="texture"
|
importer="texture"
|
||||||
type="CompressedTexture2D"
|
type="CompressedTexture2D"
|
||||||
uid="uid://cqyo3c1lqmrf5"
|
uid="uid://cqyo3c1lqmrf5"
|
||||||
path="res://.godot/imported/testtest3.png-6018875a4a62a4fd97780d49f559d924.ctex"
|
path="res://.godot/imported/testtest3.png-5bfd47758621c96c5da213ca5fc277aa.ctex"
|
||||||
metadata={
|
metadata={
|
||||||
"vram_texture": false
|
"vram_texture": false
|
||||||
}
|
}
|
||||||
|
|
||||||
[deps]
|
[deps]
|
||||||
|
|
||||||
source_file="res://testtest3.png"
|
source_file="res://tests/testtest3.png"
|
||||||
dest_files=["res://.godot/imported/testtest3.png-6018875a4a62a4fd97780d49f559d924.ctex"]
|
dest_files=["res://.godot/imported/testtest3.png-5bfd47758621c96c5da213ca5fc277aa.ctex"]
|
||||||
|
|
||||||
[params]
|
[params]
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue