att base de dados
This commit is contained in:
1 parent
ceb7908da4
commit
73693e5da9
14 files changed
+3010
-1
No files matched your search
@@ -0,0 +1,274 @@
|
||||
import yaml
|
||||
import json
|
||||
import os
|
||||
import logging
|
||||
|
||||
# --- CONFIGURAÇÕES DE LOG ---
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format="%(asctime)s - CLASSIFICADOR - %(levelname)s - %(message)s",
|
||||
handlers=[
|
||||
logging.FileHandler("classificacao_pedagogica.log"),
|
||||
logging.StreamHandler(),
|
||||
],
|
||||
)
|
||||
|
||||
# --- CONFIGURAÇÕES ---
|
||||
ARQUIVO_YAML = "all.yml"
|
||||
ARQUIVO_AUDIO = "analise_audio.json"
|
||||
ARQUIVO_FINAL = "db_projetos_classificados.json"
|
||||
|
||||
PLUGINS_NATIVOS = [
|
||||
"tripleoscillator",
|
||||
"zynaddsubfx",
|
||||
"sfxr",
|
||||
"organic",
|
||||
"audiofileprocessor",
|
||||
"lb302",
|
||||
"kicker",
|
||||
"watsyn",
|
||||
"bitinvader",
|
||||
"freeboy",
|
||||
"mallets",
|
||||
"vibed",
|
||||
]
|
||||
|
||||
# --- LÓGICA PEDAGÓGICA AVANÇADA ---
|
||||
|
||||
|
||||
def calcular_nivel_ponderado(
|
||||
num_tracks, tem_automacao, plugins_complexos, qtd_secoes_audio, fx_criativos
|
||||
):
|
||||
"""
|
||||
Calcula nível pedagógico (Iniciante, Intermediário, Avançado)
|
||||
baseado em esforço de engenharia e complexidade musical.
|
||||
"""
|
||||
pontos = 0
|
||||
|
||||
# 1. Volume de Trabalho
|
||||
if num_tracks >= 8:
|
||||
pontos += 1
|
||||
if num_tracks >= 16:
|
||||
pontos += 1
|
||||
|
||||
# 2. Profundidade Técnica
|
||||
if tem_automacao:
|
||||
pontos += 2 # Automação é sinal forte de polimento
|
||||
if plugins_complexos:
|
||||
pontos += 1.5 # Usar ZynAddSubFx requer estudo
|
||||
if fx_criativos:
|
||||
pontos += 1 # Usar efeitos além do básico
|
||||
|
||||
# 3. Estrutura Musical (Vinda do Essentia)
|
||||
# Se o áudio tem > 3 seções detectadas, há arranjo (não é só loop)
|
||||
if qtd_secoes_audio >= 3:
|
||||
pontos += 2
|
||||
elif qtd_secoes_audio >= 5:
|
||||
pontos += 3
|
||||
|
||||
# Classificação
|
||||
if pontos < 3:
|
||||
return "Iniciante"
|
||||
if pontos < 6:
|
||||
return "Intermediário"
|
||||
return "Avançado"
|
||||
|
||||
|
||||
def analisar_tags_pedagogicas(tracks, bpm, qtd_secoes, tom, escala):
|
||||
tags = []
|
||||
|
||||
# Flags de estado técnico
|
||||
tem_zyn = False
|
||||
tem_automacao = False
|
||||
tem_fx_chain = False
|
||||
qtd_nativos = 0
|
||||
qtd_vst_externos = 0
|
||||
tem_audio_processor = False
|
||||
|
||||
for t in tracks:
|
||||
inst = t.get("instrumenttrack")
|
||||
if not inst:
|
||||
continue
|
||||
|
||||
plugin = inst.get("plugin_name", "").lower()
|
||||
|
||||
# Mapeamento de Plugins e Dependências
|
||||
if plugin in PLUGINS_NATIVOS:
|
||||
qtd_nativos += 1
|
||||
elif plugin == "vestige":
|
||||
qtd_vst_externos += 1
|
||||
|
||||
if plugin == "zynaddsubfx":
|
||||
tem_zyn = True
|
||||
|
||||
if plugin == "audiofileprocessor":
|
||||
tem_audio_processor = True
|
||||
|
||||
if "automation" in str(inst).lower():
|
||||
tem_automacao = True
|
||||
|
||||
fx = inst.get("fxchain", {})
|
||||
if fx and int(fx.get("numofeffects", 0)) > 0:
|
||||
tem_fx_chain = True
|
||||
|
||||
# --- 1. Estética da Escassez e Modulação Marginal ---
|
||||
if qtd_nativos > 0 and qtd_vst_externos == 0:
|
||||
tags.append("Estética da Escassez: Síntese Nativa")
|
||||
|
||||
if tem_automacao and qtd_vst_externos == 0:
|
||||
tags.append("Design de Som Marginal (Automação como Timbre)")
|
||||
|
||||
# --- 2. Taxonomia de Bloom (Carga Cognitiva) ---
|
||||
if tem_zyn or tem_fx_chain:
|
||||
tags.append("Bloom: Criação (Sound Design Complexo)")
|
||||
elif tem_audio_processor and not tem_automacao:
|
||||
tags.append("Bloom: Aplicação (Sample Inalterado)")
|
||||
|
||||
# --- 3. Fluência Estrutural (Macroforma Musical) ---
|
||||
if qtd_secoes >= 3:
|
||||
tags.append("Fluência Estrutural: Arranjo Completo (Macroforma)")
|
||||
else:
|
||||
tags.append("Fluência Estrutural: Loop Estático")
|
||||
|
||||
# --- 4. Acessibilidade Ergonômica (Música de Computador) ---
|
||||
if tom == "A" and escala == "minor":
|
||||
tags.append("Ergonomia Autodidata (Teclado QWERTY / Lá Menor)")
|
||||
|
||||
# --- 5. Herança Cultural / Andamento ---
|
||||
if 80 <= bpm <= 95:
|
||||
tags.append("Cadência Clássica (Boom Bap)")
|
||||
elif bpm >= 130:
|
||||
tags.append("Estética Trap/Funk/Eletrônica / Alta Energia")
|
||||
|
||||
return tags
|
||||
|
||||
|
||||
def main():
|
||||
logging.info("Iniciando Classificador Mestre...")
|
||||
|
||||
# 1. Carregar YAML
|
||||
if not os.path.exists(ARQUIVO_YAML):
|
||||
logging.critical(f"{ARQUIVO_YAML} não encontrado.")
|
||||
return
|
||||
|
||||
with open(ARQUIVO_YAML, "r", encoding="utf-8") as f:
|
||||
dados_projetos = yaml.safe_load(f)
|
||||
|
||||
# 2. Carregar JSON de Áudio
|
||||
lookup_audio = {}
|
||||
if os.path.exists(ARQUIVO_AUDIO):
|
||||
with open(ARQUIVO_AUDIO, "r", encoding="utf-8") as f:
|
||||
lista_audio = json.load(f)
|
||||
for item in lista_audio:
|
||||
# Normaliza chave de busca (nome do arquivo sem extensão)
|
||||
nome_base = os.path.splitext(item["arquivo"])[0]
|
||||
lookup_audio[nome_base] = item
|
||||
else:
|
||||
logging.warning(
|
||||
"JSON de áudio não encontrado. Classificação será apenas estática."
|
||||
)
|
||||
|
||||
db_final = []
|
||||
|
||||
logging.info(f"Processando {len(dados_projetos)} entradas do YAML...")
|
||||
|
||||
for proj in dados_projetos:
|
||||
if not proj:
|
||||
continue
|
||||
|
||||
try:
|
||||
nome_arquivo = proj.get("file", "")
|
||||
if not nome_arquivo:
|
||||
continue
|
||||
|
||||
# Tenta casar com dados de áudio
|
||||
# Nota: Seu YAML usa nomes como 'trap-fyrebreak', o arquivo de audio deve ser 'trap-fyrebreak.wav'
|
||||
# O lookup_audio já está sem extensão.
|
||||
dados_audio = lookup_audio.get(nome_arquivo, {})
|
||||
analise_tec = dados_audio.get("analise_tecnica", {})
|
||||
analise_ia = dados_audio.get("analise_ia", {})
|
||||
|
||||
# Dados Técnicos
|
||||
raw_bpm = proj.get("bpm", 120)
|
||||
bpm_projeto = (
|
||||
float(raw_bpm) if str(raw_bpm).replace(".", "", 1).isdigit() else 120.0
|
||||
)
|
||||
|
||||
# Feature nova: Quantidade de seções (Intro, Verso...)
|
||||
qtd_secoes = analise_tec.get("qtd_secoes_detectadas", 1)
|
||||
|
||||
# Análise Estática (Tracks e Plugins)
|
||||
tracks = proj.get("tracks", [])
|
||||
tags, tem_auto, tem_zyn, tem_fx = analisar_tags_pedagogicas(
|
||||
tracks=proj.get("tracks", []),
|
||||
bpm=bpm_projeto,
|
||||
qtd_secoes=qtd_secoes,
|
||||
tom=analise_tec.get("tom", "N/A"),
|
||||
escala=analise_tec.get("escala", "N/A"),
|
||||
)
|
||||
|
||||
# Verifica plugins externos
|
||||
plugins_usados = set()
|
||||
usa_vst_externo = False
|
||||
for t in tracks:
|
||||
p = t.get("instrumenttrack", {}).get("plugin_name", "")
|
||||
if p:
|
||||
plugins_usados.add(p)
|
||||
if p.lower() not in PLUGINS_NATIVOS:
|
||||
usa_vst_externo = True
|
||||
|
||||
# Cálculo de Nível (Nova Lógica)
|
||||
nivel = calcular_nivel_ponderado(
|
||||
len(tracks), tem_auto, tem_zyn, qtd_secoes, tem_fx
|
||||
)
|
||||
|
||||
# Define Gênero (IA tem prioridade, depois regras manuais)
|
||||
genero = analise_ia.get("genero_predito", "Desconhecido")
|
||||
if genero == "Desconhecido" or analise_ia.get("confianca_genero", 0) < 0.4:
|
||||
# Fallback manual simples
|
||||
if "Trap Rhythm" in tags:
|
||||
genero = "Trap"
|
||||
elif bpm_projeto > 120:
|
||||
genero = "Electronic"
|
||||
else:
|
||||
genero = "HipHop/Downtempo"
|
||||
|
||||
# Montagem do Objeto
|
||||
item = {
|
||||
"id": nome_arquivo,
|
||||
"titulo": proj.get("original_title", nome_arquivo),
|
||||
"pedagogia": {
|
||||
"nivel": nivel,
|
||||
"tags_aprendizado": tags,
|
||||
"plugins_principais": list(plugins_usados),
|
||||
"requer_vst_externo": usa_vst_externo,
|
||||
},
|
||||
"tecnica": {
|
||||
"bpm": bpm_projeto,
|
||||
"tom": analise_tec.get("tom", "N/A"),
|
||||
"escala": analise_tec.get("escala", "N/A"),
|
||||
"estrutura_detectada": f"{qtd_secoes} seções distintas",
|
||||
},
|
||||
"classificacao": {
|
||||
"genero": genero,
|
||||
"mood": "Energético"
|
||||
if analise_tec.get("intensidade", -20) > -10
|
||||
else "Suave",
|
||||
},
|
||||
}
|
||||
|
||||
db_final.append(item)
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"Erro ao processar projeto '{proj.get('file')}': {e}")
|
||||
continue
|
||||
|
||||
# Salvar Resultado
|
||||
with open(ARQUIVO_FINAL, "w", encoding="utf-8") as f:
|
||||
json.dump(db_final, f, indent=4, ensure_ascii=False)
|
||||
|
||||
logging.info(f"Sucesso! {len(db_final)} projetos classificados e salvos.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in new issue
Block a user