From 726a89abb0f0bf3ef8e871e582da1bb0cf429491 Mon Sep 17 00:00:00 2001 From: Holly Date: Thu, 24 Apr 2025 09:30:53 +0100 Subject: [PATCH] let's be a bit more consistent with variable names --- .gitignore | 4 ++ src/Encoder.gd | 100 +++++++++++++++++++------------------ src/Martin1.gd | 58 ++++++++++----------- src/RobotBW8.gd | 30 +++++------ tests/checker.png.import | 6 +-- tests/spiral.png.import | 6 +-- tests/testtest.png.import | 6 +-- tests/testtest2.png.import | 6 +-- tests/testtest3.png.import | 6 +-- 9 files changed, 115 insertions(+), 107 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..dc70ce9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:de32697e7adb8503cdcf1753394fba66e117e70134a926af65d631888705253b +size 36 +.godot diff --git a/src/Encoder.gd b/src/Encoder.gd index 93aebab..ba89161 100644 --- a/src/Encoder.gd +++ b/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 diff --git a/src/Martin1.gd b/src/Martin1.gd index 75962d2..5f2887d 100644 --- a/src/Martin1.gd +++ b/src/Martin1.gd @@ -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) - EncodePrefix() - EncodeHeader([false, true, false, true, true, false, false]) + 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 diff --git a/src/RobotBW8.gd b/src/RobotBW8.gd index ee85bf1..90cf2ac 100644 --- a/src/RobotBW8.gd +++ b/src/RobotBW8.gd @@ -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) - EncodePrefix() - EncodeHeader([false, false, false, false, false, true, false]) + 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 diff --git a/tests/checker.png.import b/tests/checker.png.import index 99d5ccb..87ca134 100644 --- a/tests/checker.png.import +++ b/tests/checker.png.import @@ -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] diff --git a/tests/spiral.png.import b/tests/spiral.png.import index 5c95021..9504a8d 100644 --- a/tests/spiral.png.import +++ b/tests/spiral.png.import @@ -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] diff --git a/tests/testtest.png.import b/tests/testtest.png.import index ea2646d..9b3f71a 100644 --- a/tests/testtest.png.import +++ b/tests/testtest.png.import @@ -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] diff --git a/tests/testtest2.png.import b/tests/testtest2.png.import index 867e061..33b599a 100644 --- a/tests/testtest2.png.import +++ b/tests/testtest2.png.import @@ -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] diff --git a/tests/testtest3.png.import b/tests/testtest3.png.import index ab96a3c..0a23f37 100644 --- a/tests/testtest3.png.import +++ b/tests/testtest3.png.import @@ -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]