musicxml-io 0.1.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.
- package/LICENSE +21 -0
- package/README.md +167 -0
- package/dist/accessors/index.d.mts +82 -0
- package/dist/accessors/index.d.ts +82 -0
- package/dist/accessors/index.js +239 -0
- package/dist/accessors/index.js.map +1 -0
- package/dist/accessors/index.mjs +198 -0
- package/dist/accessors/index.mjs.map +1 -0
- package/dist/index.d.mts +285 -0
- package/dist/index.d.ts +285 -0
- package/dist/index.js +6033 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +5932 -0
- package/dist/index.mjs.map +1 -0
- package/dist/operations/index.d.mts +92 -0
- package/dist/operations/index.d.ts +92 -0
- package/dist/operations/index.js +352 -0
- package/dist/operations/index.js.map +1 -0
- package/dist/operations/index.mjs +315 -0
- package/dist/operations/index.mjs.map +1 -0
- package/dist/query/index.d.mts +103 -0
- package/dist/query/index.d.ts +103 -0
- package/dist/query/index.js +272 -0
- package/dist/query/index.js.map +1 -0
- package/dist/query/index.mjs +232 -0
- package/dist/query/index.mjs.map +1 -0
- package/dist/types-DC_TnJu_.d.mts +797 -0
- package/dist/types-DC_TnJu_.d.ts +797 -0
- package/package.json +80 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Makoto Tanji
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
# musicxml-io
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/musicxml-io)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
|
|
6
|
+
TypeScript library for parsing and serializing MusicXML.
|
|
7
|
+
|
|
8
|
+
## Architecture
|
|
9
|
+
|
|
10
|
+
```
|
|
11
|
+
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
|
12
|
+
│ MusicXML │ │ │ │ MusicXML │
|
|
13
|
+
│ .xml / .mxl │─────▶│ Score │─────▶│ .xml / .mxl │
|
|
14
|
+
└─────────────────┘ │ │ └─────────────────┘
|
|
15
|
+
parse │ ┌─────────┐ │ serialize
|
|
16
|
+
│ │ parts │ │ ┌─────────────────┐
|
|
17
|
+
│ │ └─measures │ MIDI │
|
|
18
|
+
│ │ └─entries │─────▶│ .mid │
|
|
19
|
+
│ └─────────┘ │ └─────────────────┘
|
|
20
|
+
│ │ exportMidi
|
|
21
|
+
└────────┬────────┘
|
|
22
|
+
│
|
|
23
|
+
┌─────────────┼─────────────┐
|
|
24
|
+
│ │ │
|
|
25
|
+
▼ ▼ ▼
|
|
26
|
+
┌──────────┐ ┌──────────┐ ┌──────────┐
|
|
27
|
+
│ Query │ │Operations│ │ Validate │
|
|
28
|
+
│ │ │ │ │ │
|
|
29
|
+
│findNotes │ │transpose │ │validate │
|
|
30
|
+
│getMeasure│ │addNote │ │isValid │
|
|
31
|
+
│countNotes│ │changeKey │ │assertValid
|
|
32
|
+
└──────────┘ └──────────┘ └──────────┘
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Install
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
npm install musicxml-io
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Usage
|
|
42
|
+
|
|
43
|
+
```typescript
|
|
44
|
+
import { parse, serialize, transpose } from 'musicxml-io';
|
|
45
|
+
|
|
46
|
+
const score = parse(xmlString);
|
|
47
|
+
const transposed = transpose(score, 2); // up 2 semitones
|
|
48
|
+
const output = serialize(transposed);
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### File I/O (Node.js)
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
import { parseFile, serializeToFile } from 'musicxml-io';
|
|
55
|
+
|
|
56
|
+
const score = await parseFile('input.mxl');
|
|
57
|
+
await serializeToFile(score, 'output.xml');
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Operations
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
import { addNote, changeKey, changeTime } from 'musicxml-io';
|
|
64
|
+
|
|
65
|
+
const updated = addNote(score, {
|
|
66
|
+
partIndex: 0,
|
|
67
|
+
measureNumber: 1,
|
|
68
|
+
pitch: { step: 'C', octave: 4 },
|
|
69
|
+
duration: 4,
|
|
70
|
+
type: 'quarter',
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
const inG = changeKey(score, { fifths: 1 }, 0, 1);
|
|
74
|
+
const waltz = changeTime(score, { beats: 3, beatType: 4 }, 0, 1);
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Query
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
import { findNotes, getAllNotes, getMeasureCount } from 'musicxml-io';
|
|
81
|
+
|
|
82
|
+
const notes = getAllNotes(score);
|
|
83
|
+
const quarterNotes = findNotes(score, { type: 'quarter' });
|
|
84
|
+
const count = getMeasureCount(score.parts[0]);
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### MIDI Export
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
import { exportMidi } from 'musicxml-io';
|
|
91
|
+
|
|
92
|
+
const midi = exportMidi(score, { tempo: 120 });
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Validation
|
|
96
|
+
|
|
97
|
+
```typescript
|
|
98
|
+
import { validate, isValid } from 'musicxml-io';
|
|
99
|
+
|
|
100
|
+
const { valid, errors } = validate(score);
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## API
|
|
104
|
+
|
|
105
|
+
### Parse / Serialize
|
|
106
|
+
|
|
107
|
+
| Function | Description |
|
|
108
|
+
|----------|-------------|
|
|
109
|
+
| `parse(xml)` | Parse MusicXML string |
|
|
110
|
+
| `parseFile(path)` | Parse from file |
|
|
111
|
+
| `parseCompressed(buffer)` | Parse .mxl |
|
|
112
|
+
| `parseAuto(data)` | Auto-detect format |
|
|
113
|
+
| `serialize(score)` | To MusicXML string |
|
|
114
|
+
| `serializeToFile(score, path)` | To file |
|
|
115
|
+
| `serializeCompressed(score)` | To .mxl |
|
|
116
|
+
| `exportMidi(score)` | To MIDI |
|
|
117
|
+
|
|
118
|
+
### Operations
|
|
119
|
+
|
|
120
|
+
| Function | Description |
|
|
121
|
+
|----------|-------------|
|
|
122
|
+
| `transpose(score, semitones)` | Transpose pitches |
|
|
123
|
+
| `addNote(score, options)` | Add note |
|
|
124
|
+
| `deleteNote(score, options)` | Delete note |
|
|
125
|
+
| `addChordNote(score, options)` | Add to chord |
|
|
126
|
+
| `changeKey(score, key, part, measure)` | Change key |
|
|
127
|
+
| `changeTime(score, time, part, measure)` | Change time |
|
|
128
|
+
| `insertMeasure(score, part, after)` | Insert measure |
|
|
129
|
+
| `deleteMeasure(score, part, measure)` | Delete measure |
|
|
130
|
+
|
|
131
|
+
### Query
|
|
132
|
+
|
|
133
|
+
| Function | Description |
|
|
134
|
+
|----------|-------------|
|
|
135
|
+
| `getAllNotes(score)` | All notes |
|
|
136
|
+
| `findNotes(score, filter)` | Filter notes |
|
|
137
|
+
| `getMeasure(part, number)` | Get measure |
|
|
138
|
+
| `getMeasureCount(part)` | Measure count |
|
|
139
|
+
| `getChords(measure)` | Chord groups |
|
|
140
|
+
| `countNotes(score)` | Notes per part |
|
|
141
|
+
|
|
142
|
+
### Validate
|
|
143
|
+
|
|
144
|
+
| Function | Description |
|
|
145
|
+
|----------|-------------|
|
|
146
|
+
| `validate(score)` | Validation errors |
|
|
147
|
+
| `isValid(score)` | Boolean check |
|
|
148
|
+
| `assertValid(score)` | Throw if invalid |
|
|
149
|
+
|
|
150
|
+
## Tree-shaking
|
|
151
|
+
|
|
152
|
+
```typescript
|
|
153
|
+
import { transpose } from 'musicxml-io/operations';
|
|
154
|
+
import { findNotes } from 'musicxml-io/query';
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## Round-trip Fidelity
|
|
158
|
+
|
|
159
|
+
| Metric | Score |
|
|
160
|
+
|--------|------:|
|
|
161
|
+
| Overall | 99.6% |
|
|
162
|
+
| Node coverage | 99.9% |
|
|
163
|
+
| Attribute coverage | 95.9% |
|
|
164
|
+
|
|
165
|
+
## License
|
|
166
|
+
|
|
167
|
+
MIT
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { M as Measure, N as NoteEntry, V as VoiceGroup, q as StaffGroup, r as NoteWithPosition, s as Chord, S as Score, t as NoteIteratorItem } from '../types-DC_TnJu_.mjs';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Filter options for voice/staff selection
|
|
5
|
+
*/
|
|
6
|
+
interface VoiceFilter {
|
|
7
|
+
voice?: number;
|
|
8
|
+
staff?: number;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Get all notes for a specific voice (and optionally staff)
|
|
12
|
+
*/
|
|
13
|
+
declare function getNotesForVoice(measure: Measure, filter: VoiceFilter): NoteEntry[];
|
|
14
|
+
/**
|
|
15
|
+
* Get all notes for a specific staff (regardless of voice)
|
|
16
|
+
*/
|
|
17
|
+
declare function getNotesForStaff(measure: Measure, filter: {
|
|
18
|
+
staff: number;
|
|
19
|
+
}): NoteEntry[];
|
|
20
|
+
/**
|
|
21
|
+
* Group notes by voice (and staff)
|
|
22
|
+
*/
|
|
23
|
+
declare function groupByVoice(measure: Measure): VoiceGroup[];
|
|
24
|
+
/**
|
|
25
|
+
* Group notes by staff
|
|
26
|
+
*/
|
|
27
|
+
declare function groupByStaff(measure: Measure): StaffGroup[];
|
|
28
|
+
/**
|
|
29
|
+
* Calculate absolute position of a note within a measure
|
|
30
|
+
* Position is in divisions from the start of the measure
|
|
31
|
+
*/
|
|
32
|
+
declare function getAbsolutePosition(note: NoteEntry, measure: Measure): number;
|
|
33
|
+
/**
|
|
34
|
+
* Add absolute position to all notes in a measure
|
|
35
|
+
*/
|
|
36
|
+
declare function withAbsolutePositions(measure: Measure): NoteWithPosition[];
|
|
37
|
+
/**
|
|
38
|
+
* Get chords (groups of simultaneously sounding notes)
|
|
39
|
+
*/
|
|
40
|
+
declare function getChords(measure: Measure, filter?: VoiceFilter): Chord[];
|
|
41
|
+
/**
|
|
42
|
+
* Iterate over all notes in a score
|
|
43
|
+
*/
|
|
44
|
+
declare function iterateNotes(score: Score): Generator<NoteIteratorItem>;
|
|
45
|
+
/**
|
|
46
|
+
* Get all notes from a score as an array
|
|
47
|
+
*/
|
|
48
|
+
declare function getAllNotes(score: Score): NoteIteratorItem[];
|
|
49
|
+
/**
|
|
50
|
+
* Get unique voices used in a measure
|
|
51
|
+
*/
|
|
52
|
+
declare function getVoices(measure: Measure): number[];
|
|
53
|
+
/**
|
|
54
|
+
* Get unique staves used in a measure
|
|
55
|
+
*/
|
|
56
|
+
declare function getStaves(measure: Measure): number[];
|
|
57
|
+
/**
|
|
58
|
+
* Check if a measure contains any notes
|
|
59
|
+
*/
|
|
60
|
+
declare function hasNotes(measure: Measure): boolean;
|
|
61
|
+
/**
|
|
62
|
+
* Check if a measure is a rest (no pitched notes)
|
|
63
|
+
*/
|
|
64
|
+
declare function isRestMeasure(measure: Measure): boolean;
|
|
65
|
+
/**
|
|
66
|
+
* Options for normalized position calculation
|
|
67
|
+
*/
|
|
68
|
+
interface NormalizedPositionOptions {
|
|
69
|
+
baseDivisions: number;
|
|
70
|
+
currentDivisions?: number;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Get a normalized position of a note using a common base divisions
|
|
74
|
+
* This is useful when comparing positions across measures with different divisions
|
|
75
|
+
*/
|
|
76
|
+
declare function getNormalizedPosition(note: NoteEntry, measure: Measure, options: NormalizedPositionOptions): number;
|
|
77
|
+
/**
|
|
78
|
+
* Get normalized duration of a note using a common base divisions
|
|
79
|
+
*/
|
|
80
|
+
declare function getNormalizedDuration(note: NoteEntry, options: NormalizedPositionOptions): number;
|
|
81
|
+
|
|
82
|
+
export { type NormalizedPositionOptions, type VoiceFilter, getAbsolutePosition, getAllNotes, getChords, getNormalizedDuration, getNormalizedPosition, getNotesForStaff, getNotesForVoice, getStaves, getVoices, groupByStaff, groupByVoice, hasNotes, isRestMeasure, iterateNotes, withAbsolutePositions };
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { M as Measure, N as NoteEntry, V as VoiceGroup, q as StaffGroup, r as NoteWithPosition, s as Chord, S as Score, t as NoteIteratorItem } from '../types-DC_TnJu_.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Filter options for voice/staff selection
|
|
5
|
+
*/
|
|
6
|
+
interface VoiceFilter {
|
|
7
|
+
voice?: number;
|
|
8
|
+
staff?: number;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Get all notes for a specific voice (and optionally staff)
|
|
12
|
+
*/
|
|
13
|
+
declare function getNotesForVoice(measure: Measure, filter: VoiceFilter): NoteEntry[];
|
|
14
|
+
/**
|
|
15
|
+
* Get all notes for a specific staff (regardless of voice)
|
|
16
|
+
*/
|
|
17
|
+
declare function getNotesForStaff(measure: Measure, filter: {
|
|
18
|
+
staff: number;
|
|
19
|
+
}): NoteEntry[];
|
|
20
|
+
/**
|
|
21
|
+
* Group notes by voice (and staff)
|
|
22
|
+
*/
|
|
23
|
+
declare function groupByVoice(measure: Measure): VoiceGroup[];
|
|
24
|
+
/**
|
|
25
|
+
* Group notes by staff
|
|
26
|
+
*/
|
|
27
|
+
declare function groupByStaff(measure: Measure): StaffGroup[];
|
|
28
|
+
/**
|
|
29
|
+
* Calculate absolute position of a note within a measure
|
|
30
|
+
* Position is in divisions from the start of the measure
|
|
31
|
+
*/
|
|
32
|
+
declare function getAbsolutePosition(note: NoteEntry, measure: Measure): number;
|
|
33
|
+
/**
|
|
34
|
+
* Add absolute position to all notes in a measure
|
|
35
|
+
*/
|
|
36
|
+
declare function withAbsolutePositions(measure: Measure): NoteWithPosition[];
|
|
37
|
+
/**
|
|
38
|
+
* Get chords (groups of simultaneously sounding notes)
|
|
39
|
+
*/
|
|
40
|
+
declare function getChords(measure: Measure, filter?: VoiceFilter): Chord[];
|
|
41
|
+
/**
|
|
42
|
+
* Iterate over all notes in a score
|
|
43
|
+
*/
|
|
44
|
+
declare function iterateNotes(score: Score): Generator<NoteIteratorItem>;
|
|
45
|
+
/**
|
|
46
|
+
* Get all notes from a score as an array
|
|
47
|
+
*/
|
|
48
|
+
declare function getAllNotes(score: Score): NoteIteratorItem[];
|
|
49
|
+
/**
|
|
50
|
+
* Get unique voices used in a measure
|
|
51
|
+
*/
|
|
52
|
+
declare function getVoices(measure: Measure): number[];
|
|
53
|
+
/**
|
|
54
|
+
* Get unique staves used in a measure
|
|
55
|
+
*/
|
|
56
|
+
declare function getStaves(measure: Measure): number[];
|
|
57
|
+
/**
|
|
58
|
+
* Check if a measure contains any notes
|
|
59
|
+
*/
|
|
60
|
+
declare function hasNotes(measure: Measure): boolean;
|
|
61
|
+
/**
|
|
62
|
+
* Check if a measure is a rest (no pitched notes)
|
|
63
|
+
*/
|
|
64
|
+
declare function isRestMeasure(measure: Measure): boolean;
|
|
65
|
+
/**
|
|
66
|
+
* Options for normalized position calculation
|
|
67
|
+
*/
|
|
68
|
+
interface NormalizedPositionOptions {
|
|
69
|
+
baseDivisions: number;
|
|
70
|
+
currentDivisions?: number;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Get a normalized position of a note using a common base divisions
|
|
74
|
+
* This is useful when comparing positions across measures with different divisions
|
|
75
|
+
*/
|
|
76
|
+
declare function getNormalizedPosition(note: NoteEntry, measure: Measure, options: NormalizedPositionOptions): number;
|
|
77
|
+
/**
|
|
78
|
+
* Get normalized duration of a note using a common base divisions
|
|
79
|
+
*/
|
|
80
|
+
declare function getNormalizedDuration(note: NoteEntry, options: NormalizedPositionOptions): number;
|
|
81
|
+
|
|
82
|
+
export { type NormalizedPositionOptions, type VoiceFilter, getAbsolutePosition, getAllNotes, getChords, getNormalizedDuration, getNormalizedPosition, getNotesForStaff, getNotesForVoice, getStaves, getVoices, groupByStaff, groupByVoice, hasNotes, isRestMeasure, iterateNotes, withAbsolutePositions };
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/accessors/index.ts
|
|
21
|
+
var accessors_exports = {};
|
|
22
|
+
__export(accessors_exports, {
|
|
23
|
+
getAbsolutePosition: () => getAbsolutePosition,
|
|
24
|
+
getAllNotes: () => getAllNotes,
|
|
25
|
+
getChords: () => getChords,
|
|
26
|
+
getNormalizedDuration: () => getNormalizedDuration,
|
|
27
|
+
getNormalizedPosition: () => getNormalizedPosition,
|
|
28
|
+
getNotesForStaff: () => getNotesForStaff,
|
|
29
|
+
getNotesForVoice: () => getNotesForVoice,
|
|
30
|
+
getStaves: () => getStaves,
|
|
31
|
+
getVoices: () => getVoices,
|
|
32
|
+
groupByStaff: () => groupByStaff,
|
|
33
|
+
groupByVoice: () => groupByVoice,
|
|
34
|
+
hasNotes: () => hasNotes,
|
|
35
|
+
isRestMeasure: () => isRestMeasure,
|
|
36
|
+
iterateNotes: () => iterateNotes,
|
|
37
|
+
withAbsolutePositions: () => withAbsolutePositions
|
|
38
|
+
});
|
|
39
|
+
module.exports = __toCommonJS(accessors_exports);
|
|
40
|
+
|
|
41
|
+
// src/utils/index.ts
|
|
42
|
+
function createPositionState() {
|
|
43
|
+
return { position: 0, lastNonChordPosition: 0 };
|
|
44
|
+
}
|
|
45
|
+
function updatePositionForEntry(state, entry) {
|
|
46
|
+
const pos = state.position;
|
|
47
|
+
switch (entry.type) {
|
|
48
|
+
case "note": {
|
|
49
|
+
const note = entry;
|
|
50
|
+
if (!note.chord) {
|
|
51
|
+
state.lastNonChordPosition = state.position;
|
|
52
|
+
state.position += note.duration;
|
|
53
|
+
}
|
|
54
|
+
return note.chord ? state.lastNonChordPosition : pos;
|
|
55
|
+
}
|
|
56
|
+
case "backup":
|
|
57
|
+
state.position -= entry.duration;
|
|
58
|
+
state.lastNonChordPosition = state.position;
|
|
59
|
+
return pos;
|
|
60
|
+
case "forward":
|
|
61
|
+
state.position += entry.duration;
|
|
62
|
+
state.lastNonChordPosition = state.position;
|
|
63
|
+
return pos;
|
|
64
|
+
default:
|
|
65
|
+
return pos;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
function getAbsolutePositionForNote(note, measure) {
|
|
69
|
+
const state = createPositionState();
|
|
70
|
+
for (const entry of measure.entries) {
|
|
71
|
+
if (entry === note) return entry.chord ? state.lastNonChordPosition : state.position;
|
|
72
|
+
updatePositionForEntry(state, entry);
|
|
73
|
+
}
|
|
74
|
+
return state.position;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// src/accessors/index.ts
|
|
78
|
+
function getNotesForVoice(measure, filter) {
|
|
79
|
+
return measure.entries.filter((entry) => {
|
|
80
|
+
if (entry.type !== "note") return false;
|
|
81
|
+
if (filter.voice !== void 0 && entry.voice !== filter.voice) return false;
|
|
82
|
+
if (filter.staff !== void 0 && (entry.staff ?? 1) !== filter.staff) return false;
|
|
83
|
+
return true;
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
function getNotesForStaff(measure, filter) {
|
|
87
|
+
return measure.entries.filter((entry) => {
|
|
88
|
+
if (entry.type !== "note") return false;
|
|
89
|
+
return (entry.staff ?? 1) === filter.staff;
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
function groupByVoice(measure) {
|
|
93
|
+
const groups = /* @__PURE__ */ new Map();
|
|
94
|
+
for (const entry of measure.entries) {
|
|
95
|
+
if (entry.type !== "note") continue;
|
|
96
|
+
const staff = entry.staff ?? 1;
|
|
97
|
+
const voice = entry.voice;
|
|
98
|
+
const key = `${staff}-${voice}`;
|
|
99
|
+
if (!groups.has(key)) {
|
|
100
|
+
groups.set(key, { staff, voice, notes: [] });
|
|
101
|
+
}
|
|
102
|
+
groups.get(key).notes.push(entry);
|
|
103
|
+
}
|
|
104
|
+
return Array.from(groups.values()).sort((a, b) => {
|
|
105
|
+
if (a.staff !== b.staff) return a.staff - b.staff;
|
|
106
|
+
return a.voice - b.voice;
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
function groupByStaff(measure) {
|
|
110
|
+
const groups = /* @__PURE__ */ new Map();
|
|
111
|
+
for (const entry of measure.entries) {
|
|
112
|
+
if (entry.type !== "note") continue;
|
|
113
|
+
const staff = entry.staff ?? 1;
|
|
114
|
+
if (!groups.has(staff)) {
|
|
115
|
+
groups.set(staff, { staff, notes: [] });
|
|
116
|
+
}
|
|
117
|
+
groups.get(staff).notes.push(entry);
|
|
118
|
+
}
|
|
119
|
+
return Array.from(groups.values()).sort((a, b) => a.staff - b.staff);
|
|
120
|
+
}
|
|
121
|
+
function getAbsolutePosition(note, measure) {
|
|
122
|
+
return getAbsolutePositionForNote(note, measure);
|
|
123
|
+
}
|
|
124
|
+
function withAbsolutePositions(measure) {
|
|
125
|
+
const result = [];
|
|
126
|
+
const state = createPositionState();
|
|
127
|
+
for (const entry of measure.entries) {
|
|
128
|
+
if (entry.type === "note") {
|
|
129
|
+
const notePosition = entry.chord ? state.lastNonChordPosition : state.position;
|
|
130
|
+
result.push({
|
|
131
|
+
...entry,
|
|
132
|
+
absolutePosition: notePosition
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
updatePositionForEntry(state, entry);
|
|
136
|
+
}
|
|
137
|
+
return result;
|
|
138
|
+
}
|
|
139
|
+
function getChords(measure, filter) {
|
|
140
|
+
const notesWithPos = withAbsolutePositions(measure);
|
|
141
|
+
const filteredNotes = filter ? notesWithPos.filter((note) => {
|
|
142
|
+
if (filter.voice !== void 0 && note.voice !== filter.voice) return false;
|
|
143
|
+
if (filter.staff !== void 0 && (note.staff ?? 1) !== filter.staff) return false;
|
|
144
|
+
return true;
|
|
145
|
+
}) : notesWithPos;
|
|
146
|
+
const chordMap = /* @__PURE__ */ new Map();
|
|
147
|
+
for (const note of filteredNotes) {
|
|
148
|
+
const pos = note.absolutePosition;
|
|
149
|
+
if (!chordMap.has(pos)) {
|
|
150
|
+
chordMap.set(pos, []);
|
|
151
|
+
}
|
|
152
|
+
chordMap.get(pos).push(note);
|
|
153
|
+
}
|
|
154
|
+
const chords = [];
|
|
155
|
+
for (const [position, notes] of chordMap.entries()) {
|
|
156
|
+
const duration = notes[0].duration;
|
|
157
|
+
chords.push({
|
|
158
|
+
position,
|
|
159
|
+
duration,
|
|
160
|
+
notes: notes.map(({ absolutePosition, ...note }) => note)
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
return chords.sort((a, b) => a.position - b.position);
|
|
164
|
+
}
|
|
165
|
+
function* iterateNotes(score) {
|
|
166
|
+
for (const part of score.parts) {
|
|
167
|
+
for (const measure of part.measures) {
|
|
168
|
+
const state = createPositionState();
|
|
169
|
+
for (const entry of measure.entries) {
|
|
170
|
+
if (entry.type === "note") {
|
|
171
|
+
const notePosition = entry.chord ? state.lastNonChordPosition : state.position;
|
|
172
|
+
yield {
|
|
173
|
+
part,
|
|
174
|
+
measure,
|
|
175
|
+
note: entry,
|
|
176
|
+
position: notePosition
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
updatePositionForEntry(state, entry);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
function getAllNotes(score) {
|
|
185
|
+
return Array.from(iterateNotes(score));
|
|
186
|
+
}
|
|
187
|
+
function getVoices(measure) {
|
|
188
|
+
const voices = /* @__PURE__ */ new Set();
|
|
189
|
+
for (const entry of measure.entries) {
|
|
190
|
+
if (entry.type === "note") {
|
|
191
|
+
voices.add(entry.voice);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
return Array.from(voices).sort((a, b) => a - b);
|
|
195
|
+
}
|
|
196
|
+
function getStaves(measure) {
|
|
197
|
+
const staves = /* @__PURE__ */ new Set();
|
|
198
|
+
for (const entry of measure.entries) {
|
|
199
|
+
if (entry.type === "note") {
|
|
200
|
+
staves.add(entry.staff ?? 1);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
return Array.from(staves).sort((a, b) => a - b);
|
|
204
|
+
}
|
|
205
|
+
function hasNotes(measure) {
|
|
206
|
+
return measure.entries.some((entry) => entry.type === "note");
|
|
207
|
+
}
|
|
208
|
+
function isRestMeasure(measure) {
|
|
209
|
+
const notes = measure.entries.filter((entry) => entry.type === "note");
|
|
210
|
+
return notes.length === 0 || notes.every((note) => !note.pitch);
|
|
211
|
+
}
|
|
212
|
+
function getNormalizedPosition(note, measure, options) {
|
|
213
|
+
const absolutePosition = getAbsolutePosition(note, measure);
|
|
214
|
+
const currentDivisions = options.currentDivisions ?? measure.attributes?.divisions ?? 1;
|
|
215
|
+
return absolutePosition * options.baseDivisions / currentDivisions;
|
|
216
|
+
}
|
|
217
|
+
function getNormalizedDuration(note, options) {
|
|
218
|
+
const currentDivisions = options.currentDivisions ?? 1;
|
|
219
|
+
return note.duration * options.baseDivisions / currentDivisions;
|
|
220
|
+
}
|
|
221
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
222
|
+
0 && (module.exports = {
|
|
223
|
+
getAbsolutePosition,
|
|
224
|
+
getAllNotes,
|
|
225
|
+
getChords,
|
|
226
|
+
getNormalizedDuration,
|
|
227
|
+
getNormalizedPosition,
|
|
228
|
+
getNotesForStaff,
|
|
229
|
+
getNotesForVoice,
|
|
230
|
+
getStaves,
|
|
231
|
+
getVoices,
|
|
232
|
+
groupByStaff,
|
|
233
|
+
groupByVoice,
|
|
234
|
+
hasNotes,
|
|
235
|
+
isRestMeasure,
|
|
236
|
+
iterateNotes,
|
|
237
|
+
withAbsolutePositions
|
|
238
|
+
});
|
|
239
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
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":[]}
|