@tonaljs/time-signature
Version:
Musical time signatures
1 lines • 4.44 kB
Source Map (JSON)
{"version":3,"sources":["../index.ts"],"sourcesContent":["// TYPES: PARSING\nexport type TimeSignatureLiteral = string | [number, number] | [string, string];\ntype ParsedTimeSignature = [number | number[], number];\n\n// TYPES: PROPERTIES\nexport type ValidTimeSignature = {\n readonly empty: false;\n readonly name: string;\n readonly upper: number | number[];\n readonly lower: number;\n readonly type: \"simple\" | \"compound\" | \"irregular\" | \"irrational\";\n readonly additive: number[];\n};\n\nexport type InvalidTimeSignature = {\n readonly empty: true;\n readonly name: \"\";\n readonly upper: undefined;\n readonly lower: undefined;\n readonly type: undefined;\n readonly additive: [];\n};\n\nexport type TimeSignature = ValidTimeSignature | InvalidTimeSignature;\n\n// CONSTANTS\nconst NONE: InvalidTimeSignature = {\n empty: true,\n name: \"\",\n upper: undefined,\n lower: undefined,\n type: undefined,\n additive: [],\n};\n\nconst NAMES = [\"4/4\", \"3/4\", \"2/4\", \"2/2\", \"12/8\", \"9/8\", \"6/8\", \"3/8\"];\n\n// PUBLIC API\n\nexport function names() {\n return NAMES.slice();\n}\n\nconst REGEX = /^(\\d*\\d(?:\\+\\d)*)\\/(\\d+)$/;\nconst CACHE = new Map<TimeSignatureLiteral, TimeSignature>();\n\nexport function get(literal: TimeSignatureLiteral): TimeSignature {\n const stringifiedLiteral = JSON.stringify(literal);\n const cached = CACHE.get(stringifiedLiteral);\n if (cached) {\n return cached;\n }\n\n const ts = build(parse(literal));\n CACHE.set(stringifiedLiteral, ts);\n return ts;\n}\n\nexport function parse(literal: TimeSignatureLiteral): ParsedTimeSignature {\n if (typeof literal === \"string\") {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const [_, up, low] = REGEX.exec(literal) || [];\n return parse([up, low]);\n }\n\n const [up, down] = literal;\n const denominator = +down;\n if (typeof up === \"number\") {\n return [up, denominator];\n }\n\n const list = up.split(\"+\").map((n) => +n);\n return list.length === 1 ? [list[0], denominator] : [list, denominator];\n}\n\n/** @deprecated */\nexport default { names, parse, get };\n\n// PRIVATE\n\nconst isPowerOfTwo = (x: number) => (Math.log(x) / Math.log(2)) % 1 === 0;\n\nfunction build([up, down]: ParsedTimeSignature): TimeSignature {\n const upper = Array.isArray(up) ? up.reduce((a, b) => a + b, 0) : up;\n const lower = down;\n if (upper === 0 || lower === 0) {\n return NONE;\n }\n\n const name = Array.isArray(up) ? `${up.join(\"+\")}/${down}` : `${up}/${down}`;\n const additive = Array.isArray(up) ? up : [];\n const type =\n lower === 4 || lower === 2\n ? \"simple\"\n : lower === 8 && upper % 3 === 0\n ? \"compound\"\n : isPowerOfTwo(lower)\n ? \"irregular\"\n : \"irrational\";\n\n return {\n empty: false,\n name,\n type,\n upper,\n lower,\n additive,\n };\n}\n"],"mappings":";AA0BA,IAAM,OAA6B;AAAA,EACjC,OAAO;AAAA,EACP,MAAM;AAAA,EACN,OAAO;AAAA,EACP,OAAO;AAAA,EACP,MAAM;AAAA,EACN,UAAU,CAAC;AACb;AAEA,IAAM,QAAQ,CAAC,OAAO,OAAO,OAAO,OAAO,QAAQ,OAAO,OAAO,KAAK;AAI/D,SAAS,QAAQ;AACtB,SAAO,MAAM,MAAM;AACrB;AAEA,IAAM,QAAQ;AACd,IAAM,QAAQ,oBAAI,IAAyC;AAEpD,SAAS,IAAI,SAA8C;AAChE,QAAM,qBAAqB,KAAK,UAAU,OAAO;AACjD,QAAM,SAAS,MAAM,IAAI,kBAAkB;AAC3C,MAAI,QAAQ;AACV,WAAO;AAAA,EACT;AAEA,QAAM,KAAK,MAAM,MAAM,OAAO,CAAC;AAC/B,QAAM,IAAI,oBAAoB,EAAE;AAChC,SAAO;AACT;AAEO,SAAS,MAAM,SAAoD;AACxE,MAAI,OAAO,YAAY,UAAU;AAE/B,UAAM,CAAC,GAAGA,KAAI,GAAG,IAAI,MAAM,KAAK,OAAO,KAAK,CAAC;AAC7C,WAAO,MAAM,CAACA,KAAI,GAAG,CAAC;AAAA,EACxB;AAEA,QAAM,CAAC,IAAI,IAAI,IAAI;AACnB,QAAM,cAAc,CAAC;AACrB,MAAI,OAAO,OAAO,UAAU;AAC1B,WAAO,CAAC,IAAI,WAAW;AAAA,EACzB;AAEA,QAAM,OAAO,GAAG,MAAM,GAAG,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;AACxC,SAAO,KAAK,WAAW,IAAI,CAAC,KAAK,CAAC,GAAG,WAAW,IAAI,CAAC,MAAM,WAAW;AACxE;AAGA,IAAO,yBAAQ,EAAE,OAAO,OAAO,IAAI;AAInC,IAAM,eAAe,CAAC,MAAe,KAAK,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,IAAK,MAAM;AAExE,SAAS,MAAM,CAAC,IAAI,IAAI,GAAuC;AAC7D,QAAM,QAAQ,MAAM,QAAQ,EAAE,IAAI,GAAG,OAAO,CAAC,GAAG,MAAM,IAAI,GAAG,CAAC,IAAI;AAClE,QAAM,QAAQ;AACd,MAAI,UAAU,KAAK,UAAU,GAAG;AAC9B,WAAO;AAAA,EACT;AAEA,QAAM,OAAO,MAAM,QAAQ,EAAE,IAAI,GAAG,GAAG,KAAK,GAAG,CAAC,IAAI,IAAI,KAAK,GAAG,EAAE,IAAI,IAAI;AAC1E,QAAM,WAAW,MAAM,QAAQ,EAAE,IAAI,KAAK,CAAC;AAC3C,QAAM,OACJ,UAAU,KAAK,UAAU,IACrB,WACA,UAAU,KAAK,QAAQ,MAAM,IAC3B,aACA,aAAa,KAAK,IAChB,cACA;AAEV,SAAO;AAAA,IACL,OAAO;AAAA,IACP;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;","names":["up"]}