mirror of
https://github.com/UberGuidoZ/Flipper.git
synced 2024-12-22 14:30:21 +00:00
138 lines
3.3 KiB
Python
138 lines
3.3 KiB
Python
|
#!/usr/bin/python
|
||
|
|
||
|
# flipnoise.py
|
||
|
#
|
||
|
# Converts Renoise song files (.xrns) to Flipper Zero song files (.fmf). Pass
|
||
|
# in the .xrns file as the only argument and flipnoise will unzip it, parse
|
||
|
# the Song.xml file within and generate a .fmf file you can place on your
|
||
|
# device with qFlipper.
|
||
|
#
|
||
|
# flipnoise will read the song name, artist name and BPM from the Renoise file.
|
||
|
# Empty lines are filled in with the last note played. The intention here is to
|
||
|
# primarily make chiptune/keygen-sounding music at a very high BPM (e.g., 500).
|
||
|
#
|
||
|
# Note that Flipper Zero only has a single sound channel, so only make one track
|
||
|
# in your Renoise song.
|
||
|
#
|
||
|
# Juan Irming
|
||
|
# https://amplitudeproblem.com/
|
||
|
|
||
|
import os
|
||
|
from os.path import exists
|
||
|
import shutil
|
||
|
import sys
|
||
|
import uuid
|
||
|
import xml.etree.ElementTree as ET
|
||
|
import zipfile
|
||
|
|
||
|
# ------------------------------------------------------------------------------
|
||
|
# Constants
|
||
|
|
||
|
SONG_FILENAME = "Song.xml"
|
||
|
|
||
|
RENOISE_MAGIC = "RenoiseSong"
|
||
|
|
||
|
APP_NAME = "flipnoise"
|
||
|
APP_VERSION = 1.0
|
||
|
|
||
|
# ------------------------------------------------------------------------------
|
||
|
|
||
|
|
||
|
def invalid_file_exit(filename):
|
||
|
sys.exit(filename + " is not a valid Renoise song")
|
||
|
|
||
|
|
||
|
# ------------------------------------------------------------------------------
|
||
|
|
||
|
|
||
|
def main():
|
||
|
if len(sys.argv) < 2:
|
||
|
sys.exit("Usage: " + APP_NAME + " [filename.xrns]")
|
||
|
else:
|
||
|
filename = sys.argv[1]
|
||
|
|
||
|
if not exists(filename):
|
||
|
invalid_file_exit(filename)
|
||
|
|
||
|
tmp_dir = "." + APP_NAME + "_tmp/"
|
||
|
|
||
|
if exists(tmp_dir):
|
||
|
sys.exit("Temporary directory " + tmp_dir + " already exists")
|
||
|
|
||
|
os.mkdir(tmp_dir)
|
||
|
|
||
|
shutil.copy(filename, tmp_dir)
|
||
|
|
||
|
with zipfile.ZipFile(tmp_dir + filename, 'r') as zip_handle:
|
||
|
zip_handle.extractall(tmp_dir)
|
||
|
|
||
|
try:
|
||
|
renoise = ET.parse(tmp_dir + SONG_FILENAME)
|
||
|
except:
|
||
|
invalid_file_exit(filename)
|
||
|
|
||
|
print(filename)
|
||
|
|
||
|
renoise_root = renoise.getroot()
|
||
|
|
||
|
if not renoise_root.tag == RENOISE_MAGIC:
|
||
|
invalid_file_exit(filename)
|
||
|
|
||
|
song_name = renoise_root.find("./GlobalSongData/SongName").text
|
||
|
print("Song name:", song_name)
|
||
|
|
||
|
artist = renoise_root.find("./GlobalSongData/Artist").text
|
||
|
print("Artist:", artist)
|
||
|
|
||
|
bpm = renoise_root.find("./GlobalSongData/BeatsPerMin").text
|
||
|
print("BPM:", bpm)
|
||
|
|
||
|
octave = renoise_root.find("./GlobalSongData/Octave").text
|
||
|
print("Octave:", octave)
|
||
|
|
||
|
notes = "Notes: "
|
||
|
|
||
|
for pattern in renoise_root.findall("./PatternPool/Patterns/Pattern"):
|
||
|
last_index = 0
|
||
|
last_note = ""
|
||
|
|
||
|
for line in pattern.findall("Tracks/PatternTrack/Lines/Line"):
|
||
|
index = int(line.attrib.get("index"))
|
||
|
index_delta = index - last_index
|
||
|
if index_delta == 0:
|
||
|
index_delta = 1
|
||
|
|
||
|
note = line.find("NoteColumns/NoteColumn/Note").text
|
||
|
note = note.replace("-", "")
|
||
|
|
||
|
for i in range(0, index_delta - 1):
|
||
|
notes += note + ", "
|
||
|
|
||
|
notes += note + ", "
|
||
|
|
||
|
last_index = index
|
||
|
last_note = note
|
||
|
|
||
|
notes = notes.rstrip(", ")
|
||
|
|
||
|
print(notes)
|
||
|
|
||
|
flipper_filename = artist + "-" + song_name + "." + str(uuid.uuid4()) + ".fmf"
|
||
|
with open(flipper_filename, "w") as file:
|
||
|
file.write("Filetype: Flipper Music Format\n\n")
|
||
|
file.write("Version: 0\n\n")
|
||
|
file.write("BPM: " + bpm + "\n\n")
|
||
|
file.write("Duration: 16\n\n")
|
||
|
file.write("Octave: 5\n\n")
|
||
|
file.write(notes)
|
||
|
|
||
|
print("Saved", flipper_filename)
|
||
|
|
||
|
shutil.rmtree(tmp_dir)
|
||
|
|
||
|
|
||
|
# ------------------------------------------------------------------------------
|
||
|
|
||
|
if __name__ == "__main__":
|
||
|
main()
|