diff --git a/src/__tests__/scale.spec.ts b/src/__tests__/scale.spec.ts index e2e9a0c..63a7cc1 100644 --- a/src/__tests__/scale.spec.ts +++ b/src/__tests__/scale.spec.ts @@ -1077,4 +1077,21 @@ describe('Scale', () => { ]).approximateEqualTemperament(22); expect(scale.getName(0)).toBe('0\\22<1>'); }); + + it('can calculate the ratio and cents gamuts of a complex scale', () => { + const scale = Scale.fromIntervalArray([ + new Interval( + ExtendedMonzo.fromFraction('3001/3000', 7), + 'ratio', + '3001/3000' + ), + ]); + for (let i = 0; i < 128; ++i) { + const idx = i - 69; + const ratio = scale.getRatio(idx); + const cents = scale.getCents(idx); + expect(ratio).toBeCloseTo(1.000333333333333 ** idx); + expect(cents).toBeCloseTo(0.5769818580538413 * idx); + } + }); }); diff --git a/src/scale.ts b/src/scale.ts index e300088..b079c8d 100644 --- a/src/scale.ts +++ b/src/scale.ts @@ -594,6 +594,33 @@ export class Scale { return this.intervals[index].monzo.add(this.equave.monzo.mul(numEquaves)); } + /** + * Obtain the total cents of an interval in the scale (repeats at equaves). + * @param index Zero-based index of the interval. + * @returns Cents associated with the given index. + */ + getCents(index: number) { + const numEquaves = Math.floor(index / this.size); + index -= numEquaves * this.size; + return ( + this.intervals[index].totalCents() + this.equave.totalCents() * numEquaves + ); + } + + /** + * Obtain the ratio of an interval in the scale (repeats at equaves). + * @param index Zero-based index of the interval. + * @returns Ratio associated with the given index. + */ + getRatio(index: number) { + const numEquaves = Math.floor(index / this.size); + index -= numEquaves * this.size; + return ( + this.intervals[index].monzo.valueOf() * + this.equave.monzo.valueOf() ** numEquaves + ); + } + /** * Obtain the frequency of an interval in the scale (repeats at equaves). * @param index Zero-based index of the interval.