192 lines
7.9 KiB
Python
192 lines
7.9 KiB
Python
import os
|
|
import xml.etree.ElementTree as ET
|
|
import importlib
|
|
|
|
from automations.automations import parse_automation
|
|
from basslines.basslines import parse_basslines
|
|
from samples.samples import parse_samples
|
|
from utils import SUPPORTED_PLUGINS
|
|
|
|
# Lista dos plugins suportados
|
|
|
|
|
|
def parse_mmp_file(file_path):
|
|
if not os.path.exists(file_path):
|
|
print(f"O arquivo {file_path} não existe!")
|
|
return None
|
|
|
|
try:
|
|
tree = ET.parse(file_path)
|
|
root = tree.getroot()
|
|
|
|
bpm = root.find("./head").attrib.get("bpm", "N/A")
|
|
tracks = root.findall("./song/trackcontainer/track")
|
|
track_info = []
|
|
tags = {}
|
|
tags["TAG"] = []
|
|
tags["plugin"] = []
|
|
tags["sample"] = []
|
|
tags["bassline"] = []
|
|
tags["automation"] = []
|
|
|
|
for track in tracks:
|
|
track_name = track.attrib.get("name", "N/A")
|
|
track_type = track.attrib.get("type")
|
|
|
|
if track_type == "0":
|
|
# Faixas de instrumento
|
|
# Tem que verificar o sf2, verificar caminhos dos samples.
|
|
instruments = track.findall("./instrumenttrack")
|
|
for instrumenttrack in instruments:
|
|
instrument = instrumenttrack.find(".//instrument")
|
|
if instrument is not None:
|
|
plugin_name = instrument.attrib.get("name")
|
|
if plugin_name:
|
|
plugin_info = parse_plugin_track(
|
|
instrumenttrack, plugin_name
|
|
)
|
|
if plugin_info:
|
|
# Adiciona metadados da faixa também
|
|
plugin_info["track_name"] = track_name
|
|
plugin_info["type"] = "plugin"
|
|
track_info.append(plugin_info)
|
|
# Marcando os nomes dos plugins presentes
|
|
if "plugin" not in tags["TAG"]:
|
|
tags["TAG"].append("plugin")
|
|
# Se algum plugin estiver com o nome diferente do original
|
|
if track_name not in tags:
|
|
if (
|
|
track_name not in SUPPORTED_PLUGINS
|
|
and plugin_name not in tags["plugin"]
|
|
):
|
|
tags["plugin"].append(plugin_name)
|
|
|
|
elif track_type == "1": # Bassline (aparentemente, correto)
|
|
bassline_info = parse_basslines(track)
|
|
if bassline_info:
|
|
track_info.append(bassline_info)
|
|
if bassline_info["tags"] is not None:
|
|
if "bassline" not in tags["TAG"]: # certo
|
|
tags["TAG"].append("bassline")
|
|
if track_name not in tags["TAG"]: # certo
|
|
tags["bassline"].append(track_name)
|
|
if "audiofileprocessor" not in tags["plugin"]: # certo
|
|
tags["plugin"].append(bassline_info["tags"])
|
|
if "tripleoscillator" not in tags["plugin"]:
|
|
if bassline_info["tags"] == "tripleoscillator":
|
|
tags["plugin"].append(bassline_info["tags"])
|
|
|
|
elif track_type == "2": # Sample (aparentemente, correto)
|
|
sample_info = parse_samples(file_path, track)
|
|
if sample_info:
|
|
track_info.append(sample_info)
|
|
if "sample" not in tags["TAG"]:
|
|
tags["TAG"].append("sample")
|
|
sample_name = sample_info["sample_name"]
|
|
if sample_name == None:
|
|
sample_name = track_name
|
|
tags["sample"].append(sample_name)
|
|
|
|
elif track_type in ["5", "6"]: # Automation (aparentemente, correto)
|
|
automation_info = parse_automation(file_path)
|
|
if automation_info:
|
|
track_info.append(automation_info)
|
|
if "automation" not in tags["TAG"]:
|
|
tags["TAG"].append("automation")
|
|
tags["automation"].append(track_name)
|
|
|
|
else:
|
|
print("\n\n\n\n\n\nERRO\n\n\n\n\n\n")
|
|
return
|
|
|
|
file_name_with_extension = os.path.basename(file_path)
|
|
file_name, _ = os.path.splitext(file_name_with_extension)
|
|
|
|
return {
|
|
"file": file_name,
|
|
"src": file_path,
|
|
"bpm": bpm,
|
|
"tags": tags,
|
|
"tracks": track_info,
|
|
}
|
|
|
|
except ET.ParseError as e:
|
|
print(f"Erro ao analisar o arquivo XML {file_path}: {e}")
|
|
return None
|
|
|
|
|
|
def parse_generic_track(track):
|
|
track_name = track.attrib.get("name", "N/A")
|
|
track_type = track.attrib.get("type")
|
|
|
|
return {"track_name": track_name, "type": track_type, "instruments": []}
|
|
|
|
|
|
def parse_plugin_track(instrumenttrack_element, plugin_name):
|
|
plugin_name = plugin_name.lower()
|
|
|
|
if plugin_name not in SUPPORTED_PLUGINS:
|
|
return {"error": f"Plugin '{plugin_name}' não está na lista de suportados"}
|
|
|
|
try:
|
|
# Tenta carregar um parser específico se ele existir (ex: plugins/tripleoscillator.py)
|
|
module_path = f"plugins.{plugin_name}"
|
|
plugin_module = importlib.import_module(module_path)
|
|
|
|
if hasattr(plugin_module, "parse_instrument"):
|
|
return plugin_module.parse_instrument(instrumenttrack_element)
|
|
else:
|
|
# Se o módulo existe mas não tem a função, usa o genérico
|
|
return extract_generic_attributes(instrumenttrack_element, plugin_name)
|
|
|
|
except ModuleNotFoundError:
|
|
# === ALTERAÇÃO CRUCIAL ===
|
|
# Se não existir script python para o plugin, usamos o extrator genérico.
|
|
# Isso garante que Kicker, Organic, ZynAddSubFX, etc. funcionem imediatamente.
|
|
return extract_generic_attributes(instrumenttrack_element, plugin_name)
|
|
except Exception as e:
|
|
return {"error": f"Erro crítico ao processar plugin '{plugin_name}': {e}"}
|
|
|
|
|
|
def extract_generic_attributes(instrumenttrack_element, plugin_name):
|
|
"""
|
|
Varre o XML do instrumento e extrai todos os atributos da tag do plugin
|
|
e os dados do envelope (ADSR) padrão.
|
|
"""
|
|
data = {}
|
|
|
|
# 1. Busca a tag principal do instrumento
|
|
instrument_node = instrumenttrack_element.find("./instrument")
|
|
if instrument_node is None:
|
|
return {"error": "Nó <instrument> não encontrado"}
|
|
|
|
# 2. Busca a tag específica do plugin (ex: <kicker ... /> ou <organic ... />)
|
|
# O LMMS geralmente usa o nome do plugin como nome da tag filha
|
|
plugin_node = instrument_node.find(f"./{plugin_name}")
|
|
|
|
if plugin_node is not None:
|
|
# Converte todos os atributos do XML (startfreq, vol, wave, etc.) para JSON
|
|
data[plugin_name] = plugin_node.attrib
|
|
else:
|
|
# Fallback: Se não achar pelo nome, tenta pegar o primeiro filho que não seja vazio
|
|
# Útil se houver discrepância de nomes (ex: 'lb302' vs 'lb302_instrument')
|
|
if len(list(instrument_node)) > 0:
|
|
# Pega o primeiro filho e usa seus atributos
|
|
child = list(instrument_node)[0]
|
|
data[plugin_name] = child.attrib
|
|
|
|
# 3. Extração de Envelopes (ADSR) e Filtros
|
|
# Quase todos os plugins do LMMS compartilham isso (elvol, elcut, elres)
|
|
# Eles ficam no mesmo nível de <instrument>, dentro de <eldata>
|
|
eldata_node = instrumenttrack_element.find("./eldata")
|
|
if eldata_node is not None:
|
|
data["eldata"] = eldata_node.attrib
|
|
|
|
# Sub-nós comuns de envelope
|
|
for sub in ["elvol", "elcut", "elres"]:
|
|
sub_node = eldata_node.find(f"./{sub}")
|
|
if sub_node is not None:
|
|
data[sub] = sub_node.attrib
|
|
|
|
return data
|