Skip to content

Commit

Permalink
fix: adjacent octaves enharmonics
Browse files Browse the repository at this point in the history
  • Loading branch information
danigb committed Jul 23, 2024
1 parent b113754 commit 36c07ab
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 36 deletions.
5 changes: 3 additions & 2 deletions packages/pitch-distance/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,11 +88,12 @@ export function distance(
? tcoord[1] - fcoord[1]
: -Math.floor((fifths * 7) / 12);

// If it's unison and not pitch class, it can be descending interval (#243)
// If it's unison, not pitch class, and in the same octave
// it can be descending interval (see #243 & #428)
const forceDescending =
to.height === from.height &&
to.midi !== null &&
from.midi !== null &&
from.oct === to.oct &&
from.step > to.step;
return coordToInterval([fifths, octs], forceDescending).name;
}
68 changes: 37 additions & 31 deletions packages/pitch-distance/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,36 +7,42 @@ const allIntervalsFrom = (from: string) => (str: string) =>
.join(" ");

describe("distance", () => {
describe("find intervals between notes", () => {
test("interval between notes", () => {
const fromC3 = allIntervalsFrom("C3");
expect(fromC3("C3 e3 e4 c2 e2")).toEqual("1P 3M 10M -8P -6m");
});

test("unison interval edge case #243", () => {
expect(distance("Db4", "C#5")).toEqual("7A");
expect(distance("Db4", "C#4")).toEqual("-2d");
expect(distance("Db", "C#")).toEqual("7A");
expect(distance("C#", "Db")).toEqual("2d");
});

test("intervals between pitch classes are always ascending", () => {
expect(distance("C", "D")).toEqual("2M");

const fromC = allIntervalsFrom("C");
expect(fromC("c d e f g a b")).toEqual("1P 2M 3M 4P 5P 6M 7M");

const fromG = allIntervalsFrom("G");
expect(fromG("c d e f g a b")).toEqual("4P 5P 6M 7m 1P 2M 3M");
});

test("if a note is a pitch class, the distance is between pitch classes", () => {
expect(distance("C", "C2")).toBe("1P");
expect(distance("C2", "C")).toBe("1P");
});

test("notes must be valid", () => {
expect(distance("one", "two")).toBe("");
});
test("interval between notes", () => {
const fromC3 = allIntervalsFrom("C3");
expect(fromC3("C3 e3 e4 c2 e2")).toEqual("1P 3M 10M -8P -6m");
});

test("unison interval edge case #243", () => {
expect(distance("Db4", "C#5")).toEqual("7A");
expect(distance("Db4", "C#4")).toEqual("-2d");
expect(distance("Db", "C#")).toEqual("7A");
expect(distance("C#", "Db")).toEqual("2d");
});

test("adjacent octaves #428", () => {
expect(distance("B#4", "C4")).toBe("-7A");
expect(distance("B#4", "C6")).toBe("9d");
expect(distance("B#4", "C5")).toBe("2d");
expect(distance("B##4", "C#5")).toBe("2d");
expect(distance("B#5", "C6")).toBe("2d");
});

test("intervals between pitch classes are always ascending", () => {
expect(distance("C", "D")).toEqual("2M");

const fromC = allIntervalsFrom("C");
expect(fromC("c d e f g a b")).toEqual("1P 2M 3M 4P 5P 6M 7M");

const fromG = allIntervalsFrom("G");
expect(fromG("c d e f g a b")).toEqual("4P 5P 6M 7m 1P 2M 3M");
});

test("if a note is a pitch class, the distance is between pitch classes", () => {
expect(distance("C", "C2")).toBe("1P");
expect(distance("C2", "C")).toBe("1P");
});

test("notes must be valid", () => {
expect(distance("one", "two")).toBe("");
});
});
2 changes: 1 addition & 1 deletion packages/tonal/browser/tonal.min.js

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions packages/tonal/browser/tonal.min.js.map

Large diffs are not rendered by default.

0 comments on commit 36c07ab

Please sign in to comment.