Flipper/Music_Player/flipnoise/flipnoise.py
2022-06-26 23:16:18 -06:00

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()