Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | 2x 2x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 2x 1x 1x 1x 1x 1x 1x 1x 1x 7x 7x 7x 7x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 2x 4x 4x 2x 6x 6x 6x | import {transposeKey} from './chordpro'
/**
* ABC notation (abcnotation.com): music as text. `"C"B2 B2 | "G"B4 |]` is
* two bars with chord symbols. People type only the music; the header ABC
* requires is added here, in the song's key so that transposing the chart
* transposes the notation the same way.
*/
export function withAbcHeader(abc: string, key = 'C') {
const text = abc.replace(/\r\n?/g, '\n').trim()
const has = (field: string) => new RegExp(`^${field}:`, 'm').test(text)
const head = [
has('X') ? null : 'X:1',
has('M') ? null : 'M:4/4',
has('L') ? null : 'L:1/8',
has('K') ? null : `K:${key}`,
].filter(Boolean)
// K: must be the last header line, so ours go before anything typed
return [...head, text].join('\n')
}
/** Starter patterns for the notation editor, in `key` (the song's key). */
export function abcPresets(key: string | null) {
const k = key ?? 'C'
const I = k
const IV = transposeKey(k, 5)
const V = transposeKey(k, 7)
const rhythm = `K:${k} style=rhythm\n`
// Scale steps up from the key's note (ABC: C-B, then c-b an octave up)
const LETTERS = 'CDEFGAB'
const root = Math.max(0, LETTERS.indexOf(k[0]))
const n = (step: number) => {
const i = root + step
const letter = LETTERS[i % 7]
return i < 7 ? letter : letter.toLowerCase()
}
return [
{
name: 'Straight 8ths',
abc: `${rhythm}"${I}"BBBB BBBB | "${V}"BBBB BBBB |]`,
},
{
name: 'Push the and of 4',
abc: `${rhythm}"${I}"B2 B2 B2 B"${IV}"B- | B8 |]`,
},
{
name: 'Stabs on 1 and the and of 2',
abc: `${rhythm}"${I}"B2 zB z4 | "${V}"B2 zB z4 |]`,
},
{name: 'Whole notes', abc: `${rhythm}"${I}"B8 | "${IV}"B8 |]`},
{
name: 'A melody line',
abc: `K:${k}\n"${I}"${n(0)}2 ${n(1)}${n(2)} ${n(3)}2 ${n(2)}${n(1)} | "${V}"${n(0)}8 |]`,
},
]
}
/**
* Which tab a lick reads best as: a "% instrument: bass" line in the ABC
* (ABC comments are ignored by the renderer) asks for 4-string bass tab;
* "% instrument: keys" (a two-hand part) has no tab; anything else gets
* guitar tab.
*/
export function abcTabInstrument(abc: string): 'guitar' | 'bass' | 'keys' {
return abcPart(abc) ?? 'guitar'
}
/** The instrument a lick is written for, if its ABC says. */
export function abcPart(abc: string): 'guitar' | 'bass' | 'keys' | null {
const m = abc.match(/^%\s*instrument:\s*(guitar|bass|keys)\b/im)
return (m?.[1] as 'guitar' | 'bass' | 'keys' | undefined) ?? null
}
|