Spaces:
Runtime error
Runtime error
Download src/lib/abc/model.ts from RalphThings/yue2-studio: direct link, hf CLI and curl.
- Browser
- Download file 3.51 kB
-
https://huggingface.co/spaces/RalphThings/yue2-studio/resolve/main/src/lib/abc/model.ts
- Command line
-
hf download hf://spaces/RalphThings/yue2-studio/src/lib/abc/model.ts
-
curl -L -o model.ts https://huggingface.co/spaces/RalphThings/yue2-studio/resolve/main/src/lib/abc/model.ts
3.51 kB
| /** | |
| * The note model behind the piano roll. | |
| * | |
| * Time is counted in *units*, where one unit is the tune's L: default note | |
| * length. That is the same currency ABC itself writes lengths in, so a note | |
| * written `A2` under `L:1/8` is two units long and needs no conversion in | |
| * either direction. Using seconds or beats here would mean rounding on every | |
| * round trip, and rounding is how an edited score slowly drifts out of time. | |
| */ | |
| export interface AbcNote { | |
| id: string; | |
| /** Index into AbcScore.voices. */ | |
| voice: number; | |
| /** Onset in units from the start of the piece. */ | |
| start: number; | |
| /** Length in units. Always at least 1. */ | |
| duration: number; | |
| /** MIDI note number. Rests are held separately, so this is always a pitch. */ | |
| midi: number; | |
| /** True when this note is tied into the one that follows it. */ | |
| tied: boolean; | |
| } | |
| /** | |
| * A quoted string in the music: a chord symbol like "G#m", or an annotation | |
| * like "^rit." with a placement prefix. YuE2 emits chord symbols routinely, so | |
| * these are carried through rather than refused. | |
| */ | |
| export interface AbcMark { | |
| id: string; | |
| voice: number; | |
| /** Onset in units, matching AbcNote.start. */ | |
| start: number; | |
| /** The text as written, without the quotes. */ | |
| text: string; | |
| /** True for a placement-prefixed annotation rather than a chord symbol. */ | |
| annotation: boolean; | |
| } | |
| export interface AbcVoice { | |
| /** The V: identifier as written, e.g. "Vocal". */ | |
| id: string; | |
| /** Anything after the identifier on the V: line, kept so it survives a rewrite. */ | |
| rest: string; | |
| } | |
| export interface AbcScore { | |
| /** Header lines above the first voice, verbatim and in order. */ | |
| header: string[]; | |
| voices: AbcVoice[]; | |
| notes: AbcNote[]; | |
| marks: AbcMark[]; | |
| /** Meter numerator and denominator from M:, defaulting to 4/4. */ | |
| meter: [number, number]; | |
| /** Unit note length from L:, defaulting to 1/8. */ | |
| unit: [number, number]; | |
| /** Key signature from K:, used by the grid to shade the scale. */ | |
| key: string; | |
| /** True when a repeat was written out so the grid could show it. */ | |
| repeatsExpanded: boolean; | |
| /** Beats per minute from Q:, defaulting to 120 quarter notes. */ | |
| tempo: number; | |
| } | |
| /** Seconds one unit lasts at this score's tempo. */ | |
| export function unitSeconds(score: Pick<AbcScore, "unit" | "tempo">): number { | |
| const [un, ud] = score.unit; | |
| // A unit is un/ud of a whole note; a whole note is four quarters. | |
| const quarters = (un / ud) * 4; | |
| return quarters * (60 / Math.max(20, score.tempo)); | |
| } | |
| /** Why a score could not be opened in the grid. */ | |
| export interface AbcParseFailure { | |
| ok: false; | |
| reason: string; | |
| /** The construct that stopped us, so the message can name it. */ | |
| offending: string | null; | |
| } | |
| export interface AbcParseSuccess { | |
| ok: true; | |
| score: AbcScore; | |
| } | |
| export type AbcParseResult = AbcParseSuccess | AbcParseFailure; | |
| /** How many units fill one bar, given the meter and unit length. */ | |
| export function unitsPerBar(score: Pick<AbcScore, "meter" | "unit">): number { | |
| const [mn, md] = score.meter; | |
| const [un, ud] = score.unit; | |
| const bars = (mn / md) / (un / ud); | |
| // A meter that does not divide evenly into the unit length is legal ABC but | |
| // makes a ragged grid, so it is rounded rather than left fractional. | |
| return Math.max(1, Math.round(bars)); | |
| } | |
| export function noteName(midi: number): string { | |
| const names = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"]; | |
| return `${names[((midi % 12) + 12) % 12]}${Math.floor(midi / 12) - 1}`; | |
| } | |