UNPKG

brand-music

Version:

Strongly typed music theory library

1 lines 13.4 kB
{"version":3,"sources":["../src/PitchIntervalClassSet.ts","../src/internal/refined/Int.ts","../src/internal/refined/Literal.ts","../src/internal/PitchIntervalClass.ts","../src/internal/refined/NonNegative.ts","../src/internal/refined/NonNegativeInt.ts","../src/internal/refined/TwelveBits.ts","../src/internal/PitchIntervalClassSet.ts"],"sourcesContent":["export * from \"./internal/PitchIntervalClassSet.js\";\n","export interface IntBrand {\n readonly Int: unique symbol;\n}\n\nexport type Int = number & IntBrand;\n\nexport const isInt = <T>(v: T): v is T & Int => Number.isInteger(v);\nexport const fromUnknown = <T>(v: T) => (isInt(v) ? v : undefined);\nexport const makeChecked = <T extends number>(v: T) => fromUnknown(v);\nexport const makeRound = <T extends number>(v: T) => Math.round(v) as T & Int;\nexport const makeTrunc = <T extends number>(v: T) => Math.trunc(v) as T & Int;\n\nexport const add = (a: Int, b: Int) => (a + b) as Int;\nexport const addChecked = (a: number, b: number) => makeChecked(a + b);\n\nexport const sub = (a: Int, b: Int) => (a - b) as Int;\nexport const subChecked = (a: number, b: number) => makeChecked(a - b);\n\nexport const mul = (a: Int, b: Int) => (a * b) as Int;\nexport const mulChecked = (a: number, b: number) => makeChecked(a * b);\nexport const mulRound = (a: number, b: number) => makeRound(a * b);\nexport const mulTrunc = (a: number, b: number) => makeTrunc(a * b);\n\nexport const divChecked = (a: number, b: number) => makeChecked(a * b);\nexport const divRound = (a: number, b: number) => makeRound(a * b);\nexport const divTrunc = (a: number, b: number) => makeTrunc(a * b);\n","import { mod } from \"../utils.js\";\nimport { Int } from \"./Int.js\";\n\nexport type Negate<N extends number> = N extends 0\n ? 0\n : `${N}` extends `-${infer X extends number}`\n ? X\n : `-${N}` extends `${infer X extends number}`\n ? X\n : number;\n\nexport type RangedNat<\n START extends number,\n END extends number,\n ARR extends unknown[] = [],\n ACC extends number = never,\n> = ARR[\"length\"] extends END\n ? ACC | START | END\n : RangedNat<\n START,\n END,\n [...ARR, 1],\n ARR[START] extends undefined ? ACC : ACC | ARR[\"length\"]\n >;\n\nexport const is =\n <S extends number, E extends number>(start: S, end: E) =>\n <T>(v: T): v is T & RangedNat<S, E> =>\n Number.isSafeInteger(v) &&\n start <= (v as unknown as number) &&\n (v as unknown as number) <= end;\n\nexport const clamp =\n <S extends number, E extends number>(start: S, end: E) =>\n (v: Int): RangedNat<S, E> =>\n v < start ? start : v > end ? end : (v as RangedNat<S, E>);\n\n// range: [s, e]\n// input: -5 -4 -3 -2 -1 0 1 2 3 4 5\n// output: 1 2 3 -2 -1 0 1 2 3 -2 -1\nexport const modded =\n <S extends number, E extends number>(start: S, end: E) =>\n (v: Int): RangedNat<S, E> => {\n const size = end - start + 1;\n const zero = v - start;\n\n const m = mod(zero, size);\n return (m + start) as RangedNat<S, E>;\n };\n\nexport const all = <S extends number, E extends number>(\n start: S,\n end: E,\n): readonly RangedNat<S, E>[] =>\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n [...Array(end - start + 1)].map((_, i) => (start + i) as RangedNat<S, E>);\n\nexport const asInt = (v: RangedNat<number, number>) => v as Int;\n","import * as I from \"./refined/Int.js\";\nimport { all, asInt, clamp, is, modded, RangedNat } from \"./refined/Literal.js\";\n\nconst min = 0;\nconst max = 11;\nexport type Shape = RangedNat<typeof min, typeof max>;\nexport const hasShape = is(min, max);\n\nexport interface PitchIntervalClassBrand {\n readonly PitchIntervalClass: unique symbol;\n}\n\n/**\n * Ordered pitch-class interval\n *\n * Number of ascending semitones from one pitch-class to the next, ordered from lowest to highest\n * @see {@link https://en.wikipedia.org/wiki/Pitch_interval#Ordered_pitch-class_intervals_('pitch_interval_class;_PIC')}\n */\nexport type PitchIntervalClass = Shape & PitchIntervalClassBrand;\n\nexport const mark = (_v: Shape): _v is PitchIntervalClass => true;\nexport const markNum = (v: number): v is PitchIntervalClass => hasShape(v);\nexport const markUnknown = (v: unknown): v is PitchIntervalClass => hasShape(v);\n\nexport const from = (v: Shape) => v as PitchIntervalClass;\nexport const fromNum = (v: number) => (markNum(v) ? v : undefined);\nexport const fromIntClamp = (v: I.Int) => from(clamp(min, max)(v));\nexport const fromIntMod = (v: I.Int) => from(modded(min, max)(v));\nexport const fromUnknown = (v: unknown) => (markUnknown(v) ? v : undefined);\n\nconst const_ = <T extends Shape>(value: T) => value as T & PitchIntervalClass;\nexport const MIN = const_(min);\nexport const MAX = const_(max);\nexport const ALL: readonly PitchIntervalClass[] = all(min, max).map(const_);\n\nexport const invert = (v: PitchIntervalClass, index: Shape = 0) =>\n fromIntMod(I.sub(asInt(index), asInt(v)));\n","export interface NonNegativeBrand {\n readonly NonNegative: unique symbol;\n}\n\nexport type NonNegative = number & NonNegativeBrand;\n\nexport const isNonNegative = <T>(v: T): v is T & NonNegative =>\n typeof v === \"number\" && v >= 0;\n\nexport function makeAbs<T extends number, N extends NonNegative>(\n v: T,\n edgeCases: { NaN: N },\n): (T & NonNegative) | N;\nexport function makeAbs<T extends number>(\n v: T,\n edgeCases?: { NaN?: never },\n): (T & NonNegative) | (0 & NonNegative);\nexport function makeAbs(v: number, edgeCases?: { NaN?: NonNegative }) {\n const caseNaN = edgeCases?.NaN ?? (0 as 0 & NonNegative);\n\n if (Number.isNaN(v)) {\n return caseNaN;\n } else {\n return Math.abs(v);\n }\n}\n","import { Int, isInt } from \"./Int.js\";\nimport { isNonNegative, NonNegative } from \"./NonNegative.js\";\n\nexport type NonNegativeInt = Int & NonNegative;\n\nexport const isNonNegativeInt = (v: unknown): v is NonNegativeInt =>\n isInt(v) && isNonNegative(v);\n","import { all, RangedNat } from \"./Literal.js\";\nimport { isNonNegativeInt, NonNegativeInt } from \"./NonNegativeInt.js\";\n\nexport interface TwelveBitsBrand {\n readonly TwelveBits: unique symbol;\n}\n\nexport type TwelveBits = NonNegativeInt & TwelveBitsBrand;\n\nexport const isTwelveBits = (v: unknown): v is TwelveBits =>\n isNonNegativeInt(v) && v < 1 << 12;\n\nexport type PartialTwelveBits =\n | 0b000000000000\n | 0b000000000001\n | 0b000000000010\n | 0b000000000100\n | 0b000000001000\n | 0b000000010000\n | 0b000000100000\n | 0b000001000000\n | 0b000010000000\n | 0b000100000000\n | 0b001000000000\n | 0b010000000000\n | 0b100000000000\n | 0b111111111101\n | 0b111111111011\n | 0b111111110111\n | 0b111111101111\n | 0b111111011111\n | 0b111110111111\n | 0b111101111111\n | 0b111011111111\n | 0b110111111111\n | 0b101111111111\n | 0b011111111111\n | 0b111111111111;\n\nexport type Value = RangedNat<0, 11>;\n\nexport const EMPTY = 0 as TwelveBits;\nexport const ALL = 0b111111111111 as TwelveBits;\n\nexport const masked = (v: number) => (v & ALL) as TwelveBits;\n\nconst one = (value: Value) => (1 << value) as TwelveBits;\nexport const fromValues = (...values: Value[]) => values.map(one).reduce(union);\n\nexport const values = (a: TwelveBits) =>\n all(0, 11).filter((value) => has(a, value));\n\nexport const complement = (a: TwelveBits) => masked(~a);\n\nexport const union = (a: TwelveBits, b: TwelveBits) => (a | b) as TwelveBits;\n\nexport const intersection = (a: TwelveBits, b: TwelveBits) =>\n (a & b) as TwelveBits;\n\nexport const symmetricDifference = (a: TwelveBits, b: TwelveBits) =>\n (a ^ b) as TwelveBits;\n\nexport const difference = (a: TwelveBits, b: TwelveBits) =>\n intersection(a, complement(b));\n\nexport const has = (a: TwelveBits, value: Value) =>\n Boolean(intersection(a, fromValues(value)));\n\nexport const add = (a: TwelveBits, value: Value) => union(a, fromValues(value));\n\nexport const remove = (a: TwelveBits, value: Value) =>\n intersection(a, complement(fromValues(value)));\n\nexport const toggle = (a: TwelveBits, value: Value) =>\n symmetricDifference(a, fromValues(value));\n\nexport const isSuperset = (a: TwelveBits, of: TwelveBits) =>\n !intersection(complement(a), of);\n\nexport const isSubset = (a: TwelveBits, of: TwelveBits) => isSuperset(of, a);\n","import { PitchIntervalClass } from \"./PitchIntervalClass.js\";\nimport * as PIC from \"./PitchIntervalClass.js\";\nimport * as TB from \"./refined/TwelveBits.js\";\n\nexport type Shape = TB.TwelveBits;\nexport const hasShape = TB.isTwelveBits;\n\nexport interface PitchIntervalClassSetBrand {\n readonly PitchIntervalClassSet: unique symbol;\n}\n\nexport type PitchIntervalClassSet = Shape & PitchIntervalClassSetBrand;\n\nexport const mark = (_v: Shape): _v is PitchIntervalClassSet => true;\nexport const markRaw = (v: number): v is PitchIntervalClassSet => hasShape(v);\nexport const markRawUnknown = (v: unknown): v is PitchIntervalClassSet =>\n hasShape(v);\n\nexport const fromRaw = (v: TB.TwelveBits | TB.PartialTwelveBits) =>\n v as PitchIntervalClassSet;\nexport const fromRawMasked = (v: number) => fromRaw(TB.masked(v));\nexport const fromRawUnknown = (v: unknown) =>\n TB.isTwelveBits(v) ? fromRaw(v) : undefined;\n\nexport const EMPTY = fromRaw(TB.EMPTY);\nexport const ALL = fromRaw(TB.ALL);\n\nconst one = (pc: PitchIntervalClass) => (1 << pc) as PitchIntervalClassSet;\nexport const from = (...values: PitchIntervalClass[]) =>\n values.map(one).reduce(union);\n\nexport const toggleAll = (pcs: PitchIntervalClassSet) =>\n (~pcs & ALL) as PitchIntervalClassSet;\n\nexport const union = (a: PitchIntervalClassSet, b: PitchIntervalClassSet) =>\n (a | b) as PitchIntervalClassSet;\n\nexport const intersection = (\n a: PitchIntervalClassSet,\n b: PitchIntervalClassSet,\n) => (a & b) as PitchIntervalClassSet;\n\nexport const symmetricDifference = (\n a: PitchIntervalClassSet,\n b: PitchIntervalClassSet,\n) => (a ^ b) as PitchIntervalClassSet;\n\nexport const difference = (\n a: PitchIntervalClassSet,\n b: PitchIntervalClassSet,\n) => intersection(a, toggleAll(b));\n\nexport const has = (pcs: PitchIntervalClassSet, pc: PitchIntervalClass) =>\n Boolean(intersection(pcs, from(pc)));\n\nexport const add = (pcs: PitchIntervalClassSet, pc: PitchIntervalClass) =>\n union(pcs, from(pc));\n\nexport const remove = (pcs: PitchIntervalClassSet, pc: PitchIntervalClass) =>\n intersection(pcs, toggleAll(from(pc)));\n\nexport const toggle = (pcs: PitchIntervalClassSet, pc: PitchIntervalClass) =>\n symmetricDifference(pcs, from(pc));\n\nexport const isSuperset = (\n value: PitchIntervalClassSet,\n of: PitchIntervalClassSet,\n) => !intersection(toggleAll(value), of);\n\nexport const isSubset = (\n value: PitchIntervalClassSet,\n of: PitchIntervalClassSet,\n) => isSuperset(of, value);\n\nexport const values = (pics: PitchIntervalClassSet) =>\n TB.values(pics).map(PIC.from);\n"],"mappings":"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","names":["ALL","EMPTY","from","has","hasShape","intersection","union","values","ALL","values","hasShape","EMPTY","ALL","one","from","values","union","intersection","has"]}