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