From b976423d5c968a9e7b4033a680550be01c886c18 Mon Sep 17 00:00:00 2001 From: Lumi Pakkanen Date: Tue, 21 May 2024 16:38:32 +0300 Subject: [PATCH] Make automos() work with absurd scales Generalize Diamond-mos nominals. ref #324 --- package-lock.json | 8 ++++---- package.json | 2 +- src/diamond-mos.ts | 28 ++-------------------------- src/grammars/sonic-weave.pegjs | 12 +++++++++++- src/parser/__tests__/source.spec.ts | 18 ++++++++++++++++++ src/parser/mos.ts | 4 ++-- src/stdlib/builtin.ts | 8 +++----- 7 files changed, 41 insertions(+), 39 deletions(-) diff --git a/package-lock.json b/package-lock.json index f6cb1e7a..b0372ddb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "0.3.1", "license": "MIT", "dependencies": { - "moment-of-symmetry": "^0.6.0", + "moment-of-symmetry": "^0.7.0", "xen-dev-utils": "^0.7.0" }, "bin": { @@ -2888,9 +2888,9 @@ } }, "node_modules/moment-of-symmetry": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/moment-of-symmetry/-/moment-of-symmetry-0.6.0.tgz", - "integrity": "sha512-0dpJfCm4bcsEAhQazehWvQxm75UM1B2aZsKPNmeUgsLW/DvL9EOL2/qSVE472mGG+opFe9G7Ou02PN59sJPBPA==", + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/moment-of-symmetry/-/moment-of-symmetry-0.7.0.tgz", + "integrity": "sha512-aiED8cEwD7TrjiHnJ7rus3AK5OGjBwFlNi9WqY0M+pws/usCIdId4AGOa54r0jTi0wYdoQMpAb0TZlISVTfSgA==", "dependencies": { "xen-dev-utils": "^0.7.0" }, diff --git a/package.json b/package.json index a0995dcf..226db1e5 100644 --- a/package.json +++ b/package.json @@ -67,7 +67,7 @@ "vitest": "^1.4.0" }, "dependencies": { - "moment-of-symmetry": "^0.6.0", + "moment-of-symmetry": "^0.7.0", "xen-dev-utils": "^0.7.0" }, "engines": { diff --git a/src/diamond-mos.ts b/src/diamond-mos.ts index 946f654c..299d3cfc 100644 --- a/src/diamond-mos.ts +++ b/src/diamond-mos.ts @@ -53,7 +53,7 @@ export type MosConfig = { /** * Relative scale from J onwards. Echelon depends on J. Use equave to reach higher octave numbers. */ - scale: Map; + scale: Map; /** * Intervals for relative notation. Use period to reach larger intervals. */ @@ -100,36 +100,12 @@ export type SplitMosAccidental = { accidental: Accidental | MosAccidental; }; -/** - * Diamond-mos nominals from J to Z. - * - * The number of valid nominals corresponds to the size of the MOS scale and repeats every equave. - */ -export type MosNominal = - | 'J' - | 'K' - | 'L' - | 'M' - | 'N' - | 'O' - | 'P' - | 'Q' - | 'R' - | 'S' - | 'T' - | 'U' - | 'V' - | 'W' - | 'X' - | 'Y' - | 'Z'; - /** * Absolute Diamond-mos pitch. */ export type AbsoluteMosPitch = { type: 'AbsolutePitch'; - nominal: MosNominal; + nominal: string; accidentals: SplitMosAccidental[]; octave: number; }; diff --git a/src/grammars/sonic-weave.pegjs b/src/grammars/sonic-weave.pegjs index 1678c6be..62524ed8 100644 --- a/src/grammars/sonic-weave.pegjs +++ b/src/grammars/sonic-weave.pegjs @@ -1509,8 +1509,17 @@ PitchNominal 'pitch nominal' / 'ome' // Some pitches like M3 or S9 are inaccessible due to other rules and require accidentals to disambiguate. +// Absurd nominals like SQRT#4 also require accidentals to disambiguate. AbsolutePitch - = nominal: PitchNominal accidentals: Accidental* octave: SignedBasicInteger { + = nominal: $[J-Z]|2..| accidentals: Accidental+ octave: SignedBasicInteger { + return { + type: 'AbsolutePitch', + nominal, + accidentals, + octave, + }; + } + / nominal: PitchNominal accidentals: Accidental* octave: SignedBasicInteger { return { type: 'AbsolutePitch', nominal, @@ -1562,6 +1571,7 @@ ArrowFunction // This rule is a faster version of the part of (FJS / AbsoluteFJS / (SquareSuperparticular)) which overlaps with identifiers. ReservedPattern = [sqQ]? (AugmentedToken+ / [mMnP]) [0-9]+ 'ms'? ([_v] [0-9])* + / [J-Z]|2..| [sqQxdb_ae]+ [0-9]+ ([_v] [0-9])* / PitchNominal [sqQxdb_ae]* [0-9]+ ([_v] [0-9])* // TODO: Figure out where to put this diff --git a/src/parser/__tests__/source.spec.ts b/src/parser/__tests__/source.spec.ts index b9e54f68..f50c21b4 100644 --- a/src/parser/__tests__/source.spec.ts +++ b/src/parser/__tests__/source.spec.ts @@ -1776,4 +1776,22 @@ describe('SonicWeave parser', () => { '1\\1', ]); }); + + it('supports large MOS scales', () => { + const scale = expand(` + MOS 42L 7s + JK_4 + JT♮4 + KQ&4 + J5 + i => i str(nedji(i, niente, 91)) + `); + expect(scale).toEqual([ + 'MOS {LLLLLLsLLLLLLsLLLLLLsLLLLLLsLLLLLLsLLLLLLsLLLLLLs;L=2^2/91;s=2^1/91}', + 'JK_4 "34\\\\91"', + 'JT♮4 "51\\\\91"', + 'KQ&4 "78\\\\91"', + 'J5 "91\\\\91"', + ]); + }); }); diff --git a/src/parser/mos.ts b/src/parser/mos.ts index 61eb5b09..09b0c2d1 100644 --- a/src/parser/mos.ts +++ b/src/parser/mos.ts @@ -14,7 +14,7 @@ import {TimeMonzo, TimeReal} from '../monzo'; import {ExpressionVisitor} from './expression'; import {MosMonzo, MosOptions, generateNotation, mos} from 'moment-of-symmetry'; import {Interval} from '../interval'; -import {MosConfig, MosDegree, MosNominal} from '../diamond-mos'; +import {MosConfig, MosDegree} from '../diamond-mos'; import {ONE, TWO, ZERO} from '../utils'; const TWO_MONZO = new TimeMonzo(ZERO, [ONE]); @@ -148,7 +148,7 @@ export class Tardigrade { const semiam = am.sqrt() as TimeMonzo; const r = (m: MosMonzo) => realize(m, large as TimeMonzo, small as TimeMonzo); - const scale = notation.scale as unknown as Map; + const scale = notation.scale as unknown as Map; for (const [key, value] of notation.scale) { scale.set(key, r(value)); } diff --git a/src/stdlib/builtin.ts b/src/stdlib/builtin.ts index 51ad1098..c8117eab 100644 --- a/src/stdlib/builtin.ts +++ b/src/stdlib/builtin.ts @@ -26,7 +26,7 @@ import { setNumberOfComponents, } from '../monzo'; import {type ExpressionVisitor} from '../parser'; -import {MosOptions, mos} from 'moment-of-symmetry'; +import {MosOptions, mos, nthNominal} from 'moment-of-symmetry'; import {expressionToString} from '../ast'; import { BasisElement, @@ -72,7 +72,7 @@ import { factorColor as pubFactorColor, compare, } from './public'; -import {MosNominal, scaleMonzos} from '../diamond-mos'; +import {scaleMonzos} from '../diamond-mos'; const {version: VERSION} = require('../../package.json'); // === Library === @@ -1941,9 +1941,7 @@ function automos(this: ExpressionVisitor) { type: 'AbsoluteFJS', pitch: { type: 'AbsolutePitch', - nominal: String.fromCharCode( - 'J'.charCodeAt(0) + mmod(i + 1, monzos.length) - ) as MosNominal, + nominal: nthNominal(mmod(i + 1, monzos.length)), accidentals: [{accidental: '♮', fraction: ''}], octave: i === monzos.length - 1 ? 5 : 4, },