mandioca-tabs-mcp 0.2.15 → 0.2.17

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 +1771 -38
  2. package/package.json +1 -1
package/index.mjs CHANGED
@@ -16490,6 +16490,12 @@ var init_atajos = __esm({
16490
16490
  { id: "multipista", nombre: "Ver todas las pistas", grupo: "Vista y pistas" },
16491
16491
  { id: "una-pista", nombre: "Ver una sola pista", grupo: "Vista y pistas" },
16492
16492
  { id: "anacruza", nombre: "Anacruza ac\xE1", grupo: "Compases" },
16493
+ // ★ La voz del cursor (2026-11-10). Sin tecla de fábrica: Alt+número está inerte a propósito.
16494
+ { id: "voz-1", nombre: "Escribir en la voz 1", grupo: "Escribir notas" },
16495
+ { id: "voz-2", nombre: "Escribir en la voz 2", grupo: "Escribir notas" },
16496
+ { id: "voz-3", nombre: "Escribir en la voz 3", grupo: "Escribir notas" },
16497
+ { id: "voz-4", nombre: "Escribir en la voz 4", grupo: "Escribir notas" },
16498
+ { id: "voz-siguiente", nombre: "Pasar a la voz siguiente", grupo: "Escribir notas" },
16493
16499
  // ── ⛔⛔ EL MENÚ DE LA LÍNEA DIVISORIA, que faltaba (2026-09-01) ───────────────
16494
16500
  //
16495
16501
  // Estas cuatro se construyeron el 2026-09-01 con su menú, su modelo y sus cuatro
@@ -16598,6 +16604,9 @@ var init_atajos = __esm({
16598
16604
  // ★ Agregado el 2026-09-03. Va en «Audio y mezcla» y no en un grupo propio porque es lo que
16599
16605
  // uno prende para sincronizar a oído, junto al imán y a «oír el tramo».
16600
16606
  { id: "metronomo", nombre: "Metr\xF3nomo: marcar el pulso al reproducir", grupo: "Audio y mezcla" },
16607
+ // ★ Agregados el 2026-11-10 (práctica). Sin tecla de fábrica: cada uno se la pone.
16608
+ { id: "bucle", nombre: "Bucle: repetir el pasaje marcado o el comp\xE1s del cursor", grupo: "Audio y mezcla" },
16609
+ { id: "cuenta-previa", nombre: "Cuenta previa: un comp\xE1s de clics antes de entrar", grupo: "Audio y mezcla" },
16601
16610
  { id: "oir-tramo", nombre: "O\xEDr la grabaci\xF3n desde el comp\xE1s del cursor", grupo: "Audio y mezcla" },
16602
16611
  { id: "anclar", nombre: "Anclar el comp\xE1s del cursor a la grabaci\xF3n", grupo: "Audio y mezcla" },
16603
16612
  { id: "desanclar", nombre: "Soltar el comp\xE1s del cursor de la grabaci\xF3n", grupo: "Audio y mezcla" },
@@ -20704,8 +20713,19 @@ var init_piano = __esm({
20704
20713
  });
20705
20714
 
20706
20715
  // packages/editor/src/loudness.ts
20716
+ var MUESTRAS_POR_TRAMO, MUESTRAS_POR_TRAMO_DEL_PICO, FASES_BS1770, COEFICIENTES, GANANCIA_MAXIMA;
20707
20717
  var init_loudness = __esm({
20708
20718
  "packages/editor/src/loudness.ts"() {
20719
+ MUESTRAS_POR_TRAMO = 1 << 18;
20720
+ MUESTRAS_POR_TRAMO_DEL_PICO = 1 << 14;
20721
+ FASES_BS1770 = [
20722
+ [0.001708984375, 0.010986328125, -0.0196533203125, 0.033203125, -0.0594482421875, 0.1373291015625, 0.97216796875, -0.102294921875, 0.047607421875, -0.026611328125, 0.014892578125, -0.00830078125],
20723
+ [-0.0291748046875, 0.029296875, -0.0517578125, 0.089111328125, -0.16650390625, 0.465087890625, 0.77978515625, -0.2003173828125, 0.1015625, -0.0582275390625, 0.0330810546875, -0.0189208984375],
20724
+ [-0.0189208984375, 0.0330810546875, -0.0582275390625, 0.1015625, -0.2003173828125, 0.77978515625, 0.465087890625, -0.16650390625, 0.089111328125, -0.0517578125, 0.029296875, -0.0291748046875],
20725
+ [-0.00830078125, 0.014892578125, -0.026611328125, 0.047607421875, -0.102294921875, 0.97216796875, 0.1373291015625, -0.0594482421875, 0.033203125, -0.0196533203125, 0.010986328125, 0.001708984375]
20726
+ ];
20727
+ COEFICIENTES = Float64Array.from({ length: 48 }, (_, i2) => FASES_BS1770[i2 % 4][Math.floor(i2 / 4)]);
20728
+ GANANCIA_MAXIMA = Math.max(...FASES_BS1770.map((fase) => fase.reduce((s, c) => s + Math.abs(c), 0)));
20709
20729
  }
20710
20730
  });
20711
20731
 
@@ -21620,6 +21640,22 @@ var init_barra = __esm({
21620
21640
  principiante: "Prende o apaga un clic que marca el pulso mientras suena la obra. Prendido, aparece tambi\xE9n en el mezclador con su propio volumen.",
21621
21641
  profesional: "Clic de metr\xF3nomo; volumen propio en el mezclador."
21622
21642
  },
21643
+ "barra.bucle": {
21644
+ nombre: "Bucle",
21645
+ accion: "audio-bucle",
21646
+ principiante: "Repite una y otra vez el pasaje que marcaste, o el comp\xE1s del cursor si no marcaste nada. Al lado del bot\xF3n se ven los compases que se repiten.",
21647
+ profesional: "Loop del pasaje marcado o del comp\xE1s del cursor."
21648
+ },
21649
+ "barra.practica": {
21650
+ nombre: "Pr\xE1ctica",
21651
+ principiante: "Ajustes para practicar: un comp\xE1s de cuenta antes de que entre la m\xFAsica, y que la velocidad suba sola cada tantas vueltas del bucle hasta la que elijas. De f\xE1brica todo apagado.",
21652
+ profesional: "Count-in y speed trainer del bucle."
21653
+ },
21654
+ "barra.voz": {
21655
+ nombre: "Voz",
21656
+ principiante: "En qu\xE9 voz escribes. Una voz es una l\xEDnea mel\xF3dica dentro del mismo pentagrama: por ejemplo, el bajo en la voz 1 y la melod\xEDa en la voz 2, cada una con sus propias figuras. Lo que teclees va a la voz marcada.",
21657
+ profesional: "Voz del cursor (1\u20134)."
21658
+ },
21623
21659
  "barra.selector-sigue": {
21624
21660
  nombre: "El selector sigue a la reproducci\xF3n",
21625
21661
  principiante: "Prendido, el cursor de escritura acompa\xF1a a la m\xFAsica mientras suena. Apagado, el cursor se queda donde lo pusiste, y cada vez que aprietas play vuelve a sonar el mismo pasaje: sirve para practicar una parte.",
@@ -22626,6 +22662,11 @@ var init_aspecto2 = __esm({
22626
22662
  principiante: "Marcado, la partitura muestra al principio la afinaci\xF3n de cada cuerda.",
22627
22663
  profesional: "Afinaci\xF3n en el pliego."
22628
22664
  },
22665
+ "aspecto.diagramas": {
22666
+ nombre: "Diagramas de acordes",
22667
+ principiante: "Adem\xE1s del nombre (Am, G7\u2026), un cuadrito con los trastes de cada acorde: sobre la partitura o en una lista al comienzo. Salen de las notas que escribiste; si un nombre no est\xE1 escrito con notas en ning\xFAn lado, queda solo el nombre. De f\xE1brica, apagado.",
22668
+ profesional: "Chord diagrams: en la partitura o arriba. Forma tomada de lo escrito."
22669
+ },
22629
22670
  "aspecto.restablecer": {
22630
22671
  nombre: "Restablecer",
22631
22672
  principiante: "Devuelve esta secci\xF3n a como ven\xEDa de f\xE1brica. Las dem\xE1s secciones no se tocan.",
@@ -23069,7 +23110,7 @@ function _usingCtx() {
23069
23110
  }
23070
23111
  };
23071
23112
  }
23072
- var __defProp2, __exportAll, ResizeObserverPolyfill, IntersectionObserverPolyfill, AlphaTabErrorType, AlphaTabError, VersionInfo, DynamicValue, MidiUtils, AutomationType, SyncPointData, Automation, BendPoint, BendStyle, BendType, BrushType, CrescendoType, Duration, GraceType, AccentuationType, Fingers, HarmonicType, NoteAccidentalMode, Ottavia, SlideInType, SlideOutType, Slur, SlurSegmentKind, VibratoType, TabRhythmMode, FingeringMode, NotationMode, NotationElement, NotationSettings, Lazy, LogLevel, ConsoleLogger, Logger, AccidentalType, Clef, SimileMark, ElementStyle, KeySignature, KeySignatureType, SustainPedalMarkerType, SustainPedalMarker, BarSubElement, BarStyle, BarLineStyle, Bar, TripletFeel, BeamingRules, MasterBar, BracketExtendMode, TrackNamePolicy, TrackNameMode, TrackNameOrientation, BarNumberDisplay, RenderStylesheet, RepeatGroup, GraceGroup, VoiceSubElement, VoiceStyle, Voice$1, TextAlign, TextBaseline, MeasuredText, CanvasHelper, ScoreSubElement, HeaderFooterStyle, ScoreStyle, Score, SynthConstants, TuningParseResult, TuningParseResultTone, ModelUtils, PickStroke, MusicFontSymbol, MusicFontSymbolLookup, TechniqueSymbolPlacement, InstrumentArticulation, PercussionMapper, NoteOrnament, NoteIdBag, NoteSubElement, NoteStyle, Note3, TupletGroup, WhammyType, GolpeType, FadeType, WahPedal, BarreShape, Rasgueado, TremoloPickingStyle, TremoloPickingEffect, BeatBeamingMode, BeatSubElement, BeatStyle, Beat, BendPointCloner, NoteCloner, SyncPointDataCloner, AutomationCloner, TremoloPickingEffectCloner, BeatCloner, AlphaTex1EnumMappings, AlphaTex1LanguageDefinitions, AlphaTexNodeType, AlphaTexDiagnosticsSeverity, AlphaTexDiagnosticCode, AlphaTexDiagnosticBag, AlphaTexAccidentalMode, AlphaTexVoiceMode, AlphaTexStaffNoteKind, ArgumentListParseTypesMode, TypeConversions, IOHelper, AlphaTexLexer, AlphaTexParseMode, AlphaTexParser, Atnf, AlphaTex1MetaDataReader, ApplyNodeResult, ApplyStructuralMetaDataResult, GeneralMidi, Chord3, FormatError, Color, FermataType, Fermata, Lyrics, Section, Tuning, Staff, PlaybackInformation, TrackSubElement, TrackStyle, Track, BeamDirection, AlphaTex1LanguageHandler, EndOfReaderError, OverflowError, ThrowingReadable, ScoreImporter, UnsupportedFormatError, ByteBuffer, AlphaTexErrorWithDiagnostics, AlphaTexImportState, AlphaTexImporter, Huffman$1, Found, NeedBit, NeedBits, HuffTools, InflateWindow, Inflate, ZipEntry, ZipReader, XmlNodeType, XmlNode, XmlError, XmlParser, XmlWriter, XmlDocument, DrawObject, TextDrawObject, GuitarDrawObject, SlurDrawObject, WavyLineDrawObject, TupletBracketDrawObject, WedgeDrawObject, VoltaDrawObject, OctaveClefDrawObject, TrillDrawObject, StaffLayout, Bracket, CapellaVoiceState, CapellaParser, CapellaImporter, Direction, Gp3To5Importer, GpBinaryHelpers, MixTableChange, Bounds, BinaryStylesheet, BackingTrack, GpifRhythm, GpifSound, GpifParser, PartConfigurationScoreView, PartConfigurationTrackViewGroup, PartConfiguration, LayoutConfigurationScoreView, LayoutConfigurationTrackViewGroup, LayoutConfiguration, Gp7To8Importer, BitReader, GpxFile, GpxFileSystem, GpxImporter, BeatSteps, AccidentalHelper, StaffContext, InstrumentArticulationWithPlaybackInfo, TrackInfo, MusicXmlImporter, LayoutMode, EventEmitter, EventEmitterOfT, AlphaSynthWebAudioSynthOutputDevice, WebAudioHelper, AlphaSynthWebAudioOutputBase, FileLoadError, EngravingSettingsCloner, JsonHelper, EngravingStemInfo, EngravingSettings, FontParserToken, FontParser, FontStyle, FontWeight, Font, RenderingResources, StaveProfile, SystemsLayoutMode, DisplaySettings, ImporterSettings, ScrollMode, VibratoPlaybackSettings, SlidePlaybackSettings, PlayerOutputMode, PlayerMode, PlayerSettings, CoreSettingsSerializer, EngravingStemInfoSerializer, EngravingSettingsSerializer, RenderingResourcesSerializer, DisplaySettingsSerializer, NotationSettingsSerializer, ImporterSettingsSerializer, VibratoPlaybackSettingsSerializer, SlidePlaybackSettingsSerializer, PlayerSettingsSerializer, ExporterSettingsSerializer, SettingsSerializer, ExporterSettings, Settings, ScoreLoader, BrowserMouseEventArgs, HtmlElementContainer, WebPlatform, FontSizeDefinition, FontSizes, FontLoadingChecker, CircularSampleBuffer, AlphaSynthScriptProcessorOutput, BeamingRulesSerializer, SectionSerializer, SyncPointDataSerializer, AutomationSerializer, FermataSerializer, MasterBarSerializer, BendPointSerializer, NoteStyleSerializer, NoteSerializer, TremoloPickingEffectSerializer, BeatStyleSerializer, BeatSerializer, VoiceStyleSerializer, VoiceSerializer, SustainPedalMarkerSerializer, BarStyleSerializer, BarSerializer, ChordSerializer, TuningSerializer, StaffSerializer, PlaybackInformationSerializer, InstrumentArticulationSerializer, TrackStyleSerializer, TrackSerializer, RenderStylesheetSerializer, BackingTrackSerializer, HeaderFooterStyleSerializer, ScoreStyleSerializer, ScoreSerializer, MidiFileFormat, MidiTrack, MidiFile, MidiEventType, MidiEvent, TimeSignatureEvent, AlphaTabSysExEvent, AlphaTabMetronomeEvent, AlphaTabRestEvent, NoteEvent, NoteOnEvent, NoteOffEvent, ControlChangeEvent, ProgramChangeEvent, TempoChangeEvent, PitchBendEvent, NoteBendEvent, EndOfTrackEvent, JsonConverter, MidiEventsPlayedEventArgs, PlaybackRangeChangedEventArgs, PlayerState, PlayerStateChangedEventArgs, PositionChangedEventArgs, AlphaSynthWebWorkerApi, BarBounds, BeatBounds, MasterBarBounds, NoteBounds, StaffSystemBounds, BoundsLookup, AlphaTabWorkerScoreRenderer, Cursors, ScalableHtmlElementContainer, AudioElementBackingTrackSynthOutput, QueueItem, Queue, AudioExportOptions, AudioExportChunk, SynthEvent, BackingTrackSyncPoint, MidiFileSequencerTempoChange, MidiSequencerState, MidiFileSequencer, RiffChunk, OggPacket, OggReader, VorbisStream, IntBitReaderReadResult, IntBitReader, VorbisSetupHeader, VorbisUtils, FastListArray, FastRange, VorbisCodebook, HuffmanListNode, Huffman, VorbisTimeDomainTransform, VorbisFloorData0, VorbisFloor0, VorbisFloor1Data, VorbisFloor1, VorbisFloor, VorbisResidue0, VorbisResidue1, VorbisResidue2, VorbisResidue, VorbisMapping, VorbisModeOverlapInfo, VorbisModePacketInfo, VorbisReadNextPacketResult, VorbisMode, MdctImpl, Mdct, VorbisStreamDecoder, DecodeNextPacketInfo, VorbisStreamReader, VorbisFile, Hydra, HydraIbag, HydraImod, HydraIgen, HydraInst, HydraPbag, HydraPgen, HydraPhdr, HydraPmod, HydraShdr, HydraGenAmount, Channel, Channels, LoopMode, OutputMode, Preset, SynthHelper, Envelope, Region, VoiceEnvelopeSegment, VoiceEnvelope, VoiceLfo, VoiceLowPass, Voice, ControllerType, TinySoundFont, AlphaSynthBase, AlphaSynth, AlphaSynthAudioExporter, BackingTrackAudioSynthesizer, BackingTrackPlayer, AlphaSynthAudioExporterWorkerApi, RenderFinishedEventArgs, ScoreRenderer, BrowserUiFacade, AlphaSynthWebWorklet, AlphaSynthAudioWorkletOutput, Html5Canvas, AlphaSynthMidiFileHandler, Repeat, MidiPlaybackController, BeatTickLookupItem, BeatTickLookup, MasterBarTickLookupTempoChange, MasterBarTickLookup, PlaybackRange, MidiTickLookupFindBeatResultCursorMode, MidiTickLookupFindBeatResult, TrackLookupBeatVisibilityChecker, MidiTickLookup, MidiNoteDuration, TripletFeelDurations, RasgueadoInfo, PlayThroughContext, MidiFileGenerator, ToNextBeatAnimatingCursorHandler, NonAnimatingCursorHandler, BeatXPosition, Glyph, BeatContainerGlyphBase, BeatContainerGlyph, ScoreRendererWrapper, ResizeEventArgs, BasicScrollHandler, VerticalContinuousScrollHandler, VerticalOffScreenScrollHandler, VerticalSmoothScrollHandler, HorizontalContinuousScrollHandler, HorizontalOffScreenScrollHandler, HorizontalSmoothScrollHandler, ActiveBeatsChangedEventArgs, AlphaSynthWrapper, ExternalMediaSynthOutput, ExternalMediaPlayer, BoundsLookupVisibilityChecker, AlphaTabApiBase, ProgressEventArgs, AlphaTabApi, JQueryAlphaTab, SkiaCanvas, SvgCanvas, CssFontSvgCanvas, AlphaSynthWorkerSynthOutput, AlphaSynthWebWorker, AlphaTabWebWorker, EffectBandMode, BarRendererFactory, EffectBarGlyphSizing, EffectGlyph, AlternateEndingsGlyph, EffectInfo, AlternateEndingsEffectInfo, GroupedEffectGlyph, LineRangedGlyph, BeatBarreEffectInfo, BeatTimerGlyph, BeatTimerEffectInfo, TextGlyph, CapoEffectInfo, ChordDiagramGlyph, ChordsEffectInfo, CrescendoGlyph, CrescendoEffectInfo, TargetDirectionGlyph, JumpDirectionGlyph, DirectionsContainerGlyph, DirectionsEffectInfo, MusicFontGlyph, MusicFontTextGlyph, DynamicsGlyph, DynamicsEffectInfo, FadeGlyph, FadeEffectInfo, FermataGlyph, FermataEffectInfo, GlyphGroup, ElementStyleHelper, ElementStyleScope, FingeringInfo, FingeringGroupGlyph, FingeringEffectInfo, FreeTimeEffectInfo, GuitarGolpeGlyph, GolpeEffectInfo, NoteEffectInfoBase, HarmonicsEffectInfo, LeftHandTapGlyph, LeftHandTapEffectInfo, LetRingEffectInfo, LyricsGlyph, LyricsEffectInfo, MarkerEffectInfo, NoteOrnamentGlyph, NoteOrnamentEffectInfo, AccidentalGlyph, NumberedKeySignatureGlyph, NumberedBarKeySignatureEffectInfo, OttavaGlyph, OttaviaEffectInfo, PalmMuteEffectInfo, PickSlideEffectInfo, PickStrokeGlyph, PickStrokeEffectInfo, RasgueadoEffectInfo, EffectBand, EffectBandSlotShared, EffectBandSlot, EffectBandSizingInfo, EffectBandContainer, LeftToRightLayoutingGlyphGroup, MultiVoiceContainerGlyph, TieGlyph, NoteTieGlyph, ContinuationTieGlyph, NumberGlyph, MultiBarRestGlyph, MultiBarRestBeatContainerGlyph, BeamingHelperDrawInfo, BeamingHelper, ReservedLayoutAreaSlot, ReservedLayoutArea, BarCollisionHelper, BeamingRuleLookup, BarHelpers, NoteYPosition, NoteXPosition, BarRendererBase, VibratoGlyphBase, NoteVibratoGlyph, TabBendRenderPoint, TabBendGlyph, TabWhammyBarGlyph, SimpleDipWhammyBarEffectInfo, BeatVibratoGlyph, SlightBeatVibratoEffectInfo, SlightNoteVibratoEffectInfo, SustainPedalGlyph, SustainPedalEffectInfo, TabWhammyEffectInfo, TapEffectInfo, BarTempoGlyph, TempoEffectInfo, TextEffectInfo, TrillGlyph, TrillEffectInfo, TripletFeelGlyph, TripletFeelEffectInfo, WahPedalGlyph, WahPedalEffectInfo, WhammyBarEffectInfo, WideBeatVibratoEffectInfo, WideNoteVibratoEffectInfo, RowGlyphContainer, RowContainerGlyph, ChordDiagramContainerGlyph, TuningContainerGlyph, TuningGlyph, SlurRegistry, RenderStaff, Spring, BarLayoutingInfo, MasterBarsRenderers, StaffTrackGroup, SystemBracket, SingleTrackSystemBracket, SimilarInstrumentSystemBracket, StaffSystem, ScoreLayout, HorizontalScreenLayoutPartialInfo, HorizontalScreenLayout, VerticalLayoutBase, PageViewLayout, ParchmentLayout, BarLineGlyphBase, BarLineLightGlyph, BarLineDottedGlyph, BarLineDashedGlyph, BarLineHeavyGlyph, BarLineRepeatDotsGlyph, BarLineShortGlyph, BarLineTickGlyph, BarLineGlyph, BarNumberGlyph, NumberedTieGlyph, AccidentalColumnInfo, AccidentalGroupGlyph, AugmentationDotGlyph, BeatGlyphBase, BeatOnNoteGlyphBase, DeadSlappedBeatGlyph, NumberedNoteHeadGlyph, SpacingGlyph, NumberedBeatPreNotesGlyph, NumberedBeatGlyph, TabTieGlyph, TieGlyphLabels, TabSlurGlyph, NumberedSlurGlyph, NumberedBeatContainerGlyph, NumberedNoteBeatContainerGlyphBase, NumberedDashBeatContainerGlyph, GhostParenthesisGlyph, TimeSignatureGlyph, ScoreTimeSignatureGlyph, FlagGlyph, RepeatCountGlyph, LineBarRenderer, NumberedBarRenderer, NumberedBarRendererFactory, ClefGlyph, KeySignatureGlyph, AccentuationGlyph, ArticStaccatoAboveGlyph, NoteHeadGlyphBase, NoteHeadGlyph, DeadNoteHeadGlyph, DiamondNoteHeadGlyph, GhostNoteInfo, GhostNoteContainerGlyph, PercussionNoteHeadGlyph, PictEdgeOfCymbalGlyph, ScoreChordNoteHeadInfo, ScoreNoteChordGlyphBase, TremoloPickingGlyph, ScoreNoteChordGlyph, ScoreRestGlyph, BendNoteHeadGroupGlyph, ScoreHelperNotesBaseGlyph, ScoreWhammyBarGlyph, SlashNoteHeadGlyph, StringNumberContainerGlyph, ScoreBeatGlyph, ScoreBrushGlyph, ScoreBeatPreNotesGlyph, ScoreBendGlyph, ScoreLegatoGlyph, ScoreSlideLineGlyph, ScoreTieGlyph, ScoreSlurGlyph, ScoreBeatContainerGlyph, ScoreBarRenderer, ScoreBarRendererFactory, SlashRestGlyph, SlashBeatGlyph, SlashTieGlyph, SlashBeatContainerGlyph, SlashBarRenderer, SlashBarRendererFactory, NoteNumberGlyph, TabNoteChordGlyph, TabRestGlyph, TabBeatGlyph, TabBrushGlyph, TabBeatPreNotesGlyph, TabSlideLineGlyph, TabBeatContainerGlyph, TabClefGlyph, TabTimeSignatureGlyph, TabBarRenderer, TabBarRendererFactory, LayoutEngineFactory, RenderEngineFactory, Environment, FontFileFormat, CoreSettings, _barrel_exports$8, _barrel_exports$1, ScoreExporter, AlphaTexWriter, AlphaTexPrinter, AlphaTexExporter, GpifMidiProgramInfo, GpifInstrumentSet, GpifInstrumentElement, GpifInstrumentArticulation, GpifSoundMapper, GpifWriter, Crc32, DeflaterConstants, Tree, DeflaterHuffman, DeflaterEngine, PendingBuffer, Deflater, ZipCentralDirectoryHeader, ZipWriter, Gp7Exporter, _barrel_exports, DeprecatedMidiEvent, MetaEventType, MetaEvent, MetaDataEvent, MetaNumberEvent, Midi20PerNotePitchBendEvent, SystemCommonType, SystemCommonEvent, AlphaTabSystemExclusiveEvents, SystemExclusiveEvent, _barrel_exports$3, _barrel_exports$4;
23113
+ var __defProp2, __exportAll, ResizeObserverPolyfill, IntersectionObserverPolyfill, AlphaTabErrorType, AlphaTabError, VersionInfo, DynamicValue, MidiUtils, AutomationType, SyncPointData, Automation, BendPoint, BendStyle, BendType, BrushType, CrescendoType, Duration, GraceType, AccentuationType, Fingers, HarmonicType, NoteAccidentalMode, Ottavia, SlideInType, SlideOutType, Slur, SlurSegmentKind, VibratoType, TabRhythmMode, FingeringMode, NotationMode, NotationElement, NotationSettings, Lazy, LogLevel, ConsoleLogger, Logger, AccidentalType, Clef, SimileMark, ElementStyle, KeySignature, KeySignatureType, SustainPedalMarkerType, SustainPedalMarker, BarSubElement, BarStyle, BarLineStyle, Bar, TripletFeel, BeamingRules, MasterBar, BracketExtendMode, TrackNamePolicy, TrackNameMode, TrackNameOrientation, BarNumberDisplay, RenderStylesheet, RepeatGroup, GraceGroup, VoiceSubElement, VoiceStyle, Voice$1, TextAlign, TextBaseline, MeasuredText, CanvasHelper, ScoreSubElement, HeaderFooterStyle, ScoreStyle, Score, SynthConstants, TuningParseResult, TuningParseResultTone, ModelUtils, PickStroke, MusicFontSymbol, MusicFontSymbolLookup, TechniqueSymbolPlacement, InstrumentArticulation, PercussionMapper, NoteOrnament, NoteIdBag, NoteSubElement, NoteStyle, Note3, TupletGroup, WhammyType, GolpeType, FadeType, WahPedal, BarreShape, Rasgueado, TremoloPickingStyle, TremoloPickingEffect, BeatBeamingMode, BeatSubElement, BeatStyle, Beat, BendPointCloner, NoteCloner, SyncPointDataCloner, AutomationCloner, TremoloPickingEffectCloner, BeatCloner, AlphaTex1EnumMappings, AlphaTex1LanguageDefinitions, AlphaTexNodeType, AlphaTexDiagnosticsSeverity, AlphaTexDiagnosticCode, AlphaTexDiagnosticBag, AlphaTexAccidentalMode, AlphaTexVoiceMode, AlphaTexStaffNoteKind, ArgumentListParseTypesMode, TypeConversions, IOHelper, AlphaTexLexer, AlphaTexParseMode, AlphaTexParser, Atnf, AlphaTex1MetaDataReader, ApplyNodeResult, ApplyStructuralMetaDataResult, GeneralMidi, Chord3, FormatError, Color, FermataType, Fermata, Lyrics, Section, Tuning, Staff, PlaybackInformation, TrackSubElement, TrackStyle, Track, BeamDirection, AlphaTex1LanguageHandler, EndOfReaderError, OverflowError, ThrowingReadable, ScoreImporter, UnsupportedFormatError, ByteBuffer, AlphaTexErrorWithDiagnostics, AlphaTexImportState, AlphaTexImporter, Huffman$1, Found, NeedBit, NeedBits, HuffTools, InflateWindow, Inflate, ZipEntry, ZipReader, XmlNodeType, XmlNode, XmlError, XmlParser, XmlWriter, XmlDocument, DrawObject, TextDrawObject, GuitarDrawObject, SlurDrawObject, WavyLineDrawObject, TupletBracketDrawObject, WedgeDrawObject, VoltaDrawObject, OctaveClefDrawObject, TrillDrawObject, StaffLayout, Bracket, CapellaVoiceState, CapellaParser, CapellaImporter, Direction, Gp3To5Importer, GpBinaryHelpers, MixTableChange, Bounds, BinaryStylesheet, BackingTrack, GpifRhythm, GpifSound, GpifParser, PartConfigurationScoreView, PartConfigurationTrackViewGroup, PartConfiguration, LayoutConfigurationScoreView, LayoutConfigurationTrackViewGroup, LayoutConfiguration, Gp7To8Importer, BitReader, GpxFile, GpxFileSystem, GpxImporter, BeatSteps, AccidentalHelper, StaffContext, InstrumentArticulationWithPlaybackInfo, TrackInfo, MusicXmlImporter, LayoutMode, EventEmitter, EventEmitterOfT, AlphaSynthWebAudioSynthOutputDevice, WebAudioHelper, AlphaSynthWebAudioOutputBase, FileLoadError, EngravingSettingsCloner, JsonHelper, EngravingStemInfo, EngravingSettings, FontParserToken, FontParser, FontStyle, FontWeight, Font, RenderingResources, StaveProfile, SystemsLayoutMode, DisplaySettings, ImporterSettings, ScrollMode, VibratoPlaybackSettings, SlidePlaybackSettings, PlayerOutputMode, PlayerMode, PlayerSettings, CoreSettingsSerializer, EngravingStemInfoSerializer, EngravingSettingsSerializer, RenderingResourcesSerializer, DisplaySettingsSerializer, NotationSettingsSerializer, ImporterSettingsSerializer, VibratoPlaybackSettingsSerializer, SlidePlaybackSettingsSerializer, PlayerSettingsSerializer, ExporterSettingsSerializer, SettingsSerializer, ExporterSettings, Settings, ScoreLoader, BrowserMouseEventArgs, HtmlElementContainer, WebPlatform, FontSizeDefinition, FontSizes, FontLoadingChecker, CircularSampleBuffer, AlphaSynthScriptProcessorOutput, BeamingRulesSerializer, SectionSerializer, SyncPointDataSerializer, AutomationSerializer, FermataSerializer, MasterBarSerializer, BendPointSerializer, NoteStyleSerializer, NoteSerializer, TremoloPickingEffectSerializer, BeatStyleSerializer, BeatSerializer, VoiceStyleSerializer, VoiceSerializer, SustainPedalMarkerSerializer, BarStyleSerializer, BarSerializer, ChordSerializer, TuningSerializer, StaffSerializer, PlaybackInformationSerializer, InstrumentArticulationSerializer, TrackStyleSerializer, TrackSerializer, RenderStylesheetSerializer, BackingTrackSerializer, HeaderFooterStyleSerializer, ScoreStyleSerializer, ScoreSerializer, MidiFileFormat, MidiTrack, MidiFile, MidiEventType, MidiEvent, TimeSignatureEvent, AlphaTabSysExEvent, AlphaTabMetronomeEvent, AlphaTabRestEvent, NoteEvent, NoteOnEvent, NoteOffEvent, ControlChangeEvent, ProgramChangeEvent, TempoChangeEvent, PitchBendEvent, NoteBendEvent, EndOfTrackEvent, JsonConverter, MidiEventsPlayedEventArgs, PlaybackRangeChangedEventArgs, PlayerState, PlayerStateChangedEventArgs, PositionChangedEventArgs, AlphaSynthWebWorkerApi, BarBounds, BeatBounds, MasterBarBounds, NoteBounds, StaffSystemBounds, BoundsLookup, AlphaTabWorkerScoreRenderer, Cursors, ScalableHtmlElementContainer, AudioElementBackingTrackSynthOutput, QueueItem, Queue, AudioExportOptions, AudioExportChunk, SynthEvent, BackingTrackSyncPoint, MidiFileSequencerTempoChange, MidiSequencerState, MidiFileSequencer, RiffChunk, OggPacket, OggReader, VorbisStream, IntBitReaderReadResult, IntBitReader, VorbisSetupHeader, VorbisUtils, FastListArray, FastRange, VorbisCodebook, HuffmanListNode, Huffman, VorbisTimeDomainTransform, VorbisFloorData0, VorbisFloor0, VorbisFloor1Data, VorbisFloor1, VorbisFloor, VorbisResidue0, VorbisResidue1, VorbisResidue2, VorbisResidue, VorbisMapping, VorbisModeOverlapInfo, VorbisModePacketInfo, VorbisReadNextPacketResult, VorbisMode, MdctImpl, Mdct, VorbisStreamDecoder, DecodeNextPacketInfo, VorbisStreamReader, VorbisFile, Hydra, HydraIbag, HydraImod, HydraIgen, HydraInst, HydraPbag, HydraPgen, HydraPhdr, HydraPmod, HydraShdr, HydraGenAmount, Channel, Channels, LoopMode, OutputMode, Preset, SynthHelper, Envelope, Region, VoiceEnvelopeSegment, VoiceEnvelope, VoiceLfo, VoiceLowPass, Voice, ControllerType, TinySoundFont, AlphaSynthBase, AlphaSynth, AlphaSynthAudioExporter, BackingTrackAudioSynthesizer, BackingTrackPlayer, AlphaSynthAudioExporterWorkerApi, RenderFinishedEventArgs, ScoreRenderer, BrowserUiFacade, AlphaSynthWebWorklet, AlphaSynthAudioWorkletOutput, Html5Canvas, AlphaSynthMidiFileHandler, Repeat, MidiPlaybackController, BeatTickLookupItem, BeatTickLookup, MasterBarTickLookupTempoChange, MasterBarTickLookup, PlaybackRange, MidiTickLookupFindBeatResultCursorMode, MidiTickLookupFindBeatResult, TrackLookupBeatVisibilityChecker, MidiTickLookup, MidiNoteDuration, TripletFeelDurations, RasgueadoInfo, PlayThroughContext, MidiFileGenerator, ToNextBeatAnimatingCursorHandler, NonAnimatingCursorHandler, BeatXPosition, Glyph, BeatContainerGlyphBase, BeatContainerGlyph, ScoreRendererWrapper, ResizeEventArgs, BasicScrollHandler, VerticalContinuousScrollHandler, VerticalOffScreenScrollHandler, VerticalSmoothScrollHandler, HorizontalContinuousScrollHandler, HorizontalOffScreenScrollHandler, HorizontalSmoothScrollHandler, ActiveBeatsChangedEventArgs, AlphaSynthWrapper, ExternalMediaSynthOutput, ExternalMediaPlayer, BoundsLookupVisibilityChecker, AlphaTabApiBase, ProgressEventArgs, AlphaTabApi, JQueryAlphaTab, SkiaCanvas, SvgCanvas, CssFontSvgCanvas, AlphaSynthWorkerSynthOutput, AlphaSynthWebWorker, AlphaTabWebWorker, EffectBandMode, BarRendererFactory, EffectBarGlyphSizing, EffectGlyph, AlternateEndingsGlyph, EffectInfo, AlternateEndingsEffectInfo, GroupedEffectGlyph, LineRangedGlyph, BeatBarreEffectInfo, BeatTimerGlyph, BeatTimerEffectInfo, TextGlyph, CapoEffectInfo, ChordDiagramGlyph, ChordsEffectInfo, CrescendoGlyph, CrescendoEffectInfo, TargetDirectionGlyph, JumpDirectionGlyph, DirectionsContainerGlyph, DirectionsEffectInfo, MusicFontGlyph, MusicFontTextGlyph, DynamicsGlyph, DynamicsEffectInfo, FadeGlyph, FadeEffectInfo, FermataGlyph, FermataEffectInfo, GlyphGroup, ElementStyleHelper, ElementStyleScope, FingeringInfo, FingeringGroupGlyph, FingeringEffectInfo, FreeTimeEffectInfo, GuitarGolpeGlyph, GolpeEffectInfo, NoteEffectInfoBase, HarmonicsEffectInfo, LeftHandTapGlyph, LeftHandTapEffectInfo, LetRingEffectInfo, LyricsGlyph, LyricsEffectInfo, MarkerEffectInfo, NoteOrnamentGlyph, NoteOrnamentEffectInfo, AccidentalGlyph, NumberedKeySignatureGlyph, NumberedBarKeySignatureEffectInfo, OttavaGlyph, OttaviaEffectInfo, PalmMuteEffectInfo, PickSlideEffectInfo, PickStrokeGlyph, PickStrokeEffectInfo, RasgueadoEffectInfo, EffectBand, EffectBandSlotShared, EffectBandSlot, EffectBandSizingInfo, EffectBandContainer, LeftToRightLayoutingGlyphGroup, MultiVoiceContainerGlyph, TieGlyph, NoteTieGlyph, ContinuationTieGlyph, NumberGlyph, MultiBarRestGlyph, MultiBarRestBeatContainerGlyph, BeamingHelperDrawInfo, BeamingHelper, ReservedLayoutAreaSlot, ReservedLayoutArea, BarCollisionHelper, BeamingRuleLookup, BarHelpers, NoteYPosition, NoteXPosition, BarRendererBase, VibratoGlyphBase, NoteVibratoGlyph, TabBendRenderPoint, TabBendGlyph, TabWhammyBarGlyph, SimpleDipWhammyBarEffectInfo, BeatVibratoGlyph, SlightBeatVibratoEffectInfo, SlightNoteVibratoEffectInfo, SustainPedalGlyph, SustainPedalEffectInfo, TabWhammyEffectInfo, TapEffectInfo, BarTempoGlyph, TempoEffectInfo, TextEffectInfo, TrillGlyph, TrillEffectInfo, TripletFeelGlyph, TripletFeelEffectInfo, WahPedalGlyph, WahPedalEffectInfo, WhammyBarEffectInfo, WideBeatVibratoEffectInfo, WideNoteVibratoEffectInfo, RowGlyphContainer, RowContainerGlyph, ChordDiagramContainerGlyph, TuningContainerGlyph, TuningGlyph, SlurRegistry, RenderStaff, Spring, BarLayoutingInfo, MasterBarsRenderers, StaffTrackGroup, SystemBracket, SingleTrackSystemBracket, SimilarInstrumentSystemBracket, StaffSystem, ScoreLayout, HorizontalScreenLayoutPartialInfo, HorizontalScreenLayout, VerticalLayoutBase, PageViewLayout, ParchmentLayout, BarLineGlyphBase, BarLineLightGlyph, BarLineDottedGlyph, BarLineDashedGlyph, BarLineHeavyGlyph, BarLineRepeatDotsGlyph, BarLineShortGlyph, BarLineTickGlyph, BarLineGlyph, BarNumberGlyph, NumberedTieGlyph, AccidentalColumnInfo, AccidentalGroupGlyph, AugmentationDotGlyph, BeatGlyphBase, BeatOnNoteGlyphBase, DeadSlappedBeatGlyph, NumberedNoteHeadGlyph, SpacingGlyph, NumberedBeatPreNotesGlyph, NumberedBeatGlyph, TabTieGlyph, TieGlyphLabels, TabSlurGlyph, NumberedSlurGlyph, NumberedBeatContainerGlyph, NumberedNoteBeatContainerGlyphBase, NumberedDashBeatContainerGlyph, GhostParenthesisGlyph, TimeSignatureGlyph, ScoreTimeSignatureGlyph, FlagGlyph, RepeatCountGlyph, LineBarRenderer, NumberedBarRenderer, NumberedBarRendererFactory, ClefGlyph, KeySignatureGlyph, AccentuationGlyph, ArticStaccatoAboveGlyph, NoteHeadGlyphBase, NoteHeadGlyph, DeadNoteHeadGlyph, DiamondNoteHeadGlyph, GhostNoteInfo, GhostNoteContainerGlyph, PercussionNoteHeadGlyph, PictEdgeOfCymbalGlyph, ScoreChordNoteHeadInfo, ScoreNoteChordGlyphBase, TremoloPickingGlyph, ScoreNoteChordGlyph, ScoreRestGlyph, BendNoteHeadGroupGlyph, ScoreHelperNotesBaseGlyph, ScoreWhammyBarGlyph, SlashNoteHeadGlyph, StringNumberContainerGlyph, ScoreBeatGlyph, ScoreBrushGlyph, ScoreBeatPreNotesGlyph, ScoreBendGlyph, ScoreLegatoGlyph, ScoreSlideLineGlyph, ScoreTieGlyph, ScoreSlurGlyph, ScoreBeatContainerGlyph, ScoreBarRenderer, ScoreBarRendererFactory, SlashRestGlyph, SlashBeatGlyph, SlashTieGlyph, SlashBeatContainerGlyph, SlashBarRenderer, SlashBarRendererFactory, NoteNumberGlyph, TabNoteChordGlyph, TabRestGlyph, TabBeatGlyph, TabBrushGlyph, TabBeatPreNotesGlyph, TabSlideLineGlyph, TabBeatContainerGlyph, TabClefGlyph, TabTimeSignatureGlyph, TabBarRenderer, TabBarRendererFactory, LayoutEngineFactory, RenderEngineFactory, Environment, FontFileFormat, CoreSettings, _barrel_exports$8, _barrel_exports$1, ScoreExporter, AlphaTexWriter, AlphaTexPrinter, AlphaTexExporter, GpifMidiProgramInfo, GpifInstrumentSet, GpifInstrumentElement, GpifInstrumentArticulation, GpifSoundMapper, GpifWriter, Crc32, DeflaterConstants, Tree, DeflaterHuffman, DeflaterEngine, PendingBuffer, Deflater, ZipCentralDirectoryHeader, ZipWriter, Gp7Exporter, _barrel_exports, DeprecatedMidiEvent, MetaEventType, MetaEvent, MetaDataEvent, MetaNumberEvent, Midi20PerNotePitchBendEvent, SystemCommonType, SystemCommonEvent, AlphaTabSystemExclusiveEvents, SystemExclusiveEvent, _barrel_exports$3, _barrel_exports$4, _barrel_exports$7;
23073
23114
  var init_alphaTab_core = __esm({
23074
23115
  "node_modules/@coderline/alphatab/dist/alphaTab.core.mjs"() {
23075
23116
  __defProp2 = Object.defineProperty;
@@ -87528,6 +87569,25 @@ ${AlphaTex1MetaDataReader.generateSignatures(signatures)}`,
87528
87569
  WahPedal: () => WahPedal,
87529
87570
  WhammyType: () => WhammyType
87530
87571
  });
87572
+ _barrel_exports$7 = /* @__PURE__ */ __exportAll({
87573
+ ActiveBeatsChangedEventArgs: () => ActiveBeatsChangedEventArgs,
87574
+ AlphaSynth: () => AlphaSynth,
87575
+ AlphaSynthAudioWorkletOutput: () => AlphaSynthAudioWorkletOutput,
87576
+ AlphaSynthBase: () => AlphaSynthBase,
87577
+ AlphaSynthScriptProcessorOutput: () => AlphaSynthScriptProcessorOutput,
87578
+ AlphaSynthWebAudioOutputBase: () => AlphaSynthWebAudioOutputBase,
87579
+ AlphaSynthWebWorkerApi: () => AlphaSynthWebWorkerApi,
87580
+ AudioExportChunk: () => AudioExportChunk,
87581
+ AudioExportOptions: () => AudioExportOptions,
87582
+ BackingTrackSyncPoint: () => BackingTrackSyncPoint,
87583
+ CircularSampleBuffer: () => CircularSampleBuffer,
87584
+ MidiEventsPlayedEventArgs: () => MidiEventsPlayedEventArgs,
87585
+ PlaybackRange: () => PlaybackRange,
87586
+ PlaybackRangeChangedEventArgs: () => PlaybackRangeChangedEventArgs,
87587
+ PlayerState: () => PlayerState,
87588
+ PlayerStateChangedEventArgs: () => PlayerStateChangedEventArgs,
87589
+ PositionChangedEventArgs: () => PositionChangedEventArgs
87590
+ });
87531
87591
  }
87532
87592
  });
87533
87593
 
@@ -89500,6 +89560,1184 @@ var init_importarGp = __esm({
89500
89560
  }
89501
89561
  });
89502
89562
 
89563
+ // packages/io/src/importarMidi.ts
89564
+ function esMidi(bytes) {
89565
+ return firmaEn(bytes, 0, "MThd") || firmaEn(bytes, 0, "RIFF") && firmaEn(bytes, 8, "RMID");
89566
+ }
89567
+ function importarMidi(bytes, opciones = {}) {
89568
+ const smf = leerSmf(bytes);
89569
+ const avisos = new Avisos();
89570
+ const leido = recolectar(smf, avisos);
89571
+ const score = armarScore(leido, opciones, avisos);
89572
+ const resultado = importarScore(score, opciones);
89573
+ resultado.avisos = resultado.avisos.filter((a) => !a.startsWith("Las preferencias de dibujo del archivo"));
89574
+ resultado.avisos.push(...avisos.lista());
89575
+ return resultado;
89576
+ }
89577
+ function firmaEn(bytes, desde, firma) {
89578
+ if (bytes.length < desde + firma.length) return false;
89579
+ for (let i2 = 0; i2 < firma.length; i2++) if (bytes[desde + i2] !== firma.charCodeAt(i2)) return false;
89580
+ return true;
89581
+ }
89582
+ function desenvolverRmid(bytes) {
89583
+ if (!(firmaEn(bytes, 0, "RIFF") && firmaEn(bytes, 8, "RMID"))) return bytes;
89584
+ const vista = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
89585
+ let pos = 12;
89586
+ while (pos + 8 <= bytes.length) {
89587
+ const largo = vista.getUint32(pos + 4, true);
89588
+ if (firmaEn(bytes, pos, "data")) {
89589
+ if (pos + 8 + largo > bytes.length) throw truncado("el bloque \xABdata\xBB del RMID");
89590
+ return bytes.subarray(pos + 8, pos + 8 + largo);
89591
+ }
89592
+ pos += 8 + largo + largo % 2;
89593
+ }
89594
+ throw new MidiIlegible("El archivo RMID no tiene adentro un bloque de datos MIDI.");
89595
+ }
89596
+ function leerSmf(entrada) {
89597
+ const bytes = desenvolverRmid(entrada);
89598
+ if (!firmaEn(bytes, 0, "MThd")) {
89599
+ throw new MidiIlegible("El archivo no es un MIDI: no empieza con la firma \xABMThd\xBB.");
89600
+ }
89601
+ if (bytes.length < 14) throw truncado("la cabecera");
89602
+ const vista = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
89603
+ const largoDeCabecera = vista.getUint32(4);
89604
+ if (largoDeCabecera < 6) throw new MidiIlegible("La cabecera del MIDI es m\xE1s corta de lo que manda el formato.");
89605
+ if (8 + largoDeCabecera > bytes.length) throw truncado("la cabecera");
89606
+ const formato = vista.getUint16(8);
89607
+ const declaradas = vista.getUint16(10);
89608
+ const division = vista.getUint16(12);
89609
+ let smpte = null;
89610
+ if (division & 32768) {
89611
+ const cuadros = -(division >> 8 << 24 >> 24);
89612
+ smpte = { cuadrosPorSegundo: cuadros === 29 ? 29.97 : cuadros, ticsPorCuadro: division & 255 };
89613
+ if (smpte.cuadrosPorSegundo <= 0 || smpte.ticsPorCuadro === 0) {
89614
+ throw new MidiIlegible("La cabecera del MIDI declara una divisi\xF3n de tiempo imposible.");
89615
+ }
89616
+ } else if (division === 0) {
89617
+ throw new MidiIlegible("La cabecera del MIDI declara 0 tics por negra.");
89618
+ }
89619
+ const pistas = [];
89620
+ let pos = 8 + largoDeCabecera;
89621
+ while (pistas.length < declaradas) {
89622
+ if (pos + 8 > bytes.length) {
89623
+ throw truncado(`la cabecera anuncia ${declaradas} pista(s) y s\xF3lo hay ${pistas.length}`);
89624
+ }
89625
+ const largo = vista.getUint32(pos + 4);
89626
+ const esPista = firmaEn(bytes, pos, "MTrk");
89627
+ pos += 8;
89628
+ if (pos + largo > bytes.length) throw truncado(`la pista ${pistas.length + 1}`);
89629
+ if (esPista) pistas.push(leerPista(bytes.subarray(pos, pos + largo), pistas.length + 1));
89630
+ pos += largo;
89631
+ }
89632
+ return { formato, division, smpte, pistas };
89633
+ }
89634
+ function leerPista(datos, numero2) {
89635
+ let p = 0;
89636
+ let tic = 0;
89637
+ let estado = 0;
89638
+ const eventos = [];
89639
+ const byte = () => {
89640
+ if (p >= datos.length) throw truncado(`un evento a medias en la pista ${numero2}`);
89641
+ return datos[p++];
89642
+ };
89643
+ const largoVariable = () => {
89644
+ let valor = 0;
89645
+ for (let i2 = 0; i2 < 4; i2++) {
89646
+ const b = byte();
89647
+ valor = valor * 128 + (b & 127);
89648
+ if (!(b & 128)) return valor;
89649
+ }
89650
+ throw new MidiIlegible(`La pista ${numero2} trae un n\xFAmero de m\xE1s de 4 bytes: el archivo est\xE1 da\xF1ado.`);
89651
+ };
89652
+ const tomar = (n) => {
89653
+ if (p + n > datos.length) throw truncado(`un evento a medias en la pista ${numero2}`);
89654
+ const trozo = datos.subarray(p, p + n);
89655
+ p += n;
89656
+ return trozo;
89657
+ };
89658
+ while (p < datos.length) {
89659
+ tic += largoVariable();
89660
+ let b = byte();
89661
+ if (b === 255) {
89662
+ const meta3 = byte();
89663
+ const contenido = tomar(largoVariable());
89664
+ if (meta3 === 47) break;
89665
+ eventos.push({ tipo: "meta", tic, meta: meta3, datos: contenido });
89666
+ continue;
89667
+ }
89668
+ if (b === 240 || b === 247) {
89669
+ tomar(largoVariable());
89670
+ eventos.push({ tipo: "sysex", tic });
89671
+ continue;
89672
+ }
89673
+ let dato1;
89674
+ if (b < 128) {
89675
+ if (!estado) throw new MidiIlegible(`La pista ${numero2} trae datos sin un evento que los explique: el archivo est\xE1 da\xF1ado.`);
89676
+ dato1 = b;
89677
+ b = estado;
89678
+ } else {
89679
+ if (b >= 240) throw new MidiIlegible(`La pista ${numero2} trae un mensaje de sistema que no puede ir en un archivo (0x${b.toString(16)}).`);
89680
+ estado = b;
89681
+ dato1 = byte();
89682
+ }
89683
+ const canal = b & 15;
89684
+ switch (b & 240) {
89685
+ case 128:
89686
+ byte();
89687
+ eventos.push({ tipo: "nota", tic, canal, altura: dato1 & 127, velocidad: 0 });
89688
+ break;
89689
+ case 144:
89690
+ eventos.push({ tipo: "nota", tic, canal, altura: dato1 & 127, velocidad: byte() & 127 });
89691
+ break;
89692
+ case 160:
89693
+ byte();
89694
+ eventos.push({ tipo: "presion", tic, canal });
89695
+ break;
89696
+ case 176:
89697
+ eventos.push({ tipo: "control", tic, canal, control: dato1, valor: byte() });
89698
+ break;
89699
+ case 192:
89700
+ eventos.push({ tipo: "programa", tic, canal, programa: dato1 & 127 });
89701
+ break;
89702
+ case 208:
89703
+ eventos.push({ tipo: "presion", tic, canal });
89704
+ break;
89705
+ case 224:
89706
+ eventos.push({ tipo: "bend", tic, canal, valor: dato1 | byte() << 7 });
89707
+ break;
89708
+ }
89709
+ }
89710
+ return { eventos, fin: tic };
89711
+ }
89712
+ function textoDe(datos) {
89713
+ try {
89714
+ return new TextDecoder("utf-8", { fatal: true }).decode(datos).trim();
89715
+ } catch {
89716
+ return new TextDecoder("latin1").decode(datos).trim();
89717
+ }
89718
+ }
89719
+ function recolectar(smf, avisos) {
89720
+ if (smf.formato === 2) {
89721
+ avisos.decir(
89722
+ "El archivo es MIDI de formato 2 (secuencias independientes): se ley\xF3 como si todas las pistas sonaran a la vez, que es lo que hacen casi todos los programas."
89723
+ );
89724
+ }
89725
+ const temposCrudos = [];
89726
+ for (const pista of smf.pistas)
89727
+ for (const e of pista.eventos)
89728
+ if (e.tipo === "meta" && e.meta === 81 && e.datos.length >= 3) {
89729
+ const us = e.datos[0] << 16 | e.datos[1] << 8 | e.datos[2];
89730
+ if (us > 0) temposCrudos.push({ tic: e.tic, microsegundos: us });
89731
+ }
89732
+ temposCrudos.sort((a, b) => a.tic - b.tic);
89733
+ const reloj = armarReloj(smf, temposCrudos);
89734
+ const tempos = temposCrudos.map((t) => ({
89735
+ tic: reloj(t.tic),
89736
+ // ★ Redondeado a centésimas: 60 000 000 / 428 571 da 140,0002, y ese 0,0002 no lo escribió
89737
+ // nadie — es el redondeo del propio formato, que guarda microsegundos enteros.
89738
+ bpm: Math.round(6e7 / t.microsegundos * 100) / 100
89739
+ }));
89740
+ const metricas = [];
89741
+ const tonalidades = [];
89742
+ const marcadores = [];
89743
+ const nombres = /* @__PURE__ */ new Map();
89744
+ const instrumentos = /* @__PURE__ */ new Map();
89745
+ let letras = 0;
89746
+ let textos = 0;
89747
+ for (const [indice, pista] of smf.pistas.entries()) {
89748
+ for (const e of pista.eventos) {
89749
+ if (e.tipo !== "meta") continue;
89750
+ const tic = reloj(e.tic);
89751
+ switch (e.meta) {
89752
+ case 88:
89753
+ if (e.datos.length >= 2) {
89754
+ const numerador = e.datos[0];
89755
+ const potencia = e.datos[1];
89756
+ const denominador = 2 ** potencia;
89757
+ if (numerador >= 1 && numerador <= 32 && denominador >= 1 && denominador <= 32) {
89758
+ metricas.push({ tic, numerador, denominador });
89759
+ } else {
89760
+ avisos.contar("metrica-imposible");
89761
+ }
89762
+ }
89763
+ break;
89764
+ case 89:
89765
+ if (e.datos.length >= 2) {
89766
+ const alteraciones = e.datos[0] << 24 >> 24;
89767
+ if (alteraciones >= -7 && alteraciones <= 7) tonalidades.push({ tic, alteraciones, menor: e.datos[1] === 1 });
89768
+ }
89769
+ break;
89770
+ case 3:
89771
+ if (!nombres.has(indice)) nombres.set(indice, textoDe(e.datos));
89772
+ break;
89773
+ case 4:
89774
+ if (!instrumentos.has(indice)) instrumentos.set(indice, textoDe(e.datos));
89775
+ break;
89776
+ case 6: {
89777
+ const texto4 = textoDe(e.datos);
89778
+ if (texto4) marcadores.push({ tic, texto: texto4 });
89779
+ break;
89780
+ }
89781
+ case 5:
89782
+ letras++;
89783
+ break;
89784
+ case 1:
89785
+ case 2:
89786
+ case 7:
89787
+ textos++;
89788
+ break;
89789
+ }
89790
+ }
89791
+ }
89792
+ metricas.sort((a, b) => a.tic - b.tic);
89793
+ tonalidades.sort((a, b) => a.tic - b.tic);
89794
+ marcadores.sort((a, b) => a.tic - b.tic);
89795
+ if (avisos.cuantas("metrica-imposible") > 0) {
89796
+ avisos.decir(`${avisos.cuantas("metrica-imposible")} cambio(s) de m\xE9trica con valores imposibles se ignoraron.`);
89797
+ }
89798
+ if (letras > 0) {
89799
+ avisos.decir(`El archivo trae ${letras} s\xEDlaba(s) de letra: todav\xEDa no se importan desde MIDI.`);
89800
+ }
89801
+ if (textos > 0) {
89802
+ avisos.decir(`El archivo trae ${textos} texto(s) sueltos (comentarios, derechos, indicaciones): no se importaron.`);
89803
+ }
89804
+ const porPista = [];
89805
+ const programas = [];
89806
+ const controles = [];
89807
+ let sinCerrar = 0;
89808
+ let pedal = 0;
89809
+ let bends = 0;
89810
+ let presiones = 0;
89811
+ let otrosControles = 0;
89812
+ let sysex = 0;
89813
+ for (const [indice, pista] of smf.pistas.entries()) {
89814
+ const notas = [];
89815
+ const abiertas = /* @__PURE__ */ new Map();
89816
+ for (const e of pista.eventos) {
89817
+ switch (e.tipo) {
89818
+ case "nota": {
89819
+ const clave = e.canal * 128 + e.altura;
89820
+ if (e.velocidad > 0) {
89821
+ const cola = abiertas.get(clave) ?? [];
89822
+ cola.push({ tic: e.tic, velocidad: e.velocidad });
89823
+ abiertas.set(clave, cola);
89824
+ } else {
89825
+ const abierta2 = abiertas.get(clave)?.shift();
89826
+ if (abierta2) notas.push({ ini: reloj(abierta2.tic), fin: reloj(e.tic), altura: e.altura, velocidad: abierta2.velocidad, canal: e.canal });
89827
+ }
89828
+ break;
89829
+ }
89830
+ case "programa":
89831
+ programas.push({ pista: indice, canal: e.canal, tic: e.tic, programa: e.programa });
89832
+ break;
89833
+ case "control":
89834
+ if (e.control === 7 || e.control === 10) controles.push({ pista: indice, canal: e.canal, tic: e.tic, control: e.control, valor: e.valor });
89835
+ else if (e.control === 64) {
89836
+ if (e.valor >= 64) pedal++;
89837
+ } else if (!CONTROLES_QUE_NO_SON_MUSICA.has(e.control) && e.control < 120 && !(e.control === 1 && e.valor === 0) && !(e.control === 11 && e.valor === 127)) otrosControles++;
89838
+ break;
89839
+ case "bend":
89840
+ if (e.valor !== 8192) bends++;
89841
+ break;
89842
+ case "presion":
89843
+ presiones++;
89844
+ break;
89845
+ case "sysex":
89846
+ sysex++;
89847
+ break;
89848
+ }
89849
+ }
89850
+ for (const [clave, cola] of abiertas)
89851
+ for (const abierta2 of cola) {
89852
+ sinCerrar++;
89853
+ notas.push({ ini: reloj(abierta2.tic), fin: reloj(pista.fin), altura: clave % 128, velocidad: abierta2.velocidad, canal: Math.floor(clave / 128) });
89854
+ }
89855
+ porPista.push(notas);
89856
+ }
89857
+ if (sinCerrar > 0) avisos.decir(`${sinCerrar} nota(s) no se apagaban nunca: se cortaron donde termina su pista.`);
89858
+ if (pedal > 0) avisos.decir("El archivo usa el pedal de resonancia: no se importa desde MIDI, y las notas duran lo que dura la tecla apretada.");
89859
+ if (bends > 0) avisos.decir(`El archivo trae ${bends} movimiento(s) de pitch bend (bends, vibratos, glissandos): no se importan.`);
89860
+ if (presiones > 0) avisos.decir(`El archivo trae ${presiones} evento(s) de presi\xF3n (aftertouch): no se importan.`);
89861
+ if (otrosControles > 0) avisos.decir(`El archivo trae ${otrosControles} cambio(s) de controladores (expresi\xF3n, modulaci\xF3n\u2026): no se importan; s\xED el volumen y el paneo iniciales.`);
89862
+ if (sysex > 0) avisos.decir(`El archivo trae ${sysex} mensaje(s) de sistema exclusivo, propios de un sintetizador: no se importan.`);
89863
+ const programaEn = (pista, canal, tic) => {
89864
+ let deLaPista = null;
89865
+ let deCualquiera = null;
89866
+ for (const p of programas) {
89867
+ if (p.canal !== canal || p.tic > tic) continue;
89868
+ if (p.pista === pista) deLaPista = p.programa;
89869
+ else deCualquiera = p.programa;
89870
+ }
89871
+ return deLaPista ?? deCualquiera ?? 0;
89872
+ };
89873
+ const controlInicial = (pista, canal, control, hasta) => {
89874
+ let valor = null;
89875
+ for (const c of controles) {
89876
+ if (c.canal !== canal || c.control !== control || c.tic > hasta) continue;
89877
+ if (c.pista === pista || valor === null) valor = c.valor;
89878
+ }
89879
+ return valor;
89880
+ };
89881
+ const grupos = [];
89882
+ for (const [indice, notas] of porPista.entries()) {
89883
+ const porCanal = /* @__PURE__ */ new Map();
89884
+ for (const n of notas) {
89885
+ const lista2 = porCanal.get(n.canal) ?? [];
89886
+ lista2.push(n);
89887
+ porCanal.set(n.canal, lista2);
89888
+ }
89889
+ const deEstaPista = [];
89890
+ for (const canal of [...porCanal.keys()].sort((a, b) => a - b)) {
89891
+ const lista2 = porCanal.get(canal);
89892
+ let ticCrudoDeLaPrimera = Infinity;
89893
+ for (const e of smf.pistas[indice].eventos) {
89894
+ if (e.tipo === "nota" && e.canal === canal && e.velocidad > 0) {
89895
+ ticCrudoDeLaPrimera = e.tic;
89896
+ break;
89897
+ }
89898
+ }
89899
+ const esBateria = canal === 9;
89900
+ const programa = esBateria ? 0 : programaEn(indice, canal, ticCrudoDeLaPrimera);
89901
+ const cambia = !esBateria && programas.some((p) => p.canal === canal && p.pista === indice && p.tic > ticCrudoDeLaPrimera && p.programa !== programa);
89902
+ if (cambia) avisos.contar("cambio-de-programa");
89903
+ const existente = smf.formato !== 0 && !esBateria ? deEstaPista.find((g) => !g.esBateria && g.programa === programa) : void 0;
89904
+ const volumen = controlInicial(indice, canal, 7, ticCrudoDeLaPrimera);
89905
+ const paneo = controlInicial(indice, canal, 10, ticCrudoDeLaPrimera);
89906
+ if (existente) {
89907
+ existente.canales.push(canal);
89908
+ existente.notas.push(...lista2);
89909
+ continue;
89910
+ }
89911
+ deEstaPista.push({ pista: indice, canales: [canal], esBateria, programa, nombre: "", volumen, paneo, notas: [...lista2] });
89912
+ }
89913
+ const nombreDeLaPista = smf.formato === 0 ? "" : nombres.get(indice) || instrumentos.get(indice) || "";
89914
+ for (const g of deEstaPista) {
89915
+ const delPrograma = g.esBateria ? "Bater\xEDa" : NOMBRES_GM[g.programa];
89916
+ g.nombre = nombreDeLaPista ? deEstaPista.length > 1 ? `${nombreDeLaPista} (${delPrograma})` : nombreDeLaPista : delPrograma;
89917
+ }
89918
+ grupos.push(...deEstaPista);
89919
+ }
89920
+ if (avisos.cuantas("cambio-de-programa") > 0) {
89921
+ avisos.decir(
89922
+ `${avisos.cuantas("cambio-de-programa")} pista(s) cambian de instrumento a mitad de la obra: se us\xF3 el primero. Tabs lleva un instrumento por pista.`
89923
+ );
89924
+ }
89925
+ const repetidos = /* @__PURE__ */ new Map();
89926
+ for (const g of grupos) repetidos.set(g.nombre, (repetidos.get(g.nombre) ?? 0) + 1);
89927
+ const vistos = /* @__PURE__ */ new Map();
89928
+ for (const g of grupos) {
89929
+ if ((repetidos.get(g.nombre) ?? 0) < 2) continue;
89930
+ const n = (vistos.get(g.nombre) ?? 0) + 1;
89931
+ vistos.set(g.nombre, n);
89932
+ g.nombre = `${g.nombre} ${n}`;
89933
+ }
89934
+ let titulo = "";
89935
+ if (smf.formato === 0) titulo = nombres.get(0) ?? "";
89936
+ else {
89937
+ const director = porPista.findIndex((n, i2) => n.length === 0 && (nombres.get(i2) ?? "") !== "");
89938
+ if (director >= 0) titulo = nombres.get(director) ?? "";
89939
+ }
89940
+ for (const g of grupos) {
89941
+ g.volumen = g.volumen === null ? null : Math.round(g.volumen / 127 * 16);
89942
+ g.paneo = g.paneo === null ? null : Math.round(g.paneo / 127 * 16);
89943
+ }
89944
+ return { titulo, grupos, tempos, metricas, tonalidades, marcadores };
89945
+ }
89946
+ function armarReloj(smf, tempos) {
89947
+ if (!smf.smpte) return (tic) => tic * TICS_POR_NEGRA3 / smf.division;
89948
+ const porSegundo = smf.smpte.cuadrosPorSegundo * smf.smpte.ticsPorCuadro;
89949
+ const puntos = [{ segundo: 0, negras: 0, usPorNegra: 5e5 }];
89950
+ for (const t of tempos) {
89951
+ const anterior = puntos[puntos.length - 1];
89952
+ const segundo = t.tic / porSegundo;
89953
+ const negras = anterior.negras + (segundo - anterior.segundo) * 1e6 / anterior.usPorNegra;
89954
+ if (segundo === anterior.segundo) puntos[puntos.length - 1] = { segundo, negras: anterior.negras, usPorNegra: t.microsegundos };
89955
+ else puntos.push({ segundo, negras, usPorNegra: t.microsegundos });
89956
+ }
89957
+ return (tic) => {
89958
+ const segundo = tic / porSegundo;
89959
+ let punto = puntos[0];
89960
+ for (const p of puntos) if (p.segundo <= segundo) punto = p;
89961
+ return (punto.negras + (segundo - punto.segundo) * 1e6 / punto.usPorNegra) * TICS_POR_NEGRA3;
89962
+ };
89963
+ }
89964
+ function armarCompases(leido, hasta, avisos) {
89965
+ const compases = [];
89966
+ let numerador = 4;
89967
+ let denominador = 4;
89968
+ let cursor = 0;
89969
+ let siguiente = 0;
89970
+ let corridos = 0;
89971
+ while (compases.length === 0 || cursor < hasta) {
89972
+ const largo = TICS_POR_NEGRA3 * 4 * numerador / denominador;
89973
+ while (siguiente < leido.metricas.length && leido.metricas[siguiente].tic < cursor + largo - 0.5) {
89974
+ const m = leido.metricas[siguiente];
89975
+ if (m.tic > cursor + 0.5 && (m.numerador !== numerador || m.denominador !== denominador)) {
89976
+ corridos++;
89977
+ break;
89978
+ }
89979
+ numerador = m.numerador;
89980
+ denominador = m.denominador;
89981
+ siguiente++;
89982
+ }
89983
+ const largoFinal = TICS_POR_NEGRA3 * 4 * numerador / denominador;
89984
+ compases.push({ inicio: cursor, fin: cursor + largoFinal, numerador, denominador });
89985
+ cursor += largoFinal;
89986
+ if (siguiente < leido.metricas.length && leido.metricas[siguiente].tic < cursor) {
89987
+ const m = leido.metricas[siguiente];
89988
+ numerador = m.numerador;
89989
+ denominador = m.denominador;
89990
+ siguiente++;
89991
+ }
89992
+ if (compases.length > 2e4) break;
89993
+ }
89994
+ if (corridos > 0) {
89995
+ avisos.decir(`${corridos} cambio(s) de m\xE9trica ca\xEDan a mitad de comp\xE1s: se aplicaron en la barra siguiente.`);
89996
+ }
89997
+ return compases;
89998
+ }
89999
+ function rejillaDe(c) {
90000
+ const figura = c?.rejilla ?? 16;
90001
+ const recta = TICS_POR_NEGRA3 * 4 / figura;
90002
+ const conTresillos = c?.tresillos ?? true;
90003
+ const nombre = figura === 8 ? "la corchea" : figura === 32 ? "la fusa" : "la semicorchea";
90004
+ if (figura === 8 || !conTresillos) return { recta, tresillo: null, nombre, nombreTresillo: "" };
90005
+ return { recta, tresillo: recta * 4 / 3, nombre, nombreTresillo: figura === 32 ? "al tresillo de semicorchea" : "al tresillo de corchea" };
90006
+ }
90007
+ function decidirVentanas(compases, comienzos, rejilla) {
90008
+ const ventanas = [];
90009
+ const ordenados = [...comienzos].sort((a, b) => a - b);
90010
+ let k = 0;
90011
+ for (const compas of compases) {
90012
+ for (let inicio = compas.inicio; inicio < compas.fin - 0.5; inicio += TICS_POR_NEGRA3) {
90013
+ const fin = Math.min(inicio + TICS_POR_NEGRA3, compas.fin);
90014
+ let tresillo = false;
90015
+ if (rejilla.tresillo !== null && fin - inicio === TICS_POR_NEGRA3) {
90016
+ while (k < ordenados.length && ordenados[k] < inicio) k++;
90017
+ let errorRecto = 0;
90018
+ let errorTresillo = 0;
90019
+ let fueraDeLaRecta = false;
90020
+ for (let j = k; j < ordenados.length && ordenados[j] < fin; j++) {
90021
+ const desde = ordenados[j] - inicio;
90022
+ errorRecto += Math.abs(desde - Math.round(desde / rejilla.recta) * rejilla.recta);
90023
+ const enTresillo = Math.round(desde / rejilla.tresillo) * rejilla.tresillo;
90024
+ errorTresillo += Math.abs(desde - enTresillo);
90025
+ if (enTresillo % rejilla.recta !== 0) fueraDeLaRecta = true;
90026
+ }
90027
+ tresillo = fueraDeLaRecta && errorTresillo < errorRecto * 0.5;
90028
+ }
90029
+ ventanas.push({ inicio, fin, paso: tresillo ? rejilla.tresillo : rejilla.recta, tresillo });
90030
+ }
90031
+ }
90032
+ return ventanas;
90033
+ }
90034
+ function ventanaEn(ventanas, tic) {
90035
+ let bajo = 0;
90036
+ let alto = ventanas.length - 1;
90037
+ while (bajo < alto) {
90038
+ const medio = bajo + alto + 1 >> 1;
90039
+ if (ventanas[medio].inicio <= tic) bajo = medio;
90040
+ else alto = medio - 1;
90041
+ }
90042
+ return ventanas[bajo];
90043
+ }
90044
+ function cuantizar(ventanas, tic) {
90045
+ const v = ventanaEn(ventanas, tic);
90046
+ const punto = v.inicio + Math.round((tic - v.inicio) / v.paso) * v.paso;
90047
+ return Math.min(Math.max(punto, v.inicio), v.fin);
90048
+ }
90049
+ function pasoEn(ventanas, tic) {
90050
+ const v = ventanaEn(ventanas, tic);
90051
+ return Math.min(v.paso, v.fin - tic);
90052
+ }
90053
+ function claseDe(g) {
90054
+ if (g.esBateria) return "bateria";
90055
+ if (g.programa >= 24 && g.programa <= 31) return "guitarra";
90056
+ if (g.programa >= 32 && g.programa <= 39) return "bajo";
90057
+ if (g.programa <= 7) return "piano";
90058
+ return "altura";
90059
+ }
90060
+ function digitar(alturas, afinacion, ocupadas) {
90061
+ const conOcupadas = mejorDigitacion(alturas, afinacion, ocupadas);
90062
+ const colocadas = (d) => d.filter((c) => c !== null).length;
90063
+ if (ocupadas.size === 0 || colocadas(conOcupadas) === alturas.length) return conOcupadas;
90064
+ const sinOcupadas = mejorDigitacion(alturas, afinacion, /* @__PURE__ */ new Set());
90065
+ return colocadas(sinOcupadas) > colocadas(conOcupadas) ? sinOcupadas : conOcupadas;
90066
+ }
90067
+ function mejorDigitacion(alturas, afinacion, prohibidas) {
90068
+ let mejor = null;
90069
+ const actual = [];
90070
+ const usadas = /* @__PURE__ */ new Set();
90071
+ const probar = (i2, colocadas, maximo, suma) => {
90072
+ if (i2 === alturas.length) {
90073
+ if (!mejor || colocadas > mejor.colocadas || colocadas === mejor.colocadas && (maximo < mejor.maximo || maximo === mejor.maximo && suma < mejor.suma)) {
90074
+ mejor = { cuerdas: [...actual], colocadas, maximo, suma };
90075
+ }
90076
+ return;
90077
+ }
90078
+ for (let cuerda = 1; cuerda <= afinacion.length; cuerda++) {
90079
+ if (usadas.has(cuerda) || prohibidas.has(cuerda)) continue;
90080
+ const traste = alturas[i2] - afinacion[cuerda - 1];
90081
+ if (traste < 0 || traste > TRASTES) continue;
90082
+ usadas.add(cuerda);
90083
+ actual.push(cuerda);
90084
+ probar(i2 + 1, colocadas + 1, Math.max(maximo, traste), suma + traste);
90085
+ actual.pop();
90086
+ usadas.delete(cuerda);
90087
+ }
90088
+ actual.push(null);
90089
+ probar(i2 + 1, colocadas, maximo, suma);
90090
+ actual.pop();
90091
+ };
90092
+ probar(0, 0, 0, 0);
90093
+ return mejor.cuerdas;
90094
+ }
90095
+ function repartirEnVoces(notas, ventanas, avisos, digitarEn) {
90096
+ const voces = [];
90097
+ const porComienzo = /* @__PURE__ */ new Map();
90098
+ for (const n of notas) {
90099
+ const lista2 = porComienzo.get(n.ini) ?? [];
90100
+ lista2.push(n);
90101
+ porComienzo.set(n.ini, lista2);
90102
+ }
90103
+ for (const ini of [...porComienzo.keys()].sort((a, b) => a - b)) {
90104
+ let juntas = porComienzo.get(ini);
90105
+ const paso = pasoEn(ventanas, ini);
90106
+ if (digitarEn) {
90107
+ const ocupadas = /* @__PURE__ */ new Set();
90108
+ for (const voz of voces) {
90109
+ const ultimo = voz[voz.length - 1];
90110
+ if (ultimo && ultimo.fin > ini) for (const n of ultimo.notas) ocupadas.add(n.cuerda);
90111
+ }
90112
+ juntas = [...juntas].sort((a, b) => b.altura - a.altura);
90113
+ const cuerdas = digitarEn(juntas.map((n) => n.altura), ocupadas);
90114
+ const entran = [];
90115
+ juntas.forEach((n, i2) => {
90116
+ const cuerda = cuerdas[i2];
90117
+ if (cuerda === null || cuerda === void 0) avisos.contar("sin-cuerda");
90118
+ else entran.push({ ...n, cuerda });
90119
+ });
90120
+ juntas = entran;
90121
+ if (juntas.length === 0) continue;
90122
+ }
90123
+ const subgrupos = [];
90124
+ for (const n of [...juntas].sort((a, b) => b.fin - a.fin)) {
90125
+ const cerca = subgrupos.find((s) => Math.abs(s.fin - n.fin) <= paso);
90126
+ if (cerca) {
90127
+ if (cerca.fin !== n.fin) avisos.contar("duracion-ajustada");
90128
+ cerca.notas.push(n);
90129
+ } else subgrupos.push({ fin: n.fin, notas: [n] });
90130
+ }
90131
+ subgrupos.sort((a, b) => Math.max(...b.notas.map((n) => n.altura)) - Math.max(...a.notas.map((n) => n.altura)));
90132
+ for (const s of subgrupos) {
90133
+ const libreDesde = (v) => v[v.length - 1]?.fin ?? 0;
90134
+ let voz = voces.find((v) => libreDesde(v) <= ini);
90135
+ if (!voz) {
90136
+ const recortable = voces.filter((v) => libreDesde(v) - ini <= paso && v[v.length - 1].ini < ini).sort((a, b) => libreDesde(a) - libreDesde(b))[0];
90137
+ if (recortable) {
90138
+ const anterior = recortable[recortable.length - 1];
90139
+ avisos.contar("acortadas", anterior.notas.length);
90140
+ anterior.fin = ini;
90141
+ voz = recortable;
90142
+ }
90143
+ }
90144
+ if (!voz && voces.length < MAXIMO_DE_VOCES) {
90145
+ voz = [];
90146
+ voces.push(voz);
90147
+ }
90148
+ if (!voz) {
90149
+ avisos.contar("sin-voz", s.notas.length);
90150
+ continue;
90151
+ }
90152
+ voz.push({ ini, fin: s.fin, notas: s.notas.map((n) => ({ ...n, fin: s.fin })) });
90153
+ }
90154
+ }
90155
+ return voces.length > 0 ? voces : [[]];
90156
+ }
90157
+ function figurasQueLlenan(ini, fin, ventana) {
90158
+ const salida = [];
90159
+ let resto = Math.round(fin - ini);
90160
+ const tresillo = ventana.tresillo && !(ini === ventana.inicio && fin === ventana.fin);
90161
+ const catalogo = tresillo ? FIGURAS_DE_TRESILLO : FIGURAS_RECTAS;
90162
+ while (resto > 0) {
90163
+ const f = catalogo.find((c) => c.largo <= resto + 1e-6) ?? FIGURAS_RECTAS[FIGURAS_RECTAS.length - 1];
90164
+ salida.push(f);
90165
+ resto -= f.largo;
90166
+ }
90167
+ return salida;
90168
+ }
90169
+ function armarScore(leido, opciones, avisos) {
90170
+ const rejilla = rejillaDe(opciones.cuantizacion);
90171
+ const grupos = leido.grupos.filter((g) => g.notas.length > 0);
90172
+ if (grupos.length === 0) {
90173
+ avisos.decir("El archivo no trae ninguna nota: se abri\xF3 una obra vac\xEDa con un piano.");
90174
+ }
90175
+ const medioPasoMaximo = Math.max(rejilla.recta, rejilla.tresillo ?? 0) / 2;
90176
+ let hasta = 0;
90177
+ for (const g of grupos)
90178
+ for (const n of g.notas) hasta = Math.max(hasta, n.fin, n.ini + medioPasoMaximo + 1);
90179
+ const compases = armarCompases(leido, hasta, avisos);
90180
+ const finDeLaObra2 = compases[compases.length - 1].fin;
90181
+ const compasEn = (tic) => {
90182
+ let i2 = 0;
90183
+ while (i2 + 1 < compases.length && compases[i2 + 1].inicio <= tic) i2++;
90184
+ return i2;
90185
+ };
90186
+ let redondeadas = 0;
90187
+ let hayTresillos = false;
90188
+ const velocidades = /* @__PURE__ */ new Set();
90189
+ const pistas = [];
90190
+ for (const grupo of grupos) {
90191
+ const clase = claseDe(grupo);
90192
+ const ventanas = decidirVentanas(compases, grupo.notas.map((n) => n.ini), rejilla);
90193
+ if (ventanas.some((v) => v.tresillo)) hayTresillos = true;
90194
+ let notas = [];
90195
+ for (const cruda of grupo.notas) {
90196
+ velocidades.add(cruda.velocidad);
90197
+ const ini = Math.min(cuantizar(ventanas, cruda.ini), finDeLaObra2 - pasoEn(ventanas, finDeLaObra2 - 1));
90198
+ let fin = cuantizar(ventanas, cruda.fin);
90199
+ if (fin <= ini) fin = ini + pasoEn(ventanas, ini);
90200
+ if (Math.abs(ini - cruda.ini) > 2) redondeadas++;
90201
+ else if (Math.abs(fin - cruda.fin) > 2 && clase !== "bateria") avisos.contar("duracion-ajustada");
90202
+ notas.push({ ini, fin: Math.min(fin, finDeLaObra2), altura: cruda.altura, cuerda: 0 });
90203
+ }
90204
+ notas.sort((a, b) => a.altura - b.altura || a.ini - b.ini || b.fin - a.fin);
90205
+ const limpias = [];
90206
+ for (const n of notas) {
90207
+ const anterior = limpias[limpias.length - 1];
90208
+ if (anterior && anterior.altura === n.altura) {
90209
+ if (anterior.ini === n.ini) {
90210
+ avisos.contar("repetidas");
90211
+ continue;
90212
+ }
90213
+ if (anterior.fin > n.ini) {
90214
+ anterior.fin = n.ini;
90215
+ avisos.contar("acortadas");
90216
+ }
90217
+ }
90218
+ limpias.push(n);
90219
+ }
90220
+ notas = limpias;
90221
+ const pista = { grupo, clase, ventanas, pentagramas: [], teclasDeBateria: [] };
90222
+ if (clase === "bateria") {
90223
+ pista.teclasDeBateria = [...new Set(notas.map((n) => n.altura))].sort((a, b) => a - b);
90224
+ const porComienzo = /* @__PURE__ */ new Map();
90225
+ for (const n of notas) {
90226
+ const lista2 = porComienzo.get(n.ini) ?? [];
90227
+ lista2.push(n);
90228
+ porComienzo.set(n.ini, lista2);
90229
+ }
90230
+ const comienzos = [...porComienzo.keys()].sort((a, b) => a - b);
90231
+ const eventos = comienzos.map((ini, i2) => {
90232
+ const finDelCompas = compases[compasEn(ini)].fin;
90233
+ const fin = Math.min(comienzos[i2 + 1] ?? finDelCompas, finDelCompas);
90234
+ return { ini, fin, notas: porComienzo.get(ini).map((n) => ({ ...n, fin })) };
90235
+ });
90236
+ pista.pentagramas.push({ voces: [eventos], clave: _barrel_exports$4.Clef.Neutral });
90237
+ } else if (clase === "guitarra" || clase === "bajo") {
90238
+ const afinacion = clase === "guitarra" ? AFINACION_GUITARRA : AFINACION_BAJO;
90239
+ const grave = afinacion[0];
90240
+ const aguda = afinacion[afinacion.length - 1] + TRASTES;
90241
+ const enRegistro = notas.filter((n) => n.altura >= grave && n.altura <= aguda);
90242
+ const fuera = notas.length - enRegistro.length;
90243
+ if (fuera > 0) {
90244
+ avisos.decir(
90245
+ `Se descartaron ${fuera} nota(s) fuera del registro ${clase === "guitarra" ? "de la guitarra" : "del bajo"} \xAB${grupo.nombre}\xBB (de ${nombreDeAltura(grave)} a ${nombreDeAltura(aguda)} con ${TRASTES} trastes).`
90246
+ );
90247
+ }
90248
+ const voces = repartirEnVoces(enRegistro, ventanas, avisos, (alturas, ocupadas) => digitar(alturas, afinacion, ocupadas));
90249
+ pista.pentagramas.push({ voces, clave: clase === "guitarra" ? _barrel_exports$4.Clef.G2 : _barrel_exports$4.Clef.F4 });
90250
+ } else if (clase === "piano") {
90251
+ const derecha = notas.filter((n) => n.altura >= 60);
90252
+ const izquierda = notas.filter((n) => n.altura < 60);
90253
+ pista.pentagramas.push({ voces: repartirEnVoces(derecha, ventanas, avisos, null), clave: _barrel_exports$4.Clef.G2 });
90254
+ pista.pentagramas.push({ voces: repartirEnVoces(izquierda, ventanas, avisos, null), clave: _barrel_exports$4.Clef.F4 });
90255
+ } else {
90256
+ const ordenadas = notas.map((n) => n.altura).sort((a, b) => a - b);
90257
+ const mediana = ordenadas[Math.floor(ordenadas.length / 2)] ?? 60;
90258
+ pista.pentagramas.push({
90259
+ voces: repartirEnVoces(notas, ventanas, avisos, null),
90260
+ clave: mediana < 55 ? _barrel_exports$4.Clef.F4 : _barrel_exports$4.Clef.G2
90261
+ });
90262
+ }
90263
+ pistas.push(pista);
90264
+ }
90265
+ if (redondeadas > 0) {
90266
+ avisos.decir(
90267
+ `Se redondearon ${redondeadas} nota(s) a ${rejilla.nombre}` + (hayTresillos ? ` o ${rejilla.nombreTresillo}` : "") + ": no ca\xEDan justo en la rejilla."
90268
+ );
90269
+ }
90270
+ if (avisos.cuantas("duracion-ajustada") > 0) {
90271
+ avisos.decir(`Se ajust\xF3 la duraci\xF3n de ${avisos.cuantas("duracion-ajustada")} nota(s) a la rejilla.`);
90272
+ }
90273
+ if (avisos.cuantas("acortadas") > 0) {
90274
+ avisos.decir(`Se acortaron ${avisos.cuantas("acortadas")} nota(s) que se pisaban con la siguiente.`);
90275
+ }
90276
+ if (avisos.cuantas("repetidas") > 0) {
90277
+ avisos.decir(`Se juntaron ${avisos.cuantas("repetidas")} nota(s) repetidas: la misma tecla dos veces en el mismo instante.`);
90278
+ }
90279
+ if (avisos.cuantas("sin-voz") > 0) {
90280
+ avisos.decir(`Se descartaron ${avisos.cuantas("sin-voz")} nota(s) porque sonaban m\xE1s de ${MAXIMO_DE_VOCES} voces a la vez en el mismo pentagrama.`);
90281
+ }
90282
+ if (avisos.cuantas("sin-cuerda") > 0) {
90283
+ avisos.decir(`Se descartaron ${avisos.cuantas("sin-cuerda")} nota(s) que no cab\xEDan en las cuerdas (dos notas en la misma cuerda a la vez).`);
90284
+ }
90285
+ if (velocidades.size > 1) {
90286
+ avisos.decir("La intensidad de cada nota (velocity) no se importa: todas quedan con el mismo matiz.");
90287
+ }
90288
+ const score = new _barrel_exports$4.Score();
90289
+ score.title = leido.titulo || opciones.titulo || "";
90290
+ score.stylesheet.hideDynamics = true;
90291
+ const rejillaDelTempo = pistas[0]?.ventanas ?? decidirVentanas(compases, [], rejilla);
90292
+ const temposPorTic = /* @__PURE__ */ new Map();
90293
+ for (const t of leido.tempos) {
90294
+ const tic = t.tic < finDeLaObra2 ? cuantizar(rejillaDelTempo, t.tic) : finDeLaObra2;
90295
+ if (tic < finDeLaObra2) temposPorTic.set(tic, t.bpm);
90296
+ }
90297
+ if (!temposPorTic.has(0)) temposPorTic.set(0, leido.tempos.find((t) => t.tic <= 0)?.bpm ?? 120);
90298
+ const cambiosDeTempo = [];
90299
+ for (const tic of [...temposPorTic.keys()].sort((a, b) => a - b)) {
90300
+ const bpm = temposPorTic.get(tic);
90301
+ if (cambiosDeTempo.length > 0 && cambiosDeTempo[cambiosDeTempo.length - 1].bpm === bpm) continue;
90302
+ cambiosDeTempo.push({ tic, bpm });
90303
+ }
90304
+ const tonalidadPorCompas = [];
90305
+ {
90306
+ let vigente = { alteraciones: 0, menor: false };
90307
+ let j = 0;
90308
+ let corridas = 0;
90309
+ for (const compas of compases) {
90310
+ while (j < leido.tonalidades.length && leido.tonalidades[j].tic < compas.fin - 0.5) {
90311
+ const t = leido.tonalidades[j];
90312
+ if (t.tic > compas.inicio + 0.5 && t.alteraciones !== vigente.alteraciones) {
90313
+ corridas++;
90314
+ break;
90315
+ }
90316
+ vigente = { alteraciones: t.alteraciones, menor: t.menor };
90317
+ j++;
90318
+ }
90319
+ tonalidadPorCompas.push(vigente);
90320
+ }
90321
+ if (corridas > 0) avisos.decir(`${corridas} cambio(s) de armadura ca\xEDan a mitad de comp\xE1s: se escribieron en la barra siguiente.`);
90322
+ }
90323
+ const seccionPorCompas = /* @__PURE__ */ new Map();
90324
+ let marcadoresDeMas = 0;
90325
+ for (const m of leido.marcadores) {
90326
+ const i2 = compasEn(m.tic);
90327
+ if (seccionPorCompas.has(i2)) marcadoresDeMas++;
90328
+ else seccionPorCompas.set(i2, m.texto);
90329
+ }
90330
+ if (marcadoresDeMas > 0) avisos.decir(`${marcadoresDeMas} marcador(es) ca\xEDan en un comp\xE1s que ya ten\xEDa uno: se guard\xF3 el primero.`);
90331
+ for (const [i2, compas] of compases.entries()) {
90332
+ const maestro = new _barrel_exports$4.MasterBar();
90333
+ maestro.timeSignatureNumerator = compas.numerador;
90334
+ maestro.timeSignatureDenominator = compas.denominador;
90335
+ const seccion = seccionPorCompas.get(i2);
90336
+ if (seccion) {
90337
+ maestro.section = new _barrel_exports$4.Section();
90338
+ maestro.section.text = seccion;
90339
+ maestro.section.marker = "";
90340
+ }
90341
+ for (const cambio of cambiosDeTempo) {
90342
+ if (cambio.tic < compas.inicio || cambio.tic >= compas.fin) continue;
90343
+ const automatizacion = new _barrel_exports$4.Automation();
90344
+ automatizacion.isLinear = false;
90345
+ automatizacion.type = _barrel_exports$4.AutomationType.Tempo;
90346
+ automatizacion.value = cambio.bpm;
90347
+ automatizacion.ratioPosition = (cambio.tic - compas.inicio) / (compas.fin - compas.inicio);
90348
+ maestro.tempoAutomations.push(automatizacion);
90349
+ }
90350
+ score.addMasterBar(maestro);
90351
+ }
90352
+ if (pistas.length === 0) {
90353
+ pistas.push({
90354
+ grupo: { pista: 0, canales: [0], esBateria: false, programa: 0, nombre: NOMBRES_GM[0], volumen: null, paneo: null, notas: [] },
90355
+ clase: "piano",
90356
+ ventanas: decidirVentanas(compases, [], rejilla),
90357
+ pentagramas: [{ voces: [[]], clave: _barrel_exports$4.Clef.G2 }, { voces: [[]], clave: _barrel_exports$4.Clef.F4 }],
90358
+ teclasDeBateria: []
90359
+ });
90360
+ }
90361
+ const cortesDeTempo = cambiosDeTempo.map((c) => c.tic).filter((t) => t > 0);
90362
+ const piezasQueFaltan = /* @__PURE__ */ new Map();
90363
+ for (const [indiceDePista, pista] of pistas.entries()) {
90364
+ const track = new _barrel_exports$4.Track();
90365
+ track.name = pista.grupo.nombre;
90366
+ track.shortName = pista.clase === "bateria" ? "bat" : NOMBRES_CORTOS_GM[Math.floor(pista.grupo.programa / 8)];
90367
+ track.playbackInfo.program = pista.grupo.programa;
90368
+ track.playbackInfo.volume = pista.grupo.volumen ?? 16;
90369
+ track.playbackInfo.balance = pista.grupo.paneo ?? 8;
90370
+ const canal = pista.clase === "bateria" ? 9 : pista.grupo.canales[0];
90371
+ track.playbackInfo.primaryChannel = canal;
90372
+ track.playbackInfo.secondaryChannel = canal;
90373
+ score.addTrack(track);
90374
+ const indiceDeTecla = /* @__PURE__ */ new Map();
90375
+ if (pista.clase === "bateria") {
90376
+ track.percussionArticulations = pista.teclasDeBateria.map((tecla, indice) => {
90377
+ const art = new _barrel_exports$4.InstrumentArticulation();
90378
+ art.elementType = `midi ${tecla}`;
90379
+ art.id = indice;
90380
+ art.outputMidiNumber = tecla;
90381
+ indiceDeTecla.set(tecla, indice);
90382
+ return art;
90383
+ });
90384
+ for (const [tecla, indice] of indiceDeTecla) {
90385
+ const pieza = piezaDeBateria(track, indice);
90386
+ const art = track.percussionArticulations[indice];
90387
+ if (pieza === null) {
90388
+ indiceDeTecla.delete(tecla);
90389
+ continue;
90390
+ }
90391
+ const delKit = KIT[pieza];
90392
+ art.staffLine = delKit.linea;
90393
+ art.noteHeadDefault = delKit.cabeza === "x" ? _barrel_exports$4.MusicFontSymbol.NoteheadXBlack : _barrel_exports$4.MusicFontSymbol.NoteheadBlack;
90394
+ art.noteHeadHalf = art.noteHeadDefault;
90395
+ art.noteHeadWhole = art.noteHeadDefault;
90396
+ }
90397
+ for (const voz of pista.pentagramas[0].voces)
90398
+ for (const evento of voz) {
90399
+ const quedan = evento.notas.filter((n) => indiceDeTecla.has(n.altura));
90400
+ for (const n of evento.notas)
90401
+ if (!indiceDeTecla.has(n.altura)) piezasQueFaltan.set(n.altura, (piezasQueFaltan.get(n.altura) ?? 0) + 1);
90402
+ evento.notas = quedan;
90403
+ }
90404
+ }
90405
+ for (const [numeroDePentagrama, datos] of pista.pentagramas.entries()) {
90406
+ const staff = new _barrel_exports$4.Staff();
90407
+ const esDeTrastes = pista.clase === "guitarra" || pista.clase === "bajo";
90408
+ const afinacion = pista.clase === "guitarra" ? AFINACION_GUITARRA : pista.clase === "bajo" ? AFINACION_BAJO : [];
90409
+ const descendente = [...afinacion].reverse();
90410
+ staff.stringTuning = _barrel_exports$4.Tuning.findTuning(descendente) ?? new _barrel_exports$4.Tuning("", descendente, false);
90411
+ staff.showTablature = esDeTrastes;
90412
+ staff.showStandardNotation = true;
90413
+ staff.isPercussion = pista.clase === "bateria";
90414
+ if (esDeTrastes) staff.displayTranspositionPitch = -12;
90415
+ track.addStaff(staff);
90416
+ const cortesDeEstaVoz0 = indiceDePista === 0 && numeroDePentagrama === 0 ? cortesDeTempo : [];
90417
+ const cortesDeTresillo = [];
90418
+ for (const v of pista.ventanas) if (v.tresillo) cortesDeTresillo.push(v.inicio, v.fin);
90419
+ for (const [indiceDeCompas2, compas] of compases.entries()) {
90420
+ const bar = new _barrel_exports$4.Bar();
90421
+ staff.addBar(bar);
90422
+ bar.clef = datos.clave;
90423
+ bar.clefOttava = _barrel_exports$4.Ottavia.Regular;
90424
+ if (!staff.isPercussion) {
90425
+ bar.keySignature = tonalidadPorCompas[indiceDeCompas2].alteraciones;
90426
+ bar.keySignatureType = tonalidadPorCompas[indiceDeCompas2].menor ? _barrel_exports$4.KeySignatureType.Minor : _barrel_exports$4.KeySignatureType.Major;
90427
+ }
90428
+ for (const [indiceDeVoz, eventos] of datos.voces.entries()) {
90429
+ const voice = new _barrel_exports$4.Voice();
90430
+ bar.addVoice(voice);
90431
+ llenarVoz(voice, eventos, compas, indiceDeVoz, pista, cortesDeTresillo, indiceDeVoz === 0 ? cortesDeEstaVoz0 : [], indiceDeTecla);
90432
+ }
90433
+ }
90434
+ }
90435
+ }
90436
+ if (piezasQueFaltan.size > 0) {
90437
+ const total = [...piezasQueFaltan.values()].reduce((a, b) => a + b, 0);
90438
+ avisos.decir(
90439
+ `Se descartaron ${total} golpe(s) de bater\xEDa de piezas que el kit de Tabs todav\xEDa no tiene (notas MIDI ${[...piezasQueFaltan.keys()].sort((a, b) => a - b).join(", ")}).`
90440
+ );
90441
+ }
90442
+ score.finish(new Settings());
90443
+ return score;
90444
+ }
90445
+ function llenarVoz(voice, eventos, compas, indiceDeVoz, pista, cortesDeTresillo, cortesForzados, indiceDeTecla) {
90446
+ const tramos = [];
90447
+ for (const e of eventos) {
90448
+ if (e.fin <= compas.inicio || e.ini >= compas.fin) continue;
90449
+ if (e.notas.length === 0) continue;
90450
+ tramos.push({
90451
+ ini: Math.max(e.ini, compas.inicio),
90452
+ fin: Math.min(e.fin, compas.fin),
90453
+ notas: e.notas,
90454
+ // ★ Empezó en un compás anterior: lo de acá es la continuación, ligada.
90455
+ continua: e.ini < compas.inicio
90456
+ });
90457
+ }
90458
+ if (tramos.length === 0 && indiceDeVoz > 0) {
90459
+ const vacio = new _barrel_exports$4.Beat();
90460
+ vacio.isEmpty = true;
90461
+ voice.addBeat(vacio);
90462
+ return;
90463
+ }
90464
+ const conSilencios = [];
90465
+ let cursor = compas.inicio;
90466
+ for (const t of tramos) {
90467
+ if (t.ini > cursor) conSilencios.push({ ini: cursor, fin: t.ini, notas: null, continua: false });
90468
+ conSilencios.push(t);
90469
+ cursor = t.fin;
90470
+ }
90471
+ if (cursor < compas.fin) conSilencios.push({ ini: cursor, fin: compas.fin, notas: null, continua: false });
90472
+ const cortes = [...cortesDeTresillo, ...cortesForzados].filter((c) => c > compas.inicio && c < compas.fin);
90473
+ for (const tramo of conSilencios) {
90474
+ const puntos = [tramo.ini, ...cortes.filter((c) => c > tramo.ini && c < tramo.fin).sort((a, b) => a - b), tramo.fin];
90475
+ let primera = true;
90476
+ for (let k = 0; k + 1 < puntos.length; k++) {
90477
+ const desde = puntos[k];
90478
+ const hastaTic = puntos[k + 1];
90479
+ if (hastaTic - desde < 0.5) continue;
90480
+ const ventana = ventanaEn(pista.ventanas, desde);
90481
+ for (const figura of figurasQueLlenan(desde, hastaTic, ventana)) {
90482
+ const beat = new _barrel_exports$4.Beat();
90483
+ beat.duration = figura.valor;
90484
+ beat.dots = figura.puntillos;
90485
+ if (figura.tresillo) {
90486
+ beat.tupletNumerator = 3;
90487
+ beat.tupletDenominator = 2;
90488
+ }
90489
+ for (const n of tramo.notas ?? []) {
90490
+ const note = new _barrel_exports$4.Note();
90491
+ if (pista.clase === "bateria") {
90492
+ note.percussionArticulation = indiceDeTecla.get(n.altura);
90493
+ } else if (pista.clase === "guitarra" || pista.clase === "bajo") {
90494
+ const afinacion = pista.clase === "guitarra" ? AFINACION_GUITARRA : AFINACION_BAJO;
90495
+ note.string = n.cuerda;
90496
+ note.fret = n.altura - afinacion[n.cuerda - 1];
90497
+ } else {
90498
+ note.octave = Math.floor(n.altura / 12);
90499
+ note.tone = n.altura % 12;
90500
+ }
90501
+ note.isTieDestination = pista.clase !== "bateria" && (!primera || tramo.continua);
90502
+ beat.addNote(note);
90503
+ }
90504
+ voice.addBeat(beat);
90505
+ primera = false;
90506
+ }
90507
+ }
90508
+ }
90509
+ }
90510
+ function nombreDeAltura(altura) {
90511
+ return `${NOMBRES_DE_NOTA2[altura % 12]}${Math.floor(altura / 12) - 1}`;
90512
+ }
90513
+ var MidiIlegible, truncado, TICS_POR_NEGRA3, Avisos, CONTROLES_QUE_NO_SON_MUSICA, AFINACION_GUITARRA, AFINACION_BAJO, TRASTES, MAXIMO_DE_VOCES, FIGURAS_RECTAS, FIGURAS_DE_TRESILLO, NOMBRES_DE_NOTA2, NOMBRES_GM, NOMBRES_CORTOS_GM;
90514
+ var init_importarMidi = __esm({
90515
+ "packages/io/src/importarMidi.ts"() {
90516
+ init_alphaTab();
90517
+ init_src2();
90518
+ init_importarGp();
90519
+ MidiIlegible = class extends Error {
90520
+ constructor(mensaje) {
90521
+ super(mensaje);
90522
+ this.name = "MidiIlegible";
90523
+ }
90524
+ };
90525
+ truncado = (donde) => new MidiIlegible(`El archivo MIDI est\xE1 cortado o da\xF1ado (${donde}). Puede que no se haya terminado de descargar.`);
90526
+ TICS_POR_NEGRA3 = 960;
90527
+ Avisos = class {
90528
+ cuentas = /* @__PURE__ */ new Map();
90529
+ sueltos = [];
90530
+ contar(clave, cuantas = 1) {
90531
+ this.cuentas.set(clave, (this.cuentas.get(clave) ?? 0) + cuantas);
90532
+ }
90533
+ cuantas(clave) {
90534
+ return this.cuentas.get(clave) ?? 0;
90535
+ }
90536
+ decir(texto4) {
90537
+ if (!this.sueltos.includes(texto4)) this.sueltos.push(texto4);
90538
+ }
90539
+ lista() {
90540
+ return this.sueltos;
90541
+ }
90542
+ };
90543
+ CONTROLES_QUE_NO_SON_MUSICA = /* @__PURE__ */ new Set([0, 32, 6, 38, 96, 97, 98, 99, 100, 101]);
90544
+ AFINACION_GUITARRA = [40, 45, 50, 55, 59, 64];
90545
+ AFINACION_BAJO = [28, 33, 38, 43];
90546
+ TRASTES = 24;
90547
+ MAXIMO_DE_VOCES = 4;
90548
+ FIGURAS_RECTAS = [
90549
+ [1, 0],
90550
+ [2, 1],
90551
+ [2, 0],
90552
+ [4, 1],
90553
+ [4, 0],
90554
+ [8, 1],
90555
+ [8, 0],
90556
+ [16, 1],
90557
+ [16, 0],
90558
+ [32, 1],
90559
+ [32, 0],
90560
+ [64, 1],
90561
+ [64, 0],
90562
+ [128, 0]
90563
+ ].map(([valor, puntillos]) => {
90564
+ const base = TICS_POR_NEGRA3 * 4 / valor;
90565
+ return { valor, puntillos, tresillo: false, largo: puntillos ? base * 1.5 : base };
90566
+ });
90567
+ FIGURAS_DE_TRESILLO = [4, 8, 16, 32].map((valor) => ({
90568
+ valor,
90569
+ puntillos: 0,
90570
+ tresillo: true,
90571
+ largo: TICS_POR_NEGRA3 * 4 / valor * (2 / 3)
90572
+ }));
90573
+ NOMBRES_DE_NOTA2 = ["do", "do\u266F", "re", "re\u266F", "mi", "fa", "fa\u266F", "sol", "sol\u266F", "la", "la\u266F", "si"];
90574
+ NOMBRES_GM = [
90575
+ // Pianos
90576
+ "Piano de cola",
90577
+ "Piano brillante",
90578
+ "Piano el\xE9ctrico de cola",
90579
+ "Piano de cantina",
90580
+ "Piano el\xE9ctrico",
90581
+ "Piano el\xE9ctrico 2",
90582
+ "Clavec\xEDn",
90583
+ "Clavinet",
90584
+ // Percusión afinada
90585
+ "Celesta",
90586
+ "Glockenspiel",
90587
+ "Caja de m\xFAsica",
90588
+ "Vibr\xE1fono",
90589
+ "Marimba",
90590
+ "Xil\xF3fono",
90591
+ "Campanas tubulares",
90592
+ "Dulc\xE9mele",
90593
+ // Órganos
90594
+ "\xD3rgano Hammond",
90595
+ "\xD3rgano percusivo",
90596
+ "\xD3rgano de rock",
90597
+ "\xD3rgano de iglesia",
90598
+ "Armonio",
90599
+ "Acorde\xF3n",
90600
+ "Arm\xF3nica",
90601
+ "Bandone\xF3n",
90602
+ // Guitarras
90603
+ "Guitarra de nailon",
90604
+ "Guitarra ac\xFAstica",
90605
+ "Guitarra el\xE9ctrica de jazz",
90606
+ "Guitarra el\xE9ctrica limpia",
90607
+ "Guitarra el\xE9ctrica apagada",
90608
+ "Guitarra saturada",
90609
+ "Guitarra distorsionada",
90610
+ "Arm\xF3nicos de guitarra",
90611
+ // Bajos
90612
+ "Bajo ac\xFAstico",
90613
+ "Bajo el\xE9ctrico",
90614
+ "Bajo con p\xFAa",
90615
+ "Bajo sin trastes",
90616
+ "Bajo slap",
90617
+ "Bajo slap 2",
90618
+ "Bajo sintetizado",
90619
+ "Bajo sintetizado 2",
90620
+ // Cuerdas
90621
+ "Viol\xEDn",
90622
+ "Viola",
90623
+ "Violonchelo",
90624
+ "Contrabajo",
90625
+ "Cuerdas en tr\xE9molo",
90626
+ "Cuerdas en pizzicato",
90627
+ "Arpa",
90628
+ "Timbales",
90629
+ // Conjuntos
90630
+ "Cuerdas",
90631
+ "Cuerdas 2",
90632
+ "Cuerdas sintetizadas",
90633
+ "Cuerdas sintetizadas 2",
90634
+ "Coro",
90635
+ "Voz",
90636
+ "Voz sintetizada",
90637
+ "Golpe de orquesta",
90638
+ // Metales
90639
+ "Trompeta",
90640
+ "Tromb\xF3n",
90641
+ "Tuba",
90642
+ "Trompeta con sordina",
90643
+ "Corno franc\xE9s",
90644
+ "Secci\xF3n de metales",
90645
+ "Metales sintetizados",
90646
+ "Metales sintetizados 2",
90647
+ // Lengüetas
90648
+ "Saxo soprano",
90649
+ "Saxo alto",
90650
+ "Saxo tenor",
90651
+ "Saxo bar\xEDtono",
90652
+ "Oboe",
90653
+ "Corno ingl\xE9s",
90654
+ "Fagot",
90655
+ "Clarinete",
90656
+ // Flautas
90657
+ "Flaut\xEDn",
90658
+ "Flauta",
90659
+ "Flauta dulce",
90660
+ "Flauta de pan",
90661
+ "Botella soplada",
90662
+ "Shakuhachi",
90663
+ "Silbido",
90664
+ "Ocarina",
90665
+ // Sintetizador solista
90666
+ "Sintetizador (cuadrada)",
90667
+ "Sintetizador (sierra)",
90668
+ "Sintetizador (cal\xEDope)",
90669
+ "Sintetizador (chiff)",
90670
+ "Sintetizador (charango)",
90671
+ "Sintetizador (voz)",
90672
+ "Sintetizador (quintas)",
90673
+ "Sintetizador (bajo y melod\xEDa)",
90674
+ // Colchones
90675
+ "Colch\xF3n new age",
90676
+ "Colch\xF3n c\xE1lido",
90677
+ "Colch\xF3n polif\xF3nico",
90678
+ "Colch\xF3n de coro",
90679
+ "Colch\xF3n de arco",
90680
+ "Colch\xF3n met\xE1lico",
90681
+ "Colch\xF3n halo",
90682
+ "Colch\xF3n de barrido",
90683
+ // Efectos de sintetizador
90684
+ "Efecto lluvia",
90685
+ "Efecto banda sonora",
90686
+ "Efecto cristal",
90687
+ "Efecto atm\xF3sfera",
90688
+ "Efecto brillo",
90689
+ "Efecto duendes",
90690
+ "Efecto ecos",
90691
+ "Efecto ciencia ficci\xF3n",
90692
+ // Étnicos
90693
+ "Sitar",
90694
+ "Banjo",
90695
+ "Shamisen",
90696
+ "Koto",
90697
+ "Kalimba",
90698
+ "Gaita",
90699
+ "Viol\xEDn folcl\xF3rico",
90700
+ "Shehnai",
90701
+ // Percusivos
90702
+ "Campanillas",
90703
+ "Agog\xF3",
90704
+ "Steel drum",
90705
+ "Caja china",
90706
+ "Taiko",
90707
+ "Tom mel\xF3dico",
90708
+ "Tambor sintetizado",
90709
+ "Platillo al rev\xE9s",
90710
+ // Efectos de sonido
90711
+ "Ruido de traste",
90712
+ "Respiraci\xF3n",
90713
+ "Olas",
90714
+ "P\xE1jaros",
90715
+ "Tel\xE9fono",
90716
+ "Helic\xF3ptero",
90717
+ "Aplausos",
90718
+ "Disparo"
90719
+ ];
90720
+ NOMBRES_CORTOS_GM = [
90721
+ "pno",
90722
+ "perc",
90723
+ "\xF3rg",
90724
+ "gtr",
90725
+ "bajo",
90726
+ "cuer",
90727
+ "cuer",
90728
+ "met",
90729
+ "saxo",
90730
+ "fl",
90731
+ "sint",
90732
+ "sint",
90733
+ "sint",
90734
+ "\xE9tn",
90735
+ "perc",
90736
+ "efec"
90737
+ ];
90738
+ }
90739
+ });
90740
+
89503
90741
  // packages/io/src/archivoMtabs.ts
89504
90742
  function formatoQueNecesita(documento) {
89505
90743
  for (const pista of documento.pistas.values()) {
@@ -89612,6 +90850,254 @@ var init_archivoMtabs = __esm({
89612
90850
  }
89613
90851
  });
89614
90852
 
90853
+ // packages/io/src/recorridoDeRepeticiones.ts
90854
+ function instalarRecorridoDeRepeticiones() {
90855
+ const version2 = String(VersionInfo?.VersionInfo?.version ?? VersionInfo?.version ?? "");
90856
+ const Generador = _barrel_exports$3.MidiFileGenerator;
90857
+ if (!Generador || typeof Generador._playThroughSong !== "function") return false;
90858
+ if (Generador.__recorridoDe19) return true;
90859
+ if (version2 && !version2.startsWith("1.8.")) return false;
90860
+ Generador._playThroughSong = function(score, syncPoints, createNewSyncPoints, generateMasterBar, generateTracks, finish) {
90861
+ const controller = new RecorridoDeCompases(score);
90862
+ const playContext = {
90863
+ synthTick: 0,
90864
+ synthTime: 0,
90865
+ currentTempo: score.tempo,
90866
+ automationToSyncPoint: /* @__PURE__ */ new Map(),
90867
+ syncPoints,
90868
+ createNewSyncPoints
90869
+ };
90870
+ let previousMasterBar = null;
90871
+ const barOccurence = /* @__PURE__ */ new Map();
90872
+ while (!controller.finished) {
90873
+ const index = controller.index;
90874
+ const bar = score.masterBars[index];
90875
+ const currentTick = controller.currentTick;
90876
+ controller.processCurrent();
90877
+ if (controller.shouldPlay) {
90878
+ let occurence = barOccurence.has(index) ? barOccurence.get(index) : -1;
90879
+ occurence++;
90880
+ barOccurence.set(index, occurence);
90881
+ generateMasterBar(bar, previousMasterBar, currentTick, playContext.currentTempo, occurence);
90882
+ generateTracks(index, currentTick, bar.tempoAutomations.length > 0 ? bar.tempoAutomations[0].value : playContext.currentTempo);
90883
+ playContext.synthTick = currentTick;
90884
+ Generador._processBarTime(bar, occurence, playContext);
90885
+ }
90886
+ controller.moveNext();
90887
+ previousMasterBar = bar;
90888
+ }
90889
+ if (syncPoints.length > 0) {
90890
+ const lastSyncPoint = syncPoints[syncPoints.length - 1];
90891
+ const remainingTicks = controller.currentTick - lastSyncPoint.synthTick;
90892
+ if (remainingTicks > 0) {
90893
+ const p = new _barrel_exports$7.BackingTrackSyncPoint();
90894
+ p.masterBarIndex = previousMasterBar.index;
90895
+ p.masterBarOccurence = barOccurence.get(previousMasterBar.index) - 1;
90896
+ p.synthTick = controller.currentTick;
90897
+ p.synthBpm = playContext.currentTempo;
90898
+ if (playContext.createNewSyncPoints) {
90899
+ p.syncBpm = lastSyncPoint.synthBpm;
90900
+ p.synthBpm = lastSyncPoint.synthBpm;
90901
+ } else if (syncPoints.length === 1) p.syncBpm = lastSyncPoint.synthBpm;
90902
+ else p.syncBpm = syncPoints[syncPoints.length - 2].syncBpm;
90903
+ p.synthTime = lastSyncPoint.synthTime + ticksAMs(remainingTicks, lastSyncPoint.synthBpm);
90904
+ p.syncTime = lastSyncPoint.syncTime + ticksAMs(remainingTicks, p.syncBpm);
90905
+ if (!playContext.createNewSyncPoints) lastSyncPoint.updateSyncBpm(p.synthTime, p.syncTime);
90906
+ syncPoints.push(p);
90907
+ }
90908
+ }
90909
+ finish(controller.currentTick);
90910
+ return playContext;
90911
+ };
90912
+ Generador.__recorridoDe19 = true;
90913
+ return true;
90914
+ }
90915
+ var D, Repeticion, RecorridoDeCompases, ticksAMs;
90916
+ var init_recorridoDeRepeticiones = __esm({
90917
+ "packages/io/src/recorridoDeRepeticiones.ts"() {
90918
+ init_alphaTab();
90919
+ D = {
90920
+ TargetFine: 0,
90921
+ TargetSegno: 1,
90922
+ TargetSegnoSegno: 2,
90923
+ TargetCoda: 3,
90924
+ TargetDoubleCoda: 4,
90925
+ JumpDaCoda: 17,
90926
+ JumpDaDoubleCoda: 18
90927
+ };
90928
+ Repeticion = class {
90929
+ group;
90930
+ /** Con casillas, cada cierre termina la pasada y todos comparten el contador. */
90931
+ conCasillas;
90932
+ /** La pasada actual (desde 0): elige qué casillas suenan. */
90933
+ pasada = 0;
90934
+ /** Las repeticiones hechas por cierre (sólo sin casillas). */
90935
+ iteraciones;
90936
+ /** Las casillas del último compás que las tenía: los que no tienen, las continúan. */
90937
+ casillasActuales = 0;
90938
+ /** @param pasadaFinal si se toca como última pasada (después de un salto): sólo la última casilla. */
90939
+ constructor(group, pasadaFinal) {
90940
+ this.group = group;
90941
+ this.conCasillas = group.masterBars.some((m) => m.alternateEndings !== 0);
90942
+ this.iteraciones = group.closings.map((c) => pasadaFinal ? Math.max(0, c.repeatCount - 1) : 0);
90943
+ if (pasadaFinal) for (const i2 of this.iteraciones) this.pasada = Math.max(this.pasada, i2);
90944
+ }
90945
+ suena(compas) {
90946
+ let casillas = compas.alternateEndings;
90947
+ if (casillas === 0) casillas = this.casillasActuales;
90948
+ else this.casillasActuales = casillas;
90949
+ return casillas === 0 || (casillas & 1 << this.pasada) !== 0;
90950
+ }
90951
+ /** 0 = seguir, 1 = volver al comienzo de la repetición, 2 = terminó. */
90952
+ alCerrar(cierre, sono) {
90953
+ const cierres = this.group.closings;
90954
+ const esElUltimo = cierre === cierres[cierres.length - 1];
90955
+ if (this.conCasillas) {
90956
+ if (!sono && !esElUltimo) return 0;
90957
+ if (this.pasada < cierre.repeatCount - 1) {
90958
+ this.pasada++;
90959
+ this.casillasActuales = 0;
90960
+ return 1;
90961
+ }
90962
+ return esElUltimo ? 2 : 0;
90963
+ }
90964
+ const i2 = cierres.indexOf(cierre);
90965
+ if (i2 === -1) return 0;
90966
+ if (this.iteraciones[i2] < cierre.repeatCount - 1) {
90967
+ this.iteraciones[i2]++;
90968
+ for (let j = 0; j < i2; j++) this.iteraciones[j] = 0;
90969
+ this.casillasActuales = 0;
90970
+ return 1;
90971
+ }
90972
+ return esElUltimo ? 2 : 0;
90973
+ }
90974
+ /** Si algún cierre todavía va a volver por encima de este compás. */
90975
+ vaAVolver(compas) {
90976
+ const cierres = this.group.closings;
90977
+ for (let i2 = 0; i2 < cierres.length; i2++) {
90978
+ const cierre = cierres[i2];
90979
+ if (cierre.index >= compas.index) {
90980
+ if ((this.conCasillas ? this.pasada : this.iteraciones[i2]) < cierre.repeatCount - 1) return true;
90981
+ }
90982
+ }
90983
+ return false;
90984
+ }
90985
+ };
90986
+ RecorridoDeCompases = class _RecorridoDeCompases {
90987
+ /** Los saltos en el orden en que se revisan si un compás tiene varios. */
90988
+ static SALTOS = [
90989
+ { jump: 5, target: null, playUntil: null, continueAt: null },
90990
+ { jump: 6, target: null, playUntil: D.JumpDaCoda, continueAt: D.TargetCoda },
90991
+ { jump: 7, target: null, playUntil: D.JumpDaDoubleCoda, continueAt: D.TargetDoubleCoda },
90992
+ { jump: 8, target: null, playUntil: D.TargetFine, continueAt: null },
90993
+ { jump: 9, target: D.TargetSegno, playUntil: null, continueAt: null },
90994
+ { jump: 10, target: D.TargetSegno, playUntil: D.JumpDaCoda, continueAt: D.TargetCoda },
90995
+ { jump: 11, target: D.TargetSegno, playUntil: D.JumpDaDoubleCoda, continueAt: D.TargetDoubleCoda },
90996
+ { jump: 12, target: D.TargetSegno, playUntil: D.TargetFine, continueAt: null },
90997
+ { jump: 13, target: D.TargetSegnoSegno, playUntil: null, continueAt: null },
90998
+ { jump: 14, target: D.TargetSegnoSegno, playUntil: D.JumpDaCoda, continueAt: D.TargetCoda },
90999
+ { jump: 15, target: D.TargetSegnoSegno, playUntil: D.JumpDaDoubleCoda, continueAt: D.TargetDoubleCoda },
91000
+ { jump: 16, target: D.TargetSegnoSegno, playUntil: D.TargetFine, continueAt: null }
91001
+ ];
91002
+ score;
91003
+ pila = [];
91004
+ /** El D.C./D.S. que se siguió; null si se toca normal (antes del salto o después de la coda). */
91005
+ saltoActivo = null;
91006
+ /** Los compases cuyo salto ya se tomó: cada salto se toma una sola vez. */
91007
+ saltosTomados = /* @__PURE__ */ new Set();
91008
+ shouldPlay = true;
91009
+ index = 0;
91010
+ currentTick = 0;
91011
+ constructor(score) {
91012
+ this.score = score;
91013
+ }
91014
+ get finished() {
91015
+ return this.index >= this.score.masterBars.length;
91016
+ }
91017
+ processCurrent() {
91018
+ const compas = this.score.masterBars[this.index];
91019
+ this.entrarARepeticion(compas);
91020
+ const rep = this.pila.length > 0 ? this.pila[this.pila.length - 1] : null;
91021
+ this.shouldPlay = rep === null || rep.suena(compas);
91022
+ if (this.shouldPlay) this.currentTick += compas.calculateDuration();
91023
+ }
91024
+ moveNext() {
91025
+ if (this.moverConSaltos()) return;
91026
+ const compas = this.score.masterBars[this.index];
91027
+ if (this.pila.length > 0 && compas.repeatCount > 1) {
91028
+ const rep = this.pila[this.pila.length - 1];
91029
+ switch (rep.alCerrar(compas, this.shouldPlay)) {
91030
+ case 1:
91031
+ this.index = rep.group.opening.index;
91032
+ return;
91033
+ case 2:
91034
+ this.pila.pop();
91035
+ }
91036
+ }
91037
+ this.index++;
91038
+ }
91039
+ /** Empieza la repetición del compás si hace falta: al llegar a su apertura, o tras un salto que cayó adentro. */
91040
+ entrarARepeticion(compas) {
91041
+ const group = compas.repeatGroup;
91042
+ if (!group.isClosed || this.pila.some((r) => r.group === group)) return;
91043
+ const adentro = compas.index <= group.closings[group.closings.length - 1].index;
91044
+ if (compas === group.opening || this.saltoActivo !== null && adentro) {
91045
+ this.pila.push(new Repeticion(group, this.saltoActivo !== null));
91046
+ }
91047
+ }
91048
+ moverConSaltos() {
91049
+ const compas = this.score.masterBars[this.index];
91050
+ const dir = compas.directions;
91051
+ if (!this.shouldPlay || dir === null || dir === void 0 || dir.size === 0) return false;
91052
+ if (this.saltoActivo === null) return this.tomarSalto(compas, dir);
91053
+ const hasta = this.saltoActivo.playUntil;
91054
+ if (hasta !== null && dir.has(hasta)) return this.seguirTrasElSalto(this.saltoActivo.continueAt);
91055
+ return false;
91056
+ }
91057
+ tomarSalto(compas, dir) {
91058
+ if (this.saltosTomados.has(compas) || this.pila.some((r) => r.vaAVolver(compas))) return false;
91059
+ for (const salto of _RecorridoDeCompases.SALTOS) {
91060
+ if (!dir.has(salto.jump)) continue;
91061
+ const destino = salto.target === null ? 0 : this.buscar(salto.target, true);
91062
+ if (destino === -1) continue;
91063
+ this.saltosTomados.add(compas);
91064
+ this.saltoActivo = salto;
91065
+ this.pila = [];
91066
+ this.index = destino;
91067
+ return true;
91068
+ }
91069
+ return false;
91070
+ }
91071
+ seguirTrasElSalto(seguirEn) {
91072
+ if (seguirEn === null) {
91073
+ this.index = this.score.masterBars.length;
91074
+ return true;
91075
+ }
91076
+ const coda = this.buscar(seguirEn, false);
91077
+ if (coda === -1) return false;
91078
+ this.saltoActivo = null;
91079
+ this.pila = [];
91080
+ this.index = coda;
91081
+ return true;
91082
+ }
91083
+ buscar(direccion, primeroAtras) {
91084
+ const paso = primeroAtras ? -1 : 1;
91085
+ const i2 = this.buscarHacia(direccion, paso);
91086
+ return i2 !== -1 ? i2 : this.buscarHacia(direccion, -paso);
91087
+ }
91088
+ buscarHacia(direccion, paso) {
91089
+ const compases = this.score.masterBars;
91090
+ for (let i2 = this.index; i2 >= 0 && i2 < compases.length; i2 += paso) {
91091
+ const d = compases[i2].directions;
91092
+ if (d !== null && d !== void 0 && d.has(direccion)) return i2;
91093
+ }
91094
+ return -1;
91095
+ }
91096
+ };
91097
+ ticksAMs = (ticks, tempo) => ticks * (6e4 / (tempo * 960)) | 0;
91098
+ }
91099
+ });
91100
+
89615
91101
  // packages/io/src/musicxml.ts
89616
91102
  function escapar(texto4) {
89617
91103
  return texto4.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
@@ -90079,7 +91565,7 @@ function exportarMusicXmlComprimido(score) {
90079
91565
  { mtime: FECHA_FIJA_DEL_ZIP }
90080
91566
  );
90081
91567
  }
90082
- var DIVISIONES_POR_NEGRA, FECHA_FIJA_DEL_ZIP, PASOS, NOMBRE_DE_LA_FIGURA2, ALTERACION_POR_MODO, D, SALTOS;
91568
+ var DIVISIONES_POR_NEGRA, FECHA_FIJA_DEL_ZIP, PASOS, NOMBRE_DE_LA_FIGURA2, ALTERACION_POR_MODO, D2, SALTOS;
90083
91569
  var init_musicxml = __esm({
90084
91570
  "packages/io/src/musicxml.ts"() {
90085
91571
  init_alphaTab();
@@ -90109,27 +91595,27 @@ var init_musicxml = __esm({
90109
91595
  [256, "256th"]
90110
91596
  ]);
90111
91597
  ALTERACION_POR_MODO = { 2: 0, 3: 1, 4: 2, 5: -1, 6: -2 };
90112
- D = _barrel_exports$4.Direction;
91598
+ D2 = _barrel_exports$4.Direction;
90113
91599
  SALTOS = [
90114
- [D.TargetSegno, { simbolo: "segno", sonido: 'segno="segno"' }],
90115
- [D.TargetSegnoSegno, { simbolo: "segno", sonido: 'segno="segno2"' }],
90116
- [D.TargetCoda, { simbolo: "coda", sonido: 'coda="coda"' }],
90117
- [D.TargetDoubleCoda, { simbolo: "coda", sonido: 'coda="coda2"' }],
90118
- [D.TargetFine, { texto: "Fine", sonido: 'fine="yes"' }],
90119
- [D.JumpDaCapo, { texto: "D.C.", sonido: 'dacapo="yes"' }],
90120
- [D.JumpDaCapoAlCoda, { texto: "D.C. al Coda", sonido: 'dacapo="yes"' }],
90121
- [D.JumpDaCapoAlDoubleCoda, { texto: "D.C. al Coda 2", sonido: 'dacapo="yes"' }],
90122
- [D.JumpDaCapoAlFine, { texto: "D.C. al Fine", sonido: 'dacapo="yes"' }],
90123
- [D.JumpDalSegno, { texto: "D.S.", sonido: 'dalsegno="segno"' }],
90124
- [D.JumpDalSegnoAlCoda, { texto: "D.S. al Coda", sonido: 'dalsegno="segno"' }],
90125
- [D.JumpDalSegnoAlDoubleCoda, { texto: "D.S. al Coda 2", sonido: 'dalsegno="segno"' }],
90126
- [D.JumpDalSegnoAlFine, { texto: "D.S. al Fine", sonido: 'dalsegno="segno"' }],
90127
- [D.JumpDalSegnoSegno, { texto: "D.S.S.", sonido: 'dalsegno="segno2"' }],
90128
- [D.JumpDalSegnoSegnoAlCoda, { texto: "D.S.S. al Coda", sonido: 'dalsegno="segno2"' }],
90129
- [D.JumpDalSegnoSegnoAlDoubleCoda, { texto: "D.S.S. al Coda 2", sonido: 'dalsegno="segno2"' }],
90130
- [D.JumpDalSegnoSegnoAlFine, { texto: "D.S.S. al Fine", sonido: 'dalsegno="segno2"' }],
90131
- [D.JumpDaCoda, { texto: "To Coda", sonido: 'tocoda="coda"' }],
90132
- [D.JumpDaDoubleCoda, { texto: "To Coda 2", sonido: 'tocoda="coda2"' }]
91600
+ [D2.TargetSegno, { simbolo: "segno", sonido: 'segno="segno"' }],
91601
+ [D2.TargetSegnoSegno, { simbolo: "segno", sonido: 'segno="segno2"' }],
91602
+ [D2.TargetCoda, { simbolo: "coda", sonido: 'coda="coda"' }],
91603
+ [D2.TargetDoubleCoda, { simbolo: "coda", sonido: 'coda="coda2"' }],
91604
+ [D2.TargetFine, { texto: "Fine", sonido: 'fine="yes"' }],
91605
+ [D2.JumpDaCapo, { texto: "D.C.", sonido: 'dacapo="yes"' }],
91606
+ [D2.JumpDaCapoAlCoda, { texto: "D.C. al Coda", sonido: 'dacapo="yes"' }],
91607
+ [D2.JumpDaCapoAlDoubleCoda, { texto: "D.C. al Coda 2", sonido: 'dacapo="yes"' }],
91608
+ [D2.JumpDaCapoAlFine, { texto: "D.C. al Fine", sonido: 'dacapo="yes"' }],
91609
+ [D2.JumpDalSegno, { texto: "D.S.", sonido: 'dalsegno="segno"' }],
91610
+ [D2.JumpDalSegnoAlCoda, { texto: "D.S. al Coda", sonido: 'dalsegno="segno"' }],
91611
+ [D2.JumpDalSegnoAlDoubleCoda, { texto: "D.S. al Coda 2", sonido: 'dalsegno="segno"' }],
91612
+ [D2.JumpDalSegnoAlFine, { texto: "D.S. al Fine", sonido: 'dalsegno="segno"' }],
91613
+ [D2.JumpDalSegnoSegno, { texto: "D.S.S.", sonido: 'dalsegno="segno2"' }],
91614
+ [D2.JumpDalSegnoSegnoAlCoda, { texto: "D.S.S. al Coda", sonido: 'dalsegno="segno2"' }],
91615
+ [D2.JumpDalSegnoSegnoAlDoubleCoda, { texto: "D.S.S. al Coda 2", sonido: 'dalsegno="segno2"' }],
91616
+ [D2.JumpDalSegnoSegnoAlFine, { texto: "D.S.S. al Fine", sonido: 'dalsegno="segno2"' }],
91617
+ [D2.JumpDaCoda, { texto: "To Coda", sonido: 'tocoda="coda"' }],
91618
+ [D2.JumpDaDoubleCoda, { texto: "To Coda 2", sonido: 'tocoda="coda2"' }]
90133
91619
  ];
90134
91620
  }
90135
91621
  });
@@ -90148,6 +91634,7 @@ function exportarMidi(score) {
90148
91634
  const archivo = new _barrel_exports$3.MidiFile();
90149
91635
  archivo.format = _barrel_exports$3.MidiFileFormat.MultiTrack;
90150
91636
  const manejador = new _barrel_exports$3.AlphaSynthMidiFileHandler(archivo, true);
91637
+ instalarRecorridoDeRepeticiones();
90151
91638
  new _barrel_exports$3.MidiFileGenerator(score, null, manejador).generate();
90152
91639
  return archivo.toBinary();
90153
91640
  }
@@ -90169,6 +91656,7 @@ var FORMATOS_DE_EXPORTACION;
90169
91656
  var init_exportar = __esm({
90170
91657
  "packages/io/src/exportar.ts"() {
90171
91658
  init_alphaTab();
91659
+ init_recorridoDeRepeticiones();
90172
91660
  init_musicxml();
90173
91661
  FORMATOS_DE_EXPORTACION = [
90174
91662
  {
@@ -90215,9 +91703,11 @@ var src_exports = {};
90215
91703
  __export(src_exports, {
90216
91704
  ArchivoIlegible: () => ArchivoIlegible,
90217
91705
  FORMATOS_DE_EXPORTACION: () => FORMATOS_DE_EXPORTACION,
91706
+ MidiIlegible: () => MidiIlegible,
90218
91707
  VERSION_DEL_FORMATO: () => VERSION_DEL_FORMATO,
90219
91708
  desempaquetar: () => desempaquetar,
90220
91709
  empaquetar: () => empaquetar,
91710
+ esMidi: () => esMidi,
90221
91711
  exportarAlphaTex: () => exportarAlphaTex,
90222
91712
  exportarComo: () => exportarComo,
90223
91713
  exportarGp7: () => exportarGp7,
@@ -90227,7 +91717,9 @@ __export(src_exports, {
90227
91717
  formatoDeExportacion: () => formatoDeExportacion,
90228
91718
  formatoQueNecesita: () => formatoQueNecesita,
90229
91719
  importarGp: () => importarGp,
91720
+ importarMidi: () => importarMidi,
90230
91721
  importarScore: () => importarScore,
91722
+ instalarRecorridoDeRepeticiones: () => instalarRecorridoDeRepeticiones,
90231
91723
  leerOrtografia: () => leerOrtografia,
90232
91724
  prepararMusicXml: () => prepararMusicXml,
90233
91725
  prepararParaAlphaTab: () => prepararParaAlphaTab,
@@ -90236,10 +91728,12 @@ __export(src_exports, {
90236
91728
  var init_src4 = __esm({
90237
91729
  "packages/io/src/index.ts"() {
90238
91730
  init_importarGp();
91731
+ init_importarMidi();
90239
91732
  init_musicxmlEntrada();
90240
91733
  init_archivoMtabs();
90241
91734
  init_exportar();
90242
91735
  init_musicxml();
91736
+ init_recorridoDeRepeticiones();
90243
91737
  }
90244
91738
  });
90245
91739
 
@@ -90309,6 +91803,19 @@ async function abrirDeArchivo(ruta) {
90309
91803
  };
90310
91804
  return alAbrirLaObra(abierta);
90311
91805
  }
91806
+ if (EXTENSIONES_MIDI.has(extension2)) {
91807
+ const { importarMidi: importarMidi2 } = await Promise.resolve().then(() => (init_src4(), src_exports));
91808
+ const resultado = importarMidi2(bytes, { titulo: basename(ruta).replace(/.[^.]+$/, "") });
91809
+ abierta = {
91810
+ documento: resultado.documento,
91811
+ origen: { clase: "archivo", ruta },
91812
+ avisos: resultado.avisos,
91813
+ grabaciones: [],
91814
+ grabacionesEnEspera: [],
91815
+ fuentes: []
91816
+ };
91817
+ return alAbrirLaObra(abierta);
91818
+ }
90312
91819
  if (EXTENSIONES_IMPORTABLES.has(extension2)) {
90313
91820
  const { importarGp: importarGp2 } = await Promise.resolve().then(() => (init_src4(), src_exports));
90314
91821
  const resultado = importarGp2(bytes);
@@ -90325,7 +91832,7 @@ async function abrirDeArchivo(ruta) {
90325
91832
  return alAbrirLaObra(abierta);
90326
91833
  }
90327
91834
  throw new ProblemaConLaObra(
90328
- `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).`
91835
+ `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), MusicXML (.musicxml, .xml, .mxl) y MIDI (.mid, .midi).`
90329
91836
  );
90330
91837
  }
90331
91838
  function abrirEnBlanco(opciones = {}) {
@@ -90339,6 +91846,9 @@ function abrirEnBlanco(opciones = {}) {
90339
91846
  };
90340
91847
  return alAbrirLaObra(abierta);
90341
91848
  }
91849
+ function salaDeLaObraAdoptada() {
91850
+ return abierta && abierta.origen.clase === "pesta\xF1a" ? abierta.origen.sala : null;
91851
+ }
90342
91852
  function idDeLaObraActiva() {
90343
91853
  if (!abierta || abierta.origen.clase !== "pesta\xF1a") return null;
90344
91854
  if (!laPesta\u00F1aSigueViva()) return null;
@@ -90450,7 +91960,7 @@ function reciboDeLaPesta\u00F1a(respuesta, ruta) {
90450
91960
  ...avisoDeLoQueNoSuena(mudas, 0)
90451
91961
  };
90452
91962
  }
90453
- var ProblemaConLaObra, abierta, sigueViva, EXTENSIONES_IMPORTABLES;
91963
+ var ProblemaConLaObra, abierta, sigueViva, EXTENSIONES_IMPORTABLES, EXTENSIONES_MIDI;
90454
91964
  var init_obra = __esm({
90455
91965
  "apps/mcp/src/obra.ts"() {
90456
91966
  "use strict";
@@ -90461,6 +91971,7 @@ var init_obra = __esm({
90461
91971
  abierta = null;
90462
91972
  sigueViva = null;
90463
91973
  EXTENSIONES_IMPORTABLES = /* @__PURE__ */ new Set([".gp", ".gpx", ".gp5", ".gp4", ".gp3", ".musicxml", ".xml", ".mxl"]);
91974
+ EXTENSIONES_MIDI = /* @__PURE__ */ new Set([".mid", ".midi", ".kar", ".rmi"]);
90464
91975
  }
90465
91976
  });
90466
91977
 
@@ -90469,7 +91980,7 @@ var VERSION_DEL_CONECTOR;
90469
91980
  var init_version = __esm({
90470
91981
  "apps/mcp/src/version.ts"() {
90471
91982
  "use strict";
90472
- VERSION_DEL_CONECTOR = true ? "0.2.15" : null;
91983
+ VERSION_DEL_CONECTOR = true ? "0.2.17" : null;
90473
91984
  }
90474
91985
  });
90475
91986
 
@@ -90483,6 +91994,7 @@ __export(puente_exports, {
90483
91994
  PUERTO_POR_OMISION: () => PUERTO_POR_OMISION,
90484
91995
  SALA_DE_LA_OBRA: () => SALA_DE_LA_OBRA,
90485
91996
  SALA_DE_PEDIDOS: () => SALA_DE_PEDIDOS,
91997
+ SALA_OCIOSA_MS: () => SALA_OCIOSA_MS,
90486
91998
  abrirPuente: () => abrirPuente,
90487
91999
  buscarLaPesta\u00F1a: () => buscarLaPesta\u00F1a,
90488
92000
  cerrarPuente: () => cerrarPuente,
@@ -90511,12 +92023,14 @@ function envoltorioDe(doc) {
90511
92023
  envoltoriosPorDoc.set(doc, nuevo);
90512
92024
  return nuevo;
90513
92025
  }
90514
- function origenPermitido(origen) {
92026
+ function origenPermitido(origen, puertoDelPuente = PUERTO_POR_OMISION) {
90515
92027
  if (origen === void 0) return true;
90516
92028
  if (ORIGENES_DE_TABS.includes(origen)) return true;
90517
92029
  try {
90518
92030
  const u = new URL(origen);
90519
- return (u.protocol === "http:" || u.protocol === "https:") && ["localhost", "127.0.0.1", "[::1]"].includes(u.hostname);
92031
+ const local = (u.protocol === "http:" || u.protocol === "https:") && ["localhost", "127.0.0.1", "[::1]"].includes(u.hostname);
92032
+ if (!local) return false;
92033
+ return puertoDelPuente !== PUERTO_DEL_CONECTOR || PUERTOS_LOCALES_DE_TABS.includes(u.port);
90520
92034
  } catch {
90521
92035
  return false;
90522
92036
  }
@@ -90789,8 +92303,28 @@ function abrirDeVerdad(puerto) {
90789
92303
  const apuntarLaEtiqueta = (sala) => apuntarLaEtiquetaDe(idDeLaSala(sala));
90790
92304
  const sincronizadas = /* @__PURE__ */ new Set();
90791
92305
  const deLaSala = (sala) => [...conexiones].filter(([, s]) => s === sala).map(([c]) => c);
92306
+ const relojesDeSalas = /* @__PURE__ */ new Map();
92307
+ const noSoltarla = (sala) => {
92308
+ const reloj = relojesDeSalas.get(sala);
92309
+ if (reloj) clearTimeout(reloj);
92310
+ relojesDeSalas.delete(sala);
92311
+ };
92312
+ const soltarSiSigueVacia = (sala) => {
92313
+ relojesDeSalas.delete(sala);
92314
+ if (sala === SALA_DE_LA_OBRA || sala === SALA_DE_PEDIDOS) return;
92315
+ if (deLaSala(sala).length > 0 || salaDeLaObraAdoptada() === sala) return;
92316
+ const doc = docs.get(sala);
92317
+ docs.delete(sala);
92318
+ sincronizadas.delete(sala);
92319
+ doc?.destroy();
92320
+ };
90792
92321
  const olvidarSiQuedoVacia = (sala) => {
90793
- if (deLaSala(sala).length === 0) sincronizadas.delete(sala);
92322
+ if (deLaSala(sala).length > 0) return;
92323
+ sincronizadas.delete(sala);
92324
+ noSoltarla(sala);
92325
+ const reloj = setTimeout(() => soltarSiSigueVacia(sala), SALA_OCIOSA_MS);
92326
+ reloj.unref?.();
92327
+ relojesDeSalas.set(sala, reloj);
90794
92328
  };
90795
92329
  const escuchar = (sala, doc) => {
90796
92330
  doc.on("update", (cambio, origen) => {
@@ -90809,7 +92343,7 @@ function abrirDeVerdad(puerto) {
90809
92343
  const servidor2 = new import_websocket_server.default({
90810
92344
  server: http,
90811
92345
  // Ver `origenPermitido`: una página de otro sitio recibe un 401 y no llega a la obra.
90812
- verifyClient: ({ origin }) => origenPermitido(origin || void 0)
92346
+ verifyClient: ({ origin }) => origenPermitido(origin || void 0, puerto)
90813
92347
  });
90814
92348
  servidor2.on("error", () => {
90815
92349
  });
@@ -90829,6 +92363,7 @@ function abrirDeVerdad(puerto) {
90829
92363
  return;
90830
92364
  }
90831
92365
  const sala = salaValida(pedida) ? pedida : SALA_DE_LA_OBRA;
92366
+ noSoltarla(sala);
90832
92367
  const doc = docDeLaSala(sala);
90833
92368
  if (esDeObra(sala) && deLaSala(sala).length > 0) {
90834
92369
  conexion.close(4001, "Ya hay otra pesta\xF1a conectada a la IA. Descon\xE9ctala antes de conectar \xE9sta.");
@@ -90922,8 +92457,14 @@ function abrirDeVerdad(puerto) {
90922
92457
  // separa la vida del buzón de la del documento. Ver el bloque del índice.
90923
92458
  pedidosDe: (id2) => docs.get(salaDelBuzonDe(id2)),
90924
92459
  escuchanPedidosDe: (id2) => deLaSala(salaDelBuzonDe(id2)).length,
92460
+ oyentesDe: (canal) => {
92461
+ for (const [sala, doc] of docs) if (doc === canal) return deLaSala(sala).length;
92462
+ return 0;
92463
+ },
90925
92464
  cerrar: () => new Promise((listo) => {
90926
92465
  clearInterval(latidoDelPuente);
92466
+ for (const reloj of relojesDeSalas.values()) clearTimeout(reloj);
92467
+ relojesDeSalas.clear();
90927
92468
  for (const c of conexiones.keys()) c.close();
90928
92469
  conexiones.clear();
90929
92470
  mostrador.clear();
@@ -90992,7 +92533,7 @@ async function pedirALaPesta\u00F1a(herramienta, argumentos = {}, msDelAcuse = E
90992
92533
  }, msDelAcuse);
90993
92534
  let desdeCuandoNoHayNadie = null;
90994
92535
  const latido = setInterval(() => {
90995
- if (p.pesta\u00F1as() > 0) {
92536
+ if (p.oyentesDe(canal) > 0) {
90996
92537
  desdeCuandoNoHayNadie = null;
90997
92538
  return;
90998
92539
  }
@@ -91035,7 +92576,7 @@ async function pedirALaPesta\u00F1a(herramienta, argumentos = {}, msDelAcuse = E
91035
92576
  canal.transact(() => mapa.delete(id2));
91036
92577
  }
91037
92578
  }
91038
- var envoltoriosPorDoc, SINCRONIZAR, PRESENCIA, SALA_DE_LA_OBRA, SALA_DE_PEDIDOS, PUERTO_POR_OMISION, ORIGENES_DE_TABS, puente, reclamado, ESPERA_POR_LA_PESTA\u00D1A, mostrador, casillero, TIPOS, abriendo, siguienteId, INSTANCIA, ESPERA_DEL_ACUSE_MS, LATIDO_MS, LATIDO_DEL_PUENTE_MS, AUSENCIA_PARA_DARLA_POR_IDA_MS, MARGEN_PARA_QUE_ENTRE_MS;
92579
+ var envoltoriosPorDoc, SINCRONIZAR, PRESENCIA, SALA_DE_LA_OBRA, SALA_DE_PEDIDOS, PUERTO_POR_OMISION, ORIGENES_DE_TABS, PUERTOS_LOCALES_DE_TABS, PUERTO_DEL_CONECTOR, puente, reclamado, ESPERA_POR_LA_PESTA\u00D1A, mostrador, casillero, TIPOS, abriendo, siguienteId, INSTANCIA, ESPERA_DEL_ACUSE_MS, LATIDO_MS, LATIDO_DEL_PUENTE_MS, AUSENCIA_PARA_DARLA_POR_IDA_MS, SALA_OCIOSA_MS, MARGEN_PARA_QUE_ENTRE_MS;
91039
92580
  var init_puente = __esm({
91040
92581
  "apps/mcp/src/puente.ts"() {
91041
92582
  "use strict";
@@ -91059,6 +92600,8 @@ var init_puente = __esm({
91059
92600
  "https://mandioca-tabs.entelequia.workers.dev",
91060
92601
  ...(process.env["MANDIOCA_TABS_ORIGENES"] ?? "").split(",").map((o) => o.trim().replace(/\/+$/, "")).filter(Boolean)
91061
92602
  ];
92603
+ PUERTOS_LOCALES_DE_TABS = ["5173", "4173"];
92604
+ PUERTO_DEL_CONECTOR = 5183;
91062
92605
  puente = null;
91063
92606
  reclamado = false;
91064
92607
  ESPERA_POR_LA_PESTA\u00D1A = 3500;
@@ -91074,6 +92617,7 @@ var init_puente = __esm({
91074
92617
  LATIDO_MS = 250;
91075
92618
  LATIDO_DEL_PUENTE_MS = 1e4;
91076
92619
  AUSENCIA_PARA_DARLA_POR_IDA_MS = 2e3;
92620
+ SALA_OCIOSA_MS = Number(process.env["MANDIOCA_TABS_SALA_OCIOSA_MS"] ?? 10 * 6e4);
91077
92621
  MARGEN_PARA_QUE_ENTRE_MS = 750;
91078
92622
  }
91079
92623
  });
@@ -98299,6 +99843,51 @@ var init_marcas = __esm({
98299
99843
  }
98300
99844
  });
98301
99845
 
99846
+ // packages/projection/src/diagramas.ts
99847
+ function diagramasValidos(v) {
99848
+ return DIAGRAMAS_POSIBLES.includes(v) ? v : "no";
99849
+ }
99850
+ function claveDeLaForma(forma) {
99851
+ return [...forma].sort((a, b) => a.cuerda - b.cuerda).map((n) => `${n.cuerda}:${n.traste}`).join(" ");
99852
+ }
99853
+ function formaDibujable(forma) {
99854
+ if (forma.length < 2) return false;
99855
+ return new Set(forma.map((n) => n.cuerda)).size === forma.length;
99856
+ }
99857
+ function formasDeLaPista(golpes) {
99858
+ const cuentas = /* @__PURE__ */ new Map();
99859
+ golpes.forEach(({ nombre, forma }, orden) => {
99860
+ if (!formaDibujable(forma)) return;
99861
+ const deEste = cuentas.get(nombre) ?? /* @__PURE__ */ new Map();
99862
+ cuentas.set(nombre, deEste);
99863
+ const clave = claveDeLaForma(forma);
99864
+ const previa = deEste.get(clave);
99865
+ if (previa) previa.veces += 1;
99866
+ else deEste.set(clave, { forma, veces: 1, orden });
99867
+ });
99868
+ const elegidas = /* @__PURE__ */ new Map();
99869
+ for (const [nombre, formas] of cuentas) {
99870
+ const mejor = [...formas.values()].sort((a, b) => b.veces - a.veces || a.orden - b.orden)[0];
99871
+ if (mejor) elegidas.set(nombre, mejor.forma);
99872
+ }
99873
+ return elegidas;
99874
+ }
99875
+ function cuerdasDelDiagrama(forma, cuerdas) {
99876
+ const porCuerda = new Map(forma.map((n) => [n.cuerda, n.traste]));
99877
+ const strings = [];
99878
+ for (let c = cuerdas; c >= 1; c--) strings.push(porCuerda.get(c) ?? -1);
99879
+ const pisados = forma.map((n) => n.traste).filter((t) => t > 0);
99880
+ const maximo = pisados.length ? Math.max(...pisados) : 0;
99881
+ const firstFret = maximo <= 5 ? 1 : Math.min(...pisados);
99882
+ return { strings, firstFret };
99883
+ }
99884
+ var DIAGRAMAS_POSIBLES;
99885
+ var init_diagramas = __esm({
99886
+ "packages/projection/src/diagramas.ts"() {
99887
+ DIAGRAMAS_POSIBLES = ["no", "arriba", "partitura"];
99888
+ }
99889
+ });
99890
+
98302
99891
  // packages/projection/src/estilo.ts
98303
99892
  function comoLoEscribeCss(fuente) {
98304
99893
  const partes = [];
@@ -98463,6 +100052,9 @@ function proyectar(documento, opciones = {}) {
98463
100052
  score.album = marcado(cabecera.get("album") ?? "", marcasDe(cabecera, "album"));
98464
100053
  const tempoDeCabecera = documento.cabecera.get("tempo") || 120;
98465
100054
  score.stylesheet.hideDynamics = documento.cabecera.get("mostrarMatices") === false;
100055
+ const diagramas = diagramasValidos(documento.cabecera.get("diagramasDeAcordes"));
100056
+ score.stylesheet.globalDisplayChordDiagramsOnTop = diagramas === "arriba";
100057
+ score.stylesheet.globalDisplayChordDiagramsInScore = diagramas === "partitura";
98466
100058
  score.stylesheet.barNumberDisplay = _barrel_exports$4.BarNumberDisplay.AllBars;
98467
100059
  const estiloDeLaObra = documento.leerEstilo();
98468
100060
  aplicarEstiloAlDibujo(score, ajustes, estiloDeLaObra);
@@ -98607,6 +100199,15 @@ function proyectar(documento, opciones = {}) {
98607
100199
  });
98608
100200
  acordesEscritos.sort((a, b) => a.compas - b.compas || a.tiempo - b.tiempo);
98609
100201
  const acordeVigente = buscadorDeAcorde(acordesEscritos);
100202
+ const formaDelGolpe = (idFigura) => (notasPorFigura.get(idFigura) ?? []).map((n) => ({ cuerda: n.cuerda, traste: n.traste }));
100203
+ const formasConNombre = diagramas !== "no" && pista.tipo === "trastes" ? formasDeLaPista(
100204
+ maestros.flatMap(
100205
+ (m) => deLaPista.flatMap((mapa) => {
100206
+ const id2 = mapa.get(m.id);
100207
+ return (id2 ? figurasPorCompas.get(id2) ?? [] : []).filter(({ datos: f }) => f.acorde).sort((a, b) => a.datos.tiempo - b.datos.tiempo).map(({ id: idFigura, datos: f }) => ({ nombre: f.acorde, forma: formaDelGolpe(idFigura) }));
100208
+ })
100209
+ )
100210
+ ) : null;
98610
100211
  maestros.forEach((maestro, indiceDeCompas2) => {
98611
100212
  const barra = new _barrel_exports$4.Bar();
98612
100213
  pentagrama.addBar(barra);
@@ -98654,15 +100255,23 @@ function proyectar(documento, opciones = {}) {
98654
100255
  if (figura.texto) golpe.lyrics = [marcado(figura.texto, figura.textoSegundaTipografia)];
98655
100256
  if (figura.acorde) {
98656
100257
  const nombre = marcado(figura.acorde, figura.acordeSegundaTipografia);
98657
- if (!pentagrama.chords?.has(nombre)) {
100258
+ const propia = formasConNombre ? formaDelGolpe(idFigura) : [];
100259
+ const forma = formasConNombre ? formaDibujable(propia) ? propia : formasConNombre.get(figura.acorde) : void 0;
100260
+ const id2 = forma ? `${nombre}|${claveDeLaForma(forma)}` : nombre;
100261
+ if (!pentagrama.chords?.has(id2)) {
98658
100262
  const acorde = new _barrel_exports$4.Chord();
98659
100263
  acorde.name = nombre;
98660
100264
  acorde.showName = true;
98661
- acorde.showDiagram = false;
100265
+ acorde.showDiagram = forma !== void 0;
100266
+ if (forma) {
100267
+ const { strings, firstFret } = cuerdasDelDiagrama(forma, pista.afinacion.length);
100268
+ acorde.strings = strings;
100269
+ acorde.firstFret = firstFret;
100270
+ }
98662
100271
  acorde.staff = pentagrama;
98663
- pentagrama.addChord(nombre, acorde);
100272
+ pentagrama.addChord(id2, acorde);
98664
100273
  }
98665
- golpe.chordId = nombre;
100274
+ golpe.chordId = id2;
98666
100275
  }
98667
100276
  golpe.dynamics = figura.dinamica;
98668
100277
  golpe.pickStroke = figura.puaDireccion;
@@ -98861,6 +100470,7 @@ var VOCES_POR_COMPAS, volumenDeMezcla;
98861
100470
  var init_proyectar = __esm({
98862
100471
  "packages/projection/src/proyectar.ts"() {
98863
100472
  init_alphaTab();
100473
+ init_diagramas();
98864
100474
  init_estilo();
98865
100475
  init_src3();
98866
100476
  init_marcas();
@@ -98874,6 +100484,7 @@ var init_proyectar = __esm({
98874
100484
  // packages/projection/src/index.ts
98875
100485
  var src_exports2 = {};
98876
100486
  __export(src_exports2, {
100487
+ DIAGRAMAS_POSIBLES: () => DIAGRAMAS_POSIBLES,
98877
100488
  ELEMENTOS_QUE_DIBUJA_EL_PROGRAMA: () => ELEMENTOS_QUE_DIBUJA_EL_PROGRAMA,
98878
100489
  ELEMENTOS_QUE_NO_SE_DIBUJAN: () => ELEMENTOS_QUE_NO_SE_DIBUJAN,
98879
100490
  MARCA_DE_BANDA: () => MARCA_DE_BANDA,
@@ -98881,6 +100492,7 @@ __export(src_exports2, {
98881
100492
  aplicarColoresAlDibujo: () => aplicarColoresAlDibujo,
98882
100493
  aplicarEstiloAlDibujo: () => aplicarEstiloAlDibujo,
98883
100494
  aplicarFuentesAlDibujo: () => aplicarFuentesAlDibujo,
100495
+ diagramasValidos: () => diagramasValidos,
98884
100496
  fuentePropiaDe: () => fuentePropiaDe,
98885
100497
  pasarLetraALaFila: () => pasarLetraALaFila,
98886
100498
  presentarPistas: () => presentarPistas,
@@ -98891,6 +100503,7 @@ __export(src_exports2, {
98891
100503
  var init_src5 = __esm({
98892
100504
  "packages/projection/src/index.ts"() {
98893
100505
  init_marcas();
100506
+ init_diagramas();
98894
100507
  init_proyectar();
98895
100508
  init_estilo();
98896
100509
  }
@@ -122984,6 +124597,68 @@ var EMPTY_COMPLETION_RESULT = {
122984
124597
  }
122985
124598
  };
122986
124599
 
124600
+ // apps/mcp/src/anotaciones.ts
124601
+ var LEEN = /* @__PURE__ */ new Set([
124602
+ "acorde_en_el_cursor",
124603
+ "acordes_de_la_obra",
124604
+ "afinaciones_disponibles",
124605
+ "ajustes_de_video",
124606
+ "atajos_del_programa",
124607
+ "audios_rechazados_por_largos",
124608
+ "captura",
124609
+ "direcciones_disponibles",
124610
+ "efectos_disponibles",
124611
+ "estado_de_la_conexion",
124612
+ "estado_de_la_obra",
124613
+ "estilo_de_la_obra",
124614
+ "estructura_de_la_obra",
124615
+ "formas_de_bend",
124616
+ "formatos_de_exportacion",
124617
+ "instrumentos_disponibles",
124618
+ "leer_compases",
124619
+ "leer_curva_de_bend",
124620
+ "leer_letra",
124621
+ "letra_estacionada",
124622
+ "letra_sincronizada",
124623
+ "matices_disponibles",
124624
+ "obras_conectadas",
124625
+ "obras_recientes",
124626
+ "piezas_de_bateria",
124627
+ "precision_del_alineador",
124628
+ "que_hace_un_control",
124629
+ "secciones_de_la_obra",
124630
+ "signos_de_una_nota",
124631
+ "signos_disponibles",
124632
+ "variantes_disponibles"
124633
+ ]);
124634
+ var BORRAN = /* @__PURE__ */ new Set([
124635
+ "borrar_compas",
124636
+ "borrar_compases_desde",
124637
+ "borrar_compases_hasta",
124638
+ "borrar_figura",
124639
+ "borrar_grabacion",
124640
+ "borrar_notas",
124641
+ "borrar_pista",
124642
+ "cortar_pasaje",
124643
+ "desanclar_todo",
124644
+ "olvidar_reciente",
124645
+ "quitar_cuerda",
124646
+ "quitar_grabacion",
124647
+ "quitar_silaba",
124648
+ // Pisan un archivo del disco si se les pide (`pisar`), y eso no tiene «deshacer».
124649
+ "guardar_obra",
124650
+ "guardar_grabacion",
124651
+ "guardar_letra",
124652
+ "exportar",
124653
+ "exportar_audio",
124654
+ "exportar_pdf",
124655
+ "exportar_video"
124656
+ ]);
124657
+ function anotacionesDe(nombre) {
124658
+ if (LEEN.has(nombre)) return { readOnlyHint: true, openWorldHint: false };
124659
+ return { readOnlyHint: false, destructiveHint: BORRAN.has(nombre), openWorldHint: false };
124660
+ }
124661
+
122987
124662
  // apps/mcp/src/herramientas/documento.ts
122988
124663
  init_src2();
122989
124664
  init_src3();
@@ -123204,9 +124879,9 @@ function registrarHerramientasDelDocumento(servidor2) {
123204
124879
  "abrir_obra",
123205
124880
  {
123206
124881
  title: "Abrir una obra",
123207
- 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`.",
124882
+ 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), MusicXML (.musicxml, .xml, .mxl) y MIDI (.mid, .midi). \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`.",
123208
124883
  inputSchema: {
123209
- ruta: external_exports.string().describe("La ruta completa del archivo: .mtabs, Guitar Pro (.gp, .gpx, .gp5\u2026) o MusicXML (.musicxml, .xml, .mxl)"),
124884
+ ruta: external_exports.string().describe("La ruta completa del archivo: .mtabs, Guitar Pro (.gp, .gpx, .gp5\u2026), MusicXML (.musicxml, .xml, .mxl) o MIDI (.mid)"),
123210
124885
  igual: external_exports.boolean().optional().describe(
123211
124886
  "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."
123212
124887
  )
@@ -123960,6 +125635,46 @@ function registrarHerramientasDelPuente(servidor2) {
123960
125635
  },
123961
125636
  async (args2) => texto3(await pedirALaPesta\u00F1a("metronomo", args2))
123962
125637
  );
125638
+ servidor2.registerTool(
125639
+ "elegir_voz",
125640
+ {
125641
+ title: "Elegir en qu\xE9 voz escribe el m\xFAsico",
125642
+ description: "Cambia la voz del cursor en la pantalla (1 a 4): lo que el m\xFAsico teclee despu\xE9s cae en esa voz. Es el selector \xABVoz\xBB de la barra. Las herramientas que escriben ya reciben su propia `voz`; \xE9sta es para dejarle la pantalla lista. Sin decir cu\xE1l, pasa a la siguiente. Contesta la voz y d\xF3nde qued\xF3 el cursor.",
125643
+ inputSchema: {
125644
+ voz: external_exports.number().int().min(1).max(4).optional().describe("De 1 a 4. Sin esto, la siguiente.")
125645
+ }
125646
+ },
125647
+ async (args2) => texto3(await pedirALaPesta\u00F1a("elegir_voz", args2))
125648
+ );
125649
+ servidor2.registerTool(
125650
+ "bucle",
125651
+ {
125652
+ title: "Repetir un pasaje en bucle",
125653
+ description: "Pone o saca el bucle: la reproducci\xF3n repite esos compases una y otra vez. Con `compas` (y `hasta`) repite esos; sin ellos, el pasaje marcado en pantalla o el comp\xE1s del cursor. Sin decir nada, alterna. No se guarda en la obra. La cuenta previa y la velocidad que sube se ajustan con `practica`.",
125654
+ inputSchema: {
125655
+ puesto: external_exports.boolean().optional().describe("true lo pone, false lo saca. Sin esto, alterna."),
125656
+ compas: external_exports.number().int().min(1).max(9999).optional().describe("Primer comp\xE1s del tramo, desde 1."),
125657
+ hasta: external_exports.number().int().min(1).max(9999).optional().describe("\xDAltimo comp\xE1s del tramo, incluido.")
125658
+ }
125659
+ },
125660
+ async (args2) => texto3(await pedirALaPesta\u00F1a("bucle", args2))
125661
+ );
125662
+ servidor2.registerTool(
125663
+ "practica",
125664
+ {
125665
+ title: "Ajustes de pr\xE1ctica",
125666
+ description: "C\xF3mo se practica con el bucle: `cuentaPrevia` toca un comp\xE1s de clicks antes de que entre la m\xFAsica (en cada play); `subirVelocidad` hace que, con el bucle puesto, la velocidad arranque en `desde` y suba `paso` cada `cadaVueltas` vueltas hasta `hasta`. De f\xE1brica todo apagado. Es de quien toca, no de la obra. Sin nada, contesta c\xF3mo est\xE1.",
125667
+ inputSchema: {
125668
+ cuentaPrevia: external_exports.boolean().optional(),
125669
+ subirVelocidad: external_exports.boolean().optional(),
125670
+ desde: external_exports.number().min(0.25).max(1.5).optional().describe("Velocidad de la primera vuelta; 1 es la normal."),
125671
+ hasta: external_exports.number().min(0.25).max(1.5).optional().describe("De ah\xED no pasa."),
125672
+ paso: external_exports.number().min(0.01).max(0.25).optional().describe("Cu\xE1nto sube cada vez: 0,05 es 5 %."),
125673
+ cadaVueltas: external_exports.number().int().min(1).max(16).optional()
125674
+ }
125675
+ },
125676
+ async (args2) => texto3(await pedirALaPesta\u00F1a("practica", args2))
125677
+ );
123963
125678
  servidor2.registerTool(
123964
125679
  "avanzar_al_escribir",
123965
125680
  {
@@ -124435,7 +126150,7 @@ function registrarHerramientasDelPuente(servidor2) {
124435
126150
  title: "Abrir una obra en la pantalla del m\xFAsico",
124436
126151
  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.",
124437
126152
  inputSchema: {
124438
- 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)")
126153
+ ruta: external_exports.string().min(1).describe("La ruta completa en el disco: .mtabs, Guitar Pro (.gp, .gpx, .gp5\u2026), MusicXML (.musicxml, .xml, .mxl) o MIDI (.mid)")
124439
126154
  }
124440
126155
  },
124441
126156
  async ({ ruta }) => {
@@ -124901,6 +126616,22 @@ function registrarHerramientasDeEstructura(servidor2) {
124901
126616
  });
124902
126617
  }
124903
126618
  );
126619
+ servidor2.registerTool(
126620
+ "diagramas_de_acordes",
126621
+ {
126622
+ title: "Diagramas de acordes",
126623
+ description: "Si los nombres de acorde llevan su cuadrito de trastes: `no` (s\xF3lo el nombre, de f\xE1brica), `partitura` (sobre cada acorde) o `arriba` (una lista al comienzo). Se guarda en la obra. \u26A0\uFE0F El diagrama sale de lo ESCRITO: las notas del golpe, o la forma con que ese acorde est\xE1 escrito en otro lugar de la pista. Un nombre sin notas en ning\xFAn lado queda sin diagrama: el programa no inventa digitaciones. Sin decir nada, contesta c\xF3mo est\xE1.",
126624
+ inputSchema: {
126625
+ donde: external_exports.enum(["no", "partitura", "arriba"]).optional()
126626
+ }
126627
+ },
126628
+ ({ donde }) => {
126629
+ const { documento } = obraAbierta();
126630
+ if (donde !== void 0) documento.doc.transact(() => documento.cabecera.set("diagramasDeAcordes", donde));
126631
+ const actual = documento.cabecera.get("diagramasDeAcordes");
126632
+ return texto2({ diagramasDeAcordes: actual === "partitura" || actual === "arriba" ? actual : "no" });
126633
+ }
126634
+ );
124904
126635
  servidor2.registerTool(
124905
126636
  "estilo_de_la_obra",
124906
126637
  {
@@ -126761,6 +128492,8 @@ function crearServidor() {
126761
128492
  { name: NOMBRE, version: VERSION },
126762
128493
  { instructions: INSTRUCCIONES }
126763
128494
  );
128495
+ const registrar = servidor2.registerTool.bind(servidor2);
128496
+ servidor2.registerTool = ((nombre, config2, cb) => registrar(nombre, { ...config2, annotations: { ...anotacionesDe(nombre), ...config2.annotations } }, cb));
126764
128497
  registrarHerramientasDelDocumento(servidor2);
126765
128498
  registrarHerramientasDelPuente(servidor2);
126766
128499
  registrarHerramientasDeSignos(servidor2);