first commit
This commit is contained in:
11
LICENSE
Normal file
11
LICENSE
Normal file
@@ -0,0 +1,11 @@
|
||||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
Version 2, December 2004
|
||||
|
||||
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
|
||||
|
||||
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.
|
||||
19
README.md
Normal file
19
README.md
Normal file
@@ -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 <path to your image>`
|
||||
|
||||
## License
|
||||
Do What The Fuck You Want To Public License
|
||||
78
sc55art.py
Normal file
78
sc55art.py
Normal file
@@ -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 <image path>")
|
||||
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()
|
||||
51
sc55text.py
Normal file
51
sc55text.py
Normal file
@@ -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}")
|
||||
Reference in New Issue
Block a user