musicxml-io 0.1.0 → 0.2.0

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.
@@ -215,6 +215,7 @@ interface MeasureAttributes {
215
215
  keys?: KeySignature[];
216
216
  clef?: Clef[];
217
217
  staves?: number;
218
+ instruments?: number;
218
219
  transpose?: Transpose;
219
220
  transposes?: Transpose[];
220
221
  staffDetails?: StaffDetails[];
@@ -265,7 +266,7 @@ interface TimeSignature {
265
266
  }
266
267
  interface KeySignature {
267
268
  fifths: number;
268
- mode?: 'major' | 'minor' | 'dorian' | 'phrygian' | 'lydian' | 'mixolydian' | 'aeolian' | 'ionian' | 'locrian';
269
+ mode?: 'major' | 'minor' | 'dorian' | 'phrygian' | 'lydian' | 'mixolydian' | 'aeolian' | 'ionian' | 'locrian' | 'none';
269
270
  cancel?: number;
270
271
  cancelLocation?: 'left' | 'right' | 'before-barline';
271
272
  number?: number;
@@ -284,6 +285,8 @@ interface Clef {
284
285
  line: number;
285
286
  staff?: number;
286
287
  clefOctaveChange?: number;
288
+ printObject?: boolean;
289
+ afterBarline?: boolean;
287
290
  }
288
291
  interface Transpose {
289
292
  diatonic: number;
@@ -292,7 +295,7 @@ interface Transpose {
292
295
  }
293
296
  interface Barline {
294
297
  location: 'left' | 'right' | 'middle';
295
- barStyle?: 'regular' | 'dotted' | 'dashed' | 'heavy' | 'light-light' | 'light-heavy' | 'heavy-light' | 'heavy-heavy' | 'none';
298
+ barStyle?: 'regular' | 'dotted' | 'dashed' | 'heavy' | 'light-light' | 'light-heavy' | 'heavy-light' | 'heavy-heavy' | 'tick' | 'short' | 'none';
296
299
  repeat?: {
297
300
  direction: 'forward' | 'backward';
298
301
  times?: number;
@@ -372,6 +375,9 @@ interface DirectionSound {
372
375
  volume?: number;
373
376
  pan?: number;
374
377
  };
378
+ damperPedal?: 'yes' | 'no';
379
+ softPedal?: 'yes' | 'no';
380
+ sostenutoPedal?: 'yes' | 'no';
375
381
  }
376
382
  interface DirectionEntry {
377
383
  type: 'direction';
@@ -403,6 +409,9 @@ interface SoundEntry {
403
409
  fine?: boolean;
404
410
  forwardRepeat?: boolean;
405
411
  swing?: Swing;
412
+ damperPedal?: boolean | 'yes' | 'no';
413
+ softPedal?: boolean | 'yes' | 'no';
414
+ sostenutoPedal?: boolean | 'yes' | 'no';
406
415
  }
407
416
  interface HarmonyEntry {
408
417
  type: 'harmony';
@@ -561,6 +570,7 @@ interface SlurNotation extends BaseNotation {
561
570
  slurType: 'start' | 'stop' | 'continue';
562
571
  number?: number;
563
572
  lineType?: 'solid' | 'dashed' | 'dotted' | 'wavy';
573
+ orientation?: 'over' | 'under';
564
574
  defaultX?: number;
565
575
  defaultY?: number;
566
576
  bezierX?: number;
@@ -696,6 +706,8 @@ type DirectionType = {
696
706
  number?: number;
697
707
  lineEnd?: 'up' | 'down' | 'both' | 'arrow' | 'none';
698
708
  lineType?: 'solid' | 'dashed' | 'dotted' | 'wavy';
709
+ defaultY?: number;
710
+ relativeX?: number;
699
711
  } | {
700
712
  kind: 'dashes';
701
713
  type: 'start' | 'stop' | 'continue';
@@ -793,5 +805,288 @@ interface NoteIteratorItem {
793
805
  note: NoteEntry;
794
806
  position: number;
795
807
  }
808
+ /**
809
+ * Voice to Staff mapping for inferring staff when not explicitly specified
810
+ */
811
+ interface VoiceToStaffMap {
812
+ get(voice: number): number | undefined;
813
+ has(voice: number): boolean;
814
+ entries(): IterableIterator<[number, number]>;
815
+ size: number;
816
+ }
817
+ /**
818
+ * Note with full context information
819
+ */
820
+ interface NoteWithContext {
821
+ note: NoteEntry;
822
+ part: Part;
823
+ partIndex: number;
824
+ measure: Measure;
825
+ measureIndex: number;
826
+ position: number;
827
+ }
828
+ /**
829
+ * Entry with context (for iterateEntries)
830
+ */
831
+ interface EntryWithContext {
832
+ entry: MeasureEntry;
833
+ part: Part;
834
+ partIndex: number;
835
+ measure: Measure;
836
+ measureIndex: number;
837
+ position: number;
838
+ }
839
+ /**
840
+ * Direction with context information
841
+ */
842
+ interface DirectionWithContext {
843
+ direction: DirectionEntry;
844
+ part: Part;
845
+ partIndex: number;
846
+ measure: Measure;
847
+ measureIndex: number;
848
+ position: number;
849
+ }
850
+ /**
851
+ * Staff range (min and max staff numbers)
852
+ */
853
+ interface StaffRange {
854
+ min: number;
855
+ max: number;
856
+ }
857
+ /**
858
+ * Options for position-based queries
859
+ */
860
+ interface PositionQueryOptions {
861
+ staff?: number;
862
+ voice?: number;
863
+ includeChordNotes?: boolean;
864
+ }
865
+ /**
866
+ * Vertical slice - all notes at a specific position across all parts
867
+ */
868
+ interface VerticalSlice {
869
+ measureIndex: number;
870
+ position: number;
871
+ parts: Map<number, NoteEntry[]>;
872
+ }
873
+ /**
874
+ * Voice line - continuous melodic line across measures
875
+ */
876
+ interface VoiceLine {
877
+ partIndex: number;
878
+ voice: number;
879
+ staff?: number;
880
+ notes: NoteWithContext[];
881
+ }
882
+ /**
883
+ * Adjacent notes (previous and next)
884
+ */
885
+ interface AdjacentNotes {
886
+ prev: NoteWithContext | null;
887
+ next: NoteWithContext | null;
888
+ }
889
+ /**
890
+ * Direction kind type for filtering
891
+ */
892
+ type DirectionKind = DirectionType['kind'];
893
+ /**
894
+ * Dynamic marking with context
895
+ */
896
+ interface DynamicWithContext {
897
+ dynamic: DynamicsValue;
898
+ direction: DirectionEntry;
899
+ part: Part;
900
+ partIndex: number;
901
+ measure: Measure;
902
+ measureIndex: number;
903
+ position: number;
904
+ }
905
+ /**
906
+ * Tempo marking with context
907
+ */
908
+ interface TempoWithContext {
909
+ beatUnit: NoteType;
910
+ perMinute?: number | string;
911
+ beatUnitDot?: boolean;
912
+ direction: DirectionEntry;
913
+ partIndex: number;
914
+ measureIndex: number;
915
+ position: number;
916
+ }
917
+ /**
918
+ * Pedal marking with context
919
+ */
920
+ interface PedalWithContext {
921
+ pedalType: 'start' | 'stop' | 'change' | 'continue';
922
+ direction: DirectionEntry;
923
+ partIndex: number;
924
+ measureIndex: number;
925
+ position: number;
926
+ }
927
+ /**
928
+ * Wedge (crescendo/diminuendo) with context
929
+ */
930
+ interface WedgeWithContext {
931
+ wedgeType: 'crescendo' | 'diminuendo' | 'stop';
932
+ direction: DirectionEntry;
933
+ partIndex: number;
934
+ measureIndex: number;
935
+ position: number;
936
+ }
937
+ /**
938
+ * Octave shift with context
939
+ */
940
+ interface OctaveShiftWithContext {
941
+ shiftType: 'up' | 'down' | 'stop';
942
+ size?: number;
943
+ direction: DirectionEntry;
944
+ partIndex: number;
945
+ measureIndex: number;
946
+ position: number;
947
+ }
948
+ /**
949
+ * A group of tied notes (notes connected by ties)
950
+ */
951
+ interface TiedNoteGroup {
952
+ notes: NoteWithContext[];
953
+ /** Total duration of all tied notes */
954
+ totalDuration: number;
955
+ }
956
+ /**
957
+ * A slur span from start to stop
958
+ */
959
+ interface SlurSpan {
960
+ number: number;
961
+ startNote: NoteWithContext;
962
+ endNote: NoteWithContext;
963
+ /** Notes covered by the slur (including start and end) */
964
+ notes: NoteWithContext[];
965
+ }
966
+ /**
967
+ * A tuplet group
968
+ */
969
+ interface TupletGroup {
970
+ number: number;
971
+ notes: NoteWithContext[];
972
+ /** Actual notes (numerator of time modification) */
973
+ actualNotes: number;
974
+ /** Normal notes (denominator of time modification) */
975
+ normalNotes: number;
976
+ }
977
+ /**
978
+ * A beam group (notes connected by beams)
979
+ */
980
+ interface BeamGroup {
981
+ notes: NoteWithContext[];
982
+ /** Beam level (1 for eighth notes, 2 for sixteenth, etc.) */
983
+ beamLevel: number;
984
+ }
985
+ /**
986
+ * Filter for finding notes with specific notations
987
+ */
988
+ type NotationType = Notation['type'];
989
+ /**
990
+ * Harmony entry with context
991
+ */
992
+ interface HarmonyWithContext {
993
+ harmony: HarmonyEntry;
994
+ part: Part;
995
+ partIndex: number;
996
+ measure: Measure;
997
+ measureIndex: number;
998
+ position: number;
999
+ }
1000
+ /**
1001
+ * Lyric entry with context
1002
+ */
1003
+ interface LyricWithContext {
1004
+ lyric: Lyric;
1005
+ note: NoteEntry;
1006
+ part: Part;
1007
+ partIndex: number;
1008
+ measure: Measure;
1009
+ measureIndex: number;
1010
+ position: number;
1011
+ verse: number;
1012
+ }
1013
+ /**
1014
+ * Assembled lyrics for a verse
1015
+ */
1016
+ interface AssembledLyrics {
1017
+ verse: number;
1018
+ text: string;
1019
+ syllables: {
1020
+ text: string;
1021
+ position: number;
1022
+ measureIndex: number;
1023
+ }[];
1024
+ }
1025
+ /**
1026
+ * Barline information with context
1027
+ */
1028
+ interface BarlineWithContext {
1029
+ barline: Barline;
1030
+ partIndex: number;
1031
+ measureIndex: number;
1032
+ measureNumber: string;
1033
+ }
1034
+ /**
1035
+ * Repeat structure information
1036
+ */
1037
+ interface RepeatInfo {
1038
+ type: 'forward' | 'backward';
1039
+ times?: number;
1040
+ measureIndex: number;
1041
+ measureNumber: string;
1042
+ }
1043
+ /**
1044
+ * Ending (volta bracket) information
1045
+ */
1046
+ interface EndingInfo {
1047
+ number: string;
1048
+ type: 'start' | 'stop' | 'discontinue';
1049
+ partIndex: number;
1050
+ measureIndex: number;
1051
+ measureNumber: string;
1052
+ }
1053
+ /**
1054
+ * Key change information
1055
+ */
1056
+ interface KeyChangeInfo {
1057
+ key: KeySignature;
1058
+ partIndex: number;
1059
+ measureIndex: number;
1060
+ measureNumber: string;
1061
+ position: number;
1062
+ }
1063
+ /**
1064
+ * Time signature change information
1065
+ */
1066
+ interface TimeChangeInfo {
1067
+ time: TimeSignature;
1068
+ partIndex: number;
1069
+ measureIndex: number;
1070
+ measureNumber: string;
1071
+ }
1072
+ /**
1073
+ * Clef change information
1074
+ */
1075
+ interface ClefChangeInfo {
1076
+ clef: Clef;
1077
+ staff: number;
1078
+ partIndex: number;
1079
+ measureIndex: number;
1080
+ measureNumber: string;
1081
+ position: number;
1082
+ }
1083
+ /**
1084
+ * All structural changes combined
1085
+ */
1086
+ interface StructuralChanges {
1087
+ keyChanges: KeyChangeInfo[];
1088
+ timeChanges: TimeChangeInfo[];
1089
+ clefChanges: ClefChangeInfo[];
1090
+ }
796
1091
 
797
- export type { Accidental as A, BackupEntry as B, Clef as C, DirectionEntry as D, ForwardEntry as F, KeySignature as K, Lyric as L, Measure as M, NoteEntry as N, Part as P, Score as S, TimeSignature as T, VoiceGroup as V, Pitch as a, ScoreMetadata as b, PartInfo as c, PartGroup as d, PartListEntry as e, MeasureAttributes as f, MeasureEntry as g, NoteType as h, AccidentalInfo as i, TieInfo as j, BeamInfo as k, Notation as l, DirectionType as m, DynamicsValue as n, Transpose as o, Barline as p, StaffGroup as q, NoteWithPosition as r, Chord as s, NoteIteratorItem as t, Print as u, Defaults as v, Credit as w };
1092
+ export type { TupletGroup as $, Accidental as A, BackupEntry as B, Clef as C, DirectionEntry as D, EntryWithContext as E, ForwardEntry as F, StaffRange as G, PositionQueryOptions as H, VerticalSlice as I, VoiceLine as J, KeySignature as K, Lyric as L, Measure as M, NoteEntry as N, AdjacentNotes as O, Pitch as P, DirectionKind as Q, DynamicWithContext as R, Score as S, TieInfo as T, TempoWithContext as U, VoiceGroup as V, PedalWithContext as W, WedgeWithContext as X, OctaveShiftWithContext as Y, TiedNoteGroup as Z, SlurSpan as _, ScoreMetadata as a, BeamGroup as a0, NotationType as a1, HarmonyWithContext as a2, LyricWithContext as a3, AssembledLyrics as a4, BarlineWithContext as a5, RepeatInfo as a6, EndingInfo as a7, KeyChangeInfo as a8, TimeChangeInfo as a9, ClefChangeInfo as aa, StructuralChanges as ab, HarmonyEntry as ac, PartInfo as b, PartGroup as c, PartListEntry as d, Part as e, MeasureAttributes as f, MeasureEntry as g, NoteType as h, AccidentalInfo as i, BeamInfo as j, Notation as k, DirectionType as l, DynamicsValue as m, TimeSignature as n, Transpose as o, Barline as p, StaffGroup as q, NoteWithPosition as r, Chord as s, NoteIteratorItem as t, Print as u, Defaults as v, Credit as w, VoiceToStaffMap as x, NoteWithContext as y, DirectionWithContext as z };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "musicxml-io",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Parse and serialize MusicXML (.xml/.mxl) with high round-trip fidelity",
5
5
  "author": "tan-z-tan",
6
6
  "license": "MIT",
@@ -48,7 +48,11 @@
48
48
  "typecheck": "tsc --noEmit",
49
49
  "prepublishOnly": "npm run build && npm run test",
50
50
  "coverage:roundtrip": "tsx scripts/measure-coverage.ts",
51
- "diff:roundtrip": "tsx scripts/diff-roundtrip.ts"
51
+ "diff:roundtrip": "tsx scripts/diff-roundtrip.ts",
52
+ "release": "bash scripts/release.sh",
53
+ "release:patch": "bash scripts/release.sh patch",
54
+ "release:minor": "bash scripts/release.sh minor",
55
+ "release:major": "bash scripts/release.sh major"
52
56
  },
53
57
  "keywords": [
54
58
  "musicxml",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/accessors/index.ts","../../src/utils/index.ts"],"sourcesContent":["import type {\n Score,\n Measure,\n NoteEntry,\n VoiceGroup,\n StaffGroup,\n NoteWithPosition,\n Chord,\n NoteIteratorItem,\n} from '../types';\nimport { getAbsolutePositionForNote, createPositionState, updatePositionForEntry } from '../utils';\n\n/**\n * Filter options for voice/staff selection\n */\nexport interface VoiceFilter {\n voice?: number;\n staff?: number;\n}\n\n/**\n * Get all notes for a specific voice (and optionally staff)\n */\nexport function getNotesForVoice(measure: Measure, filter: VoiceFilter): NoteEntry[] {\n return measure.entries.filter((entry): entry is NoteEntry => {\n if (entry.type !== 'note') return false;\n if (filter.voice !== undefined && entry.voice !== filter.voice) return false;\n if (filter.staff !== undefined && (entry.staff ?? 1) !== filter.staff) return false;\n return true;\n });\n}\n\n/**\n * Get all notes for a specific staff (regardless of voice)\n */\nexport function getNotesForStaff(measure: Measure, filter: { staff: number }): NoteEntry[] {\n return measure.entries.filter((entry): entry is NoteEntry => {\n if (entry.type !== 'note') return false;\n return (entry.staff ?? 1) === filter.staff;\n });\n}\n\n/**\n * Group notes by voice (and staff)\n */\nexport function groupByVoice(measure: Measure): VoiceGroup[] {\n const groups = new Map<string, VoiceGroup>();\n\n for (const entry of measure.entries) {\n if (entry.type !== 'note') continue;\n\n const staff = entry.staff ?? 1;\n const voice = entry.voice;\n const key = `${staff}-${voice}`;\n\n if (!groups.has(key)) {\n groups.set(key, { staff, voice, notes: [] });\n }\n\n groups.get(key)!.notes.push(entry);\n }\n\n // Sort by staff, then by voice\n return Array.from(groups.values()).sort((a, b) => {\n if (a.staff !== b.staff) return a.staff - b.staff;\n return a.voice - b.voice;\n });\n}\n\n/**\n * Group notes by staff\n */\nexport function groupByStaff(measure: Measure): StaffGroup[] {\n const groups = new Map<number, StaffGroup>();\n\n for (const entry of measure.entries) {\n if (entry.type !== 'note') continue;\n\n const staff = entry.staff ?? 1;\n\n if (!groups.has(staff)) {\n groups.set(staff, { staff, notes: [] });\n }\n\n groups.get(staff)!.notes.push(entry);\n }\n\n return Array.from(groups.values()).sort((a, b) => a.staff - b.staff);\n}\n\n/**\n * Calculate absolute position of a note within a measure\n * Position is in divisions from the start of the measure\n */\nexport function getAbsolutePosition(note: NoteEntry, measure: Measure): number {\n return getAbsolutePositionForNote(note, measure);\n}\n\n/**\n * Add absolute position to all notes in a measure\n */\nexport function withAbsolutePositions(measure: Measure): NoteWithPosition[] {\n const result: NoteWithPosition[] = [];\n const state = createPositionState();\n\n for (const entry of measure.entries) {\n if (entry.type === 'note') {\n const notePosition = entry.chord ? state.lastNonChordPosition : state.position;\n result.push({\n ...entry,\n absolutePosition: notePosition,\n });\n }\n updatePositionForEntry(state, entry);\n }\n\n return result;\n}\n\n/**\n * Get chords (groups of simultaneously sounding notes)\n */\nexport function getChords(measure: Measure, filter?: VoiceFilter): Chord[] {\n const notesWithPos = withAbsolutePositions(measure);\n\n // Filter by voice/staff if specified\n const filteredNotes = filter\n ? notesWithPos.filter((note) => {\n if (filter.voice !== undefined && note.voice !== filter.voice) return false;\n if (filter.staff !== undefined && (note.staff ?? 1) !== filter.staff) return false;\n return true;\n })\n : notesWithPos;\n\n // Group by position\n const chordMap = new Map<number, NoteWithPosition[]>();\n\n for (const note of filteredNotes) {\n const pos = note.absolutePosition;\n if (!chordMap.has(pos)) {\n chordMap.set(pos, []);\n }\n chordMap.get(pos)!.push(note);\n }\n\n // Convert to Chord array\n const chords: Chord[] = [];\n\n for (const [position, notes] of chordMap.entries()) {\n // All notes in a chord should have the same duration (using first note's duration)\n const duration = notes[0].duration;\n\n chords.push({\n position,\n duration,\n notes: notes.map(({ absolutePosition, ...note }) => note),\n });\n }\n\n // Sort by position\n return chords.sort((a, b) => a.position - b.position);\n}\n\n/**\n * Iterate over all notes in a score\n */\nexport function* iterateNotes(score: Score): Generator<NoteIteratorItem> {\n for (const part of score.parts) {\n for (const measure of part.measures) {\n const state = createPositionState();\n\n for (const entry of measure.entries) {\n if (entry.type === 'note') {\n const notePosition = entry.chord ? state.lastNonChordPosition : state.position;\n yield {\n part,\n measure,\n note: entry,\n position: notePosition,\n };\n }\n updatePositionForEntry(state, entry);\n }\n }\n }\n}\n\n/**\n * Get all notes from a score as an array\n */\nexport function getAllNotes(score: Score): NoteIteratorItem[] {\n return Array.from(iterateNotes(score));\n}\n\n/**\n * Get unique voices used in a measure\n */\nexport function getVoices(measure: Measure): number[] {\n const voices = new Set<number>();\n\n for (const entry of measure.entries) {\n if (entry.type === 'note') {\n voices.add(entry.voice);\n }\n }\n\n return Array.from(voices).sort((a, b) => a - b);\n}\n\n/**\n * Get unique staves used in a measure\n */\nexport function getStaves(measure: Measure): number[] {\n const staves = new Set<number>();\n\n for (const entry of measure.entries) {\n if (entry.type === 'note') {\n staves.add(entry.staff ?? 1);\n }\n }\n\n return Array.from(staves).sort((a, b) => a - b);\n}\n\n/**\n * Check if a measure contains any notes\n */\nexport function hasNotes(measure: Measure): boolean {\n return measure.entries.some((entry) => entry.type === 'note');\n}\n\n/**\n * Check if a measure is a rest (no pitched notes)\n */\nexport function isRestMeasure(measure: Measure): boolean {\n const notes = measure.entries.filter((entry): entry is NoteEntry => entry.type === 'note');\n return notes.length === 0 || notes.every((note) => !note.pitch);\n}\n\n/**\n * Options for normalized position calculation\n */\nexport interface NormalizedPositionOptions {\n baseDivisions: number;\n currentDivisions?: number;\n}\n\n/**\n * Get a normalized position of a note using a common base divisions\n * This is useful when comparing positions across measures with different divisions\n */\nexport function getNormalizedPosition(\n note: NoteEntry,\n measure: Measure,\n options: NormalizedPositionOptions\n): number {\n const absolutePosition = getAbsolutePosition(note, measure);\n const currentDivisions = options.currentDivisions ?? measure.attributes?.divisions ?? 1;\n\n // Convert from current divisions to base divisions\n return (absolutePosition * options.baseDivisions) / currentDivisions;\n}\n\n/**\n * Get normalized duration of a note using a common base divisions\n */\nexport function getNormalizedDuration(\n note: NoteEntry,\n options: NormalizedPositionOptions\n): number {\n const currentDivisions = options.currentDivisions ?? 1;\n return (note.duration * options.baseDivisions) / currentDivisions;\n}\n","import type { Pitch, Measure, MeasureEntry, NoteEntry } from '../types';\n\n// Pitch constants\nexport const STEPS: Pitch['step'][] = ['C', 'D', 'E', 'F', 'G', 'A', 'B'];\nexport const STEP_SEMITONES: Record<Pitch['step'], number> = {\n 'C': 0, 'D': 2, 'E': 4, 'F': 5, 'G': 7, 'A': 9, 'B': 11,\n};\n\n/** Convert pitch to semitone value (MIDI-like) */\nexport function pitchToSemitone(pitch: Pitch): number {\n return pitch.octave * 12 + STEP_SEMITONES[pitch.step] + (pitch.alter ?? 0);\n}\n\n// Position tracking for measure iteration\nexport interface PositionState {\n position: number;\n lastNonChordPosition: number;\n}\n\nexport function createPositionState(): PositionState {\n return { position: 0, lastNonChordPosition: 0 };\n}\n\n/** Update position state for entry, returns position before update */\nexport function updatePositionForEntry(state: PositionState, entry: MeasureEntry): number {\n const pos = state.position;\n switch (entry.type) {\n case 'note': {\n const note = entry as NoteEntry;\n if (!note.chord) {\n state.lastNonChordPosition = state.position;\n state.position += note.duration;\n }\n return note.chord ? state.lastNonChordPosition : pos;\n }\n case 'backup':\n state.position -= entry.duration;\n state.lastNonChordPosition = state.position;\n return pos;\n case 'forward':\n state.position += entry.duration;\n state.lastNonChordPosition = state.position;\n return pos;\n default:\n return pos;\n }\n}\n\n/** Get absolute position of a note within a measure */\nexport function getAbsolutePositionForNote(note: NoteEntry, measure: Measure): number {\n const state = createPositionState();\n for (const entry of measure.entries) {\n if (entry === note) return entry.chord ? state.lastNonChordPosition : state.position;\n updatePositionForEntry(state, entry);\n }\n return state.position;\n}\n\n/** Get position at end of measure */\nexport function getMeasureEndPosition(measure: Measure): number {\n const state = createPositionState();\n for (const entry of measure.entries) updatePositionForEntry(state, entry);\n return state.position;\n}\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/utils/index.ts","../../src/accessors/index.ts"],"sourcesContent":["import type { Pitch, Measure, MeasureEntry, NoteEntry } from '../types';\n\n// Pitch constants\nexport const STEPS: Pitch['step'][] = ['C', 'D', 'E', 'F', 'G', 'A', 'B'];\nexport const STEP_SEMITONES: Record<Pitch['step'], number> = {\n 'C': 0, 'D': 2, 'E': 4, 'F': 5, 'G': 7, 'A': 9, 'B': 11,\n};\n\n/** Convert pitch to semitone value (MIDI-like) */\nexport function pitchToSemitone(pitch: Pitch): number {\n return pitch.octave * 12 + STEP_SEMITONES[pitch.step] + (pitch.alter ?? 0);\n}\n\n// Position tracking for measure iteration\nexport interface PositionState {\n position: number;\n lastNonChordPosition: number;\n}\n\nexport function createPositionState(): PositionState {\n return { position: 0, lastNonChordPosition: 0 };\n}\n\n/** Update position state for entry, returns position before update */\nexport function updatePositionForEntry(state: PositionState, entry: MeasureEntry): number {\n const pos = state.position;\n switch (entry.type) {\n case 'note': {\n const note = entry as NoteEntry;\n if (!note.chord) {\n state.lastNonChordPosition = state.position;\n state.position += note.duration;\n }\n return note.chord ? state.lastNonChordPosition : pos;\n }\n case 'backup':\n state.position -= entry.duration;\n state.lastNonChordPosition = state.position;\n return pos;\n case 'forward':\n state.position += entry.duration;\n state.lastNonChordPosition = state.position;\n return pos;\n default:\n return pos;\n }\n}\n\n/** Get absolute position of a note within a measure */\nexport function getAbsolutePositionForNote(note: NoteEntry, measure: Measure): number {\n const state = createPositionState();\n for (const entry of measure.entries) {\n if (entry === note) return entry.chord ? state.lastNonChordPosition : state.position;\n updatePositionForEntry(state, entry);\n }\n return state.position;\n}\n\n/** Get position at end of measure */\nexport function getMeasureEndPosition(measure: Measure): number {\n const state = createPositionState();\n for (const entry of measure.entries) updatePositionForEntry(state, entry);\n return state.position;\n}\n","import type {\n Score,\n Measure,\n NoteEntry,\n VoiceGroup,\n StaffGroup,\n NoteWithPosition,\n Chord,\n NoteIteratorItem,\n} from '../types';\nimport { getAbsolutePositionForNote, createPositionState, updatePositionForEntry } from '../utils';\n\n/**\n * Filter options for voice/staff selection\n */\nexport interface VoiceFilter {\n voice?: number;\n staff?: number;\n}\n\n/**\n * Get all notes for a specific voice (and optionally staff)\n */\nexport function getNotesForVoice(measure: Measure, filter: VoiceFilter): NoteEntry[] {\n return measure.entries.filter((entry): entry is NoteEntry => {\n if (entry.type !== 'note') return false;\n if (filter.voice !== undefined && entry.voice !== filter.voice) return false;\n if (filter.staff !== undefined && (entry.staff ?? 1) !== filter.staff) return false;\n return true;\n });\n}\n\n/**\n * Get all notes for a specific staff (regardless of voice)\n */\nexport function getNotesForStaff(measure: Measure, filter: { staff: number }): NoteEntry[] {\n return measure.entries.filter((entry): entry is NoteEntry => {\n if (entry.type !== 'note') return false;\n return (entry.staff ?? 1) === filter.staff;\n });\n}\n\n/**\n * Group notes by voice (and staff)\n */\nexport function groupByVoice(measure: Measure): VoiceGroup[] {\n const groups = new Map<string, VoiceGroup>();\n\n for (const entry of measure.entries) {\n if (entry.type !== 'note') continue;\n\n const staff = entry.staff ?? 1;\n const voice = entry.voice;\n const key = `${staff}-${voice}`;\n\n if (!groups.has(key)) {\n groups.set(key, { staff, voice, notes: [] });\n }\n\n groups.get(key)!.notes.push(entry);\n }\n\n // Sort by staff, then by voice\n return Array.from(groups.values()).sort((a, b) => {\n if (a.staff !== b.staff) return a.staff - b.staff;\n return a.voice - b.voice;\n });\n}\n\n/**\n * Group notes by staff\n */\nexport function groupByStaff(measure: Measure): StaffGroup[] {\n const groups = new Map<number, StaffGroup>();\n\n for (const entry of measure.entries) {\n if (entry.type !== 'note') continue;\n\n const staff = entry.staff ?? 1;\n\n if (!groups.has(staff)) {\n groups.set(staff, { staff, notes: [] });\n }\n\n groups.get(staff)!.notes.push(entry);\n }\n\n return Array.from(groups.values()).sort((a, b) => a.staff - b.staff);\n}\n\n/**\n * Calculate absolute position of a note within a measure\n * Position is in divisions from the start of the measure\n */\nexport function getAbsolutePosition(note: NoteEntry, measure: Measure): number {\n return getAbsolutePositionForNote(note, measure);\n}\n\n/**\n * Add absolute position to all notes in a measure\n */\nexport function withAbsolutePositions(measure: Measure): NoteWithPosition[] {\n const result: NoteWithPosition[] = [];\n const state = createPositionState();\n\n for (const entry of measure.entries) {\n if (entry.type === 'note') {\n const notePosition = entry.chord ? state.lastNonChordPosition : state.position;\n result.push({\n ...entry,\n absolutePosition: notePosition,\n });\n }\n updatePositionForEntry(state, entry);\n }\n\n return result;\n}\n\n/**\n * Get chords (groups of simultaneously sounding notes)\n */\nexport function getChords(measure: Measure, filter?: VoiceFilter): Chord[] {\n const notesWithPos = withAbsolutePositions(measure);\n\n // Filter by voice/staff if specified\n const filteredNotes = filter\n ? notesWithPos.filter((note) => {\n if (filter.voice !== undefined && note.voice !== filter.voice) return false;\n if (filter.staff !== undefined && (note.staff ?? 1) !== filter.staff) return false;\n return true;\n })\n : notesWithPos;\n\n // Group by position\n const chordMap = new Map<number, NoteWithPosition[]>();\n\n for (const note of filteredNotes) {\n const pos = note.absolutePosition;\n if (!chordMap.has(pos)) {\n chordMap.set(pos, []);\n }\n chordMap.get(pos)!.push(note);\n }\n\n // Convert to Chord array\n const chords: Chord[] = [];\n\n for (const [position, notes] of chordMap.entries()) {\n // All notes in a chord should have the same duration (using first note's duration)\n const duration = notes[0].duration;\n\n chords.push({\n position,\n duration,\n notes: notes.map(({ absolutePosition, ...note }) => note),\n });\n }\n\n // Sort by position\n return chords.sort((a, b) => a.position - b.position);\n}\n\n/**\n * Iterate over all notes in a score\n */\nexport function* iterateNotes(score: Score): Generator<NoteIteratorItem> {\n for (const part of score.parts) {\n for (const measure of part.measures) {\n const state = createPositionState();\n\n for (const entry of measure.entries) {\n if (entry.type === 'note') {\n const notePosition = entry.chord ? state.lastNonChordPosition : state.position;\n yield {\n part,\n measure,\n note: entry,\n position: notePosition,\n };\n }\n updatePositionForEntry(state, entry);\n }\n }\n }\n}\n\n/**\n * Get all notes from a score as an array\n */\nexport function getAllNotes(score: Score): NoteIteratorItem[] {\n return Array.from(iterateNotes(score));\n}\n\n/**\n * Get unique voices used in a measure\n */\nexport function getVoices(measure: Measure): number[] {\n const voices = new Set<number>();\n\n for (const entry of measure.entries) {\n if (entry.type === 'note') {\n voices.add(entry.voice);\n }\n }\n\n return Array.from(voices).sort((a, b) => a - b);\n}\n\n/**\n * Get unique staves used in a measure\n */\nexport function getStaves(measure: Measure): number[] {\n const staves = new Set<number>();\n\n for (const entry of measure.entries) {\n if (entry.type === 'note') {\n staves.add(entry.staff ?? 1);\n }\n }\n\n return Array.from(staves).sort((a, b) => a - b);\n}\n\n/**\n * Check if a measure contains any notes\n */\nexport function hasNotes(measure: Measure): boolean {\n return measure.entries.some((entry) => entry.type === 'note');\n}\n\n/**\n * Check if a measure is a rest (no pitched notes)\n */\nexport function isRestMeasure(measure: Measure): boolean {\n const notes = measure.entries.filter((entry): entry is NoteEntry => entry.type === 'note');\n return notes.length === 0 || notes.every((note) => !note.pitch);\n}\n\n/**\n * Options for normalized position calculation\n */\nexport interface NormalizedPositionOptions {\n baseDivisions: number;\n currentDivisions?: number;\n}\n\n/**\n * Get a normalized position of a note using a common base divisions\n * This is useful when comparing positions across measures with different divisions\n */\nexport function getNormalizedPosition(\n note: NoteEntry,\n measure: Measure,\n options: NormalizedPositionOptions\n): number {\n const absolutePosition = getAbsolutePosition(note, measure);\n const currentDivisions = options.currentDivisions ?? measure.attributes?.divisions ?? 1;\n\n // Convert from current divisions to base divisions\n return (absolutePosition * options.baseDivisions) / currentDivisions;\n}\n\n/**\n * Get normalized duration of a note using a common base divisions\n */\nexport function getNormalizedDuration(\n note: NoteEntry,\n options: NormalizedPositionOptions\n): number {\n const currentDivisions = options.currentDivisions ?? 1;\n return (note.duration * options.baseDivisions) / currentDivisions;\n}\n"],"mappings":"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","names":[]}