Skip to content

Commit

Permalink
Implement octave-equivalent difference and distance
Browse files Browse the repository at this point in the history
  • Loading branch information
frostburn committed Dec 21, 2023
1 parent 64b7b53 commit 3f86fea
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 0 deletions.
44 changes: 44 additions & 0 deletions src/__tests__/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import {
approximatePrimeLimitWithErrors,
arraysEqual,
binomial,
circleDifference,
circleDistance,
clamp,
div,
dot,
Expand Down Expand Up @@ -220,3 +222,45 @@ describe('Norm', () => {
expect(norm(a, 'maximum')).toBeCloseTo(4);
});
});

describe('Pitch difference with circle equivalence', () => {
it('calculates the difference between 700.0 and 701.955', () => {
const diff = circleDifference(700.0, 701.955);
expect(diff).toBeCloseTo(-1.955);
});

it('calculates the octave-equivalent difference between 5/1 and 4\\12', () => {
const diff = circleDifference(valueToCents(5), 400.0);
expect(diff).toBeCloseTo(-13.686);
});

it('calculates the tritave-equivalent difference between 5/1 and 13/1', () => {
const diff = circleDifference(
valueToCents(5),
valueToCents(13),
valueToCents(3)
);
expect(diff).toBeCloseTo(247.741);
});
});

describe('Pitch distance with circle equivalence', () => {
it('calculates the distance between 700.0 and 701.955', () => {
const diff = circleDistance(700.0, 701.955);
expect(diff).toBeCloseTo(1.955);
});

it('calculates the octave-equivalent distance between 5/1 and 4\\12', () => {
const diff = circleDistance(valueToCents(5), 400.0);
expect(diff).toBeCloseTo(13.686);
});

it('calculates the tritave-equivalent distance between 5/1 and 13/1', () => {
const diff = circleDistance(
valueToCents(5),
valueToCents(13),
valueToCents(3)
);
expect(diff).toBeCloseTo(247.741);
});
});
23 changes: 23 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -530,3 +530,26 @@ export function norm(
}
return result;
}

/**
* Calculate the difference between two cents values such that equave equivalence is taken into account.
* @param a The first pitch measured in cents.
* @param b The second pitch measured in cents.
* @param equaveCents The interval of equivalence measured in cents.
* @returns The first pitch minus the second pitch but on a circle such that large differences wrap around.
*/
export function circleDifference(a: number, b: number, equaveCents = 1200.0) {
const half = 0.5 * equaveCents;
return mmod(a - b + half, equaveCents) - half;
}

/**
* Calculate the distance between two cents values such that equave equivalence is taken into account.
* @param a The first pitch measured in cents.
* @param b The second pitch measured in cents.
* @param equaveCents The interval of equivalence measured in cents.
* @returns The absolute distance between the two pitches measured in cents but on a circle such that large distances wrap around.
*/
export function circleDistance(a: number, b: number, equaveCents = 1200.0) {
return Math.abs(circleDifference(a, b, equaveCents));
}

0 comments on commit 3f86fea

Please sign in to comment.