Skip to content

Instantly share code, notes, and snippets.

@aynik
Created August 14, 2024 04:38
Show Gist options
  • Save aynik/d265d40adf83f31d32a2800b249509ce to your computer and use it in GitHub Desktop.
Save aynik/d265d40adf83f31d32a2800b249509ce to your computer and use it in GitHub Desktop.
RTTTL folder to Casio buzzer sequence structs
#!/usr/bin/env python3
import sys
import os
from ptttl.parser import PTTTLParser
from math import log2
DURATION_ADJUSTMENT = 18
def parse_rtttl(file_path):
with open(file_path, 'r') as f:
rtttl_string = f.read().strip()
return PTTTLParser().parse(rtttl_string)
def frequency_to_note_name(frequency):
if frequency == 0:
return "S"
notes = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B']
a4 = 440
c0 = a4 * 2**(-4.75)
if frequency < c0:
return "S"
h = round(12 * log2(frequency / c0))
octave, n = divmod(h, 12)
return f"{notes[n]}{octave}"
def get_closest_buzzer_note(note):
note_name, octave = note[:-1], note[-1]
if '#' in note_name:
base_note = note_name[0]
next_note = chr(ord(base_note) + 1) if base_note != 'G' else 'A'
next_octave = str(int(octave) + 1) if base_note == 'B' else octave
return f"BUZZER_NOTE_{base_note}{octave}SHARP_{next_note}{next_octave}FLAT"
return f"BUZZER_NOTE_{note_name}{octave}"
def create_signal_tune(ptttl_data):
signal_tune = []
track = ptttl_data.tracks[0]
for note in track:
note_name = frequency_to_note_name(note.pitch)
duration_value = round(note.duration * 1000 / DURATION_ADJUSTMENT)
if note_name == 'S':
signal_tune.extend(["BUZZER_NOTE_REST", duration_value])
else:
buzzer_note = get_closest_buzzer_note(note_name)
signal_tune.extend([buzzer_note, duration_value])
return signal_tune
def process_rtttl_files(rtttl_folder, output_file):
tune_names = []
with open(output_file, 'w') as out_f:
for filename in os.listdir(rtttl_folder):
if filename.endswith('.txt'):
file_path = os.path.join(rtttl_folder, filename)
ptttl_data = parse_rtttl(file_path)
signal_tune = create_signal_tune(ptttl_data)
tune_name = os.path.splitext(filename)[0]
tune_names.append(tune_name)
out_f.write(f"int8_t signal_tune_{tune_name}[] = {{\n")
for i in range(0, len(signal_tune), 2):
note, duration = signal_tune[i], signal_tune[i+1]
out_f.write(f" {note}, {duration},\n")
out_f.write(" 0,\n};\n\n")
# Add the struct at the end
out_f.write(f"const size_t NUM_TUNES = {len(tune_names)};\n\n")
out_f.write("int8_t *signal_tunes[] = {\n")
for tune_name in tune_names:
out_f.write(f" signal_tune_{tune_name},\n")
out_f.write("};\n")
def main():
if len(sys.argv) != 3:
print("Usage: ./rtttl_to_casio.py <rtttl_folder> <output_file>")
sys.exit(1)
rtttl_folder = sys.argv[1]
output_file = sys.argv[2]
process_rtttl_files(rtttl_folder, output_file)
print(f"Processing complete. Output written to {output_file}")
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment