async generateScore(){ if(!(await this.ensureVexFlow())){ notify('❌ VexFlow não está disponível no momento. Verifique sua conexão e tente novamente.', 'error'); return; } const VF = Vex.Flow; // Limpa score anterior this.els.score.innerHTML = ''; // Canvas/Renderer const div = this.els.score; const renderer = new VF.Renderer(div, VF.Renderer.Backends.SVG); const width = Math.max(720, div.clientWidth || 720); const height = 200; renderer.resize(width, height); const context = renderer.getContext(); const ts = this.els.timeSig.value; const stave = new VF.Stave(10, 20, width-20); stave.addClef(this.els.clef.value); stave.addTimeSignature(ts); stave.setContext(context).draw(); // --- Parser com ponto de aumento e acordes --- const raw = (this.els.notes.value || '').trim(); if(!raw){ notify('ℹ️ Informe as notas para gerar a partitura.', 'warn'); return; } const tokens = raw.split(/[\n,]+/).map(s=>s.trim()).filter(Boolean); const durMap = { '1':'w','w':'w','2':'h','h':'h','4':'q','q':'q','8':'8','16':'16' }; function buildSimple(letter, acc, oct, dur, dotted){ const key = `${letter}${acc}/${oct}`; const n = new VF.StaveNote({ keys: [key], duration: dur }); if (acc) n.addAccidental(0, new VF.Accidental(acc)); if (dotted) VF.Dot.addToAll(n); return n; } function parseToken(tok){ const parts = tok.split(/\s+/); if (parts.length < 2) return null; let namePart = parts.slice(0, parts.length-1).join(' '); let durRaw = parts[parts.length-1].toLowerCase(); // ponto de aumento (ex.: q. / h. / 8.) let dotted = false; if (/\.$/.test(durRaw)) { dotted = true; durRaw = durRaw.replace(/\.$/, ''); } let dur = durMap[durRaw] || durRaw; // pausa if (namePart.toUpperCase() === 'R'){ const rest = new VF.StaveNote({ keys: ['b/4'], duration: dur + 'r' }); if (dotted) VF.Dot.addToAll(rest); return rest; } // acorde [C4/E4/G4] const chordMatch = namePart.match(/^\[([^\]]+)\]$/); if (chordMatch){ const parts = chordMatch[1].split('/').map(s=>s.trim()).filter(Boolean); if (!parts.length) return null; const keys = [], accs = []; for (const p of parts){ const m = p.match(/^([A-Ga-g])(#|b)?(\d)$/); if (!m) return null; const letter = m[1].toLowerCase(); const acc = m[2] || ''; const oct = m[3]; keys.push(`${letter}${acc}/${oct}`); accs.push(acc); } const n = new VF.StaveNote({ keys, duration: dur }); accs.forEach((a,i)=>{ if(a) n.addAccidental(i, new VF.Accidental(a)); }); if (dotted) VF.Dot.addToAll(n); return n; } // nota simples const m = namePart.match(/^([A-Ga-g])(#|b)?(\d)$/); if (!m) return null; return buildSimple(m[1].toLowerCase(), m[2]||'', m[3], dur, dotted); } const notes = []; for (const t of tokens){ const n = parseToken(t); if (n) notes.push(n); } if (!notes.length){ notify('❌ Não foi possível interpretar as notas.', 'error'); return; } const [num, den] = ts.split('/').map(Number); const voice = new VF.Voice({num_beats: num, beat_value: den, resolution: VF.RESOLUTION}); voice.addTickables(notes); const formatter = new VF.Formatter(); formatter.joinVoices([voice]).format([voice], width-80); voice.draw(context, stave); this.els.printBtn.disabled = false; notify('✅ Partitura gerada.'); }