mandioca-tabs-mcp 0.2.8 → 0.2.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/index.mjs +1159 -585
  2. package/package.json +1 -1
package/index.mjs CHANGED
@@ -12351,7 +12351,10 @@ var init_documento = __esm({
12351
12351
  silabas;
12352
12352
  /** Las fichas de las tipografías propias. Los BYTES viajan en el .mtabs, no acá. */
12353
12353
  tipografias;
12354
- /** Mezcla de escucha y vista. Un archivo viejo no lo trae: el mapa nace vacío y nada se rompe. */
12354
+ /**
12355
+ * Mezcla de escucha y vista. Un archivo viejo no lo trae: el mapa nace vacío y nada se rompe.
12356
+ * Lo de la sesión va bajo `CLAVE_DE_LA_SESION`, con la forma de `AjustesDeLaObra` (editor).
12357
+ */
12355
12358
  ajustes;
12356
12359
  nuevoId;
12357
12360
  constructor(doc) {
@@ -12454,6 +12457,57 @@ var init_documento = __esm({
12454
12457
  obraEditora: mapa?.get("obraEditora") ?? ""
12455
12458
  };
12456
12459
  }
12460
+ // ── La presentación: saltos de renglón ───────────────────────────────────
12461
+ /**
12462
+ * ═══════════════════════════════════════════════════════════════════════════════
12463
+ * ⛔⛔ POR QUÉ EXISTE (2026-11-09, «Los Dinosaurios»)
12464
+ * ═══════════════════════════════════════════════════════════════════════════════
12465
+ *
12466
+ * Daniel: la partitura tiene que quedar «tal cual» el PDF. Algo del PDF no tenía dónde
12467
+ * guardarse y el importador lo tiraba en silencio:
12468
+ *
12469
+ * · **Los saltos de renglón.** MusicXML los escribe (`<print new-system="yes">`) y alphaTab
12470
+ * los lee (`track.lineBreaks`); el modelo no, así que el primer renglón de 2 compases
12471
+ * salía de 3.
12472
+ *
12473
+ * ★★ Van ACÁ, en un `Y.Map` anidado en la cabecera, y NO en las entidades, por la misma razón
12474
+ * que el estilo (ver `archivoMtabs.ts`, versión 3): las entidades se reescriben ENTERAS al
12475
+ * editarlas, y un programa que no conociera el campo lo borraría al guardar. Este mapa no
12476
+ * lo reescribe nadie ⇒ un programa viejo lo abre, lo ignora y lo conserva. No sube versión.
12477
+ *
12478
+ * ⚠️ Se guardan POR ID. Insertar o borrar compases no corre los saltos al compás de al lado
12479
+ * (un número de compás sí se correría). Un id que ya no existe se ignora al leer.
12480
+ */
12481
+ ponerSaltoDeRenglon(compasMaestroId, hay) {
12482
+ this.doc.transact(() => {
12483
+ const saltos = this.subMapaDePresentacion("saltosDeRenglon");
12484
+ if (hay) saltos.set(compasMaestroId, true);
12485
+ else saltos.delete(compasMaestroId);
12486
+ });
12487
+ }
12488
+ /** Los saltos de renglón, ya filtrados: sólo ids que existen. */
12489
+ leerPresentacion() {
12490
+ const mapa = this.cabecera.get("presentacion");
12491
+ const saltos = mapa?.get("saltosDeRenglon");
12492
+ const saltosDeRenglon = /* @__PURE__ */ new Set();
12493
+ for (const [id2, valor] of saltos?.entries() ?? []) {
12494
+ if (valor === true && this.compasesMaestros.has(id2)) saltosDeRenglon.add(id2);
12495
+ }
12496
+ return { saltosDeRenglon };
12497
+ }
12498
+ subMapaDePresentacion(clave) {
12499
+ let mapa = this.cabecera.get("presentacion");
12500
+ if (!mapa) {
12501
+ mapa = new YMap();
12502
+ this.cabecera.set("presentacion", mapa);
12503
+ }
12504
+ let sub = mapa.get(clave);
12505
+ if (!sub) {
12506
+ sub = new YMap();
12507
+ mapa.set(clave, sub);
12508
+ }
12509
+ return sub;
12510
+ }
12457
12511
  // ── El estilo de la obra ──────────────────────────────────────────────────
12458
12512
  /**
12459
12513
  * Escribe cómo se ve esta obra. Se puede mandar sólo lo que cambia.
@@ -13319,7 +13373,9 @@ function normalizarCompas(crudo) {
13319
13373
  // ★ Excepción: «nada» no sirve. Un documento viejo se dibujaba en clave de sol, así que
13320
13374
  // la ausencia significa sol y no «sin clave» —que alphaTab dibujaría como clave de do—.
13321
13375
  clave: numero(crudo.clave, CLAVE_POR_OMISION),
13322
- claveOctava: numero(crudo.claveOctava, SIN_OCTAVA)
13376
+ claveOctava: numero(crudo.claveOctava, SIN_OCTAVA),
13377
+ // Ausente = el primer pentagrama, que es el único que existía antes del 2026-11-09.
13378
+ ...typeof crudo.pentagrama === "number" && crudo.pentagrama > 0 ? { pentagrama: crudo.pentagrama } : {}
13323
13379
  };
13324
13380
  }
13325
13381
  function normalizarCompasMaestro(crudo) {
@@ -13357,6 +13413,8 @@ function normalizarPista(crudo) {
13357
13413
  programaMidi: numero(crudo.programaMidi, 25),
13358
13414
  volumen: numero(crudo.volumen, 16),
13359
13415
  balance: numero(crudo.balance, 8),
13416
+ // Ausente = 1 pentagrama, lo único que existía antes del 2026-11-09.
13417
+ ...typeof crudo.pentagramas === "number" && crudo.pentagramas > 1 ? { pentagramas: crudo.pentagramas } : {},
13360
13418
  // Las marcas de la segunda tipografía (2026-10-19): sólo si están, como `acorde`.
13361
13419
  ...typeof crudo.nombreSegundaTipografia === "string" ? { nombreSegundaTipografia: crudo.nombreSegundaTipografia } : {},
13362
13420
  ...typeof crudo.nombreCortoSegundaTipografia === "string" ? { nombreCortoSegundaTipografia: crudo.nombreCortoSegundaTipografia } : {}
@@ -13405,7 +13463,7 @@ var init_consultas = __esm({
13405
13463
  pistas;
13406
13464
  /** Las grabaciones de referencia, en el orden en que se muestran en el mezclador. */
13407
13465
  fuentesDeAudio;
13408
- /** pistaId → (compasMaestroId → compasId) */
13466
+ /** pistaId → (`compasMaestroId|pentagrama` → compasId) */
13409
13467
  _compases;
13410
13468
  /** compasId → figuras, ya ordenadas por voz y después por tiempo */
13411
13469
  _figuras;
@@ -13457,7 +13515,7 @@ var init_consultas = __esm({
13457
13515
  porMaestro = /* @__PURE__ */ new Map();
13458
13516
  this._compases.set(compas.pistaId, porMaestro);
13459
13517
  }
13460
- porMaestro.set(compas.compasMaestroId, id2);
13518
+ porMaestro.set(`${compas.compasMaestroId}|${compas.pentagrama ?? 0}`, id2);
13461
13519
  this._datosDeCompas.set(id2, compas);
13462
13520
  }
13463
13521
  this._figuras = /* @__PURE__ */ new Map();
@@ -13544,10 +13602,18 @@ var init_consultas = __esm({
13544
13602
  * compás de la obra. Devolver `undefined` en vez de fabricarlo es a propósito — crear
13545
13603
  * entidades es trabajo de quien edita, no de quien lee.
13546
13604
  */
13547
- compasId(pistaId, indice) {
13605
+ /**
13606
+ * El compás de una pista en la posición `indice`, en su pentagrama `pentagrama` (desde 0).
13607
+ * ★ Sin pentagrama, el primero: es lo único que existía antes del piano de dos pentagramas.
13608
+ */
13609
+ compasId(pistaId, indice, pentagrama = 0) {
13548
13610
  const maestro = this.compasesMaestros[indice];
13549
13611
  if (!maestro) return void 0;
13550
- return this._compases.get(pistaId)?.get(maestro.id);
13612
+ return this._compases.get(pistaId)?.get(`${maestro.id}|${pentagrama}`);
13613
+ }
13614
+ /** Cuántos pentagramas tiene una pista (1 si no lo dice). */
13615
+ pentagramasDe(pistaId) {
13616
+ return this.pista(pistaId)?.datos.pentagramas ?? 1;
13551
13617
  }
13552
13618
  /**
13553
13619
  * Las figuras de un compás, ordenadas. Con `voz`, solo las de esa voz.
@@ -13686,7 +13752,7 @@ function volcar(documento) {
13686
13752
  porMaestro = /* @__PURE__ */ new Map();
13687
13753
  compasesPorPista.set(datos.pistaId, porMaestro);
13688
13754
  }
13689
- porMaestro.set(datos.compasMaestroId, id2);
13755
+ porMaestro.set(`${datos.compasMaestroId}|${datos.pentagrama ?? 0}`, id2);
13690
13756
  }
13691
13757
  const figurasPorCompas = /* @__PURE__ */ new Map();
13692
13758
  for (const [id2, entidad] of documento.figuras.entries()) {
@@ -13709,9 +13775,10 @@ function volcar(documento) {
13709
13775
  const porMaestro = compasesPorPista.get(pista.id) ?? /* @__PURE__ */ new Map();
13710
13776
  const volcadoCompases = [];
13711
13777
  let totalNotasPista = 0;
13712
- for (const [indice, maestro] of compasesMaestros.entries()) {
13778
+ const pentagramas = Math.max(1, datosPista.pentagramas ?? 1);
13779
+ for (const [indice, maestro] of compasesMaestros.entries()) for (let pentagrama = 0; pentagrama < pentagramas; pentagrama++) {
13713
13780
  const datosMaestro = maestro.datos;
13714
- const compasId = porMaestro.get(maestro.id);
13781
+ const compasId = porMaestro.get(`${maestro.id}|${pentagrama}`);
13715
13782
  const figuras = compasId ? figurasPorCompas.get(compasId) ?? [] : [];
13716
13783
  figuras.sort(
13717
13784
  (a, b) => a.datos.voz !== b.datos.voz ? a.datos.voz - b.datos.voz : a.datos.tiempo - b.datos.tiempo
@@ -13743,6 +13810,7 @@ function volcar(documento) {
13743
13810
  compasDeAmalgama: `${datosMaestro.numerador}/${datosMaestro.denominador}`,
13744
13811
  figuras: volcadoFiguras
13745
13812
  };
13813
+ if (pentagrama > 0) volcadoCompas.pentagrama = pentagrama + 1;
13746
13814
  if (datosMaestro.seccion) {
13747
13815
  volcadoCompas.seccion = datosMaestro.seccion;
13748
13816
  Object.assign(volcadoCompas, segundaDe("seccion", datosMaestro.seccion, datosMaestro.seccionSegundaTipografia));
@@ -13759,13 +13827,14 @@ function volcar(documento) {
13759
13827
  ...segundaDe("nombreCorto", datosPista.nombreCorto, datosPista.nombreCortoSegundaTipografia),
13760
13828
  programaMidi: datosPista.programaMidi,
13761
13829
  tipo: tipoDeLaPista,
13830
+ ...pentagramas > 1 ? { pentagramas } : {},
13762
13831
  // ★ El orden de las claves de una pista de tablatura se mantiene —nombre, afinación,
13763
13832
  // capo…— con `tipo` insertado y nada más movido: el volcado se diffea, y reordenar
13764
13833
  // por gusto ensucia cada salida del repo sin arreglar nada.
13765
13834
  ...tipoDeLaPista === "trastes" ? { afinacion: datosPista.afinacion, capo: datosPista.capo } : {},
13766
13835
  volumen: datosPista.volumen,
13767
13836
  balance: datosPista.balance,
13768
- totalCompases: volcadoCompases.length,
13837
+ totalCompases: compasesMaestros.length,
13769
13838
  totalNotas: totalNotasPista,
13770
13839
  compases: volcadoCompases
13771
13840
  });
@@ -13979,7 +14048,8 @@ function crearDocumentoEnBlanco(opciones = {}) {
13979
14048
  programaMidi: pista.programaMidi ?? PROGRAMAS.guitarraAcustica,
13980
14049
  // 16 es "como está escrito" y 8 es el centro, en la escala del .gp y de alphaTab.
13981
14050
  volumen: pista.volumen ?? 16,
13982
- balance: pista.balance ?? 8
14051
+ balance: pista.balance ?? 8,
14052
+ ...(pista.pentagramas ?? 1) > 1 ? { pentagramas: pista.pentagramas } : {}
13983
14053
  });
13984
14054
  for (let i2 = 0; i2 < compases; i2++) {
13985
14055
  const compasMaestroId = documento.agregarCompasMaestro(normalizarCompasMaestro({
@@ -13995,11 +14065,23 @@ function crearDocumentoEnBlanco(opciones = {}) {
13995
14065
  repiteVeces: 0,
13996
14066
  esAnacruza: false
13997
14067
  }));
13998
- documento.agregarCompas(normalizarCompas({ pistaId, compasMaestroId }));
14068
+ for (const compas of compasesDeUnaPistaNueva(pistaId, compasMaestroId, pista.pentagramas ?? 1)) {
14069
+ documento.agregarCompas(compas);
14070
+ }
13999
14071
  }
14000
14072
  });
14001
14073
  return documento;
14002
14074
  }
14075
+ function compasesDeUnaPistaNueva(pistaId, compasMaestroId, pentagramas) {
14076
+ return Array.from(
14077
+ { length: Math.max(1, pentagramas) },
14078
+ (_, pentagrama) => normalizarCompas({
14079
+ pistaId,
14080
+ compasMaestroId,
14081
+ ...pentagrama > 0 ? { pentagrama, clave: CLAVE_DE_FA } : {}
14082
+ })
14083
+ );
14084
+ }
14003
14085
  function agregarPistaALaObra(documento, pista) {
14004
14086
  documento.doc.transact(() => {
14005
14087
  const pistaId = documento.agregarPista({
@@ -14011,14 +14093,17 @@ function agregarPistaALaObra(documento, pista) {
14011
14093
  programaMidi: pista.programaMidi,
14012
14094
  // 16 es "como está escrito" y 8 es el centro, en la escala del .gp y de alphaTab.
14013
14095
  volumen: 16,
14014
- balance: 8
14096
+ balance: 8,
14097
+ ...(pista.pentagramas ?? 1) > 1 ? { pentagramas: pista.pentagramas } : {}
14015
14098
  });
14016
14099
  for (const compasMaestroId of documento.compasesMaestros.keys()) {
14017
- documento.agregarCompas(normalizarCompas({ pistaId, compasMaestroId }));
14100
+ for (const compas of compasesDeUnaPistaNueva(pistaId, compasMaestroId, pista.pentagramas ?? 1)) {
14101
+ documento.agregarCompas(compas);
14102
+ }
14018
14103
  }
14019
14104
  });
14020
14105
  }
14021
- var AFINACIONES, PROGRAMAS;
14106
+ var AFINACIONES, PROGRAMAS, CLAVE_DE_FA;
14022
14107
  var init_enBlanco = __esm({
14023
14108
  "packages/model/src/enBlanco.ts"() {
14024
14109
  init_migrar();
@@ -14064,6 +14149,7 @@ var init_enBlanco = __esm({
14064
14149
  /** La batería NO se elige por programa: va por canal 10. Ver `TipoDePista`. */
14065
14150
  bateria: 0
14066
14151
  };
14152
+ CLAVE_DE_FA = 3;
14067
14153
  }
14068
14154
  });
14069
14155
 
@@ -14086,7 +14172,7 @@ var init_src2 = __esm({
14086
14172
  function posicionesEscribibles(indice, cursor) {
14087
14173
  const maestro = indice.compasMaestro(cursor.compas);
14088
14174
  if (!maestro) return [0];
14089
- const figuras = indice.figuras(indice.compasId(cursor.pistaId, cursor.compas), cursor.voz);
14175
+ const figuras = indice.figuras(indice.compasId(cursor.pistaId, cursor.compas, cursor.pentagrama), cursor.voz);
14090
14176
  const posiciones = /* @__PURE__ */ new Set([0]);
14091
14177
  for (const { datos } of figuras) posiciones.add(datos.tiempo);
14092
14178
  const fin = finDeLoEscrito(figuras);
@@ -14115,6 +14201,8 @@ function normalizar(indice, cursor) {
14115
14201
  tiempo: cursor.tiempo,
14116
14202
  cuerda: acotar(cursor.cuerda, 1, cuerdas)
14117
14203
  };
14204
+ const pentagrama = acotar(cursor.pentagrama ?? 0, 0, (pista ? indice.pentagramasDe(pista.id) : 1) - 1);
14205
+ if (pentagrama > 0) saneado.pentagrama = pentagrama;
14118
14206
  const posiciones = posicionesEscribibles(indice, saneado);
14119
14207
  saneado.tiempo = mayorMenorOIgual(posiciones, cursor.tiempo);
14120
14208
  return saneado;
@@ -14154,7 +14242,13 @@ function extremos(seleccion) {
14154
14242
  }
14155
14243
  function seleccionDesde(cursor) {
14156
14244
  const punto = { compas: cursor.compas, tiempo: cursor.tiempo };
14157
- return { pistaId: cursor.pistaId, voz: cursor.voz, ancla: punto, foco: { ...punto } };
14245
+ return {
14246
+ pistaId: cursor.pistaId,
14247
+ ...cursor.pentagrama ? { pentagrama: cursor.pentagrama } : {},
14248
+ voz: cursor.voz,
14249
+ ancla: punto,
14250
+ foco: { ...punto }
14251
+ };
14158
14252
  }
14159
14253
  function extenderHasta(seleccion, cursor) {
14160
14254
  return { ...seleccion, foco: { compas: cursor.compas, tiempo: cursor.tiempo } };
@@ -14170,7 +14264,7 @@ function figurasDelPasaje(indice, seleccion) {
14170
14264
  const { desde, hasta } = extremos(seleccion);
14171
14265
  const salida = [];
14172
14266
  for (let compas = desde.compas; compas <= hasta.compas; compas++) {
14173
- const compasId = indice.compasId(seleccion.pistaId, compas);
14267
+ const compasId = indice.compasId(seleccion.pistaId, compas, seleccion.pentagrama);
14174
14268
  for (const figura of indice.figuras(compasId, seleccion.voz)) {
14175
14269
  if (!contiene(seleccion, compas, figura.datos.tiempo)) continue;
14176
14270
  salida.push({
@@ -14193,19 +14287,19 @@ function golpesAlcanzados(indice, cursor, seleccion) {
14193
14287
  };
14194
14288
  if (seleccion?.notas?.length) {
14195
14289
  for (const marcada of seleccion.notas) {
14196
- const compasId2 = indice.compasId(seleccion.pistaId, marcada.compas);
14290
+ const compasId2 = indice.compasId(seleccion.pistaId, marcada.compas, seleccion.pentagrama);
14197
14291
  sumar(indice.figuraEn(compasId2, seleccion.voz, marcada.tiempo), compasId2, seleccion.voz);
14198
14292
  }
14199
14293
  return salida;
14200
14294
  }
14201
14295
  if (seleccion) {
14202
14296
  for (const figura of figurasDelPasaje(indice, seleccion)) {
14203
- const compasId2 = indice.compasId(seleccion.pistaId, figura.compas);
14297
+ const compasId2 = indice.compasId(seleccion.pistaId, figura.compas, seleccion.pentagrama);
14204
14298
  sumar(indice.figuraEn(compasId2, seleccion.voz, figura.tiempo), compasId2, seleccion.voz);
14205
14299
  }
14206
14300
  return salida;
14207
14301
  }
14208
- const compasId = indice.compasId(cursor.pistaId, cursor.compas);
14302
+ const compasId = indice.compasId(cursor.pistaId, cursor.compas, cursor.pentagrama);
14209
14303
  const enElCursor = compasId ? indice.figuraEn(compasId, cursor.voz, cursor.tiempo) : void 0;
14210
14304
  sumar(enElCursor, compasId, cursor.voz);
14211
14305
  return salida;
@@ -14263,7 +14357,7 @@ function destinoDeEscritura(indice, cursor) {
14263
14357
  const maestro = indice.compasMaestro(cursor.compas);
14264
14358
  if (!maestro) return null;
14265
14359
  if (!indice.pista(cursor.pistaId)) return null;
14266
- return { maestro, compasExistente: indice.compasId(cursor.pistaId, cursor.compas) };
14360
+ return { maestro, compasExistente: indice.compasId(cursor.pistaId, cursor.compas, cursor.pentagrama) };
14267
14361
  }
14268
14362
  function escribirEnLaCuerda(documento, indice, cursor, cuerda, resolverTraste, duracion) {
14269
14363
  const destino = destinoDeEscritura(indice, cursor);
@@ -14273,7 +14367,7 @@ function escribirEnLaCuerda(documento, indice, cursor, cuerda, resolverTraste, d
14273
14367
  const notaExistente = figuraExistente ? indice.notaEnCuerda(figuraExistente.id, cuerda) : void 0;
14274
14368
  let resultado = null;
14275
14369
  documento.doc.transact(() => {
14276
- const compasId = compasExistente ?? documento.agregarCompas(normalizarCompas({ pistaId: cursor.pistaId, compasMaestroId: maestro.id }));
14370
+ const compasId = compasExistente ?? documento.agregarCompas(normalizarCompas({ pistaId: cursor.pistaId, compasMaestroId: maestro.id, pentagrama: cursor.pentagrama }));
14277
14371
  let figuraId;
14278
14372
  if (figuraExistente) {
14279
14373
  figuraId = figuraExistente.id;
@@ -14303,7 +14397,7 @@ function escribirEnElGolpe(documento, indice, cursor, duracion, buscarLaQueYaEst
14303
14397
  let salida = null;
14304
14398
  documento.doc.transact(() => {
14305
14399
  const compasId = compasExistente ?? documento.agregarCompas(
14306
- normalizarCompas({ pistaId: cursor.pistaId, compasMaestroId: maestro.id })
14400
+ normalizarCompas({ pistaId: cursor.pistaId, compasMaestroId: maestro.id, pentagrama: cursor.pentagrama })
14307
14401
  );
14308
14402
  let figuraId;
14309
14403
  if (figuraExistente) {
@@ -14342,7 +14436,7 @@ function escribirPercusion(documento, indice, cursor, articulacion, opciones = {
14342
14436
  );
14343
14437
  }
14344
14438
  function borrarAltura(documento, indice, cursor, altura) {
14345
- const compasId = indice.compasId(cursor.pistaId, cursor.compas);
14439
+ const compasId = indice.compasId(cursor.pistaId, cursor.compas, cursor.pentagrama);
14346
14440
  const figura = compasId ? indice.figuraEn(compasId, cursor.voz, cursor.tiempo) : void 0;
14347
14441
  const nota = indice.notaEnAltura(figura?.id, altura);
14348
14442
  if (!nota) return false;
@@ -14350,7 +14444,7 @@ function borrarAltura(documento, indice, cursor, altura) {
14350
14444
  return true;
14351
14445
  }
14352
14446
  function borrarPercusion(documento, indice, cursor, articulacion) {
14353
- const compasId = indice.compasId(cursor.pistaId, cursor.compas);
14447
+ const compasId = indice.compasId(cursor.pistaId, cursor.compas, cursor.pentagrama);
14354
14448
  const figura = compasId ? indice.figuraEn(compasId, cursor.voz, cursor.tiempo) : void 0;
14355
14449
  const nota = indice.notaEnArticulacion(figura?.id, articulacion);
14356
14450
  if (!nota) return false;
@@ -14370,7 +14464,7 @@ function escribirTraste(documento, indice, cursor, cuerda, traste, opciones = {}
14370
14464
  );
14371
14465
  }
14372
14466
  function borrarNotaDeCuerda(documento, indice, cursor, cuerda) {
14373
- const compasId = indice.compasId(cursor.pistaId, cursor.compas);
14467
+ const compasId = indice.compasId(cursor.pistaId, cursor.compas, cursor.pentagrama);
14374
14468
  const figura = compasId ? indice.figuraEn(compasId, cursor.voz, cursor.tiempo) : void 0;
14375
14469
  if (!figura) return false;
14376
14470
  const nota = indice.notaEnCuerda(figura.id, cuerda);
@@ -14390,7 +14484,7 @@ function escribirSilencio(documento, indice, cursor, duracion = DURACION_INICIAL
14390
14484
  const notas = figuraExistente ? [...indice.notas(figuraExistente.id)] : [];
14391
14485
  let id2 = null;
14392
14486
  documento.doc.transact(() => {
14393
- const compasId = compasExistente ?? documento.agregarCompas(normalizarCompas({ pistaId: cursor.pistaId, compasMaestroId: maestro.id }));
14487
+ const compasId = compasExistente ?? documento.agregarCompas(normalizarCompas({ pistaId: cursor.pistaId, compasMaestroId: maestro.id, pentagrama: cursor.pentagrama }));
14394
14488
  if (figuraExistente) {
14395
14489
  id2 = figuraExistente.id;
14396
14490
  for (const nota of notas) documento.notas.delete(nota.id);
@@ -14536,7 +14630,7 @@ function copiar(indice, seleccion) {
14536
14630
  const copiadas = [];
14537
14631
  let recorrido = 0;
14538
14632
  for (const [i2, f] of figuras.entries()) {
14539
- const entidad = indice.figuras(indice.compasId(seleccion.pistaId, f.compas), seleccion.voz).find((x2) => x2.id === f.id);
14633
+ const entidad = indice.figuras(indice.compasId(seleccion.pistaId, f.compas, seleccion.pentagrama), seleccion.voz).find((x2) => x2.id === f.id);
14540
14634
  if (!entidad) continue;
14541
14635
  if (i2 > 0) recorrido += figuras[i2 - 1].tics;
14542
14636
  else recorrido = f.compas === desde.compas ? f.tiempo - desde.tiempo : 0;
@@ -14588,7 +14682,7 @@ function pegar(documento, indice, cursor, portapapeles2) {
14588
14682
  }
14589
14683
  const aBorrar = [];
14590
14684
  for (const [compasDelTramo, tramo] of tramos) {
14591
- const compasId = indice.compasId(cursor.pistaId, compasDelTramo);
14685
+ const compasId = indice.compasId(cursor.pistaId, compasDelTramo, cursor.pentagrama);
14592
14686
  for (const figura of indice.figuras(compasId, cursor.voz)) {
14593
14687
  const inicio = figura.datos.tiempo;
14594
14688
  const fin = inicio + ticsDeFigura(figura.datos);
@@ -14599,7 +14693,7 @@ function pegar(documento, indice, cursor, portapapeles2) {
14599
14693
  }
14600
14694
  const compasesDestino = /* @__PURE__ */ new Map();
14601
14695
  for (const compasDelTramo of tramos.keys()) {
14602
- compasesDestino.set(compasDelTramo, indice.compasId(cursor.pistaId, compasDelTramo));
14696
+ compasesDestino.set(compasDelTramo, indice.compasId(cursor.pistaId, compasDelTramo, cursor.pentagrama));
14603
14697
  }
14604
14698
  const maestrosDestino = /* @__PURE__ */ new Map();
14605
14699
  for (const compasDelTramo of tramos.keys()) {
@@ -14618,7 +14712,8 @@ function pegar(documento, indice, cursor, portapapeles2) {
14618
14712
  if (!maestroId) continue;
14619
14713
  compasId = documento.agregarCompas(normalizarCompas({
14620
14714
  pistaId: cursor.pistaId,
14621
- compasMaestroId: maestroId
14715
+ compasMaestroId: maestroId,
14716
+ pentagrama: cursor.pentagrama
14622
14717
  }));
14623
14718
  compasesDestino.set(destino.compas, compasId);
14624
14719
  }
@@ -14641,7 +14736,7 @@ function duplicarUltima(documento, indice, cursor, opciones = {}) {
14641
14736
  let compas = cursor.compas;
14642
14737
  let anterior;
14643
14738
  while (compas >= 0 && !anterior) {
14644
- const compasId = indice.compasId(cursor.pistaId, compas);
14739
+ const compasId = indice.compasId(cursor.pistaId, compas, cursor.pentagrama);
14645
14740
  const figuras = indice.figuras(compasId, cursor.voz);
14646
14741
  const candidatas = compas === cursor.compas ? figuras.filter((f) => f.datos.tiempo < cursor.tiempo) : figuras;
14647
14742
  anterior = candidatas[candidatas.length - 1];
@@ -14701,7 +14796,7 @@ function borrarPasaje(documento, indice, seleccion) {
14701
14796
  notas: indice.notas(f.id).map((n) => n.id)
14702
14797
  }));
14703
14798
  const compases = new Set(
14704
- figuras.map((f) => indice.compasId(seleccion.pistaId, f.compas)).filter(Boolean)
14799
+ figuras.map((f) => indice.compasId(seleccion.pistaId, f.compas, seleccion.pentagrama)).filter(Boolean)
14705
14800
  );
14706
14801
  documento.doc.transact(() => {
14707
14802
  for (const figura of aBorrar) {
@@ -14740,9 +14835,8 @@ function meterCompasEntre(documento, indice, anterior, siguiente) {
14740
14835
  repiteVeces: 0,
14741
14836
  orden: documento.ordenEntre(anterior?.datos.orden ?? null, siguiente?.datos.orden ?? null)
14742
14837
  }));
14743
- for (const pista of indice.pistas) {
14744
- documento.agregarCompas(normalizarCompas({ pistaId: pista.id, compasMaestroId }));
14745
- }
14838
+ const vecino = indice.posicionDeCompas((anterior ?? siguiente).id);
14839
+ for (const pista of indice.pistas) agregarCompasesDeLaPista(documento, indice, pista.id, compasMaestroId, vecino);
14746
14840
  });
14747
14841
  return true;
14748
14842
  }
@@ -14771,7 +14865,7 @@ function agregarCompasesAlFinal(documento, indice, cuantos) {
14771
14865
  })
14772
14866
  );
14773
14867
  for (const pista of pistas) {
14774
- documento.agregarCompas(normalizarCompas({ pistaId: pista.id, compasMaestroId }));
14868
+ agregarCompasesDeLaPista(documento, indice, pista.id, compasMaestroId, indice.cantidadDeCompases - 1);
14775
14869
  }
14776
14870
  ordenAnterior = orden;
14777
14871
  puestos++;
@@ -14784,8 +14878,8 @@ function borrarCompas(documento, indice, compas) {
14784
14878
  if (!maestro || indice.cantidadDeCompases <= 1) return false;
14785
14879
  const compases = [];
14786
14880
  const figuras = [];
14787
- for (const pista of indice.pistas) {
14788
- const compasId = indice.compasId(pista.id, compas);
14881
+ for (const pista of indice.pistas) for (let p = 0; p < indice.pentagramasDe(pista.id); p++) {
14882
+ const compasId = indice.compasId(pista.id, compas, p);
14789
14883
  if (!compasId) continue;
14790
14884
  compases.push(compasId);
14791
14885
  for (const figura of indice.figuras(compasId)) {
@@ -14837,8 +14931,8 @@ function borrarRango(documento, indice, desde, hasta) {
14837
14931
  const maestro = indice.compasMaestro(c);
14838
14932
  if (!maestro) continue;
14839
14933
  maestros.push(maestro.id);
14840
- for (const pista of indice.pistas) {
14841
- const compasId = indice.compasId(pista.id, c);
14934
+ for (const pista of indice.pistas) for (let p = 0; p < indice.pentagramasDe(pista.id); p++) {
14935
+ const compasId = indice.compasId(pista.id, c, p);
14842
14936
  if (!compasId) continue;
14843
14937
  compases.push(compasId);
14844
14938
  for (const figura of indice.figuras(compasId)) {
@@ -14862,6 +14956,17 @@ function borrarCompasesDesde(documento, indice, compas) {
14862
14956
  function borrarCompasesHasta(documento, indice, compas) {
14863
14957
  return borrarRango(documento, indice, 0, compas);
14864
14958
  }
14959
+ function agregarCompasesDeLaPista(documento, indice, pistaId, compasMaestroId, vecino) {
14960
+ for (let pentagrama = 0; pentagrama < indice.pentagramasDe(pistaId); pentagrama++) {
14961
+ const delVecino = vecino === void 0 ? void 0 : indice.compas(indice.compasId(pistaId, vecino, pentagrama));
14962
+ documento.agregarCompas(normalizarCompas({
14963
+ pistaId,
14964
+ compasMaestroId,
14965
+ pentagrama,
14966
+ ...delVecino ? { clave: delVecino.clave, claveOctava: delVecino.claveOctava } : {}
14967
+ }));
14968
+ }
14969
+ }
14865
14970
  var init_pasajes = __esm({
14866
14971
  "packages/editor/src/pasajes.ts"() {
14867
14972
  init_src2();
@@ -14887,7 +14992,7 @@ function ponerSilabaEnElGolpe(documento, indice, cursor, texto4, marcas) {
14887
14992
  }
14888
14993
  documento.doc.transact(() => {
14889
14994
  const compasId = compasExistente ?? documento.agregarCompas(
14890
- normalizarCompas({ pistaId: cursor.pistaId, compasMaestroId: maestro.id })
14995
+ normalizarCompas({ pistaId: cursor.pistaId, compasMaestroId: maestro.id, pentagrama: cursor.pentagrama })
14891
14996
  );
14892
14997
  const id2 = figura?.id ?? documento.agregarFigura({
14893
14998
  ...figuraNueva(compasId, cursor, DURACION_INICIAL),
@@ -15220,7 +15325,7 @@ function notasAlcanzadas(indice, cursor, seleccion) {
15220
15325
  if (seleccion?.notas?.length) {
15221
15326
  const salida = [];
15222
15327
  for (const marcada of seleccion.notas) {
15223
- const compasId2 = indice.compasId(seleccion.pistaId, marcada.compas);
15328
+ const compasId2 = indice.compasId(seleccion.pistaId, marcada.compas, seleccion.pentagrama);
15224
15329
  const figura2 = indice.figuraEn(compasId2, seleccion.voz, marcada.tiempo);
15225
15330
  const nota2 = indice.notaEnCuerda(figura2?.id, marcada.cuerda);
15226
15331
  if (nota2) salida.push(nota2);
@@ -15234,7 +15339,7 @@ function notasAlcanzadas(indice, cursor, seleccion) {
15234
15339
  }
15235
15340
  return salida;
15236
15341
  }
15237
- const compasId = indice.compasId(cursor.pistaId, cursor.compas);
15342
+ const compasId = indice.compasId(cursor.pistaId, cursor.compas, cursor.pentagrama);
15238
15343
  const figura = compasId ? indice.figuraEn(compasId, cursor.voz, cursor.tiempo) : void 0;
15239
15344
  if (!figura) return [];
15240
15345
  const nota = indice.notaEnCuerda(figura.id, cursor.cuerda);
@@ -20193,7 +20298,7 @@ function acordeDeNotas(notas, afinacion) {
20193
20298
  };
20194
20299
  }
20195
20300
  function acordeEnElCursor(indice, cursor) {
20196
- const compasId = indice.compasId(cursor.pistaId, cursor.compas);
20301
+ const compasId = indice.compasId(cursor.pistaId, cursor.compas, cursor.pentagrama);
20197
20302
  const figura = compasId ? indice.figuraEn(compasId, cursor.voz, cursor.tiempo) : void 0;
20198
20303
  if (!figura) return null;
20199
20304
  const afinacion = indice.pista(cursor.pistaId)?.datos.afinacion;
@@ -20295,7 +20400,7 @@ function ponerAcorde(documento, indice, cursor, nombre, duracion = DURACION_INIC
20295
20400
  const yaTieneNotas = figura ? indice.notas(figura.id).length > 0 : false;
20296
20401
  if (sinNombre && (yaTieneNotas || forma.length === 0)) return null;
20297
20402
  documento.doc.transact(() => {
20298
- const compasId = compasExistente ?? documento.agregarCompas(normalizarCompas({ pistaId: cursor.pistaId, compasMaestroId: maestro.id }));
20403
+ const compasId = compasExistente ?? documento.agregarCompas(normalizarCompas({ pistaId: cursor.pistaId, compasMaestroId: maestro.id, pentagrama: cursor.pentagrama }));
20299
20404
  const id2 = figura?.id ?? documento.agregarFigura({ ...figuraNueva(compasId, cursor, duracion), esSilencio: true });
20300
20405
  const mapa = documento.figuras.get(id2);
20301
20406
  if (mapa && !sinNombre) escribirConMarcas(mapa, "acorde", nombre ?? "", marcas, { recortar: true });
@@ -20540,8 +20645,8 @@ var init_instrumentos = __esm({
20540
20645
  programaMidi: PROGRAMAS.guitarraNylon
20541
20646
  },
20542
20647
  // ── Teclados ──
20543
- { clave: "piano", nombre: "Piano", nombreCorto: "pno", grupo: "Teclados", tipo: "altura", afinacion: [], programaMidi: PROGRAMAS.piano },
20544
- { clave: "piano-electrico", nombre: "Piano el\xE9ctrico", nombreCorto: "e.pno", grupo: "Teclados", tipo: "altura", afinacion: [], programaMidi: PROGRAMAS.pianoElectrico },
20648
+ { clave: "piano", nombre: "Piano", nombreCorto: "pno", grupo: "Teclados", tipo: "altura", afinacion: [], programaMidi: PROGRAMAS.piano, pentagramas: 2 },
20649
+ { clave: "piano-electrico", nombre: "Piano el\xE9ctrico", nombreCorto: "e.pno", grupo: "Teclados", tipo: "altura", afinacion: [], programaMidi: PROGRAMAS.pianoElectrico, pentagramas: 2 },
20545
20650
  { clave: "organo", nombre: "\xD3rgano", nombreCorto: "org", grupo: "Teclados", tipo: "altura", afinacion: [], programaMidi: PROGRAMAS.organo },
20546
20651
  // ── Vientos ──
20547
20652
  { clave: "trompeta", nombre: "Trompeta", nombreCorto: "tpt", grupo: "Vientos", tipo: "altura", afinacion: [], programaMidi: PROGRAMAS.trompeta },
@@ -87317,312 +87422,6 @@ var init_alphaTab = __esm({
87317
87422
  }
87318
87423
  });
87319
87424
 
87320
- // packages/io/src/importarGp.ts
87321
- function importarGp(bytes, opciones = {}) {
87322
- const score = _barrel_exports$1.ScoreLoader.loadScoreFromBytes(bytes);
87323
- return importarScore(score, opciones);
87324
- }
87325
- function importarScore(score, opciones = {}) {
87326
- const avisos = [];
87327
- const documento = crearDocumento({ clienteId: opciones.clienteId });
87328
- documento.ponerCabecera({
87329
- titulo: score.title ?? "",
87330
- artista: score.artist ?? "",
87331
- album: score.album ?? "",
87332
- tempo: score.tempo ?? 0,
87333
- mostrarMatices: !score.stylesheet.hideDynamics
87334
- });
87335
- avisos.push(
87336
- 'Las preferencias de dibujo del archivo (el "stylesheet" de Guitar Pro) no se importan, salvo si se muestran los matices. La m\xFAsica no cambia; el aspecto s\xED.'
87337
- );
87338
- if (opciones.autoria) {
87339
- documento.ponerAutoria(opciones.autoria);
87340
- } else {
87341
- documento.ponerAutoria({
87342
- escritaPor: "",
87343
- origen: "transcripcion",
87344
- obraTitulo: score.title ?? "",
87345
- obraAutores: score.artist ?? "",
87346
- obraEditora: ""
87347
- });
87348
- avisos.push(
87349
- "La autor\xEDa qued\xF3 sin completar: se import\xF3 como transcripci\xF3n con los datos del archivo. Hay que confirmarla antes de publicar o compartir el documento."
87350
- );
87351
- }
87352
- const idsDeCompasMaestro = score.masterBars.map(
87353
- (maestro) => documento.agregarCompasMaestro(normalizarCompasMaestro({
87354
- numerador: maestro.timeSignatureNumerator,
87355
- denominador: maestro.timeSignatureDenominator,
87356
- tonalidad: numeroDeTonalidad(maestro.keySignature),
87357
- seccion: maestro.section?.text ?? "",
87358
- // Solo interesa el cambio de tempo que arranca en este compás; los que caen
87359
- // en el medio son F02 y todavía no tienen dónde ir.
87360
- tempo: maestro.tempoAutomations?.[0]?.value ?? null,
87361
- repiteDesdeAca: maestro.isRepeatStart,
87362
- repiteVeces: maestro.repeatCount,
87363
- // ⚠️ Novena pérdida silenciosa de la misma familia: 2 de los 15 `.gp` de Daniel
87364
- // declaran una anacruza y el modelo la descartaba.
87365
- esAnacruza: maestro.isAnacrusis,
87366
- // ── Los signos de compás de Guitar Pro ────────────────────────────────
87367
- casillas: maestro.alternateEndings,
87368
- dobleBarra: maestro.isDoubleBar,
87369
- tiempoLibre: maestro.isFreeTime,
87370
- swing: maestro.tripletFeel,
87371
- // ⚠️ `simileMark` es del compás DE LA PISTA en alphaTab (`Bar.simileMark`), no del
87372
- // maestro. Se lee más abajo, al recorrer los compases de cada pentagrama, y se
87373
- // escribe acá arriba porque en el modelo la repetición de compás es de la obra:
87374
- // un «igual que el anterior» que valiera para la guitarra y no para el bajo
87375
- // dejaría los dos instrumentos diciendo cosas distintas sobre el mismo compás.
87376
- repiteAnterior: 0,
87377
- // ⚠️ `directions` es un `Set` o `null`, no una lista. Un `?? []` sobre un Set daría
87378
- // el Set, y `.map` no existe ahí: hay que expandirlo.
87379
- //
87380
- // ⚠️⚠️ Y se guarda el NOMBRE, no el número. `String(d)` daba `"1"` —el valor del enum
87381
- // convertido a texto— y la proyección buscaba `Direction["1"]`, que en un enum con
87382
- // mapeo inverso devuelve el *nombre* y no un número: la guarda lo descartaba y **las
87383
- // direcciones se perdían enteras, en silencio**. Lo cazó la prueba de ida y vuelta
87384
- // con signos, que es exactamente para lo que existe.
87385
- //
87386
- // ★ El nombre y no el número, además, porque acá es una LISTA y se lee: un
87387
- // `["JumpDalSegnoAlCoda"]` en el documento dice algo; un `[10]` no.
87388
- direcciones: maestro.directions ? [...maestro.directions].map(
87389
- (d) => _barrel_exports$4.Direction[d] ?? String(d)
87390
- ) : []
87391
- }))
87392
- );
87393
- for (const pista of score.tracks) {
87394
- if (pista.staves.length > 1) {
87395
- avisos.push(
87396
- `La pista "${pista.name}" tiene ${pista.staves.length} pentagramas y se import\xF3 solo el primero. La etapa 1 es tablatura de un pentagrama por pista.`
87397
- );
87398
- }
87399
- const pentagrama = pista.staves[0];
87400
- if (!pentagrama) {
87401
- avisos.push(`La pista "${pista.name}" no tiene pentagramas y se salte\xF3 entera.`);
87402
- continue;
87403
- }
87404
- const tipo = pentagrama.isPercussion ? "percusion" : pentagrama.tuning.length === 0 ? "altura" : "trastes";
87405
- const idPista = documento.agregarPista({
87406
- tipo,
87407
- nombre: pista.name ?? "",
87408
- nombreCorto: pista.shortName ?? "",
87409
- // ⚠️ Conversión 1: alphaTab la guarda de la aguda a la grave.
87410
- afinacion: [...pentagrama.tuning].reverse(),
87411
- capo: pentagrama.capo ?? 0,
87412
- programaMidi: pista.playbackInfo?.program ?? 0,
87413
- // ⚠️ SE ESTABAN PERDIENDO. El `.gp` los trae y el modelo no los guardaba, así que
87414
- // importar una canción y volver a exportarla devolvía todas las pistas al volumen y
87415
- // al centro por defecto. Séptima pérdida silenciosa de la misma familia — y ésta no
87416
- // la destapó la comparación de píxeles, porque la mezcla no se dibuja: se oye.
87417
- volumen: pista.playbackInfo?.volume ?? 16,
87418
- balance: pista.playbackInfo?.balance ?? 8
87419
- });
87420
- for (const [indice, compasDeAlphaTab] of pentagrama.bars.entries()) {
87421
- const maestroDelCompas = score.masterBars[indice];
87422
- const idCompasMaestro = idsDeCompasMaestro[indice];
87423
- if (idCompasMaestro === void 0) {
87424
- avisos.push(
87425
- `La pista "${pista.name}" tiene un comp\xE1s ${indice + 1} que no existe en la partitura (hay ${idsDeCompasMaestro.length} compases maestros). Se salte\xF3.`
87426
- );
87427
- continue;
87428
- }
87429
- const idCompas = documento.agregarCompas(normalizarCompas({
87430
- pistaId: idPista,
87431
- compasMaestroId: idCompasMaestro,
87432
- // La clave es de la pista: el bajo lleva fa y la guitarra sol en el mismo compás.
87433
- clave: compasDeAlphaTab.clef,
87434
- claveOctava: compasDeAlphaTab.clefOttava
87435
- }));
87436
- if (compasDeAlphaTab.simileMark) {
87437
- const maestro = documento.compasesMaestros.get(idCompasMaestro);
87438
- if (maestro && !maestro.get("repiteAnterior")) {
87439
- maestro.set("repiteAnterior", compasDeAlphaTab.simileMark);
87440
- }
87441
- }
87442
- const ticsDelCompas = 960 * 4 * (maestroDelCompas?.timeSignatureNumerator ?? 4) / (maestroDelCompas?.timeSignatureDenominator ?? 4);
87443
- const pedalesDelCompas = /* @__PURE__ */ new Map();
87444
- for (const marcador of compasDeAlphaTab.sustainPedals ?? []) {
87445
- pedalesDelCompas.set(Math.round(marcador.ratioPosition * ticsDelCompas), marcador.pedalType + 1);
87446
- }
87447
- for (const voz of compasDeAlphaTab.voices) {
87448
- if (voz.isEmpty) continue;
87449
- for (const golpe of voz.beats) {
87450
- const idFigura = documento.agregarFigura(
87451
- normalizarFigura({
87452
- compasId: idCompas,
87453
- voz: voz.index,
87454
- // Tics MIDI desde el comienzo del compás. alphaTab y el modelo usan la
87455
- // misma unidad (960 por negra), así que no hay conversión.
87456
- tiempo: golpe.displayStart,
87457
- // El valor del enum `Duration` de alphaTab ES el número que usa el
87458
- // modelo: 4 = negra, 8 = corchea. No es casualidad — es la decisión de
87459
- // copiar la forma de lo que ya funciona.
87460
- valor: golpe.duration,
87461
- puntillos: golpe.dots ?? 0,
87462
- esSilencio: golpe.isRest,
87463
- // ⚠️ Conversión 3: -1 significa "sin grupo irregular".
87464
- tupletNumerador: normalizarTuplet(golpe.tupletNumerator),
87465
- tupletDenominador: normalizarTuplet(golpe.tupletDenominator),
87466
- // ★ Acá viene la letra. En la canción de Daniel cada sílaba está escrita
87467
- // como texto del golpe, que es como se hace en la práctica en Guitar Pro.
87468
- // Sin este campo, importar y exportar la borraba sin decir nada.
87469
- texto: golpe.text ?? "",
87470
- dinamica: golpe.dynamics,
87471
- // ═══════════════════════════════════════════════════════════════════
87472
- // ★★★ LOS SIGNOS DE GUITAR PRO — hasta hoy se perdían TODOS en silencio
87473
- // ═══════════════════════════════════════════════════════════════════
87474
- //
87475
- // Es la misma familia de pérdidas que ya destapó dos veces la comparación de
87476
- // píxeles (el martillo, la dinámica) y una vez el inventario del manual: **el
87477
- // modelo no tenía dónde ponerlos, así que un `.gp` con un rasgueado, un slap o
87478
- // unas casillas de repetición entraba sin ellos y nadie lo decía**.
87479
- //
87480
- // ⚠️ Ninguno se convierte. Los números del modelo SON los de alphaTab, que es
87481
- // la decisión que este archivo ya había tomado para el armónico y el
87482
- // deslizamiento: una tabla de traducción es donde se pierde el valor que
87483
- // todavía no se conoce.
87484
- calderon: golpe.fermata ? golpe.fermata.type + 1 : 0,
87485
- puaDireccion: golpe.pickStroke,
87486
- rasgueo: golpe.brushType,
87487
- duracionDelRasgueo: golpe.brushDuration,
87488
- slap: golpe.slap,
87489
- pop: golpe.pop,
87490
- tapping: golpe.tap,
87491
- slapMuerto: golpe.deadSlapped,
87492
- barraOblicua: golpe.slashed,
87493
- // ⚠️ `tremoloPicking` es OPCIONAL en alphaTab (`?:`), no un enum con cero: sin
87494
- // el `?.` esto reventaría en el 99 % de los golpes. Y lo que guarda son
87495
- // `marks` —las barritas que cruzan la plica—, no una duración.
87496
- tremolo: golpe.tremoloPicking?.marks ?? 0,
87497
- adorno: golpe.graceType,
87498
- regulador: golpe.crescendo,
87499
- fundido: golpe.fade ?? 0,
87500
- wah: golpe.wahPedal,
87501
- golpeEnLaTapa: golpe.golpe,
87502
- rasgueado: golpe.rasgueado,
87503
- cejilla: golpe.barreFret,
87504
- formaDeCejilla: golpe.barreShape,
87505
- plicaInvertida: golpe.invertBeamDirection,
87506
- barrado: golpe.beamingMode,
87507
- palanca: (golpe.whammyBarPoints ?? []).map((p) => ({
87508
- desplazamiento: p.offset,
87509
- valor: p.value
87510
- })),
87511
- // ★ El pedal que cae en este golpe, si hay alguno. Se busca por tic exacto: el
87512
- // marcador de Guitar Pro se pone sobre un golpe, no entre dos.
87513
- pedal: pedalesDelCompas.get(golpe.displayStart) ?? 0
87514
- })
87515
- );
87516
- for (const nota of golpe.notes) {
87517
- documento.agregarNota(
87518
- normalizarNota({
87519
- figuraId: idFigura,
87520
- // ⚠️ Conversión 2: no hay conversión. Ver el encabezado.
87521
- cuerda: nota.string,
87522
- traste: nota.fret,
87523
- ligadaAAnterior: nota.isTieDestination,
87524
- muerta: nota.isDead,
87525
- fantasma: nota.isGhost,
87526
- palmMute: nota.isPalmMute,
87527
- letRing: nota.isLetRing,
87528
- // `vibrato` es un enum donde 0 es "sin vibrato"; el modelo solo
87529
- // necesita saber si hay o no. El tipo de vibrato es del bloque 5.
87530
- vibrato: nota.vibrato !== 0,
87531
- martillo: nota.isHammerPullOrigin,
87532
- staccato: nota.isStaccato,
87533
- deslizamientoEntrada: nota.slideInType,
87534
- deslizamientoSalida: nota.slideOutType,
87535
- armonico: nota.harmonicType,
87536
- // ── Los signos de Guitar Pro, a nivel de nota ──────────────────
87537
- acento: nota.accentuated,
87538
- ligaduraDeExpresion: nota.isSlurDestination || nota.slurDestination !== null,
87539
- vibratoDePalanca: 0,
87540
- // ★ La anchura del vibrato: el campo viejo `vibrato` solo decía si había.
87541
- anchoDeVibrato: nota.vibrato,
87542
- tappingIzquierda: nota.isLeftHandTapped,
87543
- muestraCuerda: nota.showStringNumber,
87544
- dedoIzquierda: nota.leftHandFinger,
87545
- dedoDerecha: nota.rightHandFinger,
87546
- // ⚠️ alphaTab usa −1 para «sin trino», igual que el modelo. No hay conversión,
87547
- // pero sí hay que respetarlo: un 0 sería el traste 0, o sea la cuerda al aire.
87548
- trino: nota.trillValue,
87549
- velocidadDeTrino: nota.trillSpeed,
87550
- alteracion: nota.accidentalMode,
87551
- // ⚠️ EL BEND SE PERDÍA ENTERO hasta el PR 7: el modelo no tenía dónde
87552
- // ponerlo, así que un archivo con bends entraba sin ellos y no lo decía
87553
- // nadie. Es la sexta pérdida silenciosa de la misma familia que destapó la
87554
- // comparación de píxeles en el PR 3 — con la diferencia de que ésta no la
87555
- // destapó, porque *El Pibe de mi Barrio* no tiene un solo bend (medido:
87556
- // cero propiedades `Bend` en su `score.gpif`). ★ Un fixture que no ejercita
87557
- // una funcionalidad no prueba que esté bien: prueba que no se usó.
87558
- //
87559
- // `hasBend` de alphaTab exige las dos cosas —que haya puntos y que el tipo
87560
- // no sea None—, así que preguntarlo es más honesto que mirar solo la lista.
87561
- bend: nota.hasBend ? (nota.bendPoints ?? []).map((p) => ({ desplazamiento: p.offset, valor: p.value })) : []
87562
- })
87563
- );
87564
- }
87565
- }
87566
- }
87567
- }
87568
- }
87569
- const audioEmbebido = importarAudioYSync(score, documento, idsDeCompasMaestro, avisos);
87570
- return { documento, avisos, ...audioEmbebido ? { audioEmbebido } : {} };
87571
- }
87572
- function importarAudioYSync(score, documento, idsDeCompasMaestro, avisos) {
87573
- const puntos = score.exportFlatSyncPoints();
87574
- const bytes = score.backingTrack?.rawAudioFile;
87575
- if (puntos.length === 0 && !bytes) return void 0;
87576
- const fuenteId = documento.agregarFuenteDeAudio({
87577
- nombre: score.title ? `${score.title} (del archivo)` : "Grabaci\xF3n del archivo",
87578
- // ⚠️ En cero las dos, y se llenan cuando el navegador decodifique. El importador
87579
- // corre también en la terminal, donde no hay `AudioContext` con el que averiguarlo.
87580
- duracion: 0,
87581
- picos: [],
87582
- volumen: 16,
87583
- balance: 8
87584
- });
87585
- let huerfanos = 0;
87586
- for (const punto of puntos) {
87587
- const compasMaestroId = idsDeCompasMaestro[punto.barIndex];
87588
- if (compasMaestroId === void 0) {
87589
- huerfanos++;
87590
- continue;
87591
- }
87592
- documento.agregarPuntoDeSync({
87593
- fuenteId,
87594
- compasMaestroId,
87595
- posicionEnElCompas: punto.barPosition,
87596
- ocurrencia: punto.barOccurence,
87597
- msDelAudio: punto.millisecondOffset
87598
- });
87599
- }
87600
- if (huerfanos > 0) {
87601
- avisos.push(
87602
- `${huerfanos} punto(s) de sincronizaci\xF3n del archivo apuntan a compases que no existen (la partitura tiene ${idsDeCompasMaestro.length}) y no se importaron.`
87603
- );
87604
- }
87605
- if (!bytes) {
87606
- avisos.push(
87607
- `El archivo trae ${puntos.length} punto(s) de sincronizaci\xF3n pero no la grabaci\xF3n. La tablatura queda alineada; para o\xEDrla hay que cargar el audio a mano.`
87608
- );
87609
- return void 0;
87610
- }
87611
- return { fuenteId, bytes };
87612
- }
87613
- function numeroDeTonalidad(armadura) {
87614
- return armadura;
87615
- }
87616
- function normalizarTuplet(valor) {
87617
- return valor === void 0 || valor <= 0 ? 1 : valor;
87618
- }
87619
- var init_importarGp = __esm({
87620
- "packages/io/src/importarGp.ts"() {
87621
- init_alphaTab();
87622
- init_src2();
87623
- }
87624
- });
87625
-
87626
87425
  // node_modules/fflate/esm/index.mjs
87627
87426
  import { createRequire } from "module";
87628
87427
  function deflateSync(data, opts) {
@@ -88604,12 +88403,744 @@ var init_esm = __esm({
88604
88403
  }
88605
88404
  });
88606
88405
 
88406
+ // packages/io/src/musicxmlEntrada.ts
88407
+ function textoMusicXml(bytes) {
88408
+ if (bytes.length > 4 && bytes[0] === 80 && bytes[1] === 75) {
88409
+ let archivos;
88410
+ try {
88411
+ archivos = unzipSync(bytes);
88412
+ } catch {
88413
+ return null;
88414
+ }
88415
+ const contenedor = archivos["META-INF/container.xml"];
88416
+ if (!contenedor) return null;
88417
+ const ruta = /<rootfile\b[^>]*full-path="([^"]+)"/.exec(strFromU8(contenedor))?.[1];
88418
+ const raiz = ruta ? archivos[ruta] : void 0;
88419
+ return raiz ? decodificar(raiz) : null;
88420
+ }
88421
+ const texto4 = decodificar(bytes.subarray(0, Math.min(bytes.length, 4096)));
88422
+ if (!/<score-(partwise|timewise)\b/.test(texto4) && !/<!DOCTYPE\s+score-/.test(texto4)) return null;
88423
+ return decodificar(bytes);
88424
+ }
88425
+ function decodificar(bytes) {
88426
+ if (bytes[0] === 255 && bytes[1] === 254) return new TextDecoder("utf-16le").decode(bytes);
88427
+ if (bytes[0] === 254 && bytes[1] === 255) return new TextDecoder("utf-16be").decode(bytes);
88428
+ return new TextDecoder("utf-8").decode(bytes);
88429
+ }
88430
+ function prepararMusicXml(xml) {
88431
+ const correcciones = [];
88432
+ let atributosMovidos = 0;
88433
+ let acordesSeparados = 0;
88434
+ let saltosMovidos = 0;
88435
+ let salida = xml.replace(/<part\b[^>]*>[\s\S]*?<\/part>/g, (parteOriginal) => {
88436
+ const movidos = moverAtributosDeFinDeCompas(parteOriginal);
88437
+ atributosMovidos += movidos.cuantos;
88438
+ const separados = separarAcordesEntrePentagramas(movidos.texto);
88439
+ acordesSeparados += separados.cuantos;
88440
+ const saltos = sacarSaltosDeLaIndicacion(separados.texto);
88441
+ saltosMovidos += saltos.cuantos;
88442
+ const { texto: texto4, cambio } = compactarVoces(saltos.texto);
88443
+ if (cambio) correcciones.push(cambio);
88444
+ return texto4;
88445
+ });
88446
+ if (atributosMovidos) {
88447
+ correcciones.push(
88448
+ `${atributosMovidos} cambios de clave, armadura o comp\xE1s escritos antes de la barra pasaron al comp\xE1s siguiente.`
88449
+ );
88450
+ }
88451
+ if (acordesSeparados) {
88452
+ correcciones.push(`${acordesSeparados} notas de acordes repartidos entre los dos pentagramas se pusieron en el suyo.`);
88453
+ }
88454
+ if (saltosMovidos) correcciones.push(`${saltosMovidos} saltos (D.C., D.S., Coda, Fine, Segno) se leyeron de su indicaci\xF3n.`);
88455
+ let juntados = 0;
88456
+ salida = salida.replace(/<direction\b[^>]*>[\s\S]*?<\/direction>/g, (dir) => {
88457
+ const palabras = [...dir.matchAll(/<words\b[^>]*>([\s\S]*?)<\/words>/g)];
88458
+ if (palabras.length < 2) return dir;
88459
+ juntados++;
88460
+ const todo = palabras.map((p) => p[1].trim()).filter(Boolean).join("\n");
88461
+ let primero = true;
88462
+ return dir.replace(/<words\b([^>]*)>[\s\S]*?<\/words>/g, (_m, attrs) => {
88463
+ if (!primero) return "";
88464
+ primero = false;
88465
+ return `<words${attrs}>${todo}</words>`;
88466
+ });
88467
+ });
88468
+ if (juntados) correcciones.push(`${juntados} indicaciones de texto en varios renglones se juntaron en una.`);
88469
+ let tempos = 0;
88470
+ salida = salida.replace(/<metronome\b[^>]*>[\s\S]*?<\/metronome>/g, (met) => {
88471
+ const unidad = /<beat-unit>\s*([\w-]+)\s*<\/beat-unit>/.exec(met)?.[1];
88472
+ const porMinuto = /<per-minute>\s*([\d.]+)\s*<\/per-minute>/.exec(met)?.[1];
88473
+ const negras = unidad ? NEGRAS_POR_FIGURA[unidad] : void 0;
88474
+ if (!unidad || !porMinuto || negras === void 0 || /<beat-unit>[\s\S]*<beat-unit>/.test(met)) return met;
88475
+ const puntillos = (met.match(/<beat-unit-dot\s*\/>/g) ?? []).length;
88476
+ const factor = negras * (puntillos === 0 ? 1 : puntillos === 1 ? 1.5 : 1.75);
88477
+ if (factor === 1) return met;
88478
+ tempos++;
88479
+ const bpm = Math.round(Number.parseFloat(porMinuto) * factor * 100) / 100;
88480
+ return met.replace(/<beat-unit>[\s\S]*?<\/beat-unit>/, "<beat-unit>quarter</beat-unit>").replace(/<beat-unit-dot\s*\/>/g, "").replace(/<per-minute>[\s\S]*?<\/per-minute>/, `<per-minute>${bpm}</per-minute>`);
88481
+ });
88482
+ if (tempos) correcciones.push(`${tempos} indicaciones de tempo se pasaron a negras (mismo pulso).`);
88483
+ return { xml: salida, bytes: new TextEncoder().encode(salida), correcciones };
88484
+ }
88485
+ function compasesDe(parte) {
88486
+ return [...parte.matchAll(/(<measure\b[^>]*>)([\s\S]*?)<\/measure>/g)].map((m) => ({
88487
+ inicio: m.index,
88488
+ fin: m.index + m[0].length,
88489
+ apertura: m[1],
88490
+ contenido: m[2]
88491
+ }));
88492
+ }
88493
+ function rearmar(parte, compases, nuevos) {
88494
+ let salida = "";
88495
+ let cursor = 0;
88496
+ compases.forEach((c, i2) => {
88497
+ salida += parte.slice(cursor, c.inicio) + c.apertura + nuevos[i2] + "</measure>";
88498
+ cursor = c.fin;
88499
+ });
88500
+ return salida + parte.slice(cursor);
88501
+ }
88502
+ function moverAtributosDeFinDeCompas(parte) {
88503
+ const compases = compasesDe(parte);
88504
+ let cuantos = 0;
88505
+ let arrastre = "";
88506
+ const nuevos = compases.map((c) => {
88507
+ let contenido = c.contenido;
88508
+ const primeraNota = contenido.search(/<note\b/);
88509
+ if (primeraNota >= 0) {
88510
+ let llevar = "";
88511
+ contenido = contenido.slice(0, primeraNota) + contenido.slice(primeraNota).replace(/<attributes\b[^>]*>([\s\S]*?)<\/attributes>/g, (bloque, adentro) => {
88512
+ const hijos = adentro.match(HIJO_QUE_SE_MUEVE);
88513
+ if (!hijos) return bloque;
88514
+ cuantos += hijos.length;
88515
+ llevar += hijos.join("");
88516
+ const resto = adentro.replace(HIJO_QUE_SE_MUEVE, "");
88517
+ return resto.trim() ? `<attributes>${resto}</attributes>` : "";
88518
+ });
88519
+ const entra2 = arrastre;
88520
+ arrastre = llevar;
88521
+ return (entra2 ? `<attributes>${entra2}</attributes>` : "") + contenido;
88522
+ }
88523
+ const entra = arrastre;
88524
+ arrastre = "";
88525
+ return (entra ? `<attributes>${entra}</attributes>` : "") + contenido;
88526
+ });
88527
+ return cuantos ? { texto: rearmar(parte, compases, nuevos), cuantos } : { texto: parte, cuantos: 0 };
88528
+ }
88529
+ function separarAcordesEntrePentagramas(parte) {
88530
+ const compases = compasesDe(parte);
88531
+ let cuantos = 0;
88532
+ const nuevos = compases.map((c) => {
88533
+ const notas = [...c.contenido.matchAll(/<note\b[\s\S]*?<\/note>/g)];
88534
+ if (notas.length < 2) return c.contenido;
88535
+ let salida = "";
88536
+ let cursor = 0;
88537
+ let i2 = 0;
88538
+ while (i2 < notas.length) {
88539
+ const grupo = [notas[i2]];
88540
+ let j = i2 + 1;
88541
+ while (j < notas.length) {
88542
+ const anterior = notas[j - 1];
88543
+ const entre = c.contenido.slice(anterior.index + anterior[0].length, notas[j].index);
88544
+ if (entre.trim() || !/<chord\s*\/>/.test(notas[j][0])) break;
88545
+ grupo.push(notas[j]);
88546
+ j++;
88547
+ }
88548
+ i2 = j;
88549
+ const pent = (n) => entero(n[0], /<staff>\s*(\d+)\s*<\/staff>/) ?? 1;
88550
+ const cabeza = grupo[0];
88551
+ const pentDeCabeza = pent(cabeza);
88552
+ const ajenas = grupo.filter((n) => pent(n) !== pentDeCabeza);
88553
+ const durCabeza = entero(cabeza[0], /<duration>\s*(\d+)\s*<\/duration>/);
88554
+ if (ajenas.length === 0 || /<chord\s*\/>/.test(cabeza[0]) || grupo.some((n) => /<grace\b|<cue\s*\/>/.test(n[0])) || durCabeza === null) {
88555
+ continue;
88556
+ }
88557
+ cuantos += ajenas.length;
88558
+ const propias = grupo.filter((n) => pent(n) === pentDeCabeza).map((n) => n[0]);
88559
+ let texto4 = propias.join("");
88560
+ const porPentagrama = /* @__PURE__ */ new Map();
88561
+ for (const n of ajenas) porPentagrama.set(pent(n), [...porPentagrama.get(pent(n)) ?? [], n[0]]);
88562
+ for (const notasDelPent of porPentagrama.values()) {
88563
+ const primera = notasDelPent[0].replace(/<chord\s*\/>\s*/, "");
88564
+ const durPrimera = entero(primera, /<duration>\s*(\d+)\s*<\/duration>/) ?? durCabeza;
88565
+ texto4 += `<backup><duration>${durCabeza}</duration></backup>` + primera + notasDelPent.slice(1).join("");
88566
+ const delta = durCabeza - durPrimera;
88567
+ if (delta > 0) texto4 += `<forward><duration>${delta}</duration></forward>`;
88568
+ else if (delta < 0) texto4 += `<backup><duration>${-delta}</duration></backup>`;
88569
+ }
88570
+ const ultimo = grupo[grupo.length - 1];
88571
+ salida += c.contenido.slice(cursor, cabeza.index) + texto4;
88572
+ cursor = ultimo.index + ultimo[0].length;
88573
+ }
88574
+ return salida + c.contenido.slice(cursor);
88575
+ });
88576
+ return cuantos ? { texto: rearmar(parte, compases, nuevos), cuantos } : { texto: parte, cuantos: 0 };
88577
+ }
88578
+ function sacarSaltosDeLaIndicacion(parte) {
88579
+ let cuantos = 0;
88580
+ const texto4 = parte.replace(/<direction\b[^>]*>[\s\S]*?<\/direction>/g, (dir, desde, todo) => {
88581
+ const sonido = /<sound\b([^>]*?)\/?>/.exec(dir)?.[1];
88582
+ if (!sonido) return dir;
88583
+ const atributos = ATRIBUTOS_DE_SALTO.map((a) => new RegExp(`\\b${a}="([^"]*)"`).exec(sonido)?.[0]).filter((a) => a !== void 0);
88584
+ if (atributos.length === 0) return dir;
88585
+ const copia = `<sound ${atributos.join(" ")}/>`;
88586
+ if (todo.slice(desde + dir.length).trimStart().startsWith(copia)) return dir;
88587
+ cuantos++;
88588
+ return dir + copia;
88589
+ });
88590
+ return { texto: texto4, cuantos };
88591
+ }
88592
+ function compactarVoces(parte) {
88593
+ const porPentagrama = /* @__PURE__ */ new Map();
88594
+ const pentagramaDeVoz = /* @__PURE__ */ new Map();
88595
+ for (const m of parte.matchAll(/<note\b[\s\S]*?<\/note>/g)) {
88596
+ const voz = entero(m[0], /<voice>\s*(\d+)\s*<\/voice>/);
88597
+ if (voz === null) continue;
88598
+ const pent = entero(m[0], /<staff>\s*(\d+)\s*<\/staff>/) ?? 1;
88599
+ const lista2 = porPentagrama.get(pent) ?? [];
88600
+ if (!lista2.includes(voz)) lista2.push(voz);
88601
+ porPentagrama.set(pent, lista2);
88602
+ if (!pentagramaDeVoz.has(voz)) pentagramaDeVoz.set(voz, pent);
88603
+ }
88604
+ const nueva = /* @__PURE__ */ new Map();
88605
+ let hayCambio = false;
88606
+ for (const [pent, voces] of porPentagrama) {
88607
+ ;
88608
+ [...voces].sort((a, b) => a - b).forEach((voz, i2) => {
88609
+ nueva.set(`${pent}|${voz}`, i2 + 1);
88610
+ if (voz !== i2 + 1) hayCambio = true;
88611
+ });
88612
+ }
88613
+ if (!hayCambio) return { texto: parte, cambio: null };
88614
+ const renumerar = (bloque, pentPorOmision) => {
88615
+ const voz = entero(bloque, /<voice>\s*(\d+)\s*<\/voice>/);
88616
+ if (voz === null) return bloque;
88617
+ const pent = entero(bloque, /<staff>\s*(\d+)\s*<\/staff>/) ?? pentPorOmision(voz);
88618
+ const n = nueva.get(`${pent}|${voz}`);
88619
+ return n === void 0 ? bloque : bloque.replace(/<voice>\s*\d+\s*<\/voice>/, `<voice>${n}</voice>`);
88620
+ };
88621
+ const texto4 = parte.replace(/<note\b[\s\S]*?<\/note>/g, (b) => renumerar(b, () => 1)).replace(/<forward\b[\s\S]*?<\/forward>/g, (b) => renumerar(b, (v) => pentagramaDeVoz.get(v) ?? 1));
88622
+ const id2 = /<part\b[^>]*\bid="([^"]*)"/.exec(parte)?.[1] ?? "?";
88623
+ const detalle = [...porPentagrama].map(([p, vs]) => `pentagrama ${p}: voces ${[...vs].sort((a, b) => a - b).join(", ")}`).join("; ");
88624
+ return { texto: texto4, cambio: `Parte ${id2}: las voces se renumeraron por pentagrama (${detalle}).` };
88625
+ }
88626
+ function leerOrtografia(xml) {
88627
+ return leerDelArchivo(xml).ortografia;
88628
+ }
88629
+ function leerDelArchivo(xml) {
88630
+ const ortografia = /* @__PURE__ */ new Map();
88631
+ const bajos = /* @__PURE__ */ new Map();
88632
+ let iParte = -1;
88633
+ for (const parte of xml.matchAll(/<part\b[^>]*>([\s\S]*?)<\/part>/g)) {
88634
+ iParte++;
88635
+ let divisiones = 1;
88636
+ let transposicion = 0;
88637
+ let iCompas = -1;
88638
+ for (const compas of parte[1].matchAll(/<measure\b[^>]*>([\s\S]*?)<\/measure>/g)) {
88639
+ iCompas++;
88640
+ let tic = 0;
88641
+ let ticAnterior = 0;
88642
+ let bajoPendiente = null;
88643
+ for (const el of compas[1].matchAll(/<(note|backup|forward|attributes|harmony)\b[\s\S]*?<\/\1>/g)) {
88644
+ const bloque = el[0];
88645
+ const tipo = el[1];
88646
+ if (tipo === "attributes") {
88647
+ divisiones = entero(bloque, /<divisions>\s*(\d+)\s*<\/divisions>/) ?? divisiones;
88648
+ const transponer2 = /<transpose\b[^>]*>([\s\S]*?)<\/transpose>/.exec(bloque)?.[1];
88649
+ if (transponer2 !== void 0) {
88650
+ transposicion = (entero(transponer2, /<chromatic>\s*(-?\d+)\s*<\/chromatic>/) ?? 0) + 12 * (entero(transponer2, /<octave-change>\s*(-?\d+)\s*<\/octave-change>/) ?? 0);
88651
+ }
88652
+ continue;
88653
+ }
88654
+ if (tipo === "harmony") {
88655
+ const bajo = /<bass>([\s\S]*?)<\/bass>/.exec(bloque)?.[1];
88656
+ const paso2 = bajo ? /<bass-step>\s*([A-G])\s*<\/bass-step>/.exec(bajo)?.[1] : void 0;
88657
+ if (bajoPendiente === null) {
88658
+ const alter2 = bajo ? entero(bajo, /<bass-alter>\s*(-?\d+)\s*<\/bass-alter>/) ?? 0 : 0;
88659
+ bajoPendiente = paso2 ? `/${paso2}${alter2 === -2 ? "bb" : alter2 === -1 ? "b" : alter2 === 1 ? "#" : alter2 === 2 ? "x" : ""}` : "";
88660
+ }
88661
+ continue;
88662
+ }
88663
+ const dur = entero(bloque, /<duration>\s*(\d+)\s*<\/duration>/) ?? 0;
88664
+ if (tipo === "backup") {
88665
+ tic -= dur;
88666
+ continue;
88667
+ }
88668
+ if (tipo === "forward") {
88669
+ tic += dur;
88670
+ continue;
88671
+ }
88672
+ if (/<grace\b/.test(bloque) || /<cue\s*\/>/.test(bloque)) continue;
88673
+ const acorde = /<chord\s*\/>/.test(bloque);
88674
+ const inicio = acorde ? ticAnterior : tic;
88675
+ if (!acorde) {
88676
+ ticAnterior = tic;
88677
+ tic += dur;
88678
+ }
88679
+ const pent = (entero(bloque, /<staff>\s*(\d+)\s*<\/staff>/) ?? 1) - 1;
88680
+ const ticAlphaTab = Math.round(inicio * TICS_POR_NEGRA2 / divisiones);
88681
+ if (!acorde && bajoPendiente !== null) {
88682
+ if (bajoPendiente) bajos.set(`${iParte}|${pent}|${iCompas}|${ticAlphaTab}`, bajoPendiente);
88683
+ bajoPendiente = null;
88684
+ }
88685
+ const altura = /<pitch>([\s\S]*?)<\/pitch>/.exec(bloque)?.[1];
88686
+ if (!altura) continue;
88687
+ const paso = /<step>\s*([A-G])\s*<\/step>/.exec(altura)?.[1];
88688
+ const octava = entero(altura, /<octave>\s*(-?\d+)\s*<\/octave>/);
88689
+ const alterTexto = /<alter>\s*(-?[\d.]+)\s*<\/alter>/.exec(altura)?.[1];
88690
+ const alter = alterTexto === void 0 ? 0 : Number.parseFloat(alterTexto);
88691
+ if (!paso || octava === null || !Number.isInteger(alter)) continue;
88692
+ const modo = MODO_POR_ALTER.get(alter);
88693
+ if (modo === void 0) continue;
88694
+ const midi = (octava + 1) * 12 + SEMITONOS[paso] + alter + transposicion;
88695
+ const clave = `${iParte}|${pent}|${iCompas}|${ticAlphaTab}|${midi}`;
88696
+ if (!ortografia.has(clave)) ortografia.set(clave, modo);
88697
+ }
88698
+ }
88699
+ }
88700
+ return { ortografia, bajos };
88701
+ }
88702
+ var MODO_DE_ALTERACION, MODO_POR_ALTER, SEMITONOS, TICS_POR_NEGRA2, entero, HIJO_QUE_SE_MUEVE, ATRIBUTOS_DE_SALTO, NEGRAS_POR_FIGURA;
88703
+ var init_musicxmlEntrada = __esm({
88704
+ "packages/io/src/musicxmlEntrada.ts"() {
88705
+ init_esm();
88706
+ MODO_DE_ALTERACION = {
88707
+ porDefecto: 0,
88708
+ natural: 2,
88709
+ sostenido: 3,
88710
+ dobleSostenido: 4,
88711
+ bemol: 5,
88712
+ dobleBemol: 6
88713
+ };
88714
+ MODO_POR_ALTER = /* @__PURE__ */ new Map([
88715
+ [-2, MODO_DE_ALTERACION.dobleBemol],
88716
+ [-1, MODO_DE_ALTERACION.bemol],
88717
+ [0, MODO_DE_ALTERACION.natural],
88718
+ [1, MODO_DE_ALTERACION.sostenido],
88719
+ [2, MODO_DE_ALTERACION.dobleSostenido]
88720
+ ]);
88721
+ SEMITONOS = { C: 0, D: 2, E: 4, F: 5, G: 7, A: 9, B: 11 };
88722
+ TICS_POR_NEGRA2 = 960;
88723
+ entero = (texto4, re) => {
88724
+ const m = re.exec(texto4);
88725
+ return m ? Number.parseInt(m[1], 10) : null;
88726
+ };
88727
+ HIJO_QUE_SE_MUEVE = /<(clef|key|time|transpose|staff-details)\b[^>]*?(?:\/>|>[\s\S]*?<\/\1>)/g;
88728
+ ATRIBUTOS_DE_SALTO = ["coda", "tocoda", "dacapo", "dalsegno", "fine", "segno"];
88729
+ NEGRAS_POR_FIGURA = {
88730
+ breve: 8,
88731
+ whole: 4,
88732
+ half: 2,
88733
+ quarter: 1,
88734
+ eighth: 0.5,
88735
+ "16th": 0.25,
88736
+ "32nd": 0.125
88737
+ };
88738
+ }
88739
+ });
88740
+
88741
+ // packages/io/src/importarGp.ts
88742
+ function importarGp(bytes, opciones = {}) {
88743
+ const xml = textoMusicXml(bytes);
88744
+ if (xml === null) {
88745
+ const score2 = _barrel_exports$1.ScoreLoader.loadScoreFromBytes(bytes);
88746
+ return importarScore(score2, opciones);
88747
+ }
88748
+ const preparado = prepararMusicXml(xml);
88749
+ const score = _barrel_exports$1.ScoreLoader.loadScoreFromBytes(preparado.bytes);
88750
+ const leido = leerDelArchivo(preparado.xml);
88751
+ const resultado = importarScore(score, opciones, { ortografia: leido.ortografia, bajos: leido.bajos });
88752
+ resultado.avisos.push(...preparado.correcciones);
88753
+ return resultado;
88754
+ }
88755
+ function prepararParaAlphaTab(bytes) {
88756
+ const xml = textoMusicXml(bytes);
88757
+ return xml === null ? bytes : prepararMusicXml(xml).bytes;
88758
+ }
88759
+ function importarScore(score, opciones = {}, datos = {}) {
88760
+ const avisos = [];
88761
+ const documento = crearDocumento({ clienteId: opciones.clienteId });
88762
+ documento.ponerCabecera({
88763
+ titulo: score.title ?? "",
88764
+ artista: score.artist ?? "",
88765
+ album: score.album ?? "",
88766
+ tempo: score.tempo ?? 0,
88767
+ mostrarMatices: !score.stylesheet.hideDynamics
88768
+ });
88769
+ avisos.push(
88770
+ 'Las preferencias de dibujo del archivo (el "stylesheet" de Guitar Pro) no se importan, salvo si se muestran los matices. La m\xFAsica no cambia; el aspecto s\xED.'
88771
+ );
88772
+ if (opciones.autoria) {
88773
+ documento.ponerAutoria(opciones.autoria);
88774
+ } else {
88775
+ documento.ponerAutoria({
88776
+ escritaPor: "",
88777
+ origen: "transcripcion",
88778
+ obraTitulo: score.title ?? "",
88779
+ obraAutores: score.artist ?? "",
88780
+ obraEditora: ""
88781
+ });
88782
+ avisos.push(
88783
+ "La autor\xEDa qued\xF3 sin completar: se import\xF3 como transcripci\xF3n con los datos del archivo. Hay que confirmarla antes de publicar o compartir el documento."
88784
+ );
88785
+ }
88786
+ const idsDeCompasMaestro = score.masterBars.map(
88787
+ (maestro) => documento.agregarCompasMaestro(normalizarCompasMaestro({
88788
+ numerador: maestro.timeSignatureNumerator,
88789
+ denominador: maestro.timeSignatureDenominator,
88790
+ tonalidad: numeroDeTonalidad(maestro.keySignature),
88791
+ // ⚠️ El ensayo de un MusicXML (`<rehearsal>A</rehearsal>`) llena sólo `section.marker`;
88792
+ // `text` queda vacío y las letras A, B, C… se perdían todas. Un `.gp` trae las dos y
88793
+ // manda el texto, como siempre.
88794
+ seccion: maestro.section?.text || maestro.section?.marker || "",
88795
+ // Solo interesa el cambio de tempo que arranca en este compás; los que caen
88796
+ // en el medio son F02 y todavía no tienen dónde ir.
88797
+ tempo: maestro.tempoAutomations?.[0]?.value ?? null,
88798
+ repiteDesdeAca: maestro.isRepeatStart,
88799
+ repiteVeces: maestro.repeatCount,
88800
+ // ⚠️ Novena pérdida silenciosa de la misma familia: 2 de los 15 `.gp` de Daniel
88801
+ // declaran una anacruza y el modelo la descartaba.
88802
+ esAnacruza: maestro.isAnacrusis,
88803
+ // ── Los signos de compás de Guitar Pro ────────────────────────────────
88804
+ casillas: maestro.alternateEndings,
88805
+ dobleBarra: maestro.isDoubleBar,
88806
+ tiempoLibre: maestro.isFreeTime,
88807
+ swing: maestro.tripletFeel,
88808
+ // ⚠️ `simileMark` es del compás DE LA PISTA en alphaTab (`Bar.simileMark`), no del
88809
+ // maestro. Se lee más abajo, al recorrer los compases de cada pentagrama, y se
88810
+ // escribe acá arriba porque en el modelo la repetición de compás es de la obra:
88811
+ // un «igual que el anterior» que valiera para la guitarra y no para el bajo
88812
+ // dejaría los dos instrumentos diciendo cosas distintas sobre el mismo compás.
88813
+ repiteAnterior: 0,
88814
+ // ⚠️ `directions` es un `Set` o `null`, no una lista. Un `?? []` sobre un Set daría
88815
+ // el Set, y `.map` no existe ahí: hay que expandirlo.
88816
+ //
88817
+ // ⚠️⚠️ Y se guarda el NOMBRE, no el número. `String(d)` daba `"1"` —el valor del enum
88818
+ // convertido a texto— y la proyección buscaba `Direction["1"]`, que en un enum con
88819
+ // mapeo inverso devuelve el *nombre* y no un número: la guarda lo descartaba y **las
88820
+ // direcciones se perdían enteras, en silencio**. Lo cazó la prueba de ida y vuelta
88821
+ // con signos, que es exactamente para lo que existe.
88822
+ //
88823
+ // ★ El nombre y no el número, además, porque acá es una LISTA y se lee: un
88824
+ // `["JumpDalSegnoAlCoda"]` en el documento dice algo; un `[10]` no.
88825
+ direcciones: maestro.directions ? [...maestro.directions].map(
88826
+ (d) => _barrel_exports$4.Direction[d] ?? String(d)
88827
+ ) : []
88828
+ }))
88829
+ );
88830
+ const saltos = /* @__PURE__ */ new Set();
88831
+ for (const pista of score.tracks) for (const i2 of pista.lineBreaks ?? []) saltos.add(i2);
88832
+ for (const i2 of saltos) {
88833
+ const id2 = idsDeCompasMaestro[i2];
88834
+ if (id2 !== void 0 && i2 > 0) documento.ponerSaltoDeRenglon(id2, true);
88835
+ }
88836
+ const letrasDobles = { cuantas: 0 };
88837
+ const tipoDelPentagrama = (p) => p.isPercussion ? "percusion" : p.tuning.length === 0 ? "altura" : "trastes";
88838
+ for (const pista of score.tracks) {
88839
+ if (pista.staves.length === 0) {
88840
+ avisos.push(`La pista "${pista.name}" no tiene pentagramas y se salte\xF3 entera.`);
88841
+ continue;
88842
+ }
88843
+ const unInstrumento = pista.staves.every((p) => tipoDelPentagrama(p) === tipoDelPentagrama(pista.staves[0]));
88844
+ let idDelInstrumento = null;
88845
+ for (const [numeroDePentagrama, pentagrama] of pista.staves.entries()) {
88846
+ const variosPentagramas = pista.staves.length > 1 && !unInstrumento;
88847
+ const nombreDePista = variosPentagramas ? `${pista.name ?? ""} (${numeroDePentagrama + 1})` : pista.name ?? "";
88848
+ const nombreCortoDePista = variosPentagramas ? `${pista.shortName ?? ""} ${numeroDePentagrama + 1}`.trim() : pista.shortName ?? "";
88849
+ const pentagramaEnLaPista = unInstrumento ? numeroDePentagrama : 0;
88850
+ const tipo = tipoDelPentagrama(pentagrama);
88851
+ const idPista = unInstrumento && idDelInstrumento || documento.agregarPista({
88852
+ tipo,
88853
+ nombre: nombreDePista,
88854
+ nombreCorto: nombreCortoDePista,
88855
+ // ⚠️ Conversión 1: alphaTab la guarda de la aguda a la grave.
88856
+ afinacion: [...pentagrama.tuning].reverse(),
88857
+ capo: pentagrama.capo ?? 0,
88858
+ programaMidi: pista.playbackInfo?.program ?? 0,
88859
+ // ⚠️ SE ESTABAN PERDIENDO. El `.gp` los trae y el modelo no los guardaba, así que
88860
+ // importar una canción y volver a exportarla devolvía todas las pistas al volumen y
88861
+ // al centro por defecto. Séptima pérdida silenciosa de la misma familia — y ésta no
88862
+ // la destapó la comparación de píxeles, porque la mezcla no se dibuja: se oye.
88863
+ volumen: pista.playbackInfo?.volume ?? 16,
88864
+ balance: pista.playbackInfo?.balance ?? 8,
88865
+ ...unInstrumento && pista.staves.length > 1 ? { pentagramas: pista.staves.length } : {}
88866
+ });
88867
+ idDelInstrumento = idPista;
88868
+ for (const [indice, compasDeAlphaTab] of pentagrama.bars.entries()) {
88869
+ const maestroDelCompas = score.masterBars[indice];
88870
+ const idCompasMaestro = idsDeCompasMaestro[indice];
88871
+ if (idCompasMaestro === void 0) {
88872
+ avisos.push(
88873
+ `La pista "${pista.name}" tiene un comp\xE1s ${indice + 1} que no existe en la partitura (hay ${idsDeCompasMaestro.length} compases maestros). Se salte\xF3.`
88874
+ );
88875
+ continue;
88876
+ }
88877
+ const idCompas = documento.agregarCompas(normalizarCompas({
88878
+ pistaId: idPista,
88879
+ compasMaestroId: idCompasMaestro,
88880
+ // La clave es de la pista: el bajo lleva fa y la guitarra sol en el mismo compás.
88881
+ clave: compasDeAlphaTab.clef,
88882
+ claveOctava: compasDeAlphaTab.clefOttava,
88883
+ pentagrama: pentagramaEnLaPista
88884
+ }));
88885
+ if (compasDeAlphaTab.simileMark) {
88886
+ const maestro = documento.compasesMaestros.get(idCompasMaestro);
88887
+ if (maestro && !maestro.get("repiteAnterior")) {
88888
+ maestro.set("repiteAnterior", compasDeAlphaTab.simileMark);
88889
+ }
88890
+ }
88891
+ const ticsDelCompas = 960 * 4 * (maestroDelCompas?.timeSignatureNumerator ?? 4) / (maestroDelCompas?.timeSignatureDenominator ?? 4);
88892
+ const pedalesDelCompas = /* @__PURE__ */ new Map();
88893
+ for (const marcador of compasDeAlphaTab.sustainPedals ?? []) {
88894
+ pedalesDelCompas.set(Math.round(marcador.ratioPosition * ticsDelCompas), marcador.pedalType + 1);
88895
+ }
88896
+ for (const voz of compasDeAlphaTab.voices) {
88897
+ if (voz.isEmpty) continue;
88898
+ for (const golpe of voz.beats) {
88899
+ if (golpe.isEmpty) continue;
88900
+ const idFigura = documento.agregarFigura(
88901
+ normalizarFigura({
88902
+ compasId: idCompas,
88903
+ voz: voz.index,
88904
+ // Tics MIDI desde el comienzo del compás. alphaTab y el modelo usan la
88905
+ // misma unidad (960 por negra), así que no hay conversión.
88906
+ tiempo: golpe.displayStart,
88907
+ // El valor del enum `Duration` de alphaTab ES el número que usa el
88908
+ // modelo: 4 = negra, 8 = corchea. No es casualidad — es la decisión de
88909
+ // copiar la forma de lo que ya funciona.
88910
+ valor: golpe.duration,
88911
+ puntillos: golpe.dots ?? 0,
88912
+ esSilencio: golpe.isRest,
88913
+ // ⚠️ Conversión 3: -1 significa "sin grupo irregular".
88914
+ tupletNumerador: normalizarTuplet(golpe.tupletNumerator),
88915
+ tupletDenominador: normalizarTuplet(golpe.tupletDenominator),
88916
+ // ★ Acá viene la letra. En la canción de Daniel cada sílaba está escrita
88917
+ // como texto del golpe, que es como se hace en la práctica en Guitar Pro.
88918
+ // Sin este campo, importar y exportar la borraba sin decir nada.
88919
+ texto: textoDelGolpe(golpe, letrasDobles),
88920
+ // ═══════════════════════════════════════════════════════════════════
88921
+ // ⛔⛔ LOS CIFRADOS DE ACORDE SE PERDÍAN TODOS (2026-11-09)
88922
+ // ═══════════════════════════════════════════════════════════════════
88923
+ // alphaTab los deja en `beat.chordId` → `staff.chords` (de un `.gp` y de un
88924
+ // `<harmony>` de MusicXML) y este traductor no los leía: «Am», «G7», todo afuera,
88925
+ // sin aviso. El bajo («C/E») lo lee `leerDelArchivo`, porque alphaTab lo tira.
88926
+ acorde: acordeDelGolpe(golpe, pentagrama, datos.bajos, pista.index, numeroDePentagrama, indice),
88927
+ dinamica: golpe.dynamics,
88928
+ // ═══════════════════════════════════════════════════════════════════
88929
+ // ★★★ LOS SIGNOS DE GUITAR PRO — hasta hoy se perdían TODOS en silencio
88930
+ // ═══════════════════════════════════════════════════════════════════
88931
+ //
88932
+ // Es la misma familia de pérdidas que ya destapó dos veces la comparación de
88933
+ // píxeles (el martillo, la dinámica) y una vez el inventario del manual: **el
88934
+ // modelo no tenía dónde ponerlos, así que un `.gp` con un rasgueado, un slap o
88935
+ // unas casillas de repetición entraba sin ellos y nadie lo decía**.
88936
+ //
88937
+ // ⚠️ Ninguno se convierte. Los números del modelo SON los de alphaTab, que es
88938
+ // la decisión que este archivo ya había tomado para el armónico y el
88939
+ // deslizamiento: una tabla de traducción es donde se pierde el valor que
88940
+ // todavía no se conoce.
88941
+ calderon: golpe.fermata ? golpe.fermata.type + 1 : 0,
88942
+ puaDireccion: golpe.pickStroke,
88943
+ rasgueo: golpe.brushType,
88944
+ duracionDelRasgueo: golpe.brushDuration,
88945
+ slap: golpe.slap,
88946
+ pop: golpe.pop,
88947
+ tapping: golpe.tap,
88948
+ slapMuerto: golpe.deadSlapped,
88949
+ barraOblicua: golpe.slashed,
88950
+ // ⚠️ `tremoloPicking` es OPCIONAL en alphaTab (`?:`), no un enum con cero: sin
88951
+ // el `?.` esto reventaría en el 99 % de los golpes. Y lo que guarda son
88952
+ // `marks` —las barritas que cruzan la plica—, no una duración.
88953
+ tremolo: golpe.tremoloPicking?.marks ?? 0,
88954
+ adorno: golpe.graceType,
88955
+ regulador: golpe.crescendo,
88956
+ fundido: golpe.fade ?? 0,
88957
+ wah: golpe.wahPedal,
88958
+ golpeEnLaTapa: golpe.golpe,
88959
+ rasgueado: golpe.rasgueado,
88960
+ cejilla: golpe.barreFret,
88961
+ formaDeCejilla: golpe.barreShape,
88962
+ plicaInvertida: golpe.invertBeamDirection,
88963
+ barrado: golpe.beamingMode,
88964
+ palanca: (golpe.whammyBarPoints ?? []).map((p) => ({
88965
+ desplazamiento: p.offset,
88966
+ valor: p.value
88967
+ })),
88968
+ // ★ El pedal que cae en este golpe, si hay alguno. Se busca por tic exacto: el
88969
+ // marcador de Guitar Pro se pone sobre un golpe, no entre dos.
88970
+ pedal: pedalesDelCompas.get(golpe.displayStart) ?? 0
88971
+ })
88972
+ );
88973
+ for (const nota of golpe.notes) {
88974
+ documento.agregarNota(
88975
+ normalizarNota({
88976
+ figuraId: idFigura,
88977
+ // ⚠️ Conversión 2: no hay conversión. Ver el encabezado.
88978
+ cuerda: nota.string,
88979
+ traste: nota.fret,
88980
+ // ═══════════════════════════════════════════════════════════════
88981
+ // ⛔⛔ LA ALTURA Y LA PIEZA DEL KIT NO SE COPIABAN (2026-11-09)
88982
+ // ═══════════════════════════════════════════════════════════════
88983
+ //
88984
+ // Desde la etapa 2 el TIPO de la pista se deducía bien, pero la nota sólo
88985
+ // copiaba cuerda y traste: en una pista de piano o de batería cada nota entraba
88986
+ // con `altura`/`articulacion` en null — todas iguales, dibujadas en el mismo
88987
+ // lugar, sin error. Lo destapó un arreglo de piano importado de MusicXML. La
88988
+ // prueba de exportar a GP7 no lo veía porque miraba el archivo y NUNCA lo volvía
88989
+ // a importar: el viaje de ida y vuelta se cortaba a la mitad.
88990
+ //
88991
+ // ★ Se lee con la MISMA convención con la que `proyectar` la escribe
88992
+ // (`octave * 12 + tone`, sin transposición ni armónico), y la percusión por
88993
+ // `percussionArticulation`, que es lo que `proyectar` le pone. Así la ida y la
88994
+ // vuelta son simétricas: lo que se exporta se vuelve a importar idéntico.
88995
+ altura: tipo === "altura" ? nota.calculateRealValue(false, false) : null,
88996
+ articulacion: tipo === "percusion" ? nota.percussionArticulation : null,
88997
+ ligadaAAnterior: nota.isTieDestination,
88998
+ muerta: nota.isDead,
88999
+ fantasma: nota.isGhost,
89000
+ // ⚠️ El MusicXML marca palm mute y let ring escritos como texto con guiones
89001
+ // («P.M. - - -») en el GOLPE (`beat.isPalmMute`), no en la nota: leer sólo la
89002
+ // nota los perdía (alphaTab issue #2867).
89003
+ palmMute: nota.isPalmMute || golpe.isPalmMute,
89004
+ letRing: nota.isLetRing || golpe.isLetRing,
89005
+ // `vibrato` es un enum donde 0 es "sin vibrato"; el modelo solo
89006
+ // necesita saber si hay o no. El tipo de vibrato es del bloque 5.
89007
+ vibrato: nota.vibrato !== 0,
89008
+ martillo: nota.isHammerPullOrigin,
89009
+ staccato: nota.isStaccato,
89010
+ deslizamientoEntrada: nota.slideInType,
89011
+ deslizamientoSalida: nota.slideOutType,
89012
+ armonico: nota.harmonicType,
89013
+ // ── Los signos de Guitar Pro, a nivel de nota ──────────────────
89014
+ acento: nota.accentuated,
89015
+ ligaduraDeExpresion: nota.isSlurDestination || nota.slurDestination !== null,
89016
+ vibratoDePalanca: 0,
89017
+ // ★ La anchura del vibrato: el campo viejo `vibrato` solo decía si había.
89018
+ anchoDeVibrato: nota.vibrato,
89019
+ tappingIzquierda: nota.isLeftHandTapped,
89020
+ muestraCuerda: nota.showStringNumber,
89021
+ dedoIzquierda: nota.leftHandFinger,
89022
+ dedoDerecha: nota.rightHandFinger,
89023
+ // ⚠️ alphaTab usa −1 para «sin trino», igual que el modelo. No hay conversión,
89024
+ // pero sí hay que respetarlo: un 0 sería el traste 0, o sea la cuerda al aire.
89025
+ trino: nota.trillValue,
89026
+ velocidadDeTrino: nota.trillSpeed,
89027
+ // ★ La ortografía ESCRITA en el MusicXML (su `<step>/<alter>`), que alphaTab 1.8.4
89028
+ // descarta. Sin ella, un si♭ sin signo impreso (el segundo del compás, o uno
89029
+ // ligado desde el anterior) vuelve como la♯. Ver `musicxmlEntrada.ts`.
89030
+ alteracion: ortografiaDe(datos.ortografia, pista.index, numeroDePentagrama, indice, golpe.displayStart, nota) ?? nota.accidentalMode,
89031
+ // ⚠️ EL BEND SE PERDÍA ENTERO hasta el PR 7: el modelo no tenía dónde
89032
+ // ponerlo, así que un archivo con bends entraba sin ellos y no lo decía
89033
+ // nadie. Es la sexta pérdida silenciosa de la misma familia que destapó la
89034
+ // comparación de píxeles en el PR 3 — con la diferencia de que ésta no la
89035
+ // destapó, porque *El Pibe de mi Barrio* no tiene un solo bend (medido:
89036
+ // cero propiedades `Bend` en su `score.gpif`). ★ Un fixture que no ejercita
89037
+ // una funcionalidad no prueba que esté bien: prueba que no se usó.
89038
+ //
89039
+ // `hasBend` de alphaTab exige las dos cosas —que haya puntos y que el tipo
89040
+ // no sea None—, así que preguntarlo es más honesto que mirar solo la lista.
89041
+ bend: nota.hasBend ? (nota.bendPoints ?? []).map((p) => ({ desplazamiento: p.offset, valor: p.value })) : []
89042
+ })
89043
+ );
89044
+ }
89045
+ }
89046
+ }
89047
+ }
89048
+ }
89049
+ }
89050
+ if (letrasDobles.cuantas > 0) {
89051
+ avisos.push(
89052
+ `${letrasDobles.cuantas} golpe(s) tra\xEDan letra Y un texto libre: se guard\xF3 la letra. Tabs lleva un solo texto por golpe.`
89053
+ );
89054
+ }
89055
+ const audioEmbebido = importarAudioYSync(score, documento, idsDeCompasMaestro, avisos);
89056
+ return { documento, avisos, ...audioEmbebido ? { audioEmbebido } : {} };
89057
+ }
89058
+ function importarAudioYSync(score, documento, idsDeCompasMaestro, avisos) {
89059
+ const puntos = score.exportFlatSyncPoints();
89060
+ const bytes = score.backingTrack?.rawAudioFile;
89061
+ if (puntos.length === 0 && !bytes) return void 0;
89062
+ const fuenteId = documento.agregarFuenteDeAudio({
89063
+ nombre: score.title ? `${score.title} (del archivo)` : "Grabaci\xF3n del archivo",
89064
+ // ⚠️ En cero las dos, y se llenan cuando el navegador decodifique. El importador
89065
+ // corre también en la terminal, donde no hay `AudioContext` con el que averiguarlo.
89066
+ duracion: 0,
89067
+ picos: [],
89068
+ volumen: 16,
89069
+ balance: 8
89070
+ });
89071
+ let huerfanos = 0;
89072
+ for (const punto of puntos) {
89073
+ const compasMaestroId = idsDeCompasMaestro[punto.barIndex];
89074
+ if (compasMaestroId === void 0) {
89075
+ huerfanos++;
89076
+ continue;
89077
+ }
89078
+ documento.agregarPuntoDeSync({
89079
+ fuenteId,
89080
+ compasMaestroId,
89081
+ posicionEnElCompas: punto.barPosition,
89082
+ ocurrencia: punto.barOccurence,
89083
+ msDelAudio: punto.millisecondOffset
89084
+ });
89085
+ }
89086
+ if (huerfanos > 0) {
89087
+ avisos.push(
89088
+ `${huerfanos} punto(s) de sincronizaci\xF3n del archivo apuntan a compases que no existen (la partitura tiene ${idsDeCompasMaestro.length}) y no se importaron.`
89089
+ );
89090
+ }
89091
+ if (!bytes) {
89092
+ avisos.push(
89093
+ `El archivo trae ${puntos.length} punto(s) de sincronizaci\xF3n pero no la grabaci\xF3n. La tablatura queda alineada; para o\xEDrla hay que cargar el audio a mano.`
89094
+ );
89095
+ return void 0;
89096
+ }
89097
+ return { fuenteId, bytes };
89098
+ }
89099
+ function numeroDeTonalidad(armadura) {
89100
+ return armadura;
89101
+ }
89102
+ function textoDelGolpe(golpe, letrasDobles) {
89103
+ const letra = (golpe.lyrics ?? []).find((l) => l && l.trim()) ?? "";
89104
+ const libre = golpe.text ?? "";
89105
+ if (letra && libre && letra !== libre) letrasDobles.cuantas++;
89106
+ return letra || libre;
89107
+ }
89108
+ function acordeDelGolpe(golpe, pentagrama, bajos, parte, numeroDePentagrama, compas) {
89109
+ if (!golpe.chordId) return void 0;
89110
+ const nombre = pentagrama.chords?.get(golpe.chordId)?.name?.trim();
89111
+ if (!nombre) return void 0;
89112
+ const bajo = bajos?.get(`${parte}|${numeroDePentagrama}|${compas}|${golpe.displayStart}`) ?? "";
89113
+ return bajo && !nombre.endsWith(bajo) ? nombre + bajo : nombre;
89114
+ }
89115
+ function normalizarTuplet(valor) {
89116
+ return valor === void 0 || valor <= 0 ? 1 : valor;
89117
+ }
89118
+ function ortografiaDe(ortografia, parte, pentagrama, compas, tic, nota) {
89119
+ if (!ortografia) return void 0;
89120
+ const base = `${parte}|${pentagrama}|${compas}|${tic}|`;
89121
+ return ortografia.get(base + nota.calculateRealValue(false, false)) ?? ortografia.get(base + (nota.octave * 12 + nota.tone));
89122
+ }
89123
+ var init_importarGp = __esm({
89124
+ "packages/io/src/importarGp.ts"() {
89125
+ init_alphaTab();
89126
+ init_src2();
89127
+ init_musicxmlEntrada();
89128
+ }
89129
+ });
89130
+
88607
89131
  // packages/io/src/archivoMtabs.ts
89132
+ function formatoQueNecesita(documento) {
89133
+ for (const pista of documento.pistas.values()) {
89134
+ const pentagramas = pista.get("pentagramas");
89135
+ if (typeof pentagramas === "number" && pentagramas > 1) return 5;
89136
+ }
89137
+ return 4;
89138
+ }
88608
89139
  function empaquetar(documento, opciones = {}) {
88609
89140
  const grabaciones = opciones.grabaciones ?? [];
88610
89141
  const fuentes = opciones.fuentes ?? [];
88611
89142
  const manifiesto = {
88612
- formato: VERSION_DEL_FORMATO,
89143
+ formato: formatoQueNecesita(documento),
88613
89144
  aplicacion: opciones.aplicacion ?? "Mandioca Tabs",
88614
89145
  guardado: opciones.guardado ?? "",
88615
89146
  titulo: documento.cabecera.get("titulo") ?? "",
@@ -88681,7 +89212,7 @@ var init_archivoMtabs = __esm({
88681
89212
  "packages/io/src/archivoMtabs.ts"() {
88682
89213
  init_esm();
88683
89214
  init_src2();
88684
- VERSION_DEL_FORMATO = 4;
89215
+ VERSION_DEL_FORMATO = 5;
88685
89216
  MANIFIESTO = "mandioca.json";
88686
89217
  DOCUMENTO = "documento.ydoc";
88687
89218
  CARPETA_DE_AUDIO = "audio/";
@@ -88703,10 +89234,17 @@ function elemento(nombre, texto4) {
88703
89234
  if (texto4 === null || texto4 === void 0 || texto4 === "") return [];
88704
89235
  return [`<${nombre}>${escapar(String(texto4))}</${nombre}>`];
88705
89236
  }
88706
- function alturaMusicXml(midi, fifths) {
89237
+ function alturaMusicXml(midi, fifths, modo = 0) {
88707
89238
  const octavaAlphaTab = Math.floor(midi / 12);
88708
89239
  const clase = midi - octavaAlphaTab * 12;
88709
89240
  const octava = octavaAlphaTab - 1;
89241
+ const pedida = ALTERACION_POR_MODO[modo];
89242
+ if (pedida !== void 0) {
89243
+ const sinAlterar = clase - pedida;
89244
+ const vueltas = Math.floor(sinAlterar / 12);
89245
+ const paso = PASOS.find((p) => p.semitonos === sinAlterar - vueltas * 12);
89246
+ if (paso) return { paso: paso.paso, alteracion: pedida, octava: octava + vueltas };
89247
+ }
88710
89248
  const natural = PASOS.find((p) => p.semitonos === clase);
88711
89249
  if (natural) return { paso: natural.paso, alteracion: 0, octava };
88712
89250
  if (fifths < 0) {
@@ -88789,7 +89327,8 @@ function escribirNota(note, beat, staff, opciones) {
88789
89327
  } else {
88790
89328
  const { paso, alteracion, octava } = alturaMusicXml(
88791
89329
  note.calculateRealValue(false, false),
88792
- opciones.fifths
89330
+ opciones.fifths,
89331
+ note.accidentalMode
88793
89332
  );
88794
89333
  s.push("<pitch>");
88795
89334
  s.push(`<step>${paso}</step>`);
@@ -89112,7 +89651,7 @@ function exportarMusicXmlComprimido(score) {
89112
89651
  { mtime: FECHA_FIJA_DEL_ZIP }
89113
89652
  );
89114
89653
  }
89115
- var DIVISIONES_POR_NEGRA, FECHA_FIJA_DEL_ZIP, PASOS, NOMBRE_DE_LA_FIGURA2;
89654
+ var DIVISIONES_POR_NEGRA, FECHA_FIJA_DEL_ZIP, PASOS, NOMBRE_DE_LA_FIGURA2, ALTERACION_POR_MODO;
89116
89655
  var init_musicxml = __esm({
89117
89656
  "packages/io/src/musicxml.ts"() {
89118
89657
  init_alphaTab();
@@ -89141,6 +89680,7 @@ var init_musicxml = __esm({
89141
89680
  [128, "128th"],
89142
89681
  [256, "256th"]
89143
89682
  ]);
89683
+ ALTERACION_POR_MODO = { 2: 0, 3: 1, 4: 2, 5: -1, 6: -2 };
89144
89684
  }
89145
89685
  });
89146
89686
 
@@ -89235,12 +89775,18 @@ __export(src_exports, {
89235
89775
  exportarMusicXml: () => exportarMusicXml,
89236
89776
  exportarMusicXmlComprimido: () => exportarMusicXmlComprimido,
89237
89777
  formatoDeExportacion: () => formatoDeExportacion,
89778
+ formatoQueNecesita: () => formatoQueNecesita,
89238
89779
  importarGp: () => importarGp,
89239
- importarScore: () => importarScore
89780
+ importarScore: () => importarScore,
89781
+ leerOrtografia: () => leerOrtografia,
89782
+ prepararMusicXml: () => prepararMusicXml,
89783
+ prepararParaAlphaTab: () => prepararParaAlphaTab,
89784
+ textoMusicXml: () => textoMusicXml
89240
89785
  });
89241
89786
  var init_src4 = __esm({
89242
89787
  "packages/io/src/index.ts"() {
89243
89788
  init_importarGp();
89789
+ init_musicxmlEntrada();
89244
89790
  init_archivoMtabs();
89245
89791
  init_exportar();
89246
89792
  init_musicxml();
@@ -89285,7 +89831,7 @@ function obraAbierta() {
89285
89831
  //
89286
89832
  // ★ Ahora la pestaña va PRIMERA, que es el caso más común: si alguien está usando el
89287
89833
  // MCP es casi siempre porque tiene el programa delante.
89288
- "No hay ninguna obra abierta. **Mira primero si el m\xFAsico ya tiene el programa abierto**: `conectar_con_la_app` se engancha a lo que \xE9l est\xE1 viendo, y es lo que casi siempre se quiere. Si no lo tiene, `abrir_obra` con la ruta de un archivo .mtabs o .gp, o `obra_en_blanco` para empezar una nueva."
89834
+ "No hay ninguna obra abierta. **Mira primero si el m\xFAsico ya tiene el programa abierto**: `conectar_con_la_app` se engancha a lo que \xE9l est\xE1 viendo, y es lo que casi siempre se quiere. Si no lo tiene, `abrir_obra` con la ruta de un archivo .mtabs, .gp o MusicXML, o `obra_en_blanco` para empezar una nueva."
89289
89835
  );
89290
89836
  }
89291
89837
  return abierta;
@@ -89313,14 +89859,14 @@ async function abrirDeArchivo(ruta) {
89313
89859
  };
89314
89860
  return alAbrirLaObra(abierta);
89315
89861
  }
89316
- if (extension2 === ".gp") {
89862
+ if (EXTENSIONES_IMPORTABLES.has(extension2)) {
89317
89863
  const { importarGp: importarGp2 } = await Promise.resolve().then(() => (init_src4(), src_exports));
89318
89864
  const resultado = importarGp2(bytes);
89319
89865
  abierta = {
89320
89866
  documento: resultado.documento,
89321
89867
  origen: { clase: "archivo", ruta },
89322
89868
  avisos: resultado.avisos,
89323
- // ⚠️ Un `.gp` no trae audio ni tipografías: no hay nada que devolver. Guardar esta obra
89869
+ // ⚠️ Un `.gp` o un MusicXML no trae audio ni tipografías: no hay nada que devolver. Guardar esta obra
89324
89870
  // como `.mtabs` escribe un archivo sin audio porque nunca lo tuvo, no por perderlo.
89325
89871
  grabaciones: [],
89326
89872
  grabacionesEnEspera: [],
@@ -89329,7 +89875,7 @@ async function abrirDeArchivo(ruta) {
89329
89875
  return alAbrirLaObra(abierta);
89330
89876
  }
89331
89877
  throw new ProblemaConLaObra(
89332
- `No s\xE9 abrir \xAB${basename(ruta)}\xBB: la extensi\xF3n \xAB${extension2 || "(ninguna)"}\xBB no est\xE1 soportada. Se puede abrir .mtabs (el formato de Mandioca Tabs) y .gp (Guitar Pro).`
89878
+ `No s\xE9 abrir \xAB${basename(ruta)}\xBB: la extensi\xF3n \xAB${extension2 || "(ninguna)"}\xBB no est\xE1 soportada. Se puede abrir .mtabs (el formato de Mandioca Tabs), Guitar Pro (.gp, .gpx, .gp5, .gp4, .gp3) y MusicXML (.musicxml, .xml, .mxl).`
89333
89879
  );
89334
89880
  }
89335
89881
  function abrirEnBlanco(opciones = {}) {
@@ -89452,7 +89998,7 @@ function reciboDeLaPesta\u00F1a(respuesta, ruta) {
89452
89998
  ...avisoDeLoQueNoSuena(mudas, 0)
89453
89999
  };
89454
90000
  }
89455
- var ProblemaConLaObra, abierta, sigueViva;
90001
+ var ProblemaConLaObra, abierta, sigueViva, EXTENSIONES_IMPORTABLES;
89456
90002
  var init_obra = __esm({
89457
90003
  "apps/mcp/src/obra.ts"() {
89458
90004
  "use strict";
@@ -89462,6 +90008,7 @@ var init_obra = __esm({
89462
90008
  };
89463
90009
  abierta = null;
89464
90010
  sigueViva = null;
90011
+ EXTENSIONES_IMPORTABLES = /* @__PURE__ */ new Set([".gp", ".gpx", ".gp5", ".gp4", ".gp3", ".musicxml", ".xml", ".mxl"]);
89465
90012
  }
89466
90013
  });
89467
90014
 
@@ -89470,7 +90017,7 @@ var VERSION_DEL_CONECTOR;
89470
90017
  var init_version = __esm({
89471
90018
  "apps/mcp/src/version.ts"() {
89472
90019
  "use strict";
89473
- VERSION_DEL_CONECTOR = true ? "0.2.8" : null;
90020
+ VERSION_DEL_CONECTOR = true ? "0.2.11" : null;
89474
90021
  }
89475
90022
  });
89476
90023
 
@@ -97473,10 +98020,11 @@ function proyectar(documento, opciones = {}) {
97473
98020
  for (const [id2, entidad] of documento.compases.entries()) {
97474
98021
  const compas = normalizarCompas(entidad.toJSON());
97475
98022
  datosDeCompas.set(id2, compas);
97476
- let porMaestro = compasesPorPista.get(compas.pistaId);
98023
+ const claveDePentagrama = `${compas.pistaId}|${compas.pentagrama ?? 0}`;
98024
+ let porMaestro = compasesPorPista.get(claveDePentagrama);
97477
98025
  if (!porMaestro) {
97478
98026
  porMaestro = /* @__PURE__ */ new Map();
97479
- compasesPorPista.set(compas.pistaId, porMaestro);
98027
+ compasesPorPista.set(claveDePentagrama, porMaestro);
97480
98028
  }
97481
98029
  porMaestro.set(compas.compasMaestroId, id2);
97482
98030
  }
@@ -97508,216 +98056,226 @@ function proyectar(documento, opciones = {}) {
97508
98056
  track.playbackInfo.volume = dibujar ? 16 : Math.max(0, Math.min(16, pista.volumen));
97509
98057
  if (dibujar) volumenDeMezcla.set(track, Math.max(0, pista.volumen));
97510
98058
  track.playbackInfo.balance = pista.balance;
97511
- const pentagrama = new _barrel_exports$4.Staff();
97512
- const valores = [...pista.afinacion].reverse();
97513
- pentagrama.stringTuning = _barrel_exports$4.Tuning.findTuning(valores) ?? new _barrel_exports$4.Tuning("", valores, false);
97514
- pentagrama.capo = pista.capo;
97515
- pentagrama.showTablature = pista.tipo === "trastes";
97516
- pentagrama.showStandardNotation = true;
97517
- pentagrama.isPercussion = pista.tipo === "percusion";
97518
- if (pista.tipo === "percusion") {
97519
- track.playbackInfo.primaryChannel = 9;
97520
- track.playbackInfo.secondaryChannel = 9;
97521
- track.percussionArticulations = KIT.map((pieza) => {
97522
- const art = new _barrel_exports$4.InstrumentArticulation();
97523
- art.outputMidiNumber = pieza.midi;
97524
- art.staffLine = pieza.linea;
97525
- art.noteHeadDefault = pieza.cabeza === "x" ? _barrel_exports$4.MusicFontSymbol.NoteheadXBlack : _barrel_exports$4.MusicFontSymbol.NoteheadBlack;
97526
- art.noteHeadHalf = art.noteHeadDefault;
97527
- art.noteHeadWhole = art.noteHeadDefault;
97528
- return art;
97529
- });
97530
- }
97531
- track.addStaff(pentagrama);
97532
98059
  score.addTrack(track);
97533
- const porMaestro = compasesPorPista.get(idPista) ?? /* @__PURE__ */ new Map();
97534
- let cantidadDeVoces = VOCES_POR_COMPAS;
97535
- for (const idCompas of porMaestro.values()) {
97536
- for (const { datos: datos2 } of figurasPorCompas.get(idCompas) ?? []) {
97537
- cantidadDeVoces = Math.max(cantidadDeVoces, datos2.voz + 1);
98060
+ const cantidadDePentagramas = Math.max(1, pista.pentagramas ?? 1);
98061
+ for (let numeroDePentagrama = 0; numeroDePentagrama < cantidadDePentagramas; numeroDePentagrama++) {
98062
+ const pentagrama = new _barrel_exports$4.Staff();
98063
+ const valores = [...pista.afinacion].reverse();
98064
+ pentagrama.stringTuning = _barrel_exports$4.Tuning.findTuning(valores) ?? new _barrel_exports$4.Tuning("", valores, false);
98065
+ pentagrama.capo = pista.capo;
98066
+ pentagrama.showTablature = pista.tipo === "trastes";
98067
+ pentagrama.showStandardNotation = true;
98068
+ pentagrama.isPercussion = pista.tipo === "percusion";
98069
+ if (pista.tipo === "percusion") {
98070
+ track.playbackInfo.primaryChannel = 9;
98071
+ track.playbackInfo.secondaryChannel = 9;
98072
+ track.percussionArticulations = KIT.map((pieza) => {
98073
+ const art = new _barrel_exports$4.InstrumentArticulation();
98074
+ art.outputMidiNumber = pieza.midi;
98075
+ art.staffLine = pieza.linea;
98076
+ art.noteHeadDefault = pieza.cabeza === "x" ? _barrel_exports$4.MusicFontSymbol.NoteheadXBlack : _barrel_exports$4.MusicFontSymbol.NoteheadBlack;
98077
+ art.noteHeadHalf = art.noteHeadDefault;
98078
+ art.noteHeadWhole = art.noteHeadDefault;
98079
+ return art;
98080
+ });
97538
98081
  }
97539
- }
97540
- const acordesEscritos = [];
97541
- maestros.forEach((m, indiceDeCompas2) => {
97542
- const id2 = porMaestro.get(m.id);
97543
- for (const { datos: f } of id2 ? figurasPorCompas.get(id2) ?? [] : []) {
97544
- if (f.acorde) {
97545
- acordesEscritos.push({ compas: indiceDeCompas2, tiempo: f.tiempo, nombre: f.acorde });
98082
+ track.addStaff(pentagrama);
98083
+ const porMaestro = compasesPorPista.get(`${idPista}|${numeroDePentagrama}`) ?? /* @__PURE__ */ new Map();
98084
+ let cantidadDeVoces = VOCES_POR_COMPAS;
98085
+ for (const idCompas of porMaestro.values()) {
98086
+ for (const { datos: datos2 } of figurasPorCompas.get(idCompas) ?? []) {
98087
+ cantidadDeVoces = Math.max(cantidadDeVoces, datos2.voz + 1);
97546
98088
  }
97547
98089
  }
97548
- });
97549
- const acordeVigente = buscadorDeAcorde(acordesEscritos);
97550
- maestros.forEach((maestro, indiceDeCompas2) => {
97551
- const barra = new _barrel_exports$4.Bar();
97552
- pentagrama.addBar(barra);
97553
- barra.keySignature = maestro.datos.tonalidad;
97554
- barra.simileMark = maestro.datos.repiteAnterior;
97555
- const idCompas = porMaestro.get(maestro.id);
97556
- const figuras = idCompas ? figurasPorCompas.get(idCompas) ?? [] : [];
97557
- const datosDelCompas = idCompas ? datosDeCompas.get(idCompas) : void 0;
97558
- if (datosDelCompas) {
97559
- barra.clef = datosDelCompas.clave;
97560
- barra.clefOttava = datosDelCompas.claveOctava;
97561
- }
97562
- const ticsDelCompas = 960 * 4 * maestro.datos.numerador / maestro.datos.denominador;
97563
- for (const { datos: figura } of figuras) {
97564
- if (!figura.pedal) continue;
97565
- const marcador = new _barrel_exports$4.SustainPedalMarker();
97566
- marcador.ratioPosition = ticsDelCompas > 0 ? figura.tiempo / ticsDelCompas : 0;
97567
- marcador.pedalType = figura.pedal - 1;
97568
- barra.sustainPedals.push(marcador);
97569
- }
97570
- for (let indiceDeVoz = 0; indiceDeVoz < cantidadDeVoces; indiceDeVoz++) {
97571
- const voz = new _barrel_exports$4.Voice();
97572
- barra.addVoice(voz);
97573
- const deEstaVoz = figuras.filter((f) => f.datos.voz === indiceDeVoz).sort((a, b) => a.datos.tiempo - b.datos.tiempo);
97574
- for (const { id: idFigura, datos: figura } of deEstaVoz) {
97575
- const golpe = new _barrel_exports$4.Beat();
97576
- golpe.duration = figura.valor;
97577
- golpe.dots = figura.puntillos;
97578
- if (figura.tupletNumerador > 1) {
97579
- golpe.tupletNumerator = figura.tupletNumerador;
97580
- golpe.tupletDenominator = figura.tupletDenominador;
97581
- }
97582
- if (figura.texto) golpe.lyrics = [marcado(figura.texto, figura.textoSegundaTipografia)];
97583
- if (figura.acorde) {
97584
- const nombre = marcado(figura.acorde, figura.acordeSegundaTipografia);
97585
- if (!pentagrama.chords?.has(nombre)) {
97586
- const acorde = new _barrel_exports$4.Chord();
97587
- acorde.name = nombre;
97588
- acorde.showName = true;
97589
- acorde.showDiagram = false;
97590
- acorde.staff = pentagrama;
97591
- pentagrama.addChord(nombre, acorde);
97592
- }
97593
- golpe.chordId = nombre;
97594
- }
97595
- golpe.dynamics = figura.dinamica;
97596
- golpe.pickStroke = figura.puaDireccion;
97597
- golpe.brushType = figura.rasgueo;
97598
- golpe.brushDuration = figura.duracionDelRasgueo;
97599
- golpe.slap = figura.slap;
97600
- golpe.pop = figura.pop;
97601
- golpe.tap = figura.tapping;
97602
- golpe.deadSlapped = figura.slapMuerto;
97603
- golpe.slashed = figura.barraOblicua;
97604
- golpe.graceType = figura.adorno;
97605
- golpe.crescendo = figura.regulador;
97606
- golpe.fade = figura.fundido;
97607
- golpe.wahPedal = figura.wah;
97608
- golpe.golpe = figura.golpeEnLaTapa;
97609
- golpe.rasgueado = figura.rasgueado;
97610
- golpe.barreFret = figura.cejilla;
97611
- golpe.barreShape = figura.formaDeCejilla;
97612
- golpe.invertBeamDirection = figura.plicaInvertida;
97613
- golpe.beamingMode = figura.barrado;
97614
- if (figura.tremolo > 0) {
97615
- const tremolo = new _barrel_exports$4.TremoloPickingEffect();
97616
- tremolo.marks = figura.tremolo;
97617
- golpe.tremoloPicking = tremolo;
97618
- }
97619
- if (figura.calderon > 0) {
97620
- const calderon = new _barrel_exports$4.Fermata();
97621
- calderon.type = figura.calderon - 1;
97622
- golpe.fermata = calderon;
97623
- }
97624
- if (figura.palanca.length > 0) {
97625
- golpe.whammyBarType = _barrel_exports$4.WhammyType.Custom;
97626
- golpe.whammyStyle = _barrel_exports$4.BendStyle.Default;
97627
- golpe.whammyBarPoints = figura.palanca.map(
97628
- (p) => new _barrel_exports$4.BendPoint(p.desplazamiento, p.valor)
97629
- );
98090
+ const acordesEscritos = [];
98091
+ maestros.forEach((m, indiceDeCompas2) => {
98092
+ const id2 = porMaestro.get(m.id);
98093
+ for (const { datos: f } of id2 ? figurasPorCompas.get(id2) ?? [] : []) {
98094
+ if (f.acorde) {
98095
+ acordesEscritos.push({ compas: indiceDeCompas2, tiempo: f.tiempo, nombre: f.acorde });
97630
98096
  }
97631
- const notasDelGolpe2 = notasPorFigura.get(idFigura) ?? [];
97632
- const extremosDelGolpe = extremosPorGrado(
97633
- notasDelGolpe2.map((n) => {
97634
- const a = alturaDeLaNota(n, pista.tipo, pista.afinacion);
97635
- const ac = a === null ? null : acordeVigente(indiceDeCompas2, figura.tiempo);
97636
- return { altura: a, grado: a === null || ac === null ? null : gradoDeLaNota(ac, a) };
97637
- })
97638
- );
97639
- for (const nota of notasDelGolpe2) {
97640
- const notaAlphaTab = new _barrel_exports$4.Note();
97641
- if (pista.tipo === "altura") {
97642
- const altura2 = nota.altura ?? 60;
97643
- notaAlphaTab.octave = Math.floor(altura2 / 12);
97644
- notaAlphaTab.tone = altura2 % 12;
97645
- } else if (pista.tipo === "percusion") {
97646
- notaAlphaTab.percussionArticulation = nota.articulacion ?? 0;
97647
- } else {
97648
- notaAlphaTab.string = nota.cuerda;
97649
- notaAlphaTab.fret = nota.traste;
97650
- }
97651
- notaAlphaTab.isDead = nota.muerta;
97652
- notaAlphaTab.isGhost = nota.fantasma;
97653
- notaAlphaTab.isPalmMute = nota.palmMute;
97654
- notaAlphaTab.isLetRing = nota.letRing;
97655
- notaAlphaTab.isTieDestination = nota.ligadaAAnterior;
97656
- notaAlphaTab.isHammerPullOrigin = nota.martillo;
97657
- notaAlphaTab.isStaccato = nota.staccato;
97658
- notaAlphaTab.slideInType = nota.deslizamientoEntrada;
97659
- notaAlphaTab.slideOutType = nota.deslizamientoSalida;
97660
- notaAlphaTab.harmonicType = nota.armonico;
97661
- notaAlphaTab.vibrato = nota.anchoDeVibrato;
97662
- notaAlphaTab.accentuated = nota.acento;
97663
- notaAlphaTab.isLeftHandTapped = nota.tappingIzquierda;
97664
- notaAlphaTab.showStringNumber = nota.muestraCuerda;
97665
- notaAlphaTab.leftHandFinger = nota.dedoIzquierda;
97666
- notaAlphaTab.rightHandFinger = nota.dedoDerecha;
97667
- notaAlphaTab.trillValue = nota.trino;
97668
- notaAlphaTab.trillSpeed = nota.velocidadDeTrino;
97669
- notaAlphaTab.accidentalMode = nota.alteracion;
97670
- if (nota.ligaduraDeExpresion) notaAlphaTab.isEffectSlurOrigin = true;
97671
- if (nota.bend.length > 0) {
97672
- notaAlphaTab.bendType = _barrel_exports$4.BendType.Custom;
97673
- notaAlphaTab.bendStyle = _barrel_exports$4.BendStyle.Default;
97674
- for (const punto of nota.bend) {
97675
- notaAlphaTab.addBendPoint(
97676
- new _barrel_exports$4.BendPoint(punto.desplazamiento, punto.valor)
97677
- );
98097
+ }
98098
+ });
98099
+ const acordeVigente = buscadorDeAcorde(acordesEscritos);
98100
+ maestros.forEach((maestro, indiceDeCompas2) => {
98101
+ const barra = new _barrel_exports$4.Bar();
98102
+ pentagrama.addBar(barra);
98103
+ barra.keySignature = maestro.datos.tonalidad;
98104
+ barra.simileMark = maestro.datos.repiteAnterior;
98105
+ const idCompas = porMaestro.get(maestro.id);
98106
+ const figuras = idCompas ? figurasPorCompas.get(idCompas) ?? [] : [];
98107
+ const datosDelCompas = idCompas ? datosDeCompas.get(idCompas) : void 0;
98108
+ if (datosDelCompas) {
98109
+ barra.clef = datosDelCompas.clave;
98110
+ barra.clefOttava = datosDelCompas.claveOctava;
98111
+ }
98112
+ const ticsDelCompas = 960 * 4 * maestro.datos.numerador / maestro.datos.denominador;
98113
+ for (const { datos: figura } of figuras) {
98114
+ if (!figura.pedal) continue;
98115
+ const marcador = new _barrel_exports$4.SustainPedalMarker();
98116
+ marcador.ratioPosition = ticsDelCompas > 0 ? figura.tiempo / ticsDelCompas : 0;
98117
+ marcador.pedalType = figura.pedal - 1;
98118
+ barra.sustainPedals.push(marcador);
98119
+ }
98120
+ for (let indiceDeVoz = 0; indiceDeVoz < cantidadDeVoces; indiceDeVoz++) {
98121
+ const voz = new _barrel_exports$4.Voice();
98122
+ barra.addVoice(voz);
98123
+ const deEstaVoz = figuras.filter((f) => f.datos.voz === indiceDeVoz).sort((a, b) => a.datos.tiempo - b.datos.tiempo);
98124
+ for (const { id: idFigura, datos: figura } of deEstaVoz) {
98125
+ const golpe = new _barrel_exports$4.Beat();
98126
+ golpe.duration = figura.valor;
98127
+ golpe.dots = figura.puntillos;
98128
+ if (figura.tupletNumerador > 1) {
98129
+ golpe.tupletNumerator = figura.tupletNumerador;
98130
+ golpe.tupletDenominator = figura.tupletDenominador;
98131
+ }
98132
+ if (figura.texto) golpe.lyrics = [marcado(figura.texto, figura.textoSegundaTipografia)];
98133
+ if (figura.acorde) {
98134
+ const nombre = marcado(figura.acorde, figura.acordeSegundaTipografia);
98135
+ if (!pentagrama.chords?.has(nombre)) {
98136
+ const acorde = new _barrel_exports$4.Chord();
98137
+ acorde.name = nombre;
98138
+ acorde.showName = true;
98139
+ acorde.showDiagram = false;
98140
+ acorde.staff = pentagrama;
98141
+ pentagrama.addChord(nombre, acorde);
97678
98142
  }
98143
+ golpe.chordId = nombre;
98144
+ }
98145
+ golpe.dynamics = figura.dinamica;
98146
+ golpe.pickStroke = figura.puaDireccion;
98147
+ golpe.brushType = figura.rasgueo;
98148
+ golpe.brushDuration = figura.duracionDelRasgueo;
98149
+ golpe.slap = figura.slap;
98150
+ golpe.pop = figura.pop;
98151
+ golpe.tap = figura.tapping;
98152
+ golpe.deadSlapped = figura.slapMuerto;
98153
+ golpe.slashed = figura.barraOblicua;
98154
+ golpe.graceType = figura.adorno;
98155
+ golpe.crescendo = figura.regulador;
98156
+ golpe.fade = figura.fundido;
98157
+ golpe.wahPedal = figura.wah;
98158
+ golpe.golpe = figura.golpeEnLaTapa;
98159
+ golpe.rasgueado = figura.rasgueado;
98160
+ golpe.barreFret = figura.cejilla;
98161
+ golpe.barreShape = figura.formaDeCejilla;
98162
+ golpe.invertBeamDirection = figura.plicaInvertida;
98163
+ golpe.beamingMode = figura.barrado;
98164
+ if (figura.tremolo > 0) {
98165
+ const tremolo = new _barrel_exports$4.TremoloPickingEffect();
98166
+ tremolo.marks = figura.tremolo;
98167
+ golpe.tremoloPicking = tremolo;
98168
+ }
98169
+ if (figura.calderon > 0) {
98170
+ const calderon = new _barrel_exports$4.Fermata();
98171
+ calderon.type = figura.calderon - 1;
98172
+ golpe.fermata = calderon;
98173
+ }
98174
+ if (figura.palanca.length > 0) {
98175
+ golpe.whammyBarType = _barrel_exports$4.WhammyType.Custom;
98176
+ golpe.whammyStyle = _barrel_exports$4.BendStyle.Default;
98177
+ golpe.whammyBarPoints = figura.palanca.map(
98178
+ (p) => new _barrel_exports$4.BendPoint(p.desplazamiento, p.valor)
98179
+ );
97679
98180
  }
97680
- const altura = alturaDeLaNota(nota, pista.tipo, pista.afinacion);
97681
- const acordeDeLaNota = altura === null ? null : acordeVigente(indiceDeCompas2, figura.tiempo);
97682
- const gradoDeEsta = altura === null || acordeDeLaNota === null ? null : gradoDeLaNota(acordeDeLaNota, altura);
97683
- const marca = marcaDeLaNota(
97684
- { color: nota.marcaColor, subrayada: nota.marcaSubrayada },
97685
- gradoDeEsta,
97686
- estiloDeLaObra,
97687
- leTocaLaMarca(
97688
- altura,
97689
- gradoDeEsta === null ? void 0 : extremosDelGolpe.get(gradoDeEsta),
97690
- // ★ La política es DE ESTE GRADO: querer la fundamental del bajo y a la vez
97691
- // todas las terceras es un pedido razonable, y con un ajuste general sería
97692
- // imposible.
97693
- (gradoDeEsta === null ? void 0 : estiloDeLaObra.marcasPorGrado?.[String(gradoDeEsta)]?.cual) ?? "todas"
97694
- )
98181
+ const notasDelGolpe2 = notasPorFigura.get(idFigura) ?? [];
98182
+ const extremosDelGolpe = extremosPorGrado(
98183
+ notasDelGolpe2.map((n) => {
98184
+ const a = alturaDeLaNota(n, pista.tipo, pista.afinacion);
98185
+ const ac = a === null ? null : acordeVigente(indiceDeCompas2, figura.tiempo);
98186
+ return { altura: a, grado: a === null || ac === null ? null : gradoDeLaNota(ac, a) };
98187
+ })
97695
98188
  );
97696
- if (marca.pintar) {
97697
- const color = _barrel_exports$4.Color.fromJson(marca.pintar);
97698
- if (color) {
97699
- notaAlphaTab.style ??= new _barrel_exports$4.NoteStyle();
97700
- notaAlphaTab.style.colors.set(
97701
- _barrel_exports$4.NoteSubElement.GuitarTabFretNumber,
97702
- color
97703
- );
97704
- notaAlphaTab.style.colors.set(
97705
- _barrel_exports$4.NoteSubElement.StandardNotationNoteHead,
97706
- color
97707
- );
98189
+ for (const nota of notasDelGolpe2) {
98190
+ const notaAlphaTab = new _barrel_exports$4.Note();
98191
+ if (pista.tipo === "altura") {
98192
+ const altura2 = nota.altura ?? 60;
98193
+ notaAlphaTab.octave = Math.floor(altura2 / 12);
98194
+ notaAlphaTab.tone = altura2 % 12;
98195
+ } else if (pista.tipo === "percusion") {
98196
+ notaAlphaTab.percussionArticulation = nota.articulacion ?? 0;
98197
+ } else {
98198
+ notaAlphaTab.string = nota.cuerda;
98199
+ notaAlphaTab.fret = nota.traste;
98200
+ }
98201
+ notaAlphaTab.isDead = nota.muerta;
98202
+ notaAlphaTab.isGhost = nota.fantasma;
98203
+ notaAlphaTab.isPalmMute = nota.palmMute;
98204
+ notaAlphaTab.isLetRing = nota.letRing;
98205
+ notaAlphaTab.isTieDestination = nota.ligadaAAnterior;
98206
+ notaAlphaTab.isHammerPullOrigin = nota.martillo;
98207
+ notaAlphaTab.isStaccato = nota.staccato;
98208
+ notaAlphaTab.slideInType = nota.deslizamientoEntrada;
98209
+ notaAlphaTab.slideOutType = nota.deslizamientoSalida;
98210
+ notaAlphaTab.harmonicType = nota.armonico;
98211
+ notaAlphaTab.vibrato = nota.anchoDeVibrato;
98212
+ notaAlphaTab.accentuated = nota.acento;
98213
+ notaAlphaTab.isLeftHandTapped = nota.tappingIzquierda;
98214
+ notaAlphaTab.showStringNumber = nota.muestraCuerda;
98215
+ notaAlphaTab.leftHandFinger = nota.dedoIzquierda;
98216
+ notaAlphaTab.rightHandFinger = nota.dedoDerecha;
98217
+ notaAlphaTab.trillValue = nota.trino;
98218
+ notaAlphaTab.trillSpeed = nota.velocidadDeTrino;
98219
+ notaAlphaTab.accidentalMode = nota.alteracion;
98220
+ if (nota.ligaduraDeExpresion) notaAlphaTab.isEffectSlurOrigin = true;
98221
+ if (nota.bend.length > 0) {
98222
+ notaAlphaTab.bendType = _barrel_exports$4.BendType.Custom;
98223
+ notaAlphaTab.bendStyle = _barrel_exports$4.BendStyle.Default;
98224
+ for (const punto of nota.bend) {
98225
+ notaAlphaTab.addBendPoint(
98226
+ new _barrel_exports$4.BendPoint(punto.desplazamiento, punto.valor)
98227
+ );
98228
+ }
98229
+ }
98230
+ const altura = alturaDeLaNota(nota, pista.tipo, pista.afinacion);
98231
+ const acordeDeLaNota = altura === null ? null : acordeVigente(indiceDeCompas2, figura.tiempo);
98232
+ const gradoDeEsta = altura === null || acordeDeLaNota === null ? null : gradoDeLaNota(acordeDeLaNota, altura);
98233
+ const marca = marcaDeLaNota(
98234
+ { color: nota.marcaColor, subrayada: nota.marcaSubrayada },
98235
+ gradoDeEsta,
98236
+ estiloDeLaObra,
98237
+ leTocaLaMarca(
98238
+ altura,
98239
+ gradoDeEsta === null ? void 0 : extremosDelGolpe.get(gradoDeEsta),
98240
+ // ★ La política es DE ESTE GRADO: querer la fundamental del bajo y a la vez
98241
+ // todas las terceras es un pedido razonable, y con un ajuste general sería
98242
+ // imposible.
98243
+ (gradoDeEsta === null ? void 0 : estiloDeLaObra.marcasPorGrado?.[String(gradoDeEsta)]?.cual) ?? "todas"
98244
+ )
98245
+ );
98246
+ if (marca.pintar) {
98247
+ const color = _barrel_exports$4.Color.fromJson(marca.pintar);
98248
+ if (color) {
98249
+ notaAlphaTab.style ??= new _barrel_exports$4.NoteStyle();
98250
+ notaAlphaTab.style.colors.set(
98251
+ _barrel_exports$4.NoteSubElement.GuitarTabFretNumber,
98252
+ color
98253
+ );
98254
+ notaAlphaTab.style.colors.set(
98255
+ _barrel_exports$4.NoteSubElement.StandardNotationNoteHead,
98256
+ color
98257
+ );
98258
+ }
97708
98259
  }
98260
+ if (marca.subrayar) anotarSubrayado(notaAlphaTab, marca.subrayar);
98261
+ golpe.addNote(notaAlphaTab);
97709
98262
  }
97710
- if (marca.subrayar) anotarSubrayado(notaAlphaTab, marca.subrayar);
97711
- golpe.addNote(notaAlphaTab);
98263
+ voz.addBeat(golpe);
98264
+ }
98265
+ if (voz.beats.length === 0) {
98266
+ const relleno = new _barrel_exports$4.Beat();
98267
+ relleno.isEmpty = true;
98268
+ voz.addBeat(relleno);
97712
98269
  }
97713
- voz.addBeat(golpe);
97714
- }
97715
- if (voz.beats.length === 0) {
97716
- const relleno = new _barrel_exports$4.Beat();
97717
- relleno.isEmpty = true;
97718
- voz.addBeat(relleno);
97719
98270
  }
97720
- }
98271
+ });
98272
+ }
98273
+ }
98274
+ const { saltosDeRenglon } = documento.leerPresentacion();
98275
+ if (saltosDeRenglon.size > 0) {
98276
+ maestros.forEach((maestro, indice) => {
98277
+ if (indice === 0 || !saltosDeRenglon.has(maestro.id)) return;
98278
+ for (const track of score.tracks) track.addLineBreaks(indice);
97721
98279
  });
97722
98280
  }
97723
98281
  score.finish(ajustes);
@@ -121959,10 +122517,10 @@ function duracionDesde(figura, puntillos) {
121959
122517
  }
121960
122518
  return { valor: figura, puntillos: puntillos ?? 0 };
121961
122519
  }
121962
- function ticsDelGolpe(indice, pistaId, compas, voz, golpe, tics) {
122520
+ function ticsDelGolpe(indice, pistaId, compas, voz, golpe, tics, pentagrama = 0) {
121963
122521
  if (tics !== void 0) return tics;
121964
122522
  if (golpe === void 0) return 0;
121965
- const compasId = indice.compasId(pistaId, compas);
122523
+ const compasId = indice.compasId(pistaId, compas, pentagrama);
121966
122524
  const figuras = indice.figuras(compasId, voz);
121967
122525
  const elegida = figuras[golpe - 1];
121968
122526
  if (!elegida) {
@@ -121972,8 +122530,18 @@ function ticsDelGolpe(indice, pistaId, compas, voz, golpe, tics) {
121972
122530
  }
121973
122531
  return elegida.datos.tiempo;
121974
122532
  }
121975
- function cursorEn(indice, pistaId, compas, voz, tiempo, cuerda) {
121976
- return { ...cursorInicial(indice, pistaId), compas, voz, tiempo, cuerda };
122533
+ function cursorEn(indice, pistaId, compas, voz, tiempo, cuerda, pentagrama = 0) {
122534
+ return { ...cursorInicial(indice, pistaId), compas, voz, tiempo, cuerda, ...pentagrama > 0 ? { pentagrama } : {} };
122535
+ }
122536
+ function pentagramaDelMusico(pedido, indice, pistaId, numeroDePista) {
122537
+ if (pedido === void 0) return 0;
122538
+ const tiene = indice.pentagramasDe(pistaId);
122539
+ if (pedido < 1 || pedido > tiene) {
122540
+ throw new ProblemaConLaObra(
122541
+ `La pista ${numeroDePista} tiene ${tiene} pentagrama${tiene === 1 ? "" : "s"}; no existe el ${pedido}.` + (tiene === 1 ? " S\xF3lo un piano lleva dos (1 la mano derecha, 2 la izquierda)." : "")
122542
+ );
122543
+ }
122544
+ return pedido - 1;
121977
122545
  }
121978
122546
  var campoDeSegundaTipografia = external_exports.array(
121979
122547
  external_exports.object({
@@ -122004,7 +122572,8 @@ var unaNota = {
122004
122572
  pieza: external_exports.string().optional().describe("La pieza del kit: \xABBombo\xBB, \xABCaja\xBB, \xABCharles cerrado\xBB\u2026 Solo en pistas de percusi\xF3n. La lista entera la da `piezas_de_bateria`."),
122005
122573
  golpe: external_exports.number().int().min(1).max(999).optional(),
122006
122574
  tics: external_exports.number().int().min(0).max(99999).optional(),
122007
- voz: external_exports.number().int().min(1).max(4).optional()
122575
+ voz: external_exports.number().int().min(1).max(4).optional(),
122576
+ pentagrama: external_exports.number().int().min(1).max(4).optional().describe("En qu\xE9 pentagrama de la pista, desde 1. S\xF3lo el piano tiene dos: 1 la mano derecha (arriba), 2 la izquierda. Por omisi\xF3n el 1.")
122008
122577
  };
122009
122578
  function piezaPorNombre(nombre) {
122010
122579
  const plano = (t) => t.normalize("NFD").replace(/[̀-ͯ]/g, "").trim().toLowerCase();
@@ -122089,9 +122658,9 @@ function registrarHerramientasDelDocumento(servidor2) {
122089
122658
  "abrir_obra",
122090
122659
  {
122091
122660
  title: "Abrir una obra",
122092
- description: "Abre un archivo de partitura del disco y lo deja como la obra sobre la que trabajan las dem\xE1s herramientas. Entiende .mtabs (el formato de Mandioca Tabs) y .gp (Guitar Pro). \u26A0\uFE0F **Si el m\xFAsico ya tiene el programa abierto y esperando, esto NO es lo que \xE9l ve**: un archivo abierto ac\xE1 es un documento aparte. Se comprueba antes y se avisa; para trabajar sobre su pantalla, `conectar_con_la_app`.",
122661
+ description: "Abre un archivo de partitura del disco y lo deja como la obra sobre la que trabajan las dem\xE1s herramientas. Entiende .mtabs (el formato de Mandioca Tabs), Guitar Pro (.gp, .gpx, .gp5, .gp4, .gp3) y MusicXML (.musicxml, .xml, .mxl). \u26A0\uFE0F **Si el m\xFAsico ya tiene el programa abierto y esperando, esto NO es lo que \xE9l ve**: un archivo abierto ac\xE1 es un documento aparte. Se comprueba antes y se avisa; para trabajar sobre su pantalla, `conectar_con_la_app`.",
122093
122662
  inputSchema: {
122094
- ruta: external_exports.string().describe("La ruta completa del archivo, terminada en .mtabs o .gp"),
122663
+ ruta: external_exports.string().describe("La ruta completa del archivo: .mtabs, Guitar Pro (.gp, .gpx, .gp5\u2026) o MusicXML (.musicxml, .xml, .mxl)"),
122095
122664
  igual: external_exports.boolean().optional().describe(
122096
122665
  "Abrir el archivo aunque el m\xFAsico tenga el programa abierto. Sirve para trabajar sobre un archivo del disco a prop\xF3sito, sin tocar lo que \xE9l est\xE1 mirando."
122097
122666
  )
@@ -122151,7 +122720,8 @@ function registrarHerramientasDelDocumento(servidor2) {
122151
122720
  nombre: primero.nombre,
122152
122721
  nombreCorto: primero.nombreCorto,
122153
122722
  afinacion: primero.afinacion,
122154
- programaMidi: primero.programaMidi
122723
+ programaMidi: primero.programaMidi,
122724
+ pentagramas: primero.pentagramas
122155
122725
  }
122156
122726
  } : {}
122157
122727
  });
@@ -122161,7 +122731,8 @@ function registrarHerramientasDelDocumento(servidor2) {
122161
122731
  nombre: i2.nombre,
122162
122732
  nombreCorto: i2.nombreCorto,
122163
122733
  afinacion: i2.afinacion,
122164
- programaMidi: i2.programaMidi
122734
+ programaMidi: i2.programaMidi,
122735
+ pentagramas: i2.pentagramas
122165
122736
  });
122166
122737
  }
122167
122738
  const v = volcar(obra.documento);
@@ -122345,13 +122916,14 @@ function registrarHerramientasDelDocumento(servidor2) {
122345
122916
  const pistaId = laPista.id;
122346
122917
  const compas = indiceDeCompas(nota.compas, indice);
122347
122918
  const voz = (nota.voz ?? 1) - 1;
122348
- const tiempo = ticsDelGolpe(indice, pistaId, compas, voz, nota.golpe, nota.tics);
122919
+ const pentagrama = pentagramaDelMusico(nota.pentagrama, indice, pistaId, pista ?? 1);
122920
+ const tiempo = ticsDelGolpe(indice, pistaId, compas, voz, nota.golpe, nota.tics, pentagrama);
122349
122921
  const nombrada = comoSeEscribeLaNota(laPista.tipo, laPista.nombre, pista ?? 1, nota);
122350
122922
  if (nombrada.clase === "altura") {
122351
122923
  const resultado2 = escribirAltura(
122352
122924
  documento,
122353
122925
  indice,
122354
- cursorEn(indice, pistaId, compas, voz, tiempo, 1),
122926
+ cursorEn(indice, pistaId, compas, voz, tiempo, 1, pentagrama),
122355
122927
  nombrada.altura,
122356
122928
  duracion ? { duracion } : {}
122357
122929
  );
@@ -122367,7 +122939,7 @@ function registrarHerramientasDelDocumento(servidor2) {
122367
122939
  const resultado2 = escribirPercusion(
122368
122940
  documento,
122369
122941
  indice,
122370
- cursorEn(indice, pistaId, compas, voz, tiempo, 1),
122942
+ cursorEn(indice, pistaId, compas, voz, tiempo, 1, pentagrama),
122371
122943
  nombrada.articulacion,
122372
122944
  duracion ? { duracion } : {}
122373
122945
  );
@@ -122382,7 +122954,7 @@ function registrarHerramientasDelDocumento(servidor2) {
122382
122954
  const resultado = escribirTraste(
122383
122955
  documento,
122384
122956
  indice,
122385
- cursorEn(indice, pistaId, compas, voz, tiempo, nombrada.cuerda),
122957
+ cursorEn(indice, pistaId, compas, voz, tiempo, nombrada.cuerda, pentagrama),
122386
122958
  nombrada.cuerda,
122387
122959
  nombrada.traste,
122388
122960
  duracion ? { duracion } : {}
@@ -122418,9 +122990,10 @@ function registrarHerramientasDelDocumento(servidor2) {
122418
122990
  const pistaId = laPista.id;
122419
122991
  const compas = indiceDeCompas(nota.compas, indice);
122420
122992
  const voz = (nota.voz ?? 1) - 1;
122421
- const tiempo = ticsDelGolpe(indice, pistaId, compas, voz, nota.golpe, nota.tics);
122993
+ const pentagrama = pentagramaDelMusico(nota.pentagrama, indice, pistaId, pista ?? 1);
122994
+ const tiempo = ticsDelGolpe(indice, pistaId, compas, voz, nota.golpe, nota.tics, pentagrama);
122422
122995
  const nombrada = comoSeNombraLaNota(laPista.tipo, laPista.nombre, pista ?? 1, nota);
122423
- const cursor = cursorEn(indice, pistaId, compas, voz, tiempo, nombrada.clase === "trastes" ? nombrada.cuerda : 1);
122996
+ const cursor = cursorEn(indice, pistaId, compas, voz, tiempo, nombrada.clase === "trastes" ? nombrada.cuerda : 1, pentagrama);
122424
122997
  const salio = nombrada.clase === "altura" ? borrarAltura(documento, indice, cursor, nombrada.altura) : nombrada.clase === "percusion" ? borrarPercusion(documento, indice, cursor, nombrada.articulacion) : borrarNotaDeCuerda(documento, indice, cursor, nombrada.cuerda);
122425
122998
  if (salio) borradas += 1;
122426
122999
  }
@@ -123310,7 +123883,7 @@ function registrarHerramientasDelPuente(servidor2) {
123310
123883
  title: "Abrir una obra en la pantalla del m\xFAsico",
123311
123884
  description: "Abre un `.mtabs` o un `.gp` del disco **en la pesta\xF1a que el m\xFAsico tiene delante**. \u26A0\uFE0F Esto NO es `abrir_obra`: aqu\xE9lla abre el archivo como un documento aparte, que el m\xFAsico no ve. \xC9sta se lo pone en pantalla. \u26A0\uFE0F Y no es `abrir_reciente`, que s\xF3lo alcanza los de su lista: ac\xE1 va cualquier ruta. \u2605 Funciona tambi\xE9n con la pantalla de inicio abierta y ninguna obra cargada, que es para lo que se hizo. \u26A0\uFE0F\u26A0\uFE0F **Falla si hay trabajo sin guardar**, y dice cu\xE1l: abrir otra cosa encima lo perder\xEDa, y \xE9sa no es una decisi\xF3n que se tome por el m\xFAsico.",
123312
123885
  inputSchema: {
123313
- ruta: external_exports.string().min(1).describe("La ruta completa en el disco, terminada en .mtabs o .gp")
123886
+ ruta: external_exports.string().min(1).describe("La ruta completa en el disco: .mtabs, Guitar Pro (.gp, .gpx, .gp5\u2026) o MusicXML (.musicxml, .xml, .mxl)")
123314
123887
  }
123315
123888
  },
123316
123889
  async ({ ruta }) => {
@@ -123943,7 +124516,8 @@ function registrarHerramientasDeEstructura(servidor2) {
123943
124516
  nombre: nombre ?? delCatalogo.nombre,
123944
124517
  nombreCorto: delCatalogo.nombreCorto,
123945
124518
  afinacion: delCatalogo.afinacion,
123946
- programaMidi: delCatalogo.programaMidi
124519
+ programaMidi: delCatalogo.programaMidi,
124520
+ pentagramas: delCatalogo.pentagramas
123947
124521
  });
123948
124522
  const vc = volcar(documento);
123949
124523
  return texto2({
@@ -124516,7 +125090,7 @@ function registrarHerramientasDeMusica(servidor2) {
124516
125090
  throw new ProblemaConLaObra("Ese golpe ya tiene notas: sin el nombre no hay nada que escribir.");
124517
125091
  }
124518
125092
  const golpe = indexar(sitio.documento);
124519
- const compasId = golpe.compasId(sitio.cursor.pistaId, sitio.cursor.compas);
125093
+ const compasId = golpe.compasId(sitio.cursor.pistaId, sitio.cursor.compas, sitio.cursor.pentagrama);
124520
125094
  const puesto = compasId ? golpe.figuraEn(compasId, sitio.cursor.voz, sitio.cursor.tiempo)?.datos : void 0;
124521
125095
  return texto2({
124522
125096
  acorde: nombre,