mandioca-tabs-mcp 0.2.8 → 0.2.12

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 +1201 -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.
@@ -13308,6 +13362,8 @@ function normalizarFigura(crudo) {
13308
13362
  palanca: lista(crudo.palanca)
13309
13363
  };
13310
13364
  if (typeof crudo.acorde === "string" && crudo.acorde !== "") salida.acorde = crudo.acorde;
13365
+ if (typeof crudo.octava === "number" && crudo.octava !== SIN_OCTAVA) salida.octava = crudo.octava;
13366
+ if (typeof crudo.tempo === "number" && crudo.tempo > 0) salida.tempo = crudo.tempo;
13311
13367
  if (typeof crudo.textoSegundaTipografia === "string") salida.textoSegundaTipografia = crudo.textoSegundaTipografia;
13312
13368
  if (typeof crudo.acordeSegundaTipografia === "string") salida.acordeSegundaTipografia = crudo.acordeSegundaTipografia;
13313
13369
  return salida;
@@ -13319,7 +13375,9 @@ function normalizarCompas(crudo) {
13319
13375
  // ★ Excepción: «nada» no sirve. Un documento viejo se dibujaba en clave de sol, así que
13320
13376
  // la ausencia significa sol y no «sin clave» —que alphaTab dibujaría como clave de do—.
13321
13377
  clave: numero(crudo.clave, CLAVE_POR_OMISION),
13322
- claveOctava: numero(crudo.claveOctava, SIN_OCTAVA)
13378
+ claveOctava: numero(crudo.claveOctava, SIN_OCTAVA),
13379
+ // Ausente = el primer pentagrama, que es el único que existía antes del 2026-11-09.
13380
+ ...typeof crudo.pentagrama === "number" && crudo.pentagrama > 0 ? { pentagrama: crudo.pentagrama } : {}
13323
13381
  };
13324
13382
  }
13325
13383
  function normalizarCompasMaestro(crudo) {
@@ -13357,6 +13415,9 @@ function normalizarPista(crudo) {
13357
13415
  programaMidi: numero(crudo.programaMidi, 25),
13358
13416
  volumen: numero(crudo.volumen, 16),
13359
13417
  balance: numero(crudo.balance, 8),
13418
+ // Ausente = 1 pentagrama, lo único que existía antes del 2026-11-09.
13419
+ ...typeof crudo.pentagramas === "number" && crudo.pentagramas > 1 ? { pentagramas: crudo.pentagramas } : {},
13420
+ ...typeof crudo.transposicion === "number" && crudo.transposicion !== 0 ? { transposicion: crudo.transposicion } : {},
13360
13421
  // Las marcas de la segunda tipografía (2026-10-19): sólo si están, como `acorde`.
13361
13422
  ...typeof crudo.nombreSegundaTipografia === "string" ? { nombreSegundaTipografia: crudo.nombreSegundaTipografia } : {},
13362
13423
  ...typeof crudo.nombreCortoSegundaTipografia === "string" ? { nombreCortoSegundaTipografia: crudo.nombreCortoSegundaTipografia } : {}
@@ -13405,7 +13466,7 @@ var init_consultas = __esm({
13405
13466
  pistas;
13406
13467
  /** Las grabaciones de referencia, en el orden en que se muestran en el mezclador. */
13407
13468
  fuentesDeAudio;
13408
- /** pistaId → (compasMaestroId → compasId) */
13469
+ /** pistaId → (`compasMaestroId|pentagrama` → compasId) */
13409
13470
  _compases;
13410
13471
  /** compasId → figuras, ya ordenadas por voz y después por tiempo */
13411
13472
  _figuras;
@@ -13457,7 +13518,7 @@ var init_consultas = __esm({
13457
13518
  porMaestro = /* @__PURE__ */ new Map();
13458
13519
  this._compases.set(compas.pistaId, porMaestro);
13459
13520
  }
13460
- porMaestro.set(compas.compasMaestroId, id2);
13521
+ porMaestro.set(`${compas.compasMaestroId}|${compas.pentagrama ?? 0}`, id2);
13461
13522
  this._datosDeCompas.set(id2, compas);
13462
13523
  }
13463
13524
  this._figuras = /* @__PURE__ */ new Map();
@@ -13544,10 +13605,18 @@ var init_consultas = __esm({
13544
13605
  * compás de la obra. Devolver `undefined` en vez de fabricarlo es a propósito — crear
13545
13606
  * entidades es trabajo de quien edita, no de quien lee.
13546
13607
  */
13547
- compasId(pistaId, indice) {
13608
+ /**
13609
+ * El compás de una pista en la posición `indice`, en su pentagrama `pentagrama` (desde 0).
13610
+ * ★ Sin pentagrama, el primero: es lo único que existía antes del piano de dos pentagramas.
13611
+ */
13612
+ compasId(pistaId, indice, pentagrama = 0) {
13548
13613
  const maestro = this.compasesMaestros[indice];
13549
13614
  if (!maestro) return void 0;
13550
- return this._compases.get(pistaId)?.get(maestro.id);
13615
+ return this._compases.get(pistaId)?.get(`${maestro.id}|${pentagrama}`);
13616
+ }
13617
+ /** Cuántos pentagramas tiene una pista (1 si no lo dice). */
13618
+ pentagramasDe(pistaId) {
13619
+ return this.pista(pistaId)?.datos.pentagramas ?? 1;
13551
13620
  }
13552
13621
  /**
13553
13622
  * Las figuras de un compás, ordenadas. Con `voz`, solo las de esa voz.
@@ -13686,7 +13755,7 @@ function volcar(documento) {
13686
13755
  porMaestro = /* @__PURE__ */ new Map();
13687
13756
  compasesPorPista.set(datos.pistaId, porMaestro);
13688
13757
  }
13689
- porMaestro.set(datos.compasMaestroId, id2);
13758
+ porMaestro.set(`${datos.compasMaestroId}|${datos.pentagrama ?? 0}`, id2);
13690
13759
  }
13691
13760
  const figurasPorCompas = /* @__PURE__ */ new Map();
13692
13761
  for (const [id2, entidad] of documento.figuras.entries()) {
@@ -13709,9 +13778,10 @@ function volcar(documento) {
13709
13778
  const porMaestro = compasesPorPista.get(pista.id) ?? /* @__PURE__ */ new Map();
13710
13779
  const volcadoCompases = [];
13711
13780
  let totalNotasPista = 0;
13712
- for (const [indice, maestro] of compasesMaestros.entries()) {
13781
+ const pentagramas = Math.max(1, datosPista.pentagramas ?? 1);
13782
+ for (const [indice, maestro] of compasesMaestros.entries()) for (let pentagrama = 0; pentagrama < pentagramas; pentagrama++) {
13713
13783
  const datosMaestro = maestro.datos;
13714
- const compasId = porMaestro.get(maestro.id);
13784
+ const compasId = porMaestro.get(`${maestro.id}|${pentagrama}`);
13715
13785
  const figuras = compasId ? figurasPorCompas.get(compasId) ?? [] : [];
13716
13786
  figuras.sort(
13717
13787
  (a, b) => a.datos.voz !== b.datos.voz ? a.datos.voz - b.datos.voz : a.datos.tiempo - b.datos.tiempo
@@ -13743,6 +13813,7 @@ function volcar(documento) {
13743
13813
  compasDeAmalgama: `${datosMaestro.numerador}/${datosMaestro.denominador}`,
13744
13814
  figuras: volcadoFiguras
13745
13815
  };
13816
+ if (pentagrama > 0) volcadoCompas.pentagrama = pentagrama + 1;
13746
13817
  if (datosMaestro.seccion) {
13747
13818
  volcadoCompas.seccion = datosMaestro.seccion;
13748
13819
  Object.assign(volcadoCompas, segundaDe("seccion", datosMaestro.seccion, datosMaestro.seccionSegundaTipografia));
@@ -13759,13 +13830,14 @@ function volcar(documento) {
13759
13830
  ...segundaDe("nombreCorto", datosPista.nombreCorto, datosPista.nombreCortoSegundaTipografia),
13760
13831
  programaMidi: datosPista.programaMidi,
13761
13832
  tipo: tipoDeLaPista,
13833
+ ...pentagramas > 1 ? { pentagramas } : {},
13762
13834
  // ★ El orden de las claves de una pista de tablatura se mantiene —nombre, afinación,
13763
13835
  // capo…— con `tipo` insertado y nada más movido: el volcado se diffea, y reordenar
13764
13836
  // por gusto ensucia cada salida del repo sin arreglar nada.
13765
13837
  ...tipoDeLaPista === "trastes" ? { afinacion: datosPista.afinacion, capo: datosPista.capo } : {},
13766
13838
  volumen: datosPista.volumen,
13767
13839
  balance: datosPista.balance,
13768
- totalCompases: volcadoCompases.length,
13840
+ totalCompases: compasesMaestros.length,
13769
13841
  totalNotas: totalNotasPista,
13770
13842
  compases: volcadoCompases
13771
13843
  });
@@ -13979,7 +14051,8 @@ function crearDocumentoEnBlanco(opciones = {}) {
13979
14051
  programaMidi: pista.programaMidi ?? PROGRAMAS.guitarraAcustica,
13980
14052
  // 16 es "como está escrito" y 8 es el centro, en la escala del .gp y de alphaTab.
13981
14053
  volumen: pista.volumen ?? 16,
13982
- balance: pista.balance ?? 8
14054
+ balance: pista.balance ?? 8,
14055
+ ...(pista.pentagramas ?? 1) > 1 ? { pentagramas: pista.pentagramas } : {}
13983
14056
  });
13984
14057
  for (let i2 = 0; i2 < compases; i2++) {
13985
14058
  const compasMaestroId = documento.agregarCompasMaestro(normalizarCompasMaestro({
@@ -13995,11 +14068,23 @@ function crearDocumentoEnBlanco(opciones = {}) {
13995
14068
  repiteVeces: 0,
13996
14069
  esAnacruza: false
13997
14070
  }));
13998
- documento.agregarCompas(normalizarCompas({ pistaId, compasMaestroId }));
14071
+ for (const compas of compasesDeUnaPistaNueva(pistaId, compasMaestroId, pista.pentagramas ?? 1)) {
14072
+ documento.agregarCompas(compas);
14073
+ }
13999
14074
  }
14000
14075
  });
14001
14076
  return documento;
14002
14077
  }
14078
+ function compasesDeUnaPistaNueva(pistaId, compasMaestroId, pentagramas) {
14079
+ return Array.from(
14080
+ { length: Math.max(1, pentagramas) },
14081
+ (_, pentagrama) => normalizarCompas({
14082
+ pistaId,
14083
+ compasMaestroId,
14084
+ ...pentagrama > 0 ? { pentagrama, clave: CLAVE_DE_FA } : {}
14085
+ })
14086
+ );
14087
+ }
14003
14088
  function agregarPistaALaObra(documento, pista) {
14004
14089
  documento.doc.transact(() => {
14005
14090
  const pistaId = documento.agregarPista({
@@ -14011,14 +14096,17 @@ function agregarPistaALaObra(documento, pista) {
14011
14096
  programaMidi: pista.programaMidi,
14012
14097
  // 16 es "como está escrito" y 8 es el centro, en la escala del .gp y de alphaTab.
14013
14098
  volumen: 16,
14014
- balance: 8
14099
+ balance: 8,
14100
+ ...(pista.pentagramas ?? 1) > 1 ? { pentagramas: pista.pentagramas } : {}
14015
14101
  });
14016
14102
  for (const compasMaestroId of documento.compasesMaestros.keys()) {
14017
- documento.agregarCompas(normalizarCompas({ pistaId, compasMaestroId }));
14103
+ for (const compas of compasesDeUnaPistaNueva(pistaId, compasMaestroId, pista.pentagramas ?? 1)) {
14104
+ documento.agregarCompas(compas);
14105
+ }
14018
14106
  }
14019
14107
  });
14020
14108
  }
14021
- var AFINACIONES, PROGRAMAS;
14109
+ var AFINACIONES, PROGRAMAS, CLAVE_DE_FA;
14022
14110
  var init_enBlanco = __esm({
14023
14111
  "packages/model/src/enBlanco.ts"() {
14024
14112
  init_migrar();
@@ -14064,6 +14152,7 @@ var init_enBlanco = __esm({
14064
14152
  /** La batería NO se elige por programa: va por canal 10. Ver `TipoDePista`. */
14065
14153
  bateria: 0
14066
14154
  };
14155
+ CLAVE_DE_FA = 3;
14067
14156
  }
14068
14157
  });
14069
14158
 
@@ -14086,7 +14175,7 @@ var init_src2 = __esm({
14086
14175
  function posicionesEscribibles(indice, cursor) {
14087
14176
  const maestro = indice.compasMaestro(cursor.compas);
14088
14177
  if (!maestro) return [0];
14089
- const figuras = indice.figuras(indice.compasId(cursor.pistaId, cursor.compas), cursor.voz);
14178
+ const figuras = indice.figuras(indice.compasId(cursor.pistaId, cursor.compas, cursor.pentagrama), cursor.voz);
14090
14179
  const posiciones = /* @__PURE__ */ new Set([0]);
14091
14180
  for (const { datos } of figuras) posiciones.add(datos.tiempo);
14092
14181
  const fin = finDeLoEscrito(figuras);
@@ -14115,6 +14204,8 @@ function normalizar(indice, cursor) {
14115
14204
  tiempo: cursor.tiempo,
14116
14205
  cuerda: acotar(cursor.cuerda, 1, cuerdas)
14117
14206
  };
14207
+ const pentagrama = acotar(cursor.pentagrama ?? 0, 0, (pista ? indice.pentagramasDe(pista.id) : 1) - 1);
14208
+ if (pentagrama > 0) saneado.pentagrama = pentagrama;
14118
14209
  const posiciones = posicionesEscribibles(indice, saneado);
14119
14210
  saneado.tiempo = mayorMenorOIgual(posiciones, cursor.tiempo);
14120
14211
  return saneado;
@@ -14154,7 +14245,13 @@ function extremos(seleccion) {
14154
14245
  }
14155
14246
  function seleccionDesde(cursor) {
14156
14247
  const punto = { compas: cursor.compas, tiempo: cursor.tiempo };
14157
- return { pistaId: cursor.pistaId, voz: cursor.voz, ancla: punto, foco: { ...punto } };
14248
+ return {
14249
+ pistaId: cursor.pistaId,
14250
+ ...cursor.pentagrama ? { pentagrama: cursor.pentagrama } : {},
14251
+ voz: cursor.voz,
14252
+ ancla: punto,
14253
+ foco: { ...punto }
14254
+ };
14158
14255
  }
14159
14256
  function extenderHasta(seleccion, cursor) {
14160
14257
  return { ...seleccion, foco: { compas: cursor.compas, tiempo: cursor.tiempo } };
@@ -14170,7 +14267,7 @@ function figurasDelPasaje(indice, seleccion) {
14170
14267
  const { desde, hasta } = extremos(seleccion);
14171
14268
  const salida = [];
14172
14269
  for (let compas = desde.compas; compas <= hasta.compas; compas++) {
14173
- const compasId = indice.compasId(seleccion.pistaId, compas);
14270
+ const compasId = indice.compasId(seleccion.pistaId, compas, seleccion.pentagrama);
14174
14271
  for (const figura of indice.figuras(compasId, seleccion.voz)) {
14175
14272
  if (!contiene(seleccion, compas, figura.datos.tiempo)) continue;
14176
14273
  salida.push({
@@ -14193,19 +14290,19 @@ function golpesAlcanzados(indice, cursor, seleccion) {
14193
14290
  };
14194
14291
  if (seleccion?.notas?.length) {
14195
14292
  for (const marcada of seleccion.notas) {
14196
- const compasId2 = indice.compasId(seleccion.pistaId, marcada.compas);
14293
+ const compasId2 = indice.compasId(seleccion.pistaId, marcada.compas, seleccion.pentagrama);
14197
14294
  sumar(indice.figuraEn(compasId2, seleccion.voz, marcada.tiempo), compasId2, seleccion.voz);
14198
14295
  }
14199
14296
  return salida;
14200
14297
  }
14201
14298
  if (seleccion) {
14202
14299
  for (const figura of figurasDelPasaje(indice, seleccion)) {
14203
- const compasId2 = indice.compasId(seleccion.pistaId, figura.compas);
14300
+ const compasId2 = indice.compasId(seleccion.pistaId, figura.compas, seleccion.pentagrama);
14204
14301
  sumar(indice.figuraEn(compasId2, seleccion.voz, figura.tiempo), compasId2, seleccion.voz);
14205
14302
  }
14206
14303
  return salida;
14207
14304
  }
14208
- const compasId = indice.compasId(cursor.pistaId, cursor.compas);
14305
+ const compasId = indice.compasId(cursor.pistaId, cursor.compas, cursor.pentagrama);
14209
14306
  const enElCursor = compasId ? indice.figuraEn(compasId, cursor.voz, cursor.tiempo) : void 0;
14210
14307
  sumar(enElCursor, compasId, cursor.voz);
14211
14308
  return salida;
@@ -14263,7 +14360,7 @@ function destinoDeEscritura(indice, cursor) {
14263
14360
  const maestro = indice.compasMaestro(cursor.compas);
14264
14361
  if (!maestro) return null;
14265
14362
  if (!indice.pista(cursor.pistaId)) return null;
14266
- return { maestro, compasExistente: indice.compasId(cursor.pistaId, cursor.compas) };
14363
+ return { maestro, compasExistente: indice.compasId(cursor.pistaId, cursor.compas, cursor.pentagrama) };
14267
14364
  }
14268
14365
  function escribirEnLaCuerda(documento, indice, cursor, cuerda, resolverTraste, duracion) {
14269
14366
  const destino = destinoDeEscritura(indice, cursor);
@@ -14273,7 +14370,7 @@ function escribirEnLaCuerda(documento, indice, cursor, cuerda, resolverTraste, d
14273
14370
  const notaExistente = figuraExistente ? indice.notaEnCuerda(figuraExistente.id, cuerda) : void 0;
14274
14371
  let resultado = null;
14275
14372
  documento.doc.transact(() => {
14276
- const compasId = compasExistente ?? documento.agregarCompas(normalizarCompas({ pistaId: cursor.pistaId, compasMaestroId: maestro.id }));
14373
+ const compasId = compasExistente ?? documento.agregarCompas(normalizarCompas({ pistaId: cursor.pistaId, compasMaestroId: maestro.id, pentagrama: cursor.pentagrama }));
14277
14374
  let figuraId;
14278
14375
  if (figuraExistente) {
14279
14376
  figuraId = figuraExistente.id;
@@ -14303,7 +14400,7 @@ function escribirEnElGolpe(documento, indice, cursor, duracion, buscarLaQueYaEst
14303
14400
  let salida = null;
14304
14401
  documento.doc.transact(() => {
14305
14402
  const compasId = compasExistente ?? documento.agregarCompas(
14306
- normalizarCompas({ pistaId: cursor.pistaId, compasMaestroId: maestro.id })
14403
+ normalizarCompas({ pistaId: cursor.pistaId, compasMaestroId: maestro.id, pentagrama: cursor.pentagrama })
14307
14404
  );
14308
14405
  let figuraId;
14309
14406
  if (figuraExistente) {
@@ -14342,7 +14439,7 @@ function escribirPercusion(documento, indice, cursor, articulacion, opciones = {
14342
14439
  );
14343
14440
  }
14344
14441
  function borrarAltura(documento, indice, cursor, altura) {
14345
- const compasId = indice.compasId(cursor.pistaId, cursor.compas);
14442
+ const compasId = indice.compasId(cursor.pistaId, cursor.compas, cursor.pentagrama);
14346
14443
  const figura = compasId ? indice.figuraEn(compasId, cursor.voz, cursor.tiempo) : void 0;
14347
14444
  const nota = indice.notaEnAltura(figura?.id, altura);
14348
14445
  if (!nota) return false;
@@ -14350,7 +14447,7 @@ function borrarAltura(documento, indice, cursor, altura) {
14350
14447
  return true;
14351
14448
  }
14352
14449
  function borrarPercusion(documento, indice, cursor, articulacion) {
14353
- const compasId = indice.compasId(cursor.pistaId, cursor.compas);
14450
+ const compasId = indice.compasId(cursor.pistaId, cursor.compas, cursor.pentagrama);
14354
14451
  const figura = compasId ? indice.figuraEn(compasId, cursor.voz, cursor.tiempo) : void 0;
14355
14452
  const nota = indice.notaEnArticulacion(figura?.id, articulacion);
14356
14453
  if (!nota) return false;
@@ -14370,7 +14467,7 @@ function escribirTraste(documento, indice, cursor, cuerda, traste, opciones = {}
14370
14467
  );
14371
14468
  }
14372
14469
  function borrarNotaDeCuerda(documento, indice, cursor, cuerda) {
14373
- const compasId = indice.compasId(cursor.pistaId, cursor.compas);
14470
+ const compasId = indice.compasId(cursor.pistaId, cursor.compas, cursor.pentagrama);
14374
14471
  const figura = compasId ? indice.figuraEn(compasId, cursor.voz, cursor.tiempo) : void 0;
14375
14472
  if (!figura) return false;
14376
14473
  const nota = indice.notaEnCuerda(figura.id, cuerda);
@@ -14390,7 +14487,7 @@ function escribirSilencio(documento, indice, cursor, duracion = DURACION_INICIAL
14390
14487
  const notas = figuraExistente ? [...indice.notas(figuraExistente.id)] : [];
14391
14488
  let id2 = null;
14392
14489
  documento.doc.transact(() => {
14393
- const compasId = compasExistente ?? documento.agregarCompas(normalizarCompas({ pistaId: cursor.pistaId, compasMaestroId: maestro.id }));
14490
+ const compasId = compasExistente ?? documento.agregarCompas(normalizarCompas({ pistaId: cursor.pistaId, compasMaestroId: maestro.id, pentagrama: cursor.pentagrama }));
14394
14491
  if (figuraExistente) {
14395
14492
  id2 = figuraExistente.id;
14396
14493
  for (const nota of notas) documento.notas.delete(nota.id);
@@ -14536,7 +14633,7 @@ function copiar(indice, seleccion) {
14536
14633
  const copiadas = [];
14537
14634
  let recorrido = 0;
14538
14635
  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);
14636
+ const entidad = indice.figuras(indice.compasId(seleccion.pistaId, f.compas, seleccion.pentagrama), seleccion.voz).find((x2) => x2.id === f.id);
14540
14637
  if (!entidad) continue;
14541
14638
  if (i2 > 0) recorrido += figuras[i2 - 1].tics;
14542
14639
  else recorrido = f.compas === desde.compas ? f.tiempo - desde.tiempo : 0;
@@ -14588,7 +14685,7 @@ function pegar(documento, indice, cursor, portapapeles2) {
14588
14685
  }
14589
14686
  const aBorrar = [];
14590
14687
  for (const [compasDelTramo, tramo] of tramos) {
14591
- const compasId = indice.compasId(cursor.pistaId, compasDelTramo);
14688
+ const compasId = indice.compasId(cursor.pistaId, compasDelTramo, cursor.pentagrama);
14592
14689
  for (const figura of indice.figuras(compasId, cursor.voz)) {
14593
14690
  const inicio = figura.datos.tiempo;
14594
14691
  const fin = inicio + ticsDeFigura(figura.datos);
@@ -14599,7 +14696,7 @@ function pegar(documento, indice, cursor, portapapeles2) {
14599
14696
  }
14600
14697
  const compasesDestino = /* @__PURE__ */ new Map();
14601
14698
  for (const compasDelTramo of tramos.keys()) {
14602
- compasesDestino.set(compasDelTramo, indice.compasId(cursor.pistaId, compasDelTramo));
14699
+ compasesDestino.set(compasDelTramo, indice.compasId(cursor.pistaId, compasDelTramo, cursor.pentagrama));
14603
14700
  }
14604
14701
  const maestrosDestino = /* @__PURE__ */ new Map();
14605
14702
  for (const compasDelTramo of tramos.keys()) {
@@ -14618,7 +14715,8 @@ function pegar(documento, indice, cursor, portapapeles2) {
14618
14715
  if (!maestroId) continue;
14619
14716
  compasId = documento.agregarCompas(normalizarCompas({
14620
14717
  pistaId: cursor.pistaId,
14621
- compasMaestroId: maestroId
14718
+ compasMaestroId: maestroId,
14719
+ pentagrama: cursor.pentagrama
14622
14720
  }));
14623
14721
  compasesDestino.set(destino.compas, compasId);
14624
14722
  }
@@ -14641,7 +14739,7 @@ function duplicarUltima(documento, indice, cursor, opciones = {}) {
14641
14739
  let compas = cursor.compas;
14642
14740
  let anterior;
14643
14741
  while (compas >= 0 && !anterior) {
14644
- const compasId = indice.compasId(cursor.pistaId, compas);
14742
+ const compasId = indice.compasId(cursor.pistaId, compas, cursor.pentagrama);
14645
14743
  const figuras = indice.figuras(compasId, cursor.voz);
14646
14744
  const candidatas = compas === cursor.compas ? figuras.filter((f) => f.datos.tiempo < cursor.tiempo) : figuras;
14647
14745
  anterior = candidatas[candidatas.length - 1];
@@ -14701,7 +14799,7 @@ function borrarPasaje(documento, indice, seleccion) {
14701
14799
  notas: indice.notas(f.id).map((n) => n.id)
14702
14800
  }));
14703
14801
  const compases = new Set(
14704
- figuras.map((f) => indice.compasId(seleccion.pistaId, f.compas)).filter(Boolean)
14802
+ figuras.map((f) => indice.compasId(seleccion.pistaId, f.compas, seleccion.pentagrama)).filter(Boolean)
14705
14803
  );
14706
14804
  documento.doc.transact(() => {
14707
14805
  for (const figura of aBorrar) {
@@ -14740,9 +14838,8 @@ function meterCompasEntre(documento, indice, anterior, siguiente) {
14740
14838
  repiteVeces: 0,
14741
14839
  orden: documento.ordenEntre(anterior?.datos.orden ?? null, siguiente?.datos.orden ?? null)
14742
14840
  }));
14743
- for (const pista of indice.pistas) {
14744
- documento.agregarCompas(normalizarCompas({ pistaId: pista.id, compasMaestroId }));
14745
- }
14841
+ const vecino = indice.posicionDeCompas((anterior ?? siguiente).id);
14842
+ for (const pista of indice.pistas) agregarCompasesDeLaPista(documento, indice, pista.id, compasMaestroId, vecino);
14746
14843
  });
14747
14844
  return true;
14748
14845
  }
@@ -14771,7 +14868,7 @@ function agregarCompasesAlFinal(documento, indice, cuantos) {
14771
14868
  })
14772
14869
  );
14773
14870
  for (const pista of pistas) {
14774
- documento.agregarCompas(normalizarCompas({ pistaId: pista.id, compasMaestroId }));
14871
+ agregarCompasesDeLaPista(documento, indice, pista.id, compasMaestroId, indice.cantidadDeCompases - 1);
14775
14872
  }
14776
14873
  ordenAnterior = orden;
14777
14874
  puestos++;
@@ -14784,8 +14881,8 @@ function borrarCompas(documento, indice, compas) {
14784
14881
  if (!maestro || indice.cantidadDeCompases <= 1) return false;
14785
14882
  const compases = [];
14786
14883
  const figuras = [];
14787
- for (const pista of indice.pistas) {
14788
- const compasId = indice.compasId(pista.id, compas);
14884
+ for (const pista of indice.pistas) for (let p = 0; p < indice.pentagramasDe(pista.id); p++) {
14885
+ const compasId = indice.compasId(pista.id, compas, p);
14789
14886
  if (!compasId) continue;
14790
14887
  compases.push(compasId);
14791
14888
  for (const figura of indice.figuras(compasId)) {
@@ -14837,8 +14934,8 @@ function borrarRango(documento, indice, desde, hasta) {
14837
14934
  const maestro = indice.compasMaestro(c);
14838
14935
  if (!maestro) continue;
14839
14936
  maestros.push(maestro.id);
14840
- for (const pista of indice.pistas) {
14841
- const compasId = indice.compasId(pista.id, c);
14937
+ for (const pista of indice.pistas) for (let p = 0; p < indice.pentagramasDe(pista.id); p++) {
14938
+ const compasId = indice.compasId(pista.id, c, p);
14842
14939
  if (!compasId) continue;
14843
14940
  compases.push(compasId);
14844
14941
  for (const figura of indice.figuras(compasId)) {
@@ -14862,6 +14959,17 @@ function borrarCompasesDesde(documento, indice, compas) {
14862
14959
  function borrarCompasesHasta(documento, indice, compas) {
14863
14960
  return borrarRango(documento, indice, 0, compas);
14864
14961
  }
14962
+ function agregarCompasesDeLaPista(documento, indice, pistaId, compasMaestroId, vecino) {
14963
+ for (let pentagrama = 0; pentagrama < indice.pentagramasDe(pistaId); pentagrama++) {
14964
+ const delVecino = vecino === void 0 ? void 0 : indice.compas(indice.compasId(pistaId, vecino, pentagrama));
14965
+ documento.agregarCompas(normalizarCompas({
14966
+ pistaId,
14967
+ compasMaestroId,
14968
+ pentagrama,
14969
+ ...delVecino ? { clave: delVecino.clave, claveOctava: delVecino.claveOctava } : {}
14970
+ }));
14971
+ }
14972
+ }
14865
14973
  var init_pasajes = __esm({
14866
14974
  "packages/editor/src/pasajes.ts"() {
14867
14975
  init_src2();
@@ -14887,7 +14995,7 @@ function ponerSilabaEnElGolpe(documento, indice, cursor, texto4, marcas) {
14887
14995
  }
14888
14996
  documento.doc.transact(() => {
14889
14997
  const compasId = compasExistente ?? documento.agregarCompas(
14890
- normalizarCompas({ pistaId: cursor.pistaId, compasMaestroId: maestro.id })
14998
+ normalizarCompas({ pistaId: cursor.pistaId, compasMaestroId: maestro.id, pentagrama: cursor.pentagrama })
14891
14999
  );
14892
15000
  const id2 = figura?.id ?? documento.agregarFigura({
14893
15001
  ...figuraNueva(compasId, cursor, DURACION_INICIAL),
@@ -15220,7 +15328,7 @@ function notasAlcanzadas(indice, cursor, seleccion) {
15220
15328
  if (seleccion?.notas?.length) {
15221
15329
  const salida = [];
15222
15330
  for (const marcada of seleccion.notas) {
15223
- const compasId2 = indice.compasId(seleccion.pistaId, marcada.compas);
15331
+ const compasId2 = indice.compasId(seleccion.pistaId, marcada.compas, seleccion.pentagrama);
15224
15332
  const figura2 = indice.figuraEn(compasId2, seleccion.voz, marcada.tiempo);
15225
15333
  const nota2 = indice.notaEnCuerda(figura2?.id, marcada.cuerda);
15226
15334
  if (nota2) salida.push(nota2);
@@ -15234,7 +15342,7 @@ function notasAlcanzadas(indice, cursor, seleccion) {
15234
15342
  }
15235
15343
  return salida;
15236
15344
  }
15237
- const compasId = indice.compasId(cursor.pistaId, cursor.compas);
15345
+ const compasId = indice.compasId(cursor.pistaId, cursor.compas, cursor.pentagrama);
15238
15346
  const figura = compasId ? indice.figuraEn(compasId, cursor.voz, cursor.tiempo) : void 0;
15239
15347
  if (!figura) return [];
15240
15348
  const nota = indice.notaEnCuerda(figura.id, cursor.cuerda);
@@ -20193,7 +20301,7 @@ function acordeDeNotas(notas, afinacion) {
20193
20301
  };
20194
20302
  }
20195
20303
  function acordeEnElCursor(indice, cursor) {
20196
- const compasId = indice.compasId(cursor.pistaId, cursor.compas);
20304
+ const compasId = indice.compasId(cursor.pistaId, cursor.compas, cursor.pentagrama);
20197
20305
  const figura = compasId ? indice.figuraEn(compasId, cursor.voz, cursor.tiempo) : void 0;
20198
20306
  if (!figura) return null;
20199
20307
  const afinacion = indice.pista(cursor.pistaId)?.datos.afinacion;
@@ -20295,7 +20403,7 @@ function ponerAcorde(documento, indice, cursor, nombre, duracion = DURACION_INIC
20295
20403
  const yaTieneNotas = figura ? indice.notas(figura.id).length > 0 : false;
20296
20404
  if (sinNombre && (yaTieneNotas || forma.length === 0)) return null;
20297
20405
  documento.doc.transact(() => {
20298
- const compasId = compasExistente ?? documento.agregarCompas(normalizarCompas({ pistaId: cursor.pistaId, compasMaestroId: maestro.id }));
20406
+ const compasId = compasExistente ?? documento.agregarCompas(normalizarCompas({ pistaId: cursor.pistaId, compasMaestroId: maestro.id, pentagrama: cursor.pentagrama }));
20299
20407
  const id2 = figura?.id ?? documento.agregarFigura({ ...figuraNueva(compasId, cursor, duracion), esSilencio: true });
20300
20408
  const mapa = documento.figuras.get(id2);
20301
20409
  if (mapa && !sinNombre) escribirConMarcas(mapa, "acorde", nombre ?? "", marcas, { recortar: true });
@@ -20540,8 +20648,8 @@ var init_instrumentos = __esm({
20540
20648
  programaMidi: PROGRAMAS.guitarraNylon
20541
20649
  },
20542
20650
  // ── 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 },
20651
+ { clave: "piano", nombre: "Piano", nombreCorto: "pno", grupo: "Teclados", tipo: "altura", afinacion: [], programaMidi: PROGRAMAS.piano, pentagramas: 2 },
20652
+ { clave: "piano-electrico", nombre: "Piano el\xE9ctrico", nombreCorto: "e.pno", grupo: "Teclados", tipo: "altura", afinacion: [], programaMidi: PROGRAMAS.pianoElectrico, pentagramas: 2 },
20545
20653
  { clave: "organo", nombre: "\xD3rgano", nombreCorto: "org", grupo: "Teclados", tipo: "altura", afinacion: [], programaMidi: PROGRAMAS.organo },
20546
20654
  // ── Vientos ──
20547
20655
  { clave: "trompeta", nombre: "Trompeta", nombreCorto: "tpt", grupo: "Vientos", tipo: "altura", afinacion: [], programaMidi: PROGRAMAS.trompeta },
@@ -87317,312 +87425,6 @@ var init_alphaTab = __esm({
87317
87425
  }
87318
87426
  });
87319
87427
 
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
87428
  // node_modules/fflate/esm/index.mjs
87627
87429
  import { createRequire } from "module";
87628
87430
  function deflateSync(data, opts) {
@@ -88604,12 +88406,766 @@ var init_esm = __esm({
88604
88406
  }
88605
88407
  });
88606
88408
 
88409
+ // packages/io/src/musicxmlEntrada.ts
88410
+ function textoMusicXml(bytes) {
88411
+ if (bytes.length > 4 && bytes[0] === 80 && bytes[1] === 75) {
88412
+ let archivos;
88413
+ try {
88414
+ archivos = unzipSync(bytes);
88415
+ } catch {
88416
+ return null;
88417
+ }
88418
+ const contenedor = archivos["META-INF/container.xml"];
88419
+ if (!contenedor) return null;
88420
+ const ruta = /<rootfile\b[^>]*full-path="([^"]+)"/.exec(strFromU8(contenedor))?.[1];
88421
+ const raiz = ruta ? archivos[ruta] : void 0;
88422
+ return raiz ? decodificar(raiz) : null;
88423
+ }
88424
+ const texto4 = decodificar(bytes.subarray(0, Math.min(bytes.length, 4096)));
88425
+ if (!/<score-(partwise|timewise)\b/.test(texto4) && !/<!DOCTYPE\s+score-/.test(texto4)) return null;
88426
+ return decodificar(bytes);
88427
+ }
88428
+ function decodificar(bytes) {
88429
+ if (bytes[0] === 255 && bytes[1] === 254) return new TextDecoder("utf-16le").decode(bytes);
88430
+ if (bytes[0] === 254 && bytes[1] === 255) return new TextDecoder("utf-16be").decode(bytes);
88431
+ return new TextDecoder("utf-8").decode(bytes);
88432
+ }
88433
+ function prepararMusicXml(xml) {
88434
+ const correcciones = [];
88435
+ let atributosMovidos = 0;
88436
+ let acordesSeparados = 0;
88437
+ let saltosMovidos = 0;
88438
+ let salida = xml.replace(/<part\b[^>]*>[\s\S]*?<\/part>/g, (parteOriginal) => {
88439
+ const movidos = moverAtributosDeFinDeCompas(parteOriginal);
88440
+ atributosMovidos += movidos.cuantos;
88441
+ const separados = separarAcordesEntrePentagramas(movidos.texto);
88442
+ acordesSeparados += separados.cuantos;
88443
+ const saltos = sacarSaltosDeLaIndicacion(separados.texto);
88444
+ saltosMovidos += saltos.cuantos;
88445
+ const { texto: texto4, cambio } = compactarVoces(saltos.texto);
88446
+ if (cambio) correcciones.push(cambio);
88447
+ return texto4;
88448
+ });
88449
+ if (atributosMovidos) {
88450
+ correcciones.push(
88451
+ `${atributosMovidos} cambios de clave, armadura o comp\xE1s escritos antes de la barra pasaron al comp\xE1s siguiente.`
88452
+ );
88453
+ }
88454
+ if (acordesSeparados) {
88455
+ correcciones.push(`${acordesSeparados} notas de acordes repartidos entre los dos pentagramas se pusieron en el suyo.`);
88456
+ }
88457
+ if (saltosMovidos) correcciones.push(`${saltosMovidos} saltos (D.C., D.S., Coda, Fine, Segno) se leyeron de su indicaci\xF3n.`);
88458
+ let juntados = 0;
88459
+ salida = salida.replace(/<direction\b[^>]*>[\s\S]*?<\/direction>/g, (dir) => {
88460
+ const palabras = [...dir.matchAll(/<words\b[^>]*>([\s\S]*?)<\/words>/g)];
88461
+ if (palabras.length < 2) return dir;
88462
+ juntados++;
88463
+ const todo = palabras.map((p) => p[1].trim()).filter(Boolean).join("\n");
88464
+ let primero = true;
88465
+ return dir.replace(/<words\b([^>]*)>[\s\S]*?<\/words>/g, (_m, attrs) => {
88466
+ if (!primero) return "";
88467
+ primero = false;
88468
+ return `<words${attrs}>${todo}</words>`;
88469
+ });
88470
+ });
88471
+ if (juntados) correcciones.push(`${juntados} indicaciones de texto en varios renglones se juntaron en una.`);
88472
+ let tempos = 0;
88473
+ salida = salida.replace(/<metronome\b[^>]*>[\s\S]*?<\/metronome>/g, (met) => {
88474
+ const unidad = /<beat-unit>\s*([\w-]+)\s*<\/beat-unit>/.exec(met)?.[1];
88475
+ const porMinuto = /<per-minute>\s*([\d.]+)\s*<\/per-minute>/.exec(met)?.[1];
88476
+ const negras = unidad ? NEGRAS_POR_FIGURA[unidad] : void 0;
88477
+ if (!unidad || !porMinuto || negras === void 0 || /<beat-unit>[\s\S]*<beat-unit>/.test(met)) return met;
88478
+ const puntillos = (met.match(/<beat-unit-dot\s*\/>/g) ?? []).length;
88479
+ const factor = negras * (puntillos === 0 ? 1 : puntillos === 1 ? 1.5 : 1.75);
88480
+ if (factor === 1) return met;
88481
+ tempos++;
88482
+ const bpm = Math.round(Number.parseFloat(porMinuto) * factor * 100) / 100;
88483
+ 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>`);
88484
+ });
88485
+ if (tempos) correcciones.push(`${tempos} indicaciones de tempo se pasaron a negras (mismo pulso).`);
88486
+ return { xml: salida, bytes: new TextEncoder().encode(salida), correcciones };
88487
+ }
88488
+ function compasesDe(parte) {
88489
+ return [...parte.matchAll(/(<measure\b[^>]*>)([\s\S]*?)<\/measure>/g)].map((m) => ({
88490
+ inicio: m.index,
88491
+ fin: m.index + m[0].length,
88492
+ apertura: m[1],
88493
+ contenido: m[2]
88494
+ }));
88495
+ }
88496
+ function rearmar(parte, compases, nuevos) {
88497
+ let salida = "";
88498
+ let cursor = 0;
88499
+ compases.forEach((c, i2) => {
88500
+ salida += parte.slice(cursor, c.inicio) + c.apertura + nuevos[i2] + "</measure>";
88501
+ cursor = c.fin;
88502
+ });
88503
+ return salida + parte.slice(cursor);
88504
+ }
88505
+ function moverAtributosDeFinDeCompas(parte) {
88506
+ const compases = compasesDe(parte);
88507
+ let cuantos = 0;
88508
+ let arrastre = "";
88509
+ const nuevos = compases.map((c) => {
88510
+ let contenido = c.contenido;
88511
+ const primeraNota = contenido.search(/<note\b/);
88512
+ if (primeraNota >= 0) {
88513
+ let llevar = "";
88514
+ contenido = contenido.slice(0, primeraNota) + contenido.slice(primeraNota).replace(/<attributes\b[^>]*>([\s\S]*?)<\/attributes>/g, (bloque, adentro) => {
88515
+ const hijos = adentro.match(HIJO_QUE_SE_MUEVE);
88516
+ if (!hijos) return bloque;
88517
+ cuantos += hijos.length;
88518
+ llevar += hijos.join("");
88519
+ const resto = adentro.replace(HIJO_QUE_SE_MUEVE, "");
88520
+ return resto.trim() ? `<attributes>${resto}</attributes>` : "";
88521
+ });
88522
+ const entra2 = arrastre;
88523
+ arrastre = llevar;
88524
+ return (entra2 ? `<attributes>${entra2}</attributes>` : "") + contenido;
88525
+ }
88526
+ const entra = arrastre;
88527
+ arrastre = "";
88528
+ return (entra ? `<attributes>${entra}</attributes>` : "") + contenido;
88529
+ });
88530
+ return cuantos ? { texto: rearmar(parte, compases, nuevos), cuantos } : { texto: parte, cuantos: 0 };
88531
+ }
88532
+ function separarAcordesEntrePentagramas(parte) {
88533
+ const compases = compasesDe(parte);
88534
+ let cuantos = 0;
88535
+ const nuevos = compases.map((c) => {
88536
+ const notas = [...c.contenido.matchAll(/<note\b[\s\S]*?<\/note>/g)];
88537
+ if (notas.length < 2) return c.contenido;
88538
+ let salida = "";
88539
+ let cursor = 0;
88540
+ let i2 = 0;
88541
+ while (i2 < notas.length) {
88542
+ const grupo = [notas[i2]];
88543
+ let j = i2 + 1;
88544
+ while (j < notas.length) {
88545
+ const anterior = notas[j - 1];
88546
+ const entre = c.contenido.slice(anterior.index + anterior[0].length, notas[j].index);
88547
+ if (entre.trim() || !/<chord\s*\/>/.test(notas[j][0])) break;
88548
+ grupo.push(notas[j]);
88549
+ j++;
88550
+ }
88551
+ i2 = j;
88552
+ const pent = (n) => entero(n[0], /<staff>\s*(\d+)\s*<\/staff>/) ?? 1;
88553
+ const cabeza = grupo[0];
88554
+ const pentDeCabeza = pent(cabeza);
88555
+ const ajenas = grupo.filter((n) => pent(n) !== pentDeCabeza);
88556
+ const durCabeza = entero(cabeza[0], /<duration>\s*(\d+)\s*<\/duration>/);
88557
+ if (ajenas.length === 0 || /<chord\s*\/>/.test(cabeza[0]) || grupo.some((n) => /<grace\b|<cue\s*\/>/.test(n[0])) || durCabeza === null) {
88558
+ continue;
88559
+ }
88560
+ cuantos += ajenas.length;
88561
+ const propias = grupo.filter((n) => pent(n) === pentDeCabeza).map((n) => n[0]);
88562
+ let texto4 = propias.join("");
88563
+ const porPentagrama = /* @__PURE__ */ new Map();
88564
+ for (const n of ajenas) porPentagrama.set(pent(n), [...porPentagrama.get(pent(n)) ?? [], n[0]]);
88565
+ for (const notasDelPent of porPentagrama.values()) {
88566
+ const primera = notasDelPent[0].replace(/<chord\s*\/>\s*/, "");
88567
+ const durPrimera = entero(primera, /<duration>\s*(\d+)\s*<\/duration>/) ?? durCabeza;
88568
+ texto4 += `<backup><duration>${durCabeza}</duration></backup>` + primera + notasDelPent.slice(1).join("");
88569
+ const delta = durCabeza - durPrimera;
88570
+ if (delta > 0) texto4 += `<forward><duration>${delta}</duration></forward>`;
88571
+ else if (delta < 0) texto4 += `<backup><duration>${-delta}</duration></backup>`;
88572
+ }
88573
+ const ultimo = grupo[grupo.length - 1];
88574
+ salida += c.contenido.slice(cursor, cabeza.index) + texto4;
88575
+ cursor = ultimo.index + ultimo[0].length;
88576
+ }
88577
+ return salida + c.contenido.slice(cursor);
88578
+ });
88579
+ return cuantos ? { texto: rearmar(parte, compases, nuevos), cuantos } : { texto: parte, cuantos: 0 };
88580
+ }
88581
+ function sacarSaltosDeLaIndicacion(parte) {
88582
+ let cuantos = 0;
88583
+ const texto4 = parte.replace(/<direction\b[^>]*>[\s\S]*?<\/direction>/g, (dir, desde, todo) => {
88584
+ const sonido = /<sound\b([^>]*?)\/?>/.exec(dir)?.[1];
88585
+ if (!sonido) return dir;
88586
+ const atributos = ATRIBUTOS_DE_SALTO.map((a) => new RegExp(`\\b${a}="([^"]*)"`).exec(sonido)?.[0]).filter((a) => a !== void 0);
88587
+ if (atributos.length === 0) return dir;
88588
+ const copia = `<sound ${atributos.join(" ")}/>`;
88589
+ if (todo.slice(desde + dir.length).trimStart().startsWith(copia)) return dir;
88590
+ cuantos++;
88591
+ return dir + copia;
88592
+ });
88593
+ return { texto: texto4, cuantos };
88594
+ }
88595
+ function compactarVoces(parte) {
88596
+ const porPentagrama = /* @__PURE__ */ new Map();
88597
+ const pentagramaDeVoz = /* @__PURE__ */ new Map();
88598
+ for (const m of parte.matchAll(/<note\b[\s\S]*?<\/note>/g)) {
88599
+ const voz = entero(m[0], /<voice>\s*(\d+)\s*<\/voice>/);
88600
+ if (voz === null) continue;
88601
+ const pent = entero(m[0], /<staff>\s*(\d+)\s*<\/staff>/) ?? 1;
88602
+ const lista2 = porPentagrama.get(pent) ?? [];
88603
+ if (!lista2.includes(voz)) lista2.push(voz);
88604
+ porPentagrama.set(pent, lista2);
88605
+ if (!pentagramaDeVoz.has(voz)) pentagramaDeVoz.set(voz, pent);
88606
+ }
88607
+ const nueva = /* @__PURE__ */ new Map();
88608
+ let hayCambio = false;
88609
+ for (const [pent, voces] of porPentagrama) {
88610
+ ;
88611
+ [...voces].sort((a, b) => a - b).forEach((voz, i2) => {
88612
+ nueva.set(`${pent}|${voz}`, i2 + 1);
88613
+ if (voz !== i2 + 1) hayCambio = true;
88614
+ });
88615
+ }
88616
+ if (!hayCambio) return { texto: parte, cambio: null };
88617
+ const renumerar = (bloque, pentPorOmision) => {
88618
+ const voz = entero(bloque, /<voice>\s*(\d+)\s*<\/voice>/);
88619
+ if (voz === null) return bloque;
88620
+ const pent = entero(bloque, /<staff>\s*(\d+)\s*<\/staff>/) ?? pentPorOmision(voz);
88621
+ const n = nueva.get(`${pent}|${voz}`);
88622
+ return n === void 0 ? bloque : bloque.replace(/<voice>\s*\d+\s*<\/voice>/, `<voice>${n}</voice>`);
88623
+ };
88624
+ 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));
88625
+ const id2 = /<part\b[^>]*\bid="([^"]*)"/.exec(parte)?.[1] ?? "?";
88626
+ const detalle = [...porPentagrama].map(([p, vs]) => `pentagrama ${p}: voces ${[...vs].sort((a, b) => a - b).join(", ")}`).join("; ");
88627
+ return { texto: texto4, cambio: `Parte ${id2}: las voces se renumeraron por pentagrama (${detalle}).` };
88628
+ }
88629
+ function leerOrtografia(xml) {
88630
+ return leerDelArchivo(xml).ortografia;
88631
+ }
88632
+ function leerDelArchivo(xml) {
88633
+ const ortografia = /* @__PURE__ */ new Map();
88634
+ const bajos = /* @__PURE__ */ new Map();
88635
+ let iParte = -1;
88636
+ for (const parte of xml.matchAll(/<part\b[^>]*>([\s\S]*?)<\/part>/g)) {
88637
+ iParte++;
88638
+ let divisiones = 1;
88639
+ let transposicion = 0;
88640
+ let iCompas = -1;
88641
+ for (const compas of parte[1].matchAll(/<measure\b[^>]*>([\s\S]*?)<\/measure>/g)) {
88642
+ iCompas++;
88643
+ let tic = 0;
88644
+ let ticAnterior = 0;
88645
+ let bajoPendiente = null;
88646
+ for (const el of compas[1].matchAll(/<(note|backup|forward|attributes|harmony)\b[\s\S]*?<\/\1>/g)) {
88647
+ const bloque = el[0];
88648
+ const tipo = el[1];
88649
+ if (tipo === "attributes") {
88650
+ divisiones = entero(bloque, /<divisions>\s*(\d+)\s*<\/divisions>/) ?? divisiones;
88651
+ const transponer2 = /<transpose\b[^>]*>([\s\S]*?)<\/transpose>/.exec(bloque)?.[1];
88652
+ if (transponer2 !== void 0) {
88653
+ transposicion = (entero(transponer2, /<chromatic>\s*(-?\d+)\s*<\/chromatic>/) ?? 0) + 12 * (entero(transponer2, /<octave-change>\s*(-?\d+)\s*<\/octave-change>/) ?? 0);
88654
+ }
88655
+ continue;
88656
+ }
88657
+ if (tipo === "harmony") {
88658
+ const bajo = /<bass>([\s\S]*?)<\/bass>/.exec(bloque)?.[1];
88659
+ const paso2 = bajo ? /<bass-step>\s*([A-G])\s*<\/bass-step>/.exec(bajo)?.[1] : void 0;
88660
+ if (bajoPendiente === null) {
88661
+ const alter2 = bajo ? entero(bajo, /<bass-alter>\s*(-?\d+)\s*<\/bass-alter>/) ?? 0 : 0;
88662
+ bajoPendiente = paso2 ? `/${paso2}${alter2 === -2 ? "bb" : alter2 === -1 ? "b" : alter2 === 1 ? "#" : alter2 === 2 ? "x" : ""}` : "";
88663
+ }
88664
+ continue;
88665
+ }
88666
+ const dur = entero(bloque, /<duration>\s*(\d+)\s*<\/duration>/) ?? 0;
88667
+ if (tipo === "backup") {
88668
+ tic -= dur;
88669
+ continue;
88670
+ }
88671
+ if (tipo === "forward") {
88672
+ tic += dur;
88673
+ continue;
88674
+ }
88675
+ if (/<grace\b/.test(bloque) || /<cue\s*\/>/.test(bloque)) continue;
88676
+ const acorde = /<chord\s*\/>/.test(bloque);
88677
+ const inicio = acorde ? ticAnterior : tic;
88678
+ if (!acorde) {
88679
+ ticAnterior = tic;
88680
+ tic += dur;
88681
+ }
88682
+ const pent = (entero(bloque, /<staff>\s*(\d+)\s*<\/staff>/) ?? 1) - 1;
88683
+ const ticAlphaTab = Math.round(inicio * TICS_POR_NEGRA2 / divisiones);
88684
+ if (!acorde && bajoPendiente !== null) {
88685
+ if (bajoPendiente) bajos.set(`${iParte}|${pent}|${iCompas}|${ticAlphaTab}`, bajoPendiente);
88686
+ bajoPendiente = null;
88687
+ }
88688
+ const altura = /<pitch>([\s\S]*?)<\/pitch>/.exec(bloque)?.[1];
88689
+ if (!altura) continue;
88690
+ const paso = /<step>\s*([A-G])\s*<\/step>/.exec(altura)?.[1];
88691
+ const octava = entero(altura, /<octave>\s*(-?\d+)\s*<\/octave>/);
88692
+ const alterTexto = /<alter>\s*(-?[\d.]+)\s*<\/alter>/.exec(altura)?.[1];
88693
+ const alter = alterTexto === void 0 ? 0 : Number.parseFloat(alterTexto);
88694
+ if (!paso || octava === null || !Number.isInteger(alter)) continue;
88695
+ const modo = MODO_POR_ALTER.get(alter);
88696
+ if (modo === void 0) continue;
88697
+ const midi = (octava + 1) * 12 + SEMITONOS[paso] + alter + transposicion;
88698
+ const clave = `${iParte}|${pent}|${iCompas}|${ticAlphaTab}|${midi}`;
88699
+ if (!ortografia.has(clave)) ortografia.set(clave, modo);
88700
+ }
88701
+ }
88702
+ }
88703
+ return { ortografia, bajos };
88704
+ }
88705
+ var MODO_DE_ALTERACION, MODO_POR_ALTER, SEMITONOS, TICS_POR_NEGRA2, entero, HIJO_QUE_SE_MUEVE, ATRIBUTOS_DE_SALTO, NEGRAS_POR_FIGURA;
88706
+ var init_musicxmlEntrada = __esm({
88707
+ "packages/io/src/musicxmlEntrada.ts"() {
88708
+ init_esm();
88709
+ MODO_DE_ALTERACION = {
88710
+ porDefecto: 0,
88711
+ natural: 2,
88712
+ sostenido: 3,
88713
+ dobleSostenido: 4,
88714
+ bemol: 5,
88715
+ dobleBemol: 6
88716
+ };
88717
+ MODO_POR_ALTER = /* @__PURE__ */ new Map([
88718
+ [-2, MODO_DE_ALTERACION.dobleBemol],
88719
+ [-1, MODO_DE_ALTERACION.bemol],
88720
+ [0, MODO_DE_ALTERACION.natural],
88721
+ [1, MODO_DE_ALTERACION.sostenido],
88722
+ [2, MODO_DE_ALTERACION.dobleSostenido]
88723
+ ]);
88724
+ SEMITONOS = { C: 0, D: 2, E: 4, F: 5, G: 7, A: 9, B: 11 };
88725
+ TICS_POR_NEGRA2 = 960;
88726
+ entero = (texto4, re) => {
88727
+ const m = re.exec(texto4);
88728
+ return m ? Number.parseInt(m[1], 10) : null;
88729
+ };
88730
+ HIJO_QUE_SE_MUEVE = /<(clef|key|time|transpose|staff-details)\b[^>]*?(?:\/>|>[\s\S]*?<\/\1>)/g;
88731
+ ATRIBUTOS_DE_SALTO = ["coda", "tocoda", "dacapo", "dalsegno", "fine", "segno"];
88732
+ NEGRAS_POR_FIGURA = {
88733
+ breve: 8,
88734
+ whole: 4,
88735
+ half: 2,
88736
+ quarter: 1,
88737
+ eighth: 0.5,
88738
+ "16th": 0.25,
88739
+ "32nd": 0.125
88740
+ };
88741
+ }
88742
+ });
88743
+
88744
+ // packages/io/src/importarGp.ts
88745
+ function importarGp(bytes, opciones = {}) {
88746
+ const xml = textoMusicXml(bytes);
88747
+ if (xml === null) {
88748
+ const score2 = _barrel_exports$1.ScoreLoader.loadScoreFromBytes(bytes);
88749
+ return importarScore(score2, opciones);
88750
+ }
88751
+ const preparado = prepararMusicXml(xml);
88752
+ const score = _barrel_exports$1.ScoreLoader.loadScoreFromBytes(preparado.bytes);
88753
+ const leido = leerDelArchivo(preparado.xml);
88754
+ const resultado = importarScore(score, opciones, { ortografia: leido.ortografia, bajos: leido.bajos });
88755
+ resultado.avisos.push(...preparado.correcciones);
88756
+ return resultado;
88757
+ }
88758
+ function prepararParaAlphaTab(bytes) {
88759
+ const xml = textoMusicXml(bytes);
88760
+ return xml === null ? bytes : prepararMusicXml(xml).bytes;
88761
+ }
88762
+ function importarScore(score, opciones = {}, datos = {}) {
88763
+ const avisos = [];
88764
+ const documento = crearDocumento({ clienteId: opciones.clienteId });
88765
+ documento.ponerCabecera({
88766
+ titulo: score.title ?? "",
88767
+ artista: score.artist ?? "",
88768
+ album: score.album ?? "",
88769
+ tempo: score.tempo ?? 0,
88770
+ mostrarMatices: !score.stylesheet.hideDynamics
88771
+ });
88772
+ avisos.push(
88773
+ '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.'
88774
+ );
88775
+ if (opciones.autoria) {
88776
+ documento.ponerAutoria(opciones.autoria);
88777
+ } else {
88778
+ documento.ponerAutoria({
88779
+ escritaPor: "",
88780
+ origen: "transcripcion",
88781
+ obraTitulo: score.title ?? "",
88782
+ obraAutores: score.artist ?? "",
88783
+ obraEditora: ""
88784
+ });
88785
+ avisos.push(
88786
+ "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."
88787
+ );
88788
+ }
88789
+ const idsDeCompasMaestro = score.masterBars.map(
88790
+ (maestro) => documento.agregarCompasMaestro(normalizarCompasMaestro({
88791
+ numerador: maestro.timeSignatureNumerator,
88792
+ denominador: maestro.timeSignatureDenominator,
88793
+ tonalidad: numeroDeTonalidad(maestro.keySignature),
88794
+ // ⚠️ El ensayo de un MusicXML (`<rehearsal>A</rehearsal>`) llena sólo `section.marker`;
88795
+ // `text` queda vacío y las letras A, B, C… se perdían todas. Un `.gp` trae las dos y
88796
+ // manda el texto, como siempre.
88797
+ seccion: maestro.section?.text || maestro.section?.marker || "",
88798
+ // Solo interesa el cambio de tempo que arranca en este compás; los que caen
88799
+ // en el medio son F02 y todavía no tienen dónde ir.
88800
+ tempo: maestro.tempoAutomations?.[0]?.value ?? null,
88801
+ repiteDesdeAca: maestro.isRepeatStart,
88802
+ repiteVeces: maestro.repeatCount,
88803
+ // ⚠️ Novena pérdida silenciosa de la misma familia: 2 de los 15 `.gp` de Daniel
88804
+ // declaran una anacruza y el modelo la descartaba.
88805
+ esAnacruza: maestro.isAnacrusis,
88806
+ // ── Los signos de compás de Guitar Pro ────────────────────────────────
88807
+ casillas: maestro.alternateEndings,
88808
+ dobleBarra: maestro.isDoubleBar,
88809
+ tiempoLibre: maestro.isFreeTime,
88810
+ swing: maestro.tripletFeel,
88811
+ // ⚠️ `simileMark` es del compás DE LA PISTA en alphaTab (`Bar.simileMark`), no del
88812
+ // maestro. Se lee más abajo, al recorrer los compases de cada pentagrama, y se
88813
+ // escribe acá arriba porque en el modelo la repetición de compás es de la obra:
88814
+ // un «igual que el anterior» que valiera para la guitarra y no para el bajo
88815
+ // dejaría los dos instrumentos diciendo cosas distintas sobre el mismo compás.
88816
+ repiteAnterior: 0,
88817
+ // ⚠️ `directions` es un `Set` o `null`, no una lista. Un `?? []` sobre un Set daría
88818
+ // el Set, y `.map` no existe ahí: hay que expandirlo.
88819
+ //
88820
+ // ⚠️⚠️ Y se guarda el NOMBRE, no el número. `String(d)` daba `"1"` —el valor del enum
88821
+ // convertido a texto— y la proyección buscaba `Direction["1"]`, que en un enum con
88822
+ // mapeo inverso devuelve el *nombre* y no un número: la guarda lo descartaba y **las
88823
+ // direcciones se perdían enteras, en silencio**. Lo cazó la prueba de ida y vuelta
88824
+ // con signos, que es exactamente para lo que existe.
88825
+ //
88826
+ // ★ El nombre y no el número, además, porque acá es una LISTA y se lee: un
88827
+ // `["JumpDalSegnoAlCoda"]` en el documento dice algo; un `[10]` no.
88828
+ direcciones: maestro.directions ? [...maestro.directions].map(
88829
+ (d) => _barrel_exports$4.Direction[d] ?? String(d)
88830
+ ) : []
88831
+ }))
88832
+ );
88833
+ const saltos = /* @__PURE__ */ new Set();
88834
+ for (const pista of score.tracks) for (const i2 of pista.lineBreaks ?? []) saltos.add(i2);
88835
+ for (const i2 of saltos) {
88836
+ const id2 = idsDeCompasMaestro[i2];
88837
+ if (id2 !== void 0 && i2 > 0) documento.ponerSaltoDeRenglon(id2, true);
88838
+ }
88839
+ const letrasDobles = { cuantas: 0 };
88840
+ const tipoDelPentagrama = (p) => p.isPercussion ? "percusion" : p.tuning.length === 0 ? "altura" : "trastes";
88841
+ for (const pista of score.tracks) {
88842
+ if (pista.staves.length === 0) {
88843
+ avisos.push(`La pista "${pista.name}" no tiene pentagramas y se salte\xF3 entera.`);
88844
+ continue;
88845
+ }
88846
+ const unInstrumento = pista.staves.every((p) => tipoDelPentagrama(p) === tipoDelPentagrama(pista.staves[0]));
88847
+ let idDelInstrumento = null;
88848
+ for (const [numeroDePentagrama, pentagrama] of pista.staves.entries()) {
88849
+ const variosPentagramas = pista.staves.length > 1 && !unInstrumento;
88850
+ const nombreDePista = variosPentagramas ? `${pista.name ?? ""} (${numeroDePentagrama + 1})` : pista.name ?? "";
88851
+ const nombreCortoDePista = variosPentagramas ? `${pista.shortName ?? ""} ${numeroDePentagrama + 1}`.trim() : pista.shortName ?? "";
88852
+ const pentagramaEnLaPista = unInstrumento ? numeroDePentagrama : 0;
88853
+ const tipo = tipoDelPentagrama(pentagrama);
88854
+ const idPista = unInstrumento && idDelInstrumento || documento.agregarPista({
88855
+ tipo,
88856
+ nombre: nombreDePista,
88857
+ nombreCorto: nombreCortoDePista,
88858
+ // ⚠️ Conversión 1: alphaTab la guarda de la aguda a la grave.
88859
+ afinacion: [...pentagrama.tuning].reverse(),
88860
+ capo: pentagrama.capo ?? 0,
88861
+ programaMidi: pista.playbackInfo?.program ?? 0,
88862
+ // ⚠️ SE ESTABAN PERDIENDO. El `.gp` los trae y el modelo no los guardaba, así que
88863
+ // importar una canción y volver a exportarla devolvía todas las pistas al volumen y
88864
+ // al centro por defecto. Séptima pérdida silenciosa de la misma familia — y ésta no
88865
+ // la destapó la comparación de píxeles, porque la mezcla no se dibuja: se oye.
88866
+ volumen: pista.playbackInfo?.volume ?? 16,
88867
+ balance: pista.playbackInfo?.balance ?? 8,
88868
+ ...unInstrumento && pista.staves.length > 1 ? { pentagramas: pista.staves.length } : {},
88869
+ // ⛔ La transposición de lectura (`<transpose>` de un clarinete o un saxo) se perdía: el
88870
+ // instrumento se dibujaba en altura real en vez de como se lee (2026-11-09).
88871
+ ...pentagrama.displayTranspositionPitch ? { transposicion: pentagrama.displayTranspositionPitch } : {}
88872
+ });
88873
+ idDelInstrumento = idPista;
88874
+ for (const [indice, compasDeAlphaTab] of pentagrama.bars.entries()) {
88875
+ const maestroDelCompas = score.masterBars[indice];
88876
+ const idCompasMaestro = idsDeCompasMaestro[indice];
88877
+ if (idCompasMaestro === void 0) {
88878
+ avisos.push(
88879
+ `La pista "${pista.name}" tiene un comp\xE1s ${indice + 1} que no existe en la partitura (hay ${idsDeCompasMaestro.length} compases maestros). Se salte\xF3.`
88880
+ );
88881
+ continue;
88882
+ }
88883
+ const idCompas = documento.agregarCompas(normalizarCompas({
88884
+ pistaId: idPista,
88885
+ compasMaestroId: idCompasMaestro,
88886
+ // La clave es de la pista: el bajo lleva fa y la guitarra sol en el mismo compás.
88887
+ clave: compasDeAlphaTab.clef,
88888
+ claveOctava: compasDeAlphaTab.clefOttava,
88889
+ pentagrama: pentagramaEnLaPista
88890
+ }));
88891
+ if (compasDeAlphaTab.simileMark) {
88892
+ const maestro = documento.compasesMaestros.get(idCompasMaestro);
88893
+ if (maestro && !maestro.get("repiteAnterior")) {
88894
+ maestro.set("repiteAnterior", compasDeAlphaTab.simileMark);
88895
+ }
88896
+ }
88897
+ const ticsDelCompas = 960 * 4 * (maestroDelCompas?.timeSignatureNumerator ?? 4) / (maestroDelCompas?.timeSignatureDenominator ?? 4);
88898
+ const temposAMitad = /* @__PURE__ */ new Map();
88899
+ if (pista.index === 0 && numeroDePentagrama === 0) {
88900
+ for (const a of maestroDelCompas?.tempoAutomations ?? []) {
88901
+ if (a.ratioPosition > 0) temposAMitad.set(Math.round(a.ratioPosition * ticsDelCompas), a.value);
88902
+ }
88903
+ }
88904
+ const pedalesDelCompas = /* @__PURE__ */ new Map();
88905
+ for (const marcador of compasDeAlphaTab.sustainPedals ?? []) {
88906
+ pedalesDelCompas.set(Math.round(marcador.ratioPosition * ticsDelCompas), marcador.pedalType + 1);
88907
+ }
88908
+ for (const voz of compasDeAlphaTab.voices) {
88909
+ if (voz.isEmpty) continue;
88910
+ for (const golpe of voz.beats) {
88911
+ if (golpe.isEmpty) continue;
88912
+ const idFigura = documento.agregarFigura(
88913
+ normalizarFigura({
88914
+ compasId: idCompas,
88915
+ voz: voz.index,
88916
+ // Tics MIDI desde el comienzo del compás. alphaTab y el modelo usan la
88917
+ // misma unidad (960 por negra), así que no hay conversión.
88918
+ tiempo: golpe.displayStart,
88919
+ // El valor del enum `Duration` de alphaTab ES el número que usa el
88920
+ // modelo: 4 = negra, 8 = corchea. No es casualidad — es la decisión de
88921
+ // copiar la forma de lo que ya funciona.
88922
+ valor: golpe.duration,
88923
+ puntillos: golpe.dots ?? 0,
88924
+ esSilencio: golpe.isRest,
88925
+ // ⚠️ Conversión 3: -1 significa "sin grupo irregular".
88926
+ tupletNumerador: normalizarTuplet(golpe.tupletNumerator),
88927
+ tupletDenominador: normalizarTuplet(golpe.tupletDenominator),
88928
+ // ★ Acá viene la letra. En la canción de Daniel cada sílaba está escrita
88929
+ // como texto del golpe, que es como se hace en la práctica en Guitar Pro.
88930
+ // Sin este campo, importar y exportar la borraba sin decir nada.
88931
+ texto: textoDelGolpe(golpe, letrasDobles),
88932
+ // ═══════════════════════════════════════════════════════════════════
88933
+ // ⛔⛔ LOS CIFRADOS DE ACORDE SE PERDÍAN TODOS (2026-11-09)
88934
+ // ═══════════════════════════════════════════════════════════════════
88935
+ // alphaTab los deja en `beat.chordId` → `staff.chords` (de un `.gp` y de un
88936
+ // `<harmony>` de MusicXML) y este traductor no los leía: «Am», «G7», todo afuera,
88937
+ // sin aviso. El bajo («C/E») lo lee `leerDelArchivo`, porque alphaTab lo tira.
88938
+ acorde: acordeDelGolpe(golpe, pentagrama, datos.bajos, pista.index, numeroDePentagrama, indice),
88939
+ dinamica: golpe.dynamics,
88940
+ // ⛔ El 8va / 8vb / 15ma se perdía: la notación salía una octava corrida (2026-11-09).
88941
+ octava: golpe.ottava,
88942
+ tempo: tempoDelGolpe(golpe, voz.index === 0 ? temposAMitad : void 0),
88943
+ // ═══════════════════════════════════════════════════════════════════
88944
+ // ★★★ LOS SIGNOS DE GUITAR PRO — hasta hoy se perdían TODOS en silencio
88945
+ // ═══════════════════════════════════════════════════════════════════
88946
+ //
88947
+ // Es la misma familia de pérdidas que ya destapó dos veces la comparación de
88948
+ // píxeles (el martillo, la dinámica) y una vez el inventario del manual: **el
88949
+ // modelo no tenía dónde ponerlos, así que un `.gp` con un rasgueado, un slap o
88950
+ // unas casillas de repetición entraba sin ellos y nadie lo decía**.
88951
+ //
88952
+ // ⚠️ Ninguno se convierte. Los números del modelo SON los de alphaTab, que es
88953
+ // la decisión que este archivo ya había tomado para el armónico y el
88954
+ // deslizamiento: una tabla de traducción es donde se pierde el valor que
88955
+ // todavía no se conoce.
88956
+ calderon: golpe.fermata ? golpe.fermata.type + 1 : 0,
88957
+ puaDireccion: golpe.pickStroke,
88958
+ rasgueo: golpe.brushType,
88959
+ duracionDelRasgueo: golpe.brushDuration,
88960
+ slap: golpe.slap,
88961
+ pop: golpe.pop,
88962
+ tapping: golpe.tap,
88963
+ slapMuerto: golpe.deadSlapped,
88964
+ barraOblicua: golpe.slashed,
88965
+ // ⚠️ `tremoloPicking` es OPCIONAL en alphaTab (`?:`), no un enum con cero: sin
88966
+ // el `?.` esto reventaría en el 99 % de los golpes. Y lo que guarda son
88967
+ // `marks` —las barritas que cruzan la plica—, no una duración.
88968
+ tremolo: golpe.tremoloPicking?.marks ?? 0,
88969
+ adorno: golpe.graceType,
88970
+ regulador: golpe.crescendo,
88971
+ fundido: golpe.fade ?? 0,
88972
+ wah: golpe.wahPedal,
88973
+ golpeEnLaTapa: golpe.golpe,
88974
+ rasgueado: golpe.rasgueado,
88975
+ cejilla: golpe.barreFret,
88976
+ formaDeCejilla: golpe.barreShape,
88977
+ plicaInvertida: golpe.invertBeamDirection,
88978
+ barrado: golpe.beamingMode,
88979
+ palanca: (golpe.whammyBarPoints ?? []).map((p) => ({
88980
+ desplazamiento: p.offset,
88981
+ valor: p.value
88982
+ })),
88983
+ // ★ El pedal que cae en este golpe, si hay alguno. Se busca por tic exacto: el
88984
+ // marcador de Guitar Pro se pone sobre un golpe, no entre dos.
88985
+ pedal: pedalesDelCompas.get(golpe.displayStart) ?? 0
88986
+ })
88987
+ );
88988
+ for (const nota of golpe.notes) {
88989
+ documento.agregarNota(
88990
+ normalizarNota({
88991
+ figuraId: idFigura,
88992
+ // ⚠️ Conversión 2: no hay conversión. Ver el encabezado.
88993
+ cuerda: nota.string,
88994
+ traste: nota.fret,
88995
+ // ═══════════════════════════════════════════════════════════════
88996
+ // ⛔⛔ LA ALTURA Y LA PIEZA DEL KIT NO SE COPIABAN (2026-11-09)
88997
+ // ═══════════════════════════════════════════════════════════════
88998
+ //
88999
+ // Desde la etapa 2 el TIPO de la pista se deducía bien, pero la nota sólo
89000
+ // copiaba cuerda y traste: en una pista de piano o de batería cada nota entraba
89001
+ // con `altura`/`articulacion` en null — todas iguales, dibujadas en el mismo
89002
+ // lugar, sin error. Lo destapó un arreglo de piano importado de MusicXML. La
89003
+ // prueba de exportar a GP7 no lo veía porque miraba el archivo y NUNCA lo volvía
89004
+ // a importar: el viaje de ida y vuelta se cortaba a la mitad.
89005
+ //
89006
+ // ★ Se lee con la MISMA convención con la que `proyectar` la escribe
89007
+ // (`octave * 12 + tone`, sin transposición ni armónico), y la percusión por
89008
+ // `percussionArticulation`, que es lo que `proyectar` le pone. Así la ida y la
89009
+ // vuelta son simétricas: lo que se exporta se vuelve a importar idéntico.
89010
+ altura: tipo === "altura" ? nota.calculateRealValue(false, false) : null,
89011
+ articulacion: tipo === "percusion" ? nota.percussionArticulation : null,
89012
+ ligadaAAnterior: nota.isTieDestination,
89013
+ muerta: nota.isDead,
89014
+ fantasma: nota.isGhost,
89015
+ // ⚠️ El MusicXML marca palm mute y let ring escritos como texto con guiones
89016
+ // («P.M. - - -») en el GOLPE (`beat.isPalmMute`), no en la nota: leer sólo la
89017
+ // nota los perdía (alphaTab issue #2867).
89018
+ palmMute: nota.isPalmMute || golpe.isPalmMute,
89019
+ letRing: nota.isLetRing || golpe.isLetRing,
89020
+ // `vibrato` es un enum donde 0 es "sin vibrato"; el modelo solo
89021
+ // necesita saber si hay o no. El tipo de vibrato es del bloque 5.
89022
+ vibrato: nota.vibrato !== 0,
89023
+ martillo: nota.isHammerPullOrigin,
89024
+ staccato: nota.isStaccato,
89025
+ deslizamientoEntrada: nota.slideInType,
89026
+ deslizamientoSalida: nota.slideOutType,
89027
+ armonico: nota.harmonicType,
89028
+ // ── Los signos de Guitar Pro, a nivel de nota ──────────────────
89029
+ acento: nota.accentuated,
89030
+ ligaduraDeExpresion: nota.isSlurDestination || nota.slurDestination !== null,
89031
+ vibratoDePalanca: 0,
89032
+ // ★ La anchura del vibrato: el campo viejo `vibrato` solo decía si había.
89033
+ anchoDeVibrato: nota.vibrato,
89034
+ tappingIzquierda: nota.isLeftHandTapped,
89035
+ muestraCuerda: nota.showStringNumber,
89036
+ dedoIzquierda: nota.leftHandFinger,
89037
+ dedoDerecha: nota.rightHandFinger,
89038
+ // ⚠️ alphaTab usa −1 para «sin trino», igual que el modelo. No hay conversión,
89039
+ // pero sí hay que respetarlo: un 0 sería el traste 0, o sea la cuerda al aire.
89040
+ trino: nota.trillValue,
89041
+ velocidadDeTrino: nota.trillSpeed,
89042
+ // ★ La ortografía ESCRITA en el MusicXML (su `<step>/<alter>`), que alphaTab 1.8.4
89043
+ // descarta. Sin ella, un si♭ sin signo impreso (el segundo del compás, o uno
89044
+ // ligado desde el anterior) vuelve como la♯. Ver `musicxmlEntrada.ts`.
89045
+ alteracion: ortografiaDe(datos.ortografia, pista.index, numeroDePentagrama, indice, golpe.displayStart, nota) ?? nota.accidentalMode,
89046
+ // ⚠️ EL BEND SE PERDÍA ENTERO hasta el PR 7: el modelo no tenía dónde
89047
+ // ponerlo, así que un archivo con bends entraba sin ellos y no lo decía
89048
+ // nadie. Es la sexta pérdida silenciosa de la misma familia que destapó la
89049
+ // comparación de píxeles en el PR 3 — con la diferencia de que ésta no la
89050
+ // destapó, porque *El Pibe de mi Barrio* no tiene un solo bend (medido:
89051
+ // cero propiedades `Bend` en su `score.gpif`). ★ Un fixture que no ejercita
89052
+ // una funcionalidad no prueba que esté bien: prueba que no se usó.
89053
+ //
89054
+ // `hasBend` de alphaTab exige las dos cosas —que haya puntos y que el tipo
89055
+ // no sea None—, así que preguntarlo es más honesto que mirar solo la lista.
89056
+ bend: nota.hasBend ? (nota.bendPoints ?? []).map((p) => ({ desplazamiento: p.offset, valor: p.value })) : []
89057
+ })
89058
+ );
89059
+ }
89060
+ }
89061
+ }
89062
+ }
89063
+ }
89064
+ }
89065
+ if (letrasDobles.cuantas > 0) {
89066
+ avisos.push(
89067
+ `${letrasDobles.cuantas} golpe(s) tra\xEDan letra Y un texto libre: se guard\xF3 la letra. Tabs lleva un solo texto por golpe.`
89068
+ );
89069
+ }
89070
+ const audioEmbebido = importarAudioYSync(score, documento, idsDeCompasMaestro, avisos);
89071
+ return { documento, avisos, ...audioEmbebido ? { audioEmbebido } : {} };
89072
+ }
89073
+ function importarAudioYSync(score, documento, idsDeCompasMaestro, avisos) {
89074
+ const puntos = score.exportFlatSyncPoints();
89075
+ const bytes = score.backingTrack?.rawAudioFile;
89076
+ if (puntos.length === 0 && !bytes) return void 0;
89077
+ const fuenteId = documento.agregarFuenteDeAudio({
89078
+ nombre: score.title ? `${score.title} (del archivo)` : "Grabaci\xF3n del archivo",
89079
+ // ⚠️ En cero las dos, y se llenan cuando el navegador decodifique. El importador
89080
+ // corre también en la terminal, donde no hay `AudioContext` con el que averiguarlo.
89081
+ duracion: 0,
89082
+ picos: [],
89083
+ volumen: 16,
89084
+ balance: 8
89085
+ });
89086
+ let huerfanos = 0;
89087
+ for (const punto of puntos) {
89088
+ const compasMaestroId = idsDeCompasMaestro[punto.barIndex];
89089
+ if (compasMaestroId === void 0) {
89090
+ huerfanos++;
89091
+ continue;
89092
+ }
89093
+ documento.agregarPuntoDeSync({
89094
+ fuenteId,
89095
+ compasMaestroId,
89096
+ posicionEnElCompas: punto.barPosition,
89097
+ ocurrencia: punto.barOccurence,
89098
+ msDelAudio: punto.millisecondOffset
89099
+ });
89100
+ }
89101
+ if (huerfanos > 0) {
89102
+ avisos.push(
89103
+ `${huerfanos} punto(s) de sincronizaci\xF3n del archivo apuntan a compases que no existen (la partitura tiene ${idsDeCompasMaestro.length}) y no se importaron.`
89104
+ );
89105
+ }
89106
+ if (!bytes) {
89107
+ avisos.push(
89108
+ `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.`
89109
+ );
89110
+ return void 0;
89111
+ }
89112
+ return { fuenteId, bytes };
89113
+ }
89114
+ function numeroDeTonalidad(armadura) {
89115
+ return armadura;
89116
+ }
89117
+ function textoDelGolpe(golpe, letrasDobles) {
89118
+ const letra = (golpe.lyrics ?? []).find((l) => l && l.trim()) ?? "";
89119
+ const libre = golpe.text ?? "";
89120
+ if (letra && libre && letra !== libre) letrasDobles.cuantas++;
89121
+ return letra || libre;
89122
+ }
89123
+ function acordeDelGolpe(golpe, pentagrama, bajos, parte, numeroDePentagrama, compas) {
89124
+ if (!golpe.chordId) return void 0;
89125
+ const nombre = pentagrama.chords?.get(golpe.chordId)?.name?.trim();
89126
+ if (!nombre) return void 0;
89127
+ const bajo = bajos?.get(`${parte}|${numeroDePentagrama}|${compas}|${golpe.displayStart}`) ?? "";
89128
+ return bajo && !nombre.endsWith(bajo) ? nombre + bajo : nombre;
89129
+ }
89130
+ function tempoDelGolpe(golpe, delMaestro) {
89131
+ if (golpe.displayStart === 0) return void 0;
89132
+ const propio = golpe.automations?.find((a) => a.type === _barrel_exports$4.AutomationType.Tempo)?.value;
89133
+ return propio ?? delMaestro?.get(golpe.displayStart);
89134
+ }
89135
+ function normalizarTuplet(valor) {
89136
+ return valor === void 0 || valor <= 0 ? 1 : valor;
89137
+ }
89138
+ function ortografiaDe(ortografia, parte, pentagrama, compas, tic, nota) {
89139
+ if (!ortografia) return void 0;
89140
+ const base = `${parte}|${pentagrama}|${compas}|${tic}|`;
89141
+ return ortografia.get(base + nota.calculateRealValue(false, false)) ?? ortografia.get(base + (nota.octave * 12 + nota.tone));
89142
+ }
89143
+ var init_importarGp = __esm({
89144
+ "packages/io/src/importarGp.ts"() {
89145
+ init_alphaTab();
89146
+ init_src2();
89147
+ init_musicxmlEntrada();
89148
+ }
89149
+ });
89150
+
88607
89151
  // packages/io/src/archivoMtabs.ts
89152
+ function formatoQueNecesita(documento) {
89153
+ for (const pista of documento.pistas.values()) {
89154
+ const pentagramas = pista.get("pentagramas");
89155
+ if (typeof pentagramas === "number" && pentagramas > 1) return 5;
89156
+ const transposicion = pista.get("transposicion");
89157
+ if (typeof transposicion === "number" && transposicion !== 0) return 5;
89158
+ }
89159
+ for (const figura of documento.figuras.values()) {
89160
+ if (figura.get("octava") !== void 0 || figura.get("tempo") !== void 0) return 5;
89161
+ }
89162
+ return 4;
89163
+ }
88608
89164
  function empaquetar(documento, opciones = {}) {
88609
89165
  const grabaciones = opciones.grabaciones ?? [];
88610
89166
  const fuentes = opciones.fuentes ?? [];
88611
89167
  const manifiesto = {
88612
- formato: VERSION_DEL_FORMATO,
89168
+ formato: formatoQueNecesita(documento),
88613
89169
  aplicacion: opciones.aplicacion ?? "Mandioca Tabs",
88614
89170
  guardado: opciones.guardado ?? "",
88615
89171
  titulo: documento.cabecera.get("titulo") ?? "",
@@ -88681,7 +89237,7 @@ var init_archivoMtabs = __esm({
88681
89237
  "packages/io/src/archivoMtabs.ts"() {
88682
89238
  init_esm();
88683
89239
  init_src2();
88684
- VERSION_DEL_FORMATO = 4;
89240
+ VERSION_DEL_FORMATO = 5;
88685
89241
  MANIFIESTO = "mandioca.json";
88686
89242
  DOCUMENTO = "documento.ydoc";
88687
89243
  CARPETA_DE_AUDIO = "audio/";
@@ -88703,10 +89259,17 @@ function elemento(nombre, texto4) {
88703
89259
  if (texto4 === null || texto4 === void 0 || texto4 === "") return [];
88704
89260
  return [`<${nombre}>${escapar(String(texto4))}</${nombre}>`];
88705
89261
  }
88706
- function alturaMusicXml(midi, fifths) {
89262
+ function alturaMusicXml(midi, fifths, modo = 0) {
88707
89263
  const octavaAlphaTab = Math.floor(midi / 12);
88708
89264
  const clase = midi - octavaAlphaTab * 12;
88709
89265
  const octava = octavaAlphaTab - 1;
89266
+ const pedida = ALTERACION_POR_MODO[modo];
89267
+ if (pedida !== void 0) {
89268
+ const sinAlterar = clase - pedida;
89269
+ const vueltas = Math.floor(sinAlterar / 12);
89270
+ const paso = PASOS.find((p) => p.semitonos === sinAlterar - vueltas * 12);
89271
+ if (paso) return { paso: paso.paso, alteracion: pedida, octava: octava + vueltas };
89272
+ }
88710
89273
  const natural = PASOS.find((p) => p.semitonos === clase);
88711
89274
  if (natural) return { paso: natural.paso, alteracion: 0, octava };
88712
89275
  if (fifths < 0) {
@@ -88789,7 +89352,8 @@ function escribirNota(note, beat, staff, opciones) {
88789
89352
  } else {
88790
89353
  const { paso, alteracion, octava } = alturaMusicXml(
88791
89354
  note.calculateRealValue(false, false),
88792
- opciones.fifths
89355
+ opciones.fifths,
89356
+ note.accidentalMode
88793
89357
  );
88794
89358
  s.push("<pitch>");
88795
89359
  s.push(`<step>${paso}</step>`);
@@ -89112,7 +89676,7 @@ function exportarMusicXmlComprimido(score) {
89112
89676
  { mtime: FECHA_FIJA_DEL_ZIP }
89113
89677
  );
89114
89678
  }
89115
- var DIVISIONES_POR_NEGRA, FECHA_FIJA_DEL_ZIP, PASOS, NOMBRE_DE_LA_FIGURA2;
89679
+ var DIVISIONES_POR_NEGRA, FECHA_FIJA_DEL_ZIP, PASOS, NOMBRE_DE_LA_FIGURA2, ALTERACION_POR_MODO;
89116
89680
  var init_musicxml = __esm({
89117
89681
  "packages/io/src/musicxml.ts"() {
89118
89682
  init_alphaTab();
@@ -89141,6 +89705,7 @@ var init_musicxml = __esm({
89141
89705
  [128, "128th"],
89142
89706
  [256, "256th"]
89143
89707
  ]);
89708
+ ALTERACION_POR_MODO = { 2: 0, 3: 1, 4: 2, 5: -1, 6: -2 };
89144
89709
  }
89145
89710
  });
89146
89711
 
@@ -89235,12 +89800,18 @@ __export(src_exports, {
89235
89800
  exportarMusicXml: () => exportarMusicXml,
89236
89801
  exportarMusicXmlComprimido: () => exportarMusicXmlComprimido,
89237
89802
  formatoDeExportacion: () => formatoDeExportacion,
89803
+ formatoQueNecesita: () => formatoQueNecesita,
89238
89804
  importarGp: () => importarGp,
89239
- importarScore: () => importarScore
89805
+ importarScore: () => importarScore,
89806
+ leerOrtografia: () => leerOrtografia,
89807
+ prepararMusicXml: () => prepararMusicXml,
89808
+ prepararParaAlphaTab: () => prepararParaAlphaTab,
89809
+ textoMusicXml: () => textoMusicXml
89240
89810
  });
89241
89811
  var init_src4 = __esm({
89242
89812
  "packages/io/src/index.ts"() {
89243
89813
  init_importarGp();
89814
+ init_musicxmlEntrada();
89244
89815
  init_archivoMtabs();
89245
89816
  init_exportar();
89246
89817
  init_musicxml();
@@ -89285,7 +89856,7 @@ function obraAbierta() {
89285
89856
  //
89286
89857
  // ★ Ahora la pestaña va PRIMERA, que es el caso más común: si alguien está usando el
89287
89858
  // 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."
89859
+ "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
89860
  );
89290
89861
  }
89291
89862
  return abierta;
@@ -89313,14 +89884,14 @@ async function abrirDeArchivo(ruta) {
89313
89884
  };
89314
89885
  return alAbrirLaObra(abierta);
89315
89886
  }
89316
- if (extension2 === ".gp") {
89887
+ if (EXTENSIONES_IMPORTABLES.has(extension2)) {
89317
89888
  const { importarGp: importarGp2 } = await Promise.resolve().then(() => (init_src4(), src_exports));
89318
89889
  const resultado = importarGp2(bytes);
89319
89890
  abierta = {
89320
89891
  documento: resultado.documento,
89321
89892
  origen: { clase: "archivo", ruta },
89322
89893
  avisos: resultado.avisos,
89323
- // ⚠️ Un `.gp` no trae audio ni tipografías: no hay nada que devolver. Guardar esta obra
89894
+ // ⚠️ Un `.gp` o un MusicXML no trae audio ni tipografías: no hay nada que devolver. Guardar esta obra
89324
89895
  // como `.mtabs` escribe un archivo sin audio porque nunca lo tuvo, no por perderlo.
89325
89896
  grabaciones: [],
89326
89897
  grabacionesEnEspera: [],
@@ -89329,7 +89900,7 @@ async function abrirDeArchivo(ruta) {
89329
89900
  return alAbrirLaObra(abierta);
89330
89901
  }
89331
89902
  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).`
89903
+ `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
89904
  );
89334
89905
  }
89335
89906
  function abrirEnBlanco(opciones = {}) {
@@ -89452,7 +90023,7 @@ function reciboDeLaPesta\u00F1a(respuesta, ruta) {
89452
90023
  ...avisoDeLoQueNoSuena(mudas, 0)
89453
90024
  };
89454
90025
  }
89455
- var ProblemaConLaObra, abierta, sigueViva;
90026
+ var ProblemaConLaObra, abierta, sigueViva, EXTENSIONES_IMPORTABLES;
89456
90027
  var init_obra = __esm({
89457
90028
  "apps/mcp/src/obra.ts"() {
89458
90029
  "use strict";
@@ -89462,6 +90033,7 @@ var init_obra = __esm({
89462
90033
  };
89463
90034
  abierta = null;
89464
90035
  sigueViva = null;
90036
+ EXTENSIONES_IMPORTABLES = /* @__PURE__ */ new Set([".gp", ".gpx", ".gp5", ".gp4", ".gp3", ".musicxml", ".xml", ".mxl"]);
89465
90037
  }
89466
90038
  });
89467
90039
 
@@ -89470,7 +90042,7 @@ var VERSION_DEL_CONECTOR;
89470
90042
  var init_version = __esm({
89471
90043
  "apps/mcp/src/version.ts"() {
89472
90044
  "use strict";
89473
- VERSION_DEL_CONECTOR = true ? "0.2.8" : null;
90045
+ VERSION_DEL_CONECTOR = true ? "0.2.12" : null;
89474
90046
  }
89475
90047
  });
89476
90048
 
@@ -97473,10 +98045,11 @@ function proyectar(documento, opciones = {}) {
97473
98045
  for (const [id2, entidad] of documento.compases.entries()) {
97474
98046
  const compas = normalizarCompas(entidad.toJSON());
97475
98047
  datosDeCompas.set(id2, compas);
97476
- let porMaestro = compasesPorPista.get(compas.pistaId);
98048
+ const claveDePentagrama = `${compas.pistaId}|${compas.pentagrama ?? 0}`;
98049
+ let porMaestro = compasesPorPista.get(claveDePentagrama);
97477
98050
  if (!porMaestro) {
97478
98051
  porMaestro = /* @__PURE__ */ new Map();
97479
- compasesPorPista.set(compas.pistaId, porMaestro);
98052
+ compasesPorPista.set(claveDePentagrama, porMaestro);
97480
98053
  }
97481
98054
  porMaestro.set(compas.compasMaestroId, id2);
97482
98055
  }
@@ -97494,6 +98067,7 @@ function proyectar(documento, opciones = {}) {
97494
98067
  if (lista2) lista2.push(nota);
97495
98068
  else notasPorFigura.set(nota.figuraId, [nota]);
97496
98069
  }
98070
+ const temposAMitad = [];
97497
98071
  const pistasEnOrden = [...documento.pistasEnOrden()];
97498
98072
  const canales = canalesDeLasPistas(
97499
98073
  pistasEnOrden.map(({ datos }) => normalizarPista(datos).tipo)
@@ -97508,216 +98082,242 @@ function proyectar(documento, opciones = {}) {
97508
98082
  track.playbackInfo.volume = dibujar ? 16 : Math.max(0, Math.min(16, pista.volumen));
97509
98083
  if (dibujar) volumenDeMezcla.set(track, Math.max(0, pista.volumen));
97510
98084
  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
98085
  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);
98086
+ const cantidadDePentagramas = Math.max(1, pista.pentagramas ?? 1);
98087
+ for (let numeroDePentagrama = 0; numeroDePentagrama < cantidadDePentagramas; numeroDePentagrama++) {
98088
+ const pentagrama = new _barrel_exports$4.Staff();
98089
+ const valores = [...pista.afinacion].reverse();
98090
+ pentagrama.stringTuning = _barrel_exports$4.Tuning.findTuning(valores) ?? new _barrel_exports$4.Tuning("", valores, false);
98091
+ pentagrama.capo = pista.capo;
98092
+ pentagrama.displayTranspositionPitch = pista.transposicion ?? 0;
98093
+ pentagrama.showTablature = pista.tipo === "trastes";
98094
+ pentagrama.showStandardNotation = true;
98095
+ pentagrama.isPercussion = pista.tipo === "percusion";
98096
+ if (pista.tipo === "percusion") {
98097
+ track.playbackInfo.primaryChannel = 9;
98098
+ track.playbackInfo.secondaryChannel = 9;
98099
+ track.percussionArticulations = KIT.map((pieza) => {
98100
+ const art = new _barrel_exports$4.InstrumentArticulation();
98101
+ art.outputMidiNumber = pieza.midi;
98102
+ art.staffLine = pieza.linea;
98103
+ art.noteHeadDefault = pieza.cabeza === "x" ? _barrel_exports$4.MusicFontSymbol.NoteheadXBlack : _barrel_exports$4.MusicFontSymbol.NoteheadBlack;
98104
+ art.noteHeadHalf = art.noteHeadDefault;
98105
+ art.noteHeadWhole = art.noteHeadDefault;
98106
+ return art;
98107
+ });
97538
98108
  }
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 });
98109
+ track.addStaff(pentagrama);
98110
+ const porMaestro = compasesPorPista.get(`${idPista}|${numeroDePentagrama}`) ?? /* @__PURE__ */ new Map();
98111
+ let cantidadDeVoces = VOCES_POR_COMPAS;
98112
+ for (const idCompas of porMaestro.values()) {
98113
+ for (const { datos: datos2 } of figurasPorCompas.get(idCompas) ?? []) {
98114
+ cantidadDeVoces = Math.max(cantidadDeVoces, datos2.voz + 1);
97546
98115
  }
97547
98116
  }
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
- );
98117
+ const acordesEscritos = [];
98118
+ maestros.forEach((m, indiceDeCompas2) => {
98119
+ const id2 = porMaestro.get(m.id);
98120
+ for (const { datos: f } of id2 ? figurasPorCompas.get(id2) ?? [] : []) {
98121
+ if (f.acorde) {
98122
+ acordesEscritos.push({ compas: indiceDeCompas2, tiempo: f.tiempo, nombre: f.acorde });
97630
98123
  }
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
- );
98124
+ }
98125
+ });
98126
+ const acordeVigente = buscadorDeAcorde(acordesEscritos);
98127
+ maestros.forEach((maestro, indiceDeCompas2) => {
98128
+ const barra = new _barrel_exports$4.Bar();
98129
+ pentagrama.addBar(barra);
98130
+ barra.keySignature = maestro.datos.tonalidad;
98131
+ barra.simileMark = maestro.datos.repiteAnterior;
98132
+ const idCompas = porMaestro.get(maestro.id);
98133
+ const figuras = idCompas ? figurasPorCompas.get(idCompas) ?? [] : [];
98134
+ const datosDelCompas = idCompas ? datosDeCompas.get(idCompas) : void 0;
98135
+ if (datosDelCompas) {
98136
+ barra.clef = datosDelCompas.clave;
98137
+ barra.clefOttava = datosDelCompas.claveOctava;
98138
+ }
98139
+ const ticsDelCompas = 960 * 4 * maestro.datos.numerador / maestro.datos.denominador;
98140
+ for (const { datos: figura } of figuras) {
98141
+ if (!figura.pedal) continue;
98142
+ const marcador = new _barrel_exports$4.SustainPedalMarker();
98143
+ marcador.ratioPosition = ticsDelCompas > 0 ? figura.tiempo / ticsDelCompas : 0;
98144
+ marcador.pedalType = figura.pedal - 1;
98145
+ barra.sustainPedals.push(marcador);
98146
+ }
98147
+ for (let indiceDeVoz = 0; indiceDeVoz < cantidadDeVoces; indiceDeVoz++) {
98148
+ const voz = new _barrel_exports$4.Voice();
98149
+ barra.addVoice(voz);
98150
+ const deEstaVoz = figuras.filter((f) => f.datos.voz === indiceDeVoz).sort((a, b) => a.datos.tiempo - b.datos.tiempo);
98151
+ for (const { id: idFigura, datos: figura } of deEstaVoz) {
98152
+ const golpe = new _barrel_exports$4.Beat();
98153
+ golpe.duration = figura.valor;
98154
+ golpe.dots = figura.puntillos;
98155
+ if (figura.octava !== void 0) golpe.ottava = figura.octava;
98156
+ if (figura.tempo !== void 0) temposAMitad.push({ compas: indiceDeCompas2, tiempo: figura.tiempo, valor: figura.tempo, tics: ticsDelCompas });
98157
+ if (figura.tupletNumerador > 1) {
98158
+ golpe.tupletNumerator = figura.tupletNumerador;
98159
+ golpe.tupletDenominator = figura.tupletDenominador;
98160
+ }
98161
+ if (figura.texto) golpe.lyrics = [marcado(figura.texto, figura.textoSegundaTipografia)];
98162
+ if (figura.acorde) {
98163
+ const nombre = marcado(figura.acorde, figura.acordeSegundaTipografia);
98164
+ if (!pentagrama.chords?.has(nombre)) {
98165
+ const acorde = new _barrel_exports$4.Chord();
98166
+ acorde.name = nombre;
98167
+ acorde.showName = true;
98168
+ acorde.showDiagram = false;
98169
+ acorde.staff = pentagrama;
98170
+ pentagrama.addChord(nombre, acorde);
97678
98171
  }
98172
+ golpe.chordId = nombre;
98173
+ }
98174
+ golpe.dynamics = figura.dinamica;
98175
+ golpe.pickStroke = figura.puaDireccion;
98176
+ golpe.brushType = figura.rasgueo;
98177
+ golpe.brushDuration = figura.duracionDelRasgueo;
98178
+ golpe.slap = figura.slap;
98179
+ golpe.pop = figura.pop;
98180
+ golpe.tap = figura.tapping;
98181
+ golpe.deadSlapped = figura.slapMuerto;
98182
+ golpe.slashed = figura.barraOblicua;
98183
+ golpe.graceType = figura.adorno;
98184
+ golpe.crescendo = figura.regulador;
98185
+ golpe.fade = figura.fundido;
98186
+ golpe.wahPedal = figura.wah;
98187
+ golpe.golpe = figura.golpeEnLaTapa;
98188
+ golpe.rasgueado = figura.rasgueado;
98189
+ golpe.barreFret = figura.cejilla;
98190
+ golpe.barreShape = figura.formaDeCejilla;
98191
+ golpe.invertBeamDirection = figura.plicaInvertida;
98192
+ golpe.beamingMode = figura.barrado;
98193
+ if (figura.tremolo > 0) {
98194
+ const tremolo = new _barrel_exports$4.TremoloPickingEffect();
98195
+ tremolo.marks = figura.tremolo;
98196
+ golpe.tremoloPicking = tremolo;
98197
+ }
98198
+ if (figura.calderon > 0) {
98199
+ const calderon = new _barrel_exports$4.Fermata();
98200
+ calderon.type = figura.calderon - 1;
98201
+ golpe.fermata = calderon;
98202
+ }
98203
+ if (figura.palanca.length > 0) {
98204
+ golpe.whammyBarType = _barrel_exports$4.WhammyType.Custom;
98205
+ golpe.whammyStyle = _barrel_exports$4.BendStyle.Default;
98206
+ golpe.whammyBarPoints = figura.palanca.map(
98207
+ (p) => new _barrel_exports$4.BendPoint(p.desplazamiento, p.valor)
98208
+ );
97679
98209
  }
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
- )
98210
+ const notasDelGolpe2 = notasPorFigura.get(idFigura) ?? [];
98211
+ const extremosDelGolpe = extremosPorGrado(
98212
+ notasDelGolpe2.map((n) => {
98213
+ const a = alturaDeLaNota(n, pista.tipo, pista.afinacion);
98214
+ const ac = a === null ? null : acordeVigente(indiceDeCompas2, figura.tiempo);
98215
+ return { altura: a, grado: a === null || ac === null ? null : gradoDeLaNota(ac, a) };
98216
+ })
97695
98217
  );
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
- );
98218
+ for (const nota of notasDelGolpe2) {
98219
+ const notaAlphaTab = new _barrel_exports$4.Note();
98220
+ if (pista.tipo === "altura") {
98221
+ const altura2 = nota.altura ?? 60;
98222
+ notaAlphaTab.octave = Math.floor(altura2 / 12);
98223
+ notaAlphaTab.tone = altura2 % 12;
98224
+ } else if (pista.tipo === "percusion") {
98225
+ notaAlphaTab.percussionArticulation = nota.articulacion ?? 0;
98226
+ } else {
98227
+ notaAlphaTab.string = nota.cuerda;
98228
+ notaAlphaTab.fret = nota.traste;
97708
98229
  }
98230
+ notaAlphaTab.isDead = nota.muerta;
98231
+ notaAlphaTab.isGhost = nota.fantasma;
98232
+ notaAlphaTab.isPalmMute = nota.palmMute;
98233
+ notaAlphaTab.isLetRing = nota.letRing;
98234
+ notaAlphaTab.isTieDestination = nota.ligadaAAnterior;
98235
+ notaAlphaTab.isHammerPullOrigin = nota.martillo;
98236
+ notaAlphaTab.isStaccato = nota.staccato;
98237
+ notaAlphaTab.slideInType = nota.deslizamientoEntrada;
98238
+ notaAlphaTab.slideOutType = nota.deslizamientoSalida;
98239
+ notaAlphaTab.harmonicType = nota.armonico;
98240
+ notaAlphaTab.vibrato = nota.anchoDeVibrato;
98241
+ notaAlphaTab.accentuated = nota.acento;
98242
+ notaAlphaTab.isLeftHandTapped = nota.tappingIzquierda;
98243
+ notaAlphaTab.showStringNumber = nota.muestraCuerda;
98244
+ notaAlphaTab.leftHandFinger = nota.dedoIzquierda;
98245
+ notaAlphaTab.rightHandFinger = nota.dedoDerecha;
98246
+ notaAlphaTab.trillValue = nota.trino;
98247
+ notaAlphaTab.trillSpeed = nota.velocidadDeTrino;
98248
+ notaAlphaTab.accidentalMode = nota.alteracion;
98249
+ if (nota.ligaduraDeExpresion) notaAlphaTab.isEffectSlurOrigin = true;
98250
+ if (nota.bend.length > 0) {
98251
+ notaAlphaTab.bendType = _barrel_exports$4.BendType.Custom;
98252
+ notaAlphaTab.bendStyle = _barrel_exports$4.BendStyle.Default;
98253
+ for (const punto of nota.bend) {
98254
+ notaAlphaTab.addBendPoint(
98255
+ new _barrel_exports$4.BendPoint(punto.desplazamiento, punto.valor)
98256
+ );
98257
+ }
98258
+ }
98259
+ const altura = alturaDeLaNota(nota, pista.tipo, pista.afinacion);
98260
+ const acordeDeLaNota = altura === null ? null : acordeVigente(indiceDeCompas2, figura.tiempo);
98261
+ const gradoDeEsta = altura === null || acordeDeLaNota === null ? null : gradoDeLaNota(acordeDeLaNota, altura);
98262
+ const marca = marcaDeLaNota(
98263
+ { color: nota.marcaColor, subrayada: nota.marcaSubrayada },
98264
+ gradoDeEsta,
98265
+ estiloDeLaObra,
98266
+ leTocaLaMarca(
98267
+ altura,
98268
+ gradoDeEsta === null ? void 0 : extremosDelGolpe.get(gradoDeEsta),
98269
+ // ★ La política es DE ESTE GRADO: querer la fundamental del bajo y a la vez
98270
+ // todas las terceras es un pedido razonable, y con un ajuste general sería
98271
+ // imposible.
98272
+ (gradoDeEsta === null ? void 0 : estiloDeLaObra.marcasPorGrado?.[String(gradoDeEsta)]?.cual) ?? "todas"
98273
+ )
98274
+ );
98275
+ if (marca.pintar) {
98276
+ const color = _barrel_exports$4.Color.fromJson(marca.pintar);
98277
+ if (color) {
98278
+ notaAlphaTab.style ??= new _barrel_exports$4.NoteStyle();
98279
+ notaAlphaTab.style.colors.set(
98280
+ _barrel_exports$4.NoteSubElement.GuitarTabFretNumber,
98281
+ color
98282
+ );
98283
+ notaAlphaTab.style.colors.set(
98284
+ _barrel_exports$4.NoteSubElement.StandardNotationNoteHead,
98285
+ color
98286
+ );
98287
+ }
98288
+ }
98289
+ if (marca.subrayar) anotarSubrayado(notaAlphaTab, marca.subrayar);
98290
+ golpe.addNote(notaAlphaTab);
97709
98291
  }
97710
- if (marca.subrayar) anotarSubrayado(notaAlphaTab, marca.subrayar);
97711
- golpe.addNote(notaAlphaTab);
98292
+ voz.addBeat(golpe);
98293
+ }
98294
+ if (voz.beats.length === 0) {
98295
+ const relleno = new _barrel_exports$4.Beat();
98296
+ relleno.isEmpty = true;
98297
+ voz.addBeat(relleno);
97712
98298
  }
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
98299
  }
97720
- }
98300
+ });
98301
+ }
98302
+ }
98303
+ const yaPuestos = /* @__PURE__ */ new Set();
98304
+ for (const t of temposAMitad.sort((a, b) => a.compas - b.compas || a.tiempo - b.tiempo)) {
98305
+ const clave = `${t.compas}|${t.tiempo}`;
98306
+ const maestro = score.masterBars[t.compas];
98307
+ if (!maestro || yaPuestos.has(clave) || t.tics <= 0) continue;
98308
+ yaPuestos.add(clave);
98309
+ const automatizacion = new _barrel_exports$4.Automation();
98310
+ automatizacion.isLinear = false;
98311
+ automatizacion.type = _barrel_exports$4.AutomationType.Tempo;
98312
+ automatizacion.value = t.valor;
98313
+ automatizacion.ratioPosition = t.tiempo / t.tics;
98314
+ maestro.tempoAutomations.push(automatizacion);
98315
+ }
98316
+ const { saltosDeRenglon } = documento.leerPresentacion();
98317
+ if (saltosDeRenglon.size > 0) {
98318
+ maestros.forEach((maestro, indice) => {
98319
+ if (indice === 0 || !saltosDeRenglon.has(maestro.id)) return;
98320
+ for (const track of score.tracks) track.addLineBreaks(indice);
97721
98321
  });
97722
98322
  }
97723
98323
  score.finish(ajustes);
@@ -121959,10 +122559,10 @@ function duracionDesde(figura, puntillos) {
121959
122559
  }
121960
122560
  return { valor: figura, puntillos: puntillos ?? 0 };
121961
122561
  }
121962
- function ticsDelGolpe(indice, pistaId, compas, voz, golpe, tics) {
122562
+ function ticsDelGolpe(indice, pistaId, compas, voz, golpe, tics, pentagrama = 0) {
121963
122563
  if (tics !== void 0) return tics;
121964
122564
  if (golpe === void 0) return 0;
121965
- const compasId = indice.compasId(pistaId, compas);
122565
+ const compasId = indice.compasId(pistaId, compas, pentagrama);
121966
122566
  const figuras = indice.figuras(compasId, voz);
121967
122567
  const elegida = figuras[golpe - 1];
121968
122568
  if (!elegida) {
@@ -121972,8 +122572,18 @@ function ticsDelGolpe(indice, pistaId, compas, voz, golpe, tics) {
121972
122572
  }
121973
122573
  return elegida.datos.tiempo;
121974
122574
  }
121975
- function cursorEn(indice, pistaId, compas, voz, tiempo, cuerda) {
121976
- return { ...cursorInicial(indice, pistaId), compas, voz, tiempo, cuerda };
122575
+ function cursorEn(indice, pistaId, compas, voz, tiempo, cuerda, pentagrama = 0) {
122576
+ return { ...cursorInicial(indice, pistaId), compas, voz, tiempo, cuerda, ...pentagrama > 0 ? { pentagrama } : {} };
122577
+ }
122578
+ function pentagramaDelMusico(pedido, indice, pistaId, numeroDePista) {
122579
+ if (pedido === void 0) return 0;
122580
+ const tiene = indice.pentagramasDe(pistaId);
122581
+ if (pedido < 1 || pedido > tiene) {
122582
+ throw new ProblemaConLaObra(
122583
+ `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)." : "")
122584
+ );
122585
+ }
122586
+ return pedido - 1;
121977
122587
  }
121978
122588
  var campoDeSegundaTipografia = external_exports.array(
121979
122589
  external_exports.object({
@@ -122004,7 +122614,8 @@ var unaNota = {
122004
122614
  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
122615
  golpe: external_exports.number().int().min(1).max(999).optional(),
122006
122616
  tics: external_exports.number().int().min(0).max(99999).optional(),
122007
- voz: external_exports.number().int().min(1).max(4).optional()
122617
+ voz: external_exports.number().int().min(1).max(4).optional(),
122618
+ 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
122619
  };
122009
122620
  function piezaPorNombre(nombre) {
122010
122621
  const plano = (t) => t.normalize("NFD").replace(/[̀-ͯ]/g, "").trim().toLowerCase();
@@ -122089,9 +122700,9 @@ function registrarHerramientasDelDocumento(servidor2) {
122089
122700
  "abrir_obra",
122090
122701
  {
122091
122702
  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`.",
122703
+ 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
122704
  inputSchema: {
122094
- ruta: external_exports.string().describe("La ruta completa del archivo, terminada en .mtabs o .gp"),
122705
+ ruta: external_exports.string().describe("La ruta completa del archivo: .mtabs, Guitar Pro (.gp, .gpx, .gp5\u2026) o MusicXML (.musicxml, .xml, .mxl)"),
122095
122706
  igual: external_exports.boolean().optional().describe(
122096
122707
  "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
122708
  )
@@ -122151,7 +122762,8 @@ function registrarHerramientasDelDocumento(servidor2) {
122151
122762
  nombre: primero.nombre,
122152
122763
  nombreCorto: primero.nombreCorto,
122153
122764
  afinacion: primero.afinacion,
122154
- programaMidi: primero.programaMidi
122765
+ programaMidi: primero.programaMidi,
122766
+ pentagramas: primero.pentagramas
122155
122767
  }
122156
122768
  } : {}
122157
122769
  });
@@ -122161,7 +122773,8 @@ function registrarHerramientasDelDocumento(servidor2) {
122161
122773
  nombre: i2.nombre,
122162
122774
  nombreCorto: i2.nombreCorto,
122163
122775
  afinacion: i2.afinacion,
122164
- programaMidi: i2.programaMidi
122776
+ programaMidi: i2.programaMidi,
122777
+ pentagramas: i2.pentagramas
122165
122778
  });
122166
122779
  }
122167
122780
  const v = volcar(obra.documento);
@@ -122345,13 +122958,14 @@ function registrarHerramientasDelDocumento(servidor2) {
122345
122958
  const pistaId = laPista.id;
122346
122959
  const compas = indiceDeCompas(nota.compas, indice);
122347
122960
  const voz = (nota.voz ?? 1) - 1;
122348
- const tiempo = ticsDelGolpe(indice, pistaId, compas, voz, nota.golpe, nota.tics);
122961
+ const pentagrama = pentagramaDelMusico(nota.pentagrama, indice, pistaId, pista ?? 1);
122962
+ const tiempo = ticsDelGolpe(indice, pistaId, compas, voz, nota.golpe, nota.tics, pentagrama);
122349
122963
  const nombrada = comoSeEscribeLaNota(laPista.tipo, laPista.nombre, pista ?? 1, nota);
122350
122964
  if (nombrada.clase === "altura") {
122351
122965
  const resultado2 = escribirAltura(
122352
122966
  documento,
122353
122967
  indice,
122354
- cursorEn(indice, pistaId, compas, voz, tiempo, 1),
122968
+ cursorEn(indice, pistaId, compas, voz, tiempo, 1, pentagrama),
122355
122969
  nombrada.altura,
122356
122970
  duracion ? { duracion } : {}
122357
122971
  );
@@ -122367,7 +122981,7 @@ function registrarHerramientasDelDocumento(servidor2) {
122367
122981
  const resultado2 = escribirPercusion(
122368
122982
  documento,
122369
122983
  indice,
122370
- cursorEn(indice, pistaId, compas, voz, tiempo, 1),
122984
+ cursorEn(indice, pistaId, compas, voz, tiempo, 1, pentagrama),
122371
122985
  nombrada.articulacion,
122372
122986
  duracion ? { duracion } : {}
122373
122987
  );
@@ -122382,7 +122996,7 @@ function registrarHerramientasDelDocumento(servidor2) {
122382
122996
  const resultado = escribirTraste(
122383
122997
  documento,
122384
122998
  indice,
122385
- cursorEn(indice, pistaId, compas, voz, tiempo, nombrada.cuerda),
122999
+ cursorEn(indice, pistaId, compas, voz, tiempo, nombrada.cuerda, pentagrama),
122386
123000
  nombrada.cuerda,
122387
123001
  nombrada.traste,
122388
123002
  duracion ? { duracion } : {}
@@ -122418,9 +123032,10 @@ function registrarHerramientasDelDocumento(servidor2) {
122418
123032
  const pistaId = laPista.id;
122419
123033
  const compas = indiceDeCompas(nota.compas, indice);
122420
123034
  const voz = (nota.voz ?? 1) - 1;
122421
- const tiempo = ticsDelGolpe(indice, pistaId, compas, voz, nota.golpe, nota.tics);
123035
+ const pentagrama = pentagramaDelMusico(nota.pentagrama, indice, pistaId, pista ?? 1);
123036
+ const tiempo = ticsDelGolpe(indice, pistaId, compas, voz, nota.golpe, nota.tics, pentagrama);
122422
123037
  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);
123038
+ const cursor = cursorEn(indice, pistaId, compas, voz, tiempo, nombrada.clase === "trastes" ? nombrada.cuerda : 1, pentagrama);
122424
123039
  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
123040
  if (salio) borradas += 1;
122426
123041
  }
@@ -123310,7 +123925,7 @@ function registrarHerramientasDelPuente(servidor2) {
123310
123925
  title: "Abrir una obra en la pantalla del m\xFAsico",
123311
123926
  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
123927
  inputSchema: {
123313
- ruta: external_exports.string().min(1).describe("La ruta completa en el disco, terminada en .mtabs o .gp")
123928
+ 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
123929
  }
123315
123930
  },
123316
123931
  async ({ ruta }) => {
@@ -123943,7 +124558,8 @@ function registrarHerramientasDeEstructura(servidor2) {
123943
124558
  nombre: nombre ?? delCatalogo.nombre,
123944
124559
  nombreCorto: delCatalogo.nombreCorto,
123945
124560
  afinacion: delCatalogo.afinacion,
123946
- programaMidi: delCatalogo.programaMidi
124561
+ programaMidi: delCatalogo.programaMidi,
124562
+ pentagramas: delCatalogo.pentagramas
123947
124563
  });
123948
124564
  const vc = volcar(documento);
123949
124565
  return texto2({
@@ -124516,7 +125132,7 @@ function registrarHerramientasDeMusica(servidor2) {
124516
125132
  throw new ProblemaConLaObra("Ese golpe ya tiene notas: sin el nombre no hay nada que escribir.");
124517
125133
  }
124518
125134
  const golpe = indexar(sitio.documento);
124519
- const compasId = golpe.compasId(sitio.cursor.pistaId, sitio.cursor.compas);
125135
+ const compasId = golpe.compasId(sitio.cursor.pistaId, sitio.cursor.compas, sitio.cursor.pentagrama);
124520
125136
  const puesto = compasId ? golpe.figuraEn(compasId, sitio.cursor.voz, sitio.cursor.tiempo)?.datos : void 0;
124521
125137
  return texto2({
124522
125138
  acorde: nombre,