This commit is contained in:
JotaChina committed 2025-11-20 13:43:09 -03:00
1 parent 42da68afa0
commit 12c5b55bce
29 files changed
+162410 -343433

No files matched your search

+112 -64
View File
@@ -9,6 +9,7 @@ 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!")
@@ -18,126 +19,173 @@ def parse_mmp_file(file_path):
tree = ET.parse(file_path)
root = tree.getroot()
bpm = root.find('./head').attrib.get('bpm', 'N/A')
tracks = root.findall('./song/trackcontainer/track')
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'] = []
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')
track_name = track.attrib.get("name", "N/A")
track_type = track.attrib.get("type")
if track_type == '0':
if track_type == "0":
# Faixas de instrumento
# Tem que verificar o sf2, verificar caminhos dos samples.
instruments = track.findall('./instrumenttrack')
instruments = track.findall("./instrumenttrack")
for instrumenttrack in instruments:
instrument = instrumenttrack.find('.//instrument')
instrument = instrumenttrack.find(".//instrument")
if instrument is not None:
plugin_name = instrument.attrib.get('name')
plugin_name = instrument.attrib.get("name")
if plugin_name:
plugin_info = parse_plugin_track(instrumenttrack, 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'
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')
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)
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)
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)
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" 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)
tags["sample"].append(sample_name)
elif track_type in ['5', '6']: # Automation (aparentemente, correto)
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)
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
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
"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}')
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')
track_name = track.attrib.get("name", "N/A")
track_type = track.attrib.get("type")
return {
'track_name': track_name,
'type': track_type,
'instruments': []
}
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"}
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'):
if hasattr(plugin_module, "parse_instrument"):
return plugin_module.parse_instrument(instrumenttrack_element)
else:
return {'error': f"O plugin '{plugin_name}' não possui a função 'parse_instrument'"}
# 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:
return {'error': f"Módulo do plugin '{plugin_name}' não encontrado"}
# === 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 ao carregar plugin '{plugin_name}': {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