commit f04580e54d83a3bb27d0327adae93bb61b43d921 Author: drel Date: Sun Dec 28 23:14:40 2025 +0300 first commit diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..7a3094a --- /dev/null +++ b/LICENSE @@ -0,0 +1,11 @@ +DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE +Version 2, December 2004 + +Copyright (C) 2004 Sam Hocevar + +Everyone is permitted to copy and distribute verbatim or modified copies of this license document, and changing it is allowed as long as the name is changed. + +DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE +TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. You just DO WHAT THE FUCK YOU WANT TO. diff --git a/README.md b/README.md new file mode 100644 index 0000000..24173ec --- /dev/null +++ b/README.md @@ -0,0 +1,19 @@ +# SC-55 Tools +Simple ass tools for creating Roland SC-55 (and maybe SC-88(Pro/20)??? Don't have emulator for that.) exclusive SysEx commands for art and text. + +## Installation +It's as simple as cloning this repository or downloading the ZIP file. + +sc55text.py - should work right out of the box. + +sc55art.py - requires Pillow to be installed. (not doing requirements.txt for one fricking thing) + +## Usage +Using sc55text.py: +`python sc55text.py [your text here]` + +Using sc55art.py: +`python sc55text.py ` + +## License +Do What The Fuck You Want To Public License \ No newline at end of file diff --git a/image.png b/image.png new file mode 100644 index 0000000..1b7e1f0 Binary files /dev/null and b/image.png differ diff --git a/image.syx b/image.syx new file mode 100644 index 0000000..4232e3d Binary files /dev/null and b/image.syx differ diff --git a/sc55art.py b/sc55art.py new file mode 100644 index 0000000..a19b6cd --- /dev/null +++ b/sc55art.py @@ -0,0 +1,78 @@ +import sys +import os +from PIL import Image + +def process_image_to_canvas(image_path, threshold=128): + try: + img = Image.open(image_path).convert('L') + img = img.resize((16, 16)) + + img = img.transpose(Image.FLIP_TOP_BOTTOM) + img = img.transpose(Image.ROTATE_270) + + pixels = img.load() + + my_canvas = [[] for _ in range(4)] + + row_ranges = [(0, 5), (5, 10), (10, 15), (15, 16)] + + for row_idx, (start_y, end_y) in enumerate(row_ranges): + for x in range(16): + bits = "" + for y in range(start_y, end_y): + bits += "1" if pixels[x, y] < threshold else "0" + + while len(bits) < 5: + bits += "0" + + my_canvas[row_idx].append(bits) + + return my_canvas + except Exception as e: + print(f"Error occurred while processing an image: {e}") + sys.exit(1) + +def create_sysex_file(filename, canvas): + model_id = 0x45 + address = [0x10, 0x01, 0x00] + + data = [] + for block_row in canvas: + for column_str in block_row: + val = int(column_str, 2) + data.append(val) + + if len(data) < 64: + data += [0] * (64 - len(data)) + + def calc_checksum(addr, payload): + s = sum(addr) + sum(payload) + return (128 - (s % 128)) % 128 + + checksum = calc_checksum(address, data) + full_packet = bytes([0xF0, 0x41, 0x10, model_id, 0x12] + address + data + [checksum] + [0xF7]) + + with open(filename, "wb") as f: + f.write(full_packet) + print(f"Output file: {filename}") + print("HEX:", " ".join(f"{b:02X}" for b in full_packet)) + +def main(): + if len(sys.argv) < 2: + print("Usage: python sc55art.py ") + return + + input_path = sys.argv[1] + + if not os.path.exists(input_path): + print(f"File {input_path} not found.") + return + + base_name = os.path.splitext(input_path)[0] + output_filename = f"{base_name}.syx" + + canvas = process_image_to_canvas(input_path) + create_sysex_file(output_filename, canvas) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/sc55text.py b/sc55text.py new file mode 100644 index 0000000..2013528 --- /dev/null +++ b/sc55text.py @@ -0,0 +1,51 @@ +import sys +import re + +def create_text_sysex(text): + if not text: + text = "EMPTY" + + if len(text) > 32: + print("Text cannot be longer than 32 symbols.") + sys.exit(1) + + model_id = 0x45 + address = [0x10, 0x00, 0x00] + + text_bytes = [ord(char) for char in text] + + def calc_checksum(addr, payload): + total = sum(addr) + sum(payload) + return (128 - (total % 128)) % 128 + + checksum = calc_checksum(address, text_bytes) + + full_packet = bytes([0xF0, 0x41, 0x10, model_id, 0x12] + address + text_bytes + [checksum] + [0xF7]) + + return full_packet + +def sanitize_filename(text): + name = text.replace(" ", "_") + name = re.sub(r'[\\/*?:"<>|]', "", name) + name = name.strip(". ") + return name if name else "output" + +if __name__ == "__main__": + input_text = " ".join(sys.argv[1:]) + + if not input_text: + print("Usage: python sc55text.py [text]") + sys.exit(1) + + sysex_data = create_text_sysex(input_text) + + safe_name = sanitize_filename(input_text) + filename = f"{safe_name}.syx" + + try: + with open(filename, "wb") as f: + f.write(sysex_data) + print(f"Output file: {filename}") + print("HEX:", " ".join(f"{b:02X}" for b in sysex_data)) + except Exception as e: + print(f"Error occurred while saving the file: {e}") \ No newline at end of file diff --git a/test.mid b/test.mid new file mode 100644 index 0000000..e129bdd Binary files /dev/null and b/test.mid differ diff --git a/text.syx b/text.syx new file mode 100644 index 0000000..e2b63eb Binary files /dev/null and b/text.syx differ