Skip to content

Commit

Permalink
Make infinite hardness legal in MOS declaration
Browse files Browse the repository at this point in the history
  • Loading branch information
frostburn committed May 20, 2024
1 parent e731d4b commit ebcd73f
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 29 deletions.
2 changes: 2 additions & 0 deletions documentation/intermediate-dsl.md
Original file line number Diff line number Diff line change
Expand Up @@ -942,6 +942,8 @@ Below `n` is an integer, `x` and `y` are integers in the range from 1 to 9, and
| Large declaration | `L = expr` |
| Small declaration | `s = expr` |

It's also legal to set `hardness = inf` implying `s = 0.0c`.

### Diamond-mos notation
Once `MOS` has been declared [Diamond-mos notation](https://en.xen.wiki/w/Diamond-mos_notation) becomes available.

Expand Down
4 changes: 2 additions & 2 deletions src/grammars/mos.pegjs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ AbstractStepPattern
}

SmallIntegerPattern
= pattern: [1-9]+ __ equave: RationalEquave? {
= pattern: [0-9]+ __ equave: RationalEquave? {
return {
type: 'IntegerPattern',
pattern: pattern.map(d => parseInt(d, 10)),
Expand All @@ -67,7 +67,7 @@ SmallIntegerPattern
}

LargeIntegerPattern
= pattern: PositiveBasicInteger|2.., _ ',' _| equave: (__ ','? __ @RationalEquave?) {
= pattern: BasicInteger|2.., _ ',' _| equave: (__ ','? __ @RationalEquave?) {
return {
type: 'IntegerPattern',
pattern,
Expand Down
56 changes: 56 additions & 0 deletions src/parser/__tests__/source.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1720,4 +1720,60 @@ describe('SonicWeave parser', () => {
'P7ms',
]);
});

it('supports infinite hardness (explicit)', () => {
const scale = expand(`
MOS {
5L 2s
hardness = inf
}
J4 = 123 Hz
automos()
nedji
`);
expect(scale).toEqual([
'MOS {LLLsLLs;L=2^1/5;s=1}',
'1\\5',
'2\\5',
'3\\5',
'3\\5',
'4\\5',
'1\\1',
'1\\1',
]);
});

it('supports infinite hardness (implicit)', () => {
const scale = expand(`
MOS 101010;
automos()
nedji
`);
expect(scale).toEqual([
'MOS {LsLsLs;L=2^1/3;s=1}',
'1\\3',
'1\\3',
'2\\3',
'2\\3',
'1\\1',
'1\\1',
]);
});

it('supports infinite hardness (s=1)', () => {
const scale = expand(`
MOS {LsLsLs;L=2^1/3;s=1}
automos()
nedji
`);
expect(scale).toEqual([
'MOS {LsLsLs;L=2^1/3;s=1}',
'1\\3',
'1\\3',
'2\\3',
'2\\3',
'1\\1',
'1\\1',
]);
});
});
80 changes: 53 additions & 27 deletions src/parser/mos.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ function realize(mosMonzo: MosMonzo, large: TimeMonzo, small: TimeMonzo) {
export class Tardigrade {
subVisitor: ExpressionVisitor;
equave?: TimeMonzo;
hardness?: TimeMonzo;
hardness?: TimeMonzo | TimeReal;
large?: TimeMonzo;
small?: TimeMonzo;
pattern?: string;
Expand All @@ -50,17 +50,22 @@ export class Tardigrade {
let large: TimeMonzo | TimeReal;
if (this.equave) {
if (this.hardness) {
// L /_ s = r
// L = s^r
// L^countL * s^countS = equave
// s^(countL * r + countS) = equave
small = this.equave.pow(
TimeMonzo.fromFraction(countL)
.mul(this.hardness)
.add(TimeMonzo.fromFraction(countS))
.inverse()
);
large = small.pow(this.hardness);
if (this.hardness.valueOf() === Infinity) {
small = this.equave.pow(0);
large = this.equave.pow(countL.inverse());
} else {
// L /_ s = r
// L = s^r
// L^countL * s^countS = equave
// s^(countL * r + countS) = equave
small = this.equave.pow(
TimeMonzo.fromFraction(countL)
.mul(this.hardness)
.add(TimeMonzo.fromFraction(countS))
.inverse()
);
large = small.pow(this.hardness);
}
} else if (this.large) {
large = this.large;
small = this.equave
Expand All @@ -78,21 +83,35 @@ export class Tardigrade {
}
} else {
if (this.hardness) {
if (this.large) {
large = this.large;
small = large.pow(this.hardness.inverse());
} else if (this.small) {
small = this.small;
large = small.pow(this.hardness);
if (this.hardness.valueOf() === Infinity) {
if (this.large) {
large = this.large;
} else if (this.small) {
throw new Error(
'Small step may not be given with infinite hardness.'
);
} else {
// Assume octave
large = TWO_MONZO.pow(countL.inverse());
}
small = large.pow(0);
} else {
// Assume octave
small = TWO_MONZO.pow(
TimeMonzo.fromFraction(countL)
.mul(this.hardness)
.add(TimeMonzo.fromFraction(countS))
.inverse()
);
large = small.pow(this.hardness);
if (this.large) {
large = this.large;
small = large.pow(this.hardness.inverse());
} else if (this.small) {
small = this.small;
large = small.pow(this.hardness);
} else {
// Assume octave
small = TWO_MONZO.pow(
TimeMonzo.fromFraction(countL)
.mul(this.hardness)
.add(TimeMonzo.fromFraction(countS))
.inverse()
);
large = small.pow(this.hardness);
}
}
} else if (this.large) {
large = this.large;
Expand Down Expand Up @@ -188,7 +207,11 @@ export class Tardigrade {
const small = Math.min(...node.pattern);
const large = Math.max(...node.pattern);
this.pattern = node.pattern.map(i => (i === small ? 's' : 'L')).join('');
this.hardness = TimeMonzo.fromFraction(new Fraction(large, small));
if (small) {
this.hardness = TimeMonzo.fromFraction(new Fraction(large, small));
} else {
this.hardness = TimeReal.fromValue(Infinity);
}
if (node.equave) {
this.equave = this.visitRationalEquave(node.equave);
}
Expand Down Expand Up @@ -235,6 +258,9 @@ export class Tardigrade {
if (!(value instanceof Interval)) {
throw new Error(`${node.type} must evaluate to an interval.`);
}
if (node.type === 'HardnessDeclaration' && value.valueOf() === Infinity) {
return (this.hardness = value.value);
}
if (!(value.value instanceof TimeMonzo)) {
throw new Error(`${node.type} must evaluate to a radical.`);
}
Expand Down

0 comments on commit ebcd73f

Please sign in to comment.