brand-music
Version:
Strongly typed music theory library
1 lines • 10.8 kB
Source Map (JSON)
{"version":3,"sources":["../src/IntervalClass.ts","../src/internal/utils.ts","../src/internal/refined/Literal.ts","../src/internal/refined/Int.ts","../src/internal/PitchIntervalClass.ts","../src/internal/conversion.ts","../src/internal/IntervalClass.ts"],"sourcesContent":["export {\n icBetweenPc as between,\n icFromPic as fromPic,\n} from \"./internal/conversion.js\";\nexport * from \"./internal/IntervalClass.js\";\n","// mod(-3, 5) = 2\nexport const mod = (a: number, n: number) => ((a % n) + n) % n;\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","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 * 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","import * as IC from \"./IntervalClass.js\";\nimport * as MNN from \"./MidiNoteNumber.js\";\nimport * as PC from \"./PitchClass.js\";\nimport * as PI from \"./PitchInterval.js\";\nimport * as PIC from \"./PitchIntervalClass.js\";\nimport * as I from \"./refined/Int.js\";\nimport { asInt } from \"./refined/Literal.js\";\nimport * as ST from \"./Semitones.js\";\n\nexport const icFromPic = (pic: PIC.PitchIntervalClass) =>\n Math.min(pic, PIC.invert(pic)) as IC.IntervalClass;\nexport const icBetweenPc = (a: PC.PitchClass, b: PC.PitchClass) =>\n icFromPic(picBetweenPc(a, b));\n\nconst mnnAdd = (value: MNN.MidiNoteNumber, interval: PI.PitchInterval) =>\n I.add(asInt(value), asInt(interval));\nexport const mnnTransposeChecked = (\n value: MNN.MidiNoteNumber,\n interval: PI.PitchInterval,\n) => MNN.fromNum(mnnAdd(value, interval));\nexport const mnnTransposeClamped = (\n value: MNN.MidiNoteNumber,\n interval: PI.PitchInterval,\n) => MNN.fromIntClamp(mnnAdd(value, interval));\nexport const mnnTransposeModded = (\n value: MNN.MidiNoteNumber,\n interval: PI.PitchInterval,\n) => MNN.fromIntMod(mnnAdd(value, interval));\n\nexport const pcTranspose = (\n value: PC.PitchClass,\n interval: PIC.PitchIntervalClass,\n) => PC.fromIntMod(I.add(asInt(value), asInt(interval)));\nexport const pcFromMnn = (mnn: MNN.MidiNoteNumber) => PC.fromIntMod(asInt(mnn));\n\nexport const piBetweenMnn = (\n from: MNN.MidiNoteNumber,\n to: MNN.MidiNoteNumber,\n) => PI.from(I.sub(asInt(to), asInt(from)));\n\nexport const picBetweenPc = (from: PC.PitchClass, to: PC.PitchClass) =>\n PIC.fromIntMod(I.sub(asInt(to), asInt(from)));\n\n/**\n * Gets the pitch interval class of the pitch interval.\n *\n * @example\n * ```ts\n * import * as PI from \"brand-music/PitchInterval\";\n * import * as PIC from \"brand-music/PitchIntervalClass\";\n *\n * const picOfPi = PIC.fromPi(PI.from(-2)); // 10\n * const picOfSemitones = PIC.fromSemitones(PI.semitones(PI.from(-2))); // 2\n * ```\n */\nexport const picFromPi = (pi: PI.PitchInterval) => PIC.fromIntMod(pi);\nexport const picFromSemitones = (semitones: ST.Semitones) =>\n PIC.fromIntMod(semitones);\n\nexport const stFromPi = (pi: PI.PitchInterval) => ST.fromIntAbs(pi);\nexport const stBetweenMnn = (a: MNN.MidiNoteNumber, b: MNN.MidiNoteNumber) =>\n ST.fromIntAbs(I.sub(asInt(a), asInt(b)));\n","import * as I from \"./refined/Int.js\";\nimport { all, clamp, is, modded, RangedNat } from \"./refined/Literal.js\";\n\nconst min = 0;\nconst max = 6;\nexport type Shape = RangedNat<typeof min, typeof max>;\nexport const hasShape = is(min, max);\n\nexport interface IntervalClassBrand {\n readonly IntervalClass: unique symbol;\n}\n\n/**\n * Unordered 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#Unordered_pitch-class_intervals_('interval_class;_IC')}\n */\nexport type IntervalClass = Shape & IntervalClassBrand;\n\nexport const mark = (_v: Shape): _v is IntervalClass => true;\nexport const markNum = (v: number): v is IntervalClass => hasShape(v);\nexport const markUnknown = (v: unknown): v is IntervalClass => hasShape(v);\n\nexport const from = (v: Shape) => v as IntervalClass;\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 & IntervalClass;\nexport const MIN = const_(min);\nexport const MAX = const_(max);\nexport const ALL: readonly IntervalClass[] = all(min, max).map(const_);\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA,aAAAA;AAAA,EAAA,WAAAC;AAAA,EAAA,WAAAC;AAAA,EAAA;AAAA,cAAAC;AAAA,EAAA;AAAA,oBAAAC;AAAA,EAAA;AAAA;AAAA;AAAA,kBAAAC;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;;;ACCO,IAAM,MAAM,CAAC,GAAW,OAAgB,IAAI,IAAK,KAAK;;;ACwBtD,IAAM,KACX,CAAqC,OAAU,QAC/C,CAAI,MACF,OAAO,cAAc,CAAC,KACtB,SAAU,KACT,KAA2B;AAEzB,IAAM,QACX,CAAqC,OAAU,QAC/C,CAAC,MACC,IAAI,QAAQ,QAAQ,IAAI,MAAM,MAAO;AAKlC,IAAM,SACX,CAAqC,OAAU,QAC/C,CAAC,MAA4B;AAC3B,QAAM,OAAO,MAAM,QAAQ;AAC3B,QAAM,OAAO,IAAI;AAEjB,QAAM,IAAI,IAAI,MAAM,IAAI;AACxB,SAAQ,IAAI;AACd;AAEK,IAAM,MAAM,CACjB,OACA;AAAA;AAAA,EAGA,CAAC,GAAG,MAAM,MAAM,QAAQ,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,MAAO,QAAQ,CAAqB;AAAA;AAEnE,IAAM,QAAQ,CAAC,MAAiC;;;AC1ChD,IAAM,MAAM,CAAC,GAAQ,MAAY,IAAI;;;ACZ5C,IAAM,MAAM;AACZ,IAAM,MAAM;AAEL,IAAM,WAAW,GAAG,KAAK,GAAG;AAkB5B,IAAM,OAAO,CAAC,MAAa;AAG3B,IAAM,aAAa,CAAC,MAAa,KAAK,OAAO,KAAK,GAAG,EAAE,CAAC,CAAC;AAGhE,IAAM,SAAS,CAAkB,UAAa;AACvC,IAAM,MAAM,OAAO,GAAG;AACtB,IAAM,MAAM,OAAO,GAAG;AACtB,IAAM,MAAqC,IAAI,KAAK,GAAG,EAAE,IAAI,MAAM;AAEnE,IAAM,SAAS,CAAC,GAAuB,QAAe,MAC3D,WAAa,IAAI,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC;;;AC3BnC,IAAM,YAAY,CAAC,QACxB,KAAK,IAAI,KAAS,OAAO,GAAG,CAAC;AACxB,IAAM,cAAc,CAAC,GAAkB,MAC5C,UAAU,aAAa,GAAG,CAAC,CAAC;AA4BvB,IAAM,eAAe,CAACC,OAAqB,OAC5C,WAAa,IAAI,MAAM,EAAE,GAAG,MAAMA,KAAI,CAAC,CAAC;;;ACtC9C,IAAMC,OAAM;AACZ,IAAMC,OAAM;AAEL,IAAMC,YAAW,GAAGF,MAAKC,IAAG;AAc5B,IAAM,OAAO,CAAC,OAAmC;AACjD,IAAM,UAAU,CAAC,MAAkCC,UAAS,CAAC;AAC7D,IAAM,cAAc,CAAC,MAAmCA,UAAS,CAAC;AAElE,IAAMC,QAAO,CAAC,MAAa;AAC3B,IAAM,UAAU,CAAC,MAAe,QAAQ,CAAC,IAAI,IAAI;AACjD,IAAM,eAAe,CAAC,MAAaA,MAAK,MAAMH,MAAKC,IAAG,EAAE,CAAC,CAAC;AAC1D,IAAMG,cAAa,CAAC,MAAaD,MAAK,OAAOH,MAAKC,IAAG,EAAE,CAAC,CAAC;AACzD,IAAM,cAAc,CAAC,MAAgB,YAAY,CAAC,IAAI,IAAI;AAEjE,IAAMI,UAAS,CAAkB,UAAa;AACvC,IAAMC,OAAMD,QAAOL,IAAG;AACtB,IAAMO,OAAMF,QAAOJ,IAAG;AACtB,IAAMO,OAAgC,IAAIR,MAAKC,IAAG,EAAE,IAAII,OAAM;","names":["ALL","MAX","MIN","from","fromIntMod","hasShape","from","min","max","hasShape","from","fromIntMod","const_","MIN","MAX","ALL"]}