tonal-guitar 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/README.md +602 -0
- package/dist/index.d.mts +866 -0
- package/dist/index.d.ts +866 -0
- package/dist/index.js +3331 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +3266 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +84 -0
package/README.md
ADDED
|
@@ -0,0 +1,602 @@
|
|
|
1
|
+
# tonal-guitar [](https://www.npmjs.com/package/tonal-guitar)
|
|
2
|
+
|
|
3
|
+
> Guitar fretboard, shapes, patterns, and sequences — built on Tonal.js
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install tonal-guitar @tonaljs/note @tonaljs/interval
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Optional peer dependencies for scale/chord/key integration:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install @tonaljs/scale @tonaljs/chord @tonaljs/key
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Usage
|
|
18
|
+
|
|
19
|
+
```js
|
|
20
|
+
import {
|
|
21
|
+
buildFrettedScale,
|
|
22
|
+
get,
|
|
23
|
+
walkPattern,
|
|
24
|
+
thirds,
|
|
25
|
+
toAsciiTab,
|
|
26
|
+
toAlphaTeX,
|
|
27
|
+
} from "tonal-guitar";
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Quick Start
|
|
31
|
+
|
|
32
|
+
```js
|
|
33
|
+
import {
|
|
34
|
+
buildFrettedScale,
|
|
35
|
+
get,
|
|
36
|
+
walkPattern,
|
|
37
|
+
thirds,
|
|
38
|
+
toAsciiTab,
|
|
39
|
+
toAlphaTeX,
|
|
40
|
+
} from "tonal-guitar";
|
|
41
|
+
|
|
42
|
+
// 1. Get a shape and build a scale on the fretboard
|
|
43
|
+
const shape = get("CAGED E Shape");
|
|
44
|
+
const scale = buildFrettedScale(shape, "A");
|
|
45
|
+
|
|
46
|
+
// 2. Generate a pattern and walk it
|
|
47
|
+
const pattern = thirds(7); // ascending thirds over 7-note scale
|
|
48
|
+
const notes = walkPattern(scale, pattern);
|
|
49
|
+
|
|
50
|
+
// 3. Output as ASCII tab or AlphaTeX
|
|
51
|
+
console.log(toAsciiTab(notes));
|
|
52
|
+
console.log(toAlphaTeX(notes, { tempo: 100, duration: 8 }));
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## API
|
|
56
|
+
|
|
57
|
+
### Tuning Constants
|
|
58
|
+
|
|
59
|
+
Pre-defined tunings as `string[]` arrays (low string to high string):
|
|
60
|
+
|
|
61
|
+
```js
|
|
62
|
+
import { STANDARD, DROP_D, DADGAD, OPEN_G, STANDARD_7, STANDARD_8 } from "tonal-guitar";
|
|
63
|
+
|
|
64
|
+
STANDARD; // => ["E2", "A2", "D3", "G3", "B3", "E4"]
|
|
65
|
+
DROP_D; // => ["D2", "A2", "D3", "G3", "B3", "E4"]
|
|
66
|
+
DADGAD; // => ["D2", "A2", "D3", "G3", "A3", "D4"]
|
|
67
|
+
OPEN_G; // => ["D2", "G2", "D3", "G3", "B3", "D4"]
|
|
68
|
+
STANDARD_7; // => ["B1", "E2", "A2", "D3", "G3", "B3", "E4"]
|
|
69
|
+
STANDARD_8; // => ["F#1", "B1", "E2", "A2", "D3", "G3", "B3", "E4"]
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Fretboard Math
|
|
73
|
+
|
|
74
|
+
#### `noteAt(tuning: string[], stringIndex: number, fret: number) => string`
|
|
75
|
+
|
|
76
|
+
Get the note name at a string/fret position:
|
|
77
|
+
|
|
78
|
+
```js
|
|
79
|
+
noteAt(STANDARD, 0, 5); // => "A2" (5th fret, low E string)
|
|
80
|
+
noteAt(STANDARD, 1, 3); // => "C3" (3rd fret, A string)
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
#### `fretFor(tuning: string[], stringIndex: number, targetNote: string) => number | null`
|
|
84
|
+
|
|
85
|
+
Reverse lookup — find which fret a note is on a given string:
|
|
86
|
+
|
|
87
|
+
```js
|
|
88
|
+
fretFor(STANDARD, 0, "A2"); // => 5
|
|
89
|
+
fretFor(STANDARD, 1, "C3"); // => 3
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
#### `findNearestFret(tuning: string[], stringIndex: number, pitchClass: string) => number | null`
|
|
93
|
+
|
|
94
|
+
Find the lowest fret where a pitch class appears on a string:
|
|
95
|
+
|
|
96
|
+
```js
|
|
97
|
+
findNearestFret(STANDARD, 0, "A"); // => 5
|
|
98
|
+
findNearestFret(STANDARD, 1, "A"); // => 0
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
#### `findFretInPosition(tuning: string[], stringIndex: number, pitchClass: string, referenceFret: number, span?: number) => number | null`
|
|
102
|
+
|
|
103
|
+
Find a pitch class within a position window centered on a reference fret:
|
|
104
|
+
|
|
105
|
+
```js
|
|
106
|
+
findFretInPosition(STANDARD, 0, "A", 5, 5); // => 5
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
#### `findNote(pitchClass: string, tuning?: string[], fretRange?: [number, number]) => FretboardPosition[]`
|
|
110
|
+
|
|
111
|
+
Find all positions of a pitch class across the fretboard:
|
|
112
|
+
|
|
113
|
+
```js
|
|
114
|
+
findNote("A"); // => [{string: 0, fret: 5, note: "A2", midi: 45}, ...]
|
|
115
|
+
findNote("A", STANDARD, [0, 12]); // limit to first 12 frets
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
#### `fretboard(tuning?: string[], fretRange?: [number, number]) => FretboardPosition[]`
|
|
119
|
+
|
|
120
|
+
Generate the complete fretboard grid:
|
|
121
|
+
|
|
122
|
+
```js
|
|
123
|
+
fretboard(STANDARD, [0, 4]); // every note on strings 0-5, frets 0-4
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Shape Registry
|
|
127
|
+
|
|
128
|
+
Built-in shapes are registered at import time: CAGED scale shapes (5), CAGED chord shapes (5), 3NPS patterns (7), and pentatonic boxes (5).
|
|
129
|
+
|
|
130
|
+
#### `get(name: string) => ScaleShape | undefined`
|
|
131
|
+
|
|
132
|
+
Retrieve a scale shape by name:
|
|
133
|
+
|
|
134
|
+
```js
|
|
135
|
+
get("CAGED E Shape"); // => { name: "CAGED E Shape", system: "caged", strings: [...], ... }
|
|
136
|
+
get("3NPS Pattern 1"); // => { name: "3NPS Pattern 1", system: "3nps", ... }
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
#### `all() => ScaleShape[]`
|
|
140
|
+
|
|
141
|
+
Get all registered scale shapes.
|
|
142
|
+
|
|
143
|
+
#### `names() => string[]`
|
|
144
|
+
|
|
145
|
+
Get all registered scale shape names:
|
|
146
|
+
|
|
147
|
+
```js
|
|
148
|
+
names(); // => ["CAGED E Shape", "CAGED D Shape", "CAGED C Shape", ...]
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
#### `add(shape: ScaleShape) => ScaleShape`
|
|
152
|
+
|
|
153
|
+
Register a custom shape:
|
|
154
|
+
|
|
155
|
+
```js
|
|
156
|
+
add({
|
|
157
|
+
name: "My Custom Shape",
|
|
158
|
+
system: "custom",
|
|
159
|
+
strings: [["1P", "2M"], ["4P", "5P"], null, null, null, null],
|
|
160
|
+
rootString: 0,
|
|
161
|
+
});
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
#### `removeAll() => void`
|
|
165
|
+
|
|
166
|
+
Clear all registered shapes.
|
|
167
|
+
|
|
168
|
+
#### `chordShapes`
|
|
169
|
+
|
|
170
|
+
Separate registry for chord shapes with the same API: `chordShapes.get()`, `chordShapes.all()`, `chordShapes.names()`, `chordShapes.add()`, `chordShapes.removeAll()`.
|
|
171
|
+
|
|
172
|
+
### Build Engine
|
|
173
|
+
|
|
174
|
+
#### `buildFrettedScale(shape: ScaleShape, root: string, tuning?: string[]) => FrettedScale`
|
|
175
|
+
|
|
176
|
+
Apply a scale shape to a root note and tuning, returning all fretted positions:
|
|
177
|
+
|
|
178
|
+
```js
|
|
179
|
+
const scale = buildFrettedScale(get("CAGED E Shape"), "A");
|
|
180
|
+
// => {
|
|
181
|
+
// empty: false,
|
|
182
|
+
// root: "A",
|
|
183
|
+
// scaleType: "",
|
|
184
|
+
// scaleName: "",
|
|
185
|
+
// shapeName: "CAGED E Shape",
|
|
186
|
+
// tuning: ["E2", "A2", "D3", "G3", "B3", "E4"],
|
|
187
|
+
// notes: [
|
|
188
|
+
// { string: 0, fret: 5, note: "A2", pc: "A", interval: "1P", degree: 1, midi: 45, ... },
|
|
189
|
+
// { string: 0, fret: 7, note: "B2", pc: "B", interval: "2M", degree: 2, midi: 47, ... },
|
|
190
|
+
// ...
|
|
191
|
+
// ]
|
|
192
|
+
// }
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
Each `FrettedNote` contains:
|
|
196
|
+
- `string` — 0-indexed string (0 = lowest)
|
|
197
|
+
- `fret` — fret number
|
|
198
|
+
- `note` — full note name with octave (e.g. `"A2"`)
|
|
199
|
+
- `pc` — pitch class (e.g. `"A"`)
|
|
200
|
+
- `interval` — interval from root (e.g. `"1P"`, `"3M"`)
|
|
201
|
+
- `scaleIndex` — 0-based position in scale
|
|
202
|
+
- `degree` — 1-based degree (scaleIndex + 1)
|
|
203
|
+
- `intervalNumber` — numeric part of interval (e.g. 3 for `"3M"`)
|
|
204
|
+
- `midi` — MIDI number
|
|
205
|
+
|
|
206
|
+
Returns a `FrettedScale` with `empty: true` for invalid inputs.
|
|
207
|
+
|
|
208
|
+
#### `applyChordShape(shape: ChordShape, root: string, tuning?: string[]) => Fingering`
|
|
209
|
+
|
|
210
|
+
Apply a chord shape to a root, returning a `Fingering` with per-string fret numbers:
|
|
211
|
+
|
|
212
|
+
```js
|
|
213
|
+
const chord = applyChordShape(chordShapes.get("E Shape"), "A");
|
|
214
|
+
// => {
|
|
215
|
+
// positions: [...FrettedNote[]],
|
|
216
|
+
// frets: [5, 7, 7, 6, 5, 5],
|
|
217
|
+
// root: "A",
|
|
218
|
+
// shapeName: "E Shape",
|
|
219
|
+
// startFret: 5
|
|
220
|
+
// }
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### Pattern Generators
|
|
224
|
+
|
|
225
|
+
All generators return `number[]` degree sequences.
|
|
226
|
+
|
|
227
|
+
#### `ascendingIntervals(scaleLength: number, interval: number, octaves?: number) => number[]`
|
|
228
|
+
|
|
229
|
+
Generate ascending interval pattern:
|
|
230
|
+
|
|
231
|
+
```js
|
|
232
|
+
ascendingIntervals(7, 2); // 3rds: [1,3, 2,4, 3,5, 4,6, 5,7, 6,8]
|
|
233
|
+
ascendingIntervals(7, 3); // 4ths: [1,4, 2,5, 3,6, 4,7, 5,8]
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
#### `descendingIntervals(scaleLength: number, interval: number, startDegree?: number) => number[]`
|
|
237
|
+
|
|
238
|
+
Generate descending interval pattern:
|
|
239
|
+
|
|
240
|
+
```js
|
|
241
|
+
descendingIntervals(7, 2); // 3rds: [8,6, 7,5, 6,4, 5,3, 4,2, 3,1]
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
#### `ascendingLinear(from: number, to: number) => number[]`
|
|
245
|
+
|
|
246
|
+
```js
|
|
247
|
+
ascendingLinear(1, 8); // => [1, 2, 3, 4, 5, 6, 7, 8]
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
#### `descendingLinear(from: number, to: number) => number[]`
|
|
251
|
+
|
|
252
|
+
```js
|
|
253
|
+
descendingLinear(8, 1); // => [8, 7, 6, 5, 4, 3, 2, 1]
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
#### `grouping(scaleLength: number, groupSize: number, step?: number) => number[]`
|
|
257
|
+
|
|
258
|
+
Generate overlapping groups:
|
|
259
|
+
|
|
260
|
+
```js
|
|
261
|
+
grouping(7, 4); // => [1,2,3,4, 2,3,4,5, 3,4,5,6, 4,5,6,7]
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
#### `thirds(scaleLength) / fourths(scaleLength) / sixths(scaleLength)`
|
|
265
|
+
|
|
266
|
+
Convenience wrappers:
|
|
267
|
+
|
|
268
|
+
```js
|
|
269
|
+
thirds(7); // same as ascendingIntervals(7, 2)
|
|
270
|
+
fourths(7); // same as ascendingIntervals(7, 3)
|
|
271
|
+
sixths(7); // same as ascendingIntervals(7, 5)
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
### Pattern Walker
|
|
275
|
+
|
|
276
|
+
#### `walkPattern(scale: FrettedScale, pattern: number[], options?: WalkOptions) => FrettedNote[]`
|
|
277
|
+
|
|
278
|
+
Walk a degree pattern through a fretted scale, picking concrete notes:
|
|
279
|
+
|
|
280
|
+
```js
|
|
281
|
+
const scale = buildFrettedScale(get("CAGED E Shape"), "A");
|
|
282
|
+
const notes = walkPattern(scale, [1, 3, 5, 7, 6, 5, 4, 3, 2, 1]);
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
Options:
|
|
286
|
+
- `direction`: `"auto"` (default) — auto-detects ascending/descending from consecutive degrees. `"up"`, `"down"`, `"nearest"` for fixed direction.
|
|
287
|
+
|
|
288
|
+
Auto-direction compares consecutive pattern degrees: `[1,3,5,7]` ascends, then `[7,6,5,4,3,2,1]` descends. The walker picks the right octave at each step.
|
|
289
|
+
|
|
290
|
+
### Sequences
|
|
291
|
+
|
|
292
|
+
#### `applySequence(scale: FrettedScale, sequence: number[], options?: SequenceOptions) => FrettedNote[][]`
|
|
293
|
+
|
|
294
|
+
Apply a degree sequence to a fretted scale, optionally shifting incrementally across degrees:
|
|
295
|
+
|
|
296
|
+
```js
|
|
297
|
+
const passes = applySequence(scale, SEQ_1235, {
|
|
298
|
+
incremental: true, // shift pattern across each degree
|
|
299
|
+
boundToShape: true, // stop when notes go outside the shape
|
|
300
|
+
});
|
|
301
|
+
// Pass 1: [1,2,3,5], Pass 2: [2,3,4,6], Pass 3: [3,4,5,7], ...
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
Options:
|
|
305
|
+
- `incremental` — shift pattern by +1 each pass (default: `false`)
|
|
306
|
+
- `boundToShape` — stop passes when notes exceed shape range (default: `true`)
|
|
307
|
+
- `startDegree` — starting degree (default: `1`)
|
|
308
|
+
- `passes` — max number of passes (default: all that fit)
|
|
309
|
+
|
|
310
|
+
#### `flattenSequence(passes: FrettedNote[][]) => FrettedNote[]`
|
|
311
|
+
|
|
312
|
+
Flatten multi-pass results into a single array:
|
|
313
|
+
|
|
314
|
+
```js
|
|
315
|
+
const allNotes = flattenSequence(passes);
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
#### Built-in Sequences
|
|
319
|
+
|
|
320
|
+
```js
|
|
321
|
+
import {
|
|
322
|
+
ASCENDING_THIRDS, // [1,3, 2,4, 3,5, 4,6, 5,7, 6,8]
|
|
323
|
+
DESCENDING_THIRDS, // [8,6, 7,5, 6,4, 5,3, 4,2, 3,1]
|
|
324
|
+
SEQ_1235, // [1,2,3,5]
|
|
325
|
+
SEQ_1234_GROUP, // [1,2,3,4]
|
|
326
|
+
SEQ_UP_DOWN, // [1,2,3,4,3,2]
|
|
327
|
+
SEQ_TRIAD_CLIMB, // [1,3,5,3]
|
|
328
|
+
SEQ_1357_DESC, // [1,3,5,7,6,5,4,3,2,1]
|
|
329
|
+
} from "tonal-guitar";
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
### Notation
|
|
333
|
+
|
|
334
|
+
#### `parseChordFrets(input: string | (number | null)[]) => (number | null)[]`
|
|
335
|
+
|
|
336
|
+
Parse chord fret notation:
|
|
337
|
+
|
|
338
|
+
```js
|
|
339
|
+
parseChordFrets("x32010"); // => [null, 3, 2, 0, 1, 0]
|
|
340
|
+
parseChordFrets("8-10-10-9-8-8"); // => [8, 10, 10, 9, 8, 8]
|
|
341
|
+
parseChordFrets("x-3-2-0-1-0"); // => [null, 3, 2, 0, 1, 0]
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
#### `formatChordFrets(frets: (number | null)[]) => string`
|
|
345
|
+
|
|
346
|
+
Format fret array back to notation:
|
|
347
|
+
|
|
348
|
+
```js
|
|
349
|
+
formatChordFrets([null, 3, 2, 0, 1, 0]); // => "x32010"
|
|
350
|
+
formatChordFrets([8, 10, 10, 9, 8, 8]); // => "8-10-10-9-8-8"
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
#### `parseScalePattern(input: string) => number[][]`
|
|
354
|
+
|
|
355
|
+
Parse scale pattern shorthand:
|
|
356
|
+
|
|
357
|
+
```js
|
|
358
|
+
parseScalePattern("5-8,5-7,5-7,5-7,5-8,5-8");
|
|
359
|
+
// => [[5,8],[5,7],[5,7],[5,7],[5,8],[5,8]]
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
### Output Formatters
|
|
363
|
+
|
|
364
|
+
#### `toAlphaTeX(notes: FrettedNote[], options?: AlphaTexOptions) => string`
|
|
365
|
+
|
|
366
|
+
Format notes as [AlphaTeX](https://www.alphatab.net/docs/alphatex/) notation:
|
|
367
|
+
|
|
368
|
+
```js
|
|
369
|
+
toAlphaTeX(notes, {
|
|
370
|
+
title: "A Major Thirds",
|
|
371
|
+
tempo: 120,
|
|
372
|
+
duration: 8,
|
|
373
|
+
key: "A",
|
|
374
|
+
});
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
Options:
|
|
378
|
+
- `title` — piece title (default: `"Exercise"`)
|
|
379
|
+
- `tempo` — BPM (default: `120`)
|
|
380
|
+
- `duration` — default note duration: `4`, `8`, `16` (default: `8`)
|
|
381
|
+
- `tuning` — override tuning (default: `STANDARD`)
|
|
382
|
+
- `key` — key signature (default: `"C"`)
|
|
383
|
+
- `timeSignature` — e.g. `[4, 4]`
|
|
384
|
+
- `notesPerBar` — notes per bar (default: derived from duration)
|
|
385
|
+
- `noteDurations` — per-note duration array
|
|
386
|
+
- `rhythmPattern` — repeating duration cycle, e.g. `[8, 8, 16, 16]`
|
|
387
|
+
|
|
388
|
+
#### `toAsciiTab(notes: FrettedNote[], options?: AsciiTabOptions) => string`
|
|
389
|
+
|
|
390
|
+
Format notes as ASCII tablature:
|
|
391
|
+
|
|
392
|
+
```js
|
|
393
|
+
toAsciiTab(notes);
|
|
394
|
+
// e|---5----|
|
|
395
|
+
// B|-----5--|
|
|
396
|
+
// G|---6----|
|
|
397
|
+
// D|-----7--|
|
|
398
|
+
// A|---7----|
|
|
399
|
+
// E|-5------|
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
### Arpeggios & Chord Detection
|
|
403
|
+
|
|
404
|
+
These functions require `@tonaljs/chord` (optional peer dependency).
|
|
405
|
+
|
|
406
|
+
#### `arpeggioFromShape(shape: ScaleShape, chordName: string, parentRoot: string, tuning?: string[]) => FrettedScale`
|
|
407
|
+
|
|
408
|
+
Derive a chord-tone arpeggio from a scale shape. Builds the parent scale, then filters to notes whose pitch-class chroma belongs to the named chord.
|
|
409
|
+
|
|
410
|
+
```js
|
|
411
|
+
import { arpeggioFromShape, get } from "tonal-guitar";
|
|
412
|
+
|
|
413
|
+
// Am7 arpeggio from the G Shape in the key of C major
|
|
414
|
+
const am7 = arpeggioFromShape(get("G Shape"), "Am7", "C");
|
|
415
|
+
// am7.root === "A"
|
|
416
|
+
// am7.scaleType === "minor seventh"
|
|
417
|
+
// am7.notes: 10 FrettedNotes, all with pc in {"A","C","E","G"}
|
|
418
|
+
// Each note's .interval is in the C-major (parent) frame, e.g. "6M" for A
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
The returned notes carry their **parent-scale** `interval` and `degree` fields unchanged — the chord name determines which pitch classes are kept, but the notes still report their position within the parent scale.
|
|
422
|
+
|
|
423
|
+
#### `arpeggioFromScale(parent: FrettedScale, chordName: string) => FrettedScale`
|
|
424
|
+
|
|
425
|
+
Same as `arpeggioFromShape` but takes an already-built parent `FrettedScale`. Use this when you want to reuse a scale you have already built:
|
|
426
|
+
|
|
427
|
+
```js
|
|
428
|
+
const cMajor = buildFrettedScale(get("G Shape"), "C");
|
|
429
|
+
const am7 = arpeggioFromScale(cMajor, "Am7");
|
|
430
|
+
const em7 = arpeggioFromScale(cMajor, "Em7");
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
Bare chord types (no tonic) fall back to `parent.root`:
|
|
434
|
+
|
|
435
|
+
```js
|
|
436
|
+
arpeggioFromScale(cMajor, "m7"); // tonic = "C"
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
#### `filterChordTones(scale: FrettedScale, intervals: string[]) => FrettedScale`
|
|
440
|
+
|
|
441
|
+
Low-level parent-frame filter. Retains notes whose `interval` field (relative to the parent root) is in the provided set. Use this when you have already translated intervals to the parent frame, or when you want zero Tonal dependencies:
|
|
442
|
+
|
|
443
|
+
```js
|
|
444
|
+
import { filterChordTones, buildFrettedScale, get } from "tonal-guitar";
|
|
445
|
+
|
|
446
|
+
// Am7 in C major, parent-frame intervals: A=6M, C=1P, E=3M, G=5P
|
|
447
|
+
const cMajor = buildFrettedScale(get("G Shape"), "C");
|
|
448
|
+
filterChordTones(cMajor, ["6M", "1P", "3M", "5P"]);
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
#### `inferShapeContext(input: InferenceInput, options?: InferenceOptions) => InferenceCandidate[]`
|
|
452
|
+
|
|
453
|
+
Detect which registered scale shapes cover a given grip or arpeggio. Accepts a compact fret string, a fret array, or a `FrettedScale`:
|
|
454
|
+
|
|
455
|
+
```js
|
|
456
|
+
import { inferShapeContext } from "tonal-guitar";
|
|
457
|
+
|
|
458
|
+
// From a chord grip
|
|
459
|
+
const candidates = inferShapeContext("x32010");
|
|
460
|
+
// candidates[0].shape — best matching ScaleShape
|
|
461
|
+
// candidates[0].shapeRoot — parent-scale root (e.g. "C")
|
|
462
|
+
// candidates[0].score — total weighted match score
|
|
463
|
+
// candidates[0].breakdown — transparent per-term breakdown
|
|
464
|
+
|
|
465
|
+
// From an arpeggio, filtered to CAGED system, top 3
|
|
466
|
+
const arp = arpeggioFromShape(get("G Shape"), "Am7", "C");
|
|
467
|
+
inferShapeContext(arp, { system: "caged", limit: 3 });
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
Returns `[]` when fewer than 3 distinct pitch classes are present (use `{ includeWeak: true }` to override).
|
|
471
|
+
|
|
472
|
+
#### Strummed voicing rendering
|
|
473
|
+
|
|
474
|
+
Both `toAlphaTeX` and `toAsciiTab` now accept `FrettedNote[][]` — each inner array is one simultaneous beat (strum/chord):
|
|
475
|
+
|
|
476
|
+
```js
|
|
477
|
+
import { applyChordShape, chordShapes, toAlphaTeX, toAsciiTab } from "tonal-guitar";
|
|
478
|
+
|
|
479
|
+
const voicing = applyChordShape(chordShapes.get("C Major Open"), "C");
|
|
480
|
+
|
|
481
|
+
// Render as strummed chord
|
|
482
|
+
toAlphaTeX([voicing.positions], { duration: 4 });
|
|
483
|
+
// => header + :4 (3.5 2.4 0.3 1.2 0.1) |
|
|
484
|
+
|
|
485
|
+
toAsciiTab([voicing.positions]);
|
|
486
|
+
// e|0|
|
|
487
|
+
// B|1|
|
|
488
|
+
// G|0|
|
|
489
|
+
// D|2|
|
|
490
|
+
// A|3|
|
|
491
|
+
// E|-|
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
Flat `FrettedNote[]` (original form) is still accepted and produces identical output.
|
|
495
|
+
|
|
496
|
+
### Tonal.js Integration
|
|
497
|
+
|
|
498
|
+
These functions require optional peer dependencies (`@tonaljs/scale`, `@tonaljs/chord`, `@tonaljs/key`).
|
|
499
|
+
|
|
500
|
+
#### `buildFromScale(shape: ScaleShape, scaleName: string, tuning?: string[]) => FrettedScale`
|
|
501
|
+
|
|
502
|
+
Build a fretted scale using Tonal's `Scale.get()` for validation. Populates `scaleType` and `scaleName`:
|
|
503
|
+
|
|
504
|
+
```js
|
|
505
|
+
const scale = buildFromScale(get("CAGED E Shape"), "A major");
|
|
506
|
+
scale.scaleType; // => "major"
|
|
507
|
+
scale.scaleName; // => "A major"
|
|
508
|
+
|
|
509
|
+
buildFromScale(get("Pentatonic Box 1"), "A minor pentatonic");
|
|
510
|
+
```
|
|
511
|
+
|
|
512
|
+
#### `relatedScales(frettedScale: FrettedScale) => Array<{ root: string, scale: string }>`
|
|
513
|
+
|
|
514
|
+
Find all modal relatives (scales sharing the same pitch classes):
|
|
515
|
+
|
|
516
|
+
```js
|
|
517
|
+
const scale = buildFromScale(get("Pentatonic Box 1"), "A minor pentatonic");
|
|
518
|
+
relatedScales(scale);
|
|
519
|
+
// => [
|
|
520
|
+
// { root: "C", scale: "major pentatonic" },
|
|
521
|
+
// { root: "D", scale: "egyptian" },
|
|
522
|
+
// { root: "E", scale: "malkos raga" },
|
|
523
|
+
// { root: "G", scale: "ritusen" },
|
|
524
|
+
// { root: "A", scale: "minor pentatonic" }
|
|
525
|
+
// ]
|
|
526
|
+
```
|
|
527
|
+
|
|
528
|
+
#### `identifyChord(frets: (number | null)[], tuning?: string[]) => string[]`
|
|
529
|
+
|
|
530
|
+
Identify chord names from fret positions:
|
|
531
|
+
|
|
532
|
+
```js
|
|
533
|
+
identifyChord([null, 3, 2, 0, 1, 0]); // => ["C"]
|
|
534
|
+
identifyChord([0, 2, 2, 1, 0, 0]); // => ["E"]
|
|
535
|
+
```
|
|
536
|
+
|
|
537
|
+
#### `analyzeInKey(frets: (number | null)[], keyName: string, tuning?: string[]) => KeyAnalysis`
|
|
538
|
+
|
|
539
|
+
Analyze a chord voicing in the context of a major key:
|
|
540
|
+
|
|
541
|
+
```js
|
|
542
|
+
analyzeInKey([null, 3, 2, 0, 1, 0], "C");
|
|
543
|
+
// => { empty: false, chord: "C", numeral: "I", degree: 1 }
|
|
544
|
+
|
|
545
|
+
analyzeInKey([null, 3, 2, 0, 1, 0], "G");
|
|
546
|
+
// => { empty: false, chord: "C", numeral: "IV", degree: 4 }
|
|
547
|
+
```
|
|
548
|
+
|
|
549
|
+
Returns `{ empty: true }` if the chord is not found in the key.
|
|
550
|
+
|
|
551
|
+
#### `isShapeCompatible(shape: ScaleShape, scaleName: string) => boolean`
|
|
552
|
+
|
|
553
|
+
Check if a shape's intervals are all present in a given scale:
|
|
554
|
+
|
|
555
|
+
```js
|
|
556
|
+
isShapeCompatible(get("CAGED E Shape"), "A major"); // => true
|
|
557
|
+
isShapeCompatible(get("Pentatonic Box 1"), "A major"); // => true (subset)
|
|
558
|
+
```
|
|
559
|
+
|
|
560
|
+
#### `modeShapes(modeName: string, shapeSystem?: string) => ScaleShape[]`
|
|
561
|
+
|
|
562
|
+
Get all registered shapes compatible with a mode/scale:
|
|
563
|
+
|
|
564
|
+
```js
|
|
565
|
+
modeShapes("A major", "caged"); // all CAGED shapes that fit A major
|
|
566
|
+
modeShapes("A dorian"); // all shapes (any system) that fit A dorian
|
|
567
|
+
```
|
|
568
|
+
|
|
569
|
+
## Types
|
|
570
|
+
|
|
571
|
+
The package exports these TypeScript interfaces:
|
|
572
|
+
|
|
573
|
+
- `FrettedNote` — a note on the fretboard with position, pitch, and interval info
|
|
574
|
+
- `FrettedScale` — a scale applied to the fretboard (with `empty` sentinel pattern)
|
|
575
|
+
- `ScaleShape` — a scale shape definition (intervals per string)
|
|
576
|
+
- `ChordShape` — a chord voicing definition (one interval per string + fingerings + optional harmonic metadata)
|
|
577
|
+
- `Barre` — barre chord finger placement
|
|
578
|
+
- `Fingering` — chord shape applied to a specific root
|
|
579
|
+
- `FretboardPosition` — absolute position on the fretboard (string, fret, note, midi)
|
|
580
|
+
- `VoicingFamily` — voicing family enum (`"caged"`, `"shell"`, `"open"`, `"barre"`, etc.)
|
|
581
|
+
- `VoicingPatternDictionary` — dictionary type for voicing patterns (used by jazz shells)
|
|
582
|
+
- `InferenceInput` — input forms for `inferShapeContext`
|
|
583
|
+
- `InferenceOptions` — options for `inferShapeContext`
|
|
584
|
+
- `InferenceCandidate` — a ranked shape-detection result
|
|
585
|
+
- `InferenceProbe` — normalised internal probe used by the scoring core
|
|
586
|
+
- `ScoreBreakdown` — transparent per-term score breakdown on each `InferenceCandidate`
|
|
587
|
+
- `WalkOptions` — options for `walkPattern`
|
|
588
|
+
- `SequenceOptions` — options for `applySequence`
|
|
589
|
+
- `AlphaTexOptions` — options for `toAlphaTeX`
|
|
590
|
+
- `AsciiTabOptions` — options for `toAsciiTab`
|
|
591
|
+
- `KeyAnalysis` — result of `analyzeInKey`
|
|
592
|
+
|
|
593
|
+
## Related
|
|
594
|
+
|
|
595
|
+
- [@tonaljs/scale](https://github.com/tonaljs/tonal/tree/main/packages/scale) — scale definitions and lookups
|
|
596
|
+
- [@tonaljs/chord](https://github.com/tonaljs/tonal/tree/main/packages/chord) — chord detection and properties
|
|
597
|
+
- [@tonaljs/mode](https://github.com/tonaljs/tonal/tree/main/packages/mode) — modal scale relationships
|
|
598
|
+
- [@tonaljs/key](https://github.com/tonaljs/tonal/tree/main/packages/key) — key signatures and analysis
|
|
599
|
+
|
|
600
|
+
## License
|
|
601
|
+
|
|
602
|
+
MIT
|