Skip to content

Commit

Permalink
Merge pull request #8 from kilmc/expose-more-features
Browse files Browse the repository at this point in the history
[Release] Expose more features and increase compatibility
  • Loading branch information
kilmc authored Aug 31, 2023
2 parents 9113236 + 2f778d4 commit e5cd18c
Show file tree
Hide file tree
Showing 13 changed files with 187 additions and 149 deletions.
5 changes: 5 additions & 0 deletions .changeset/smart-steaks-buy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@kilmc/music-fns": minor
---

Expose getScaleChords, guessScale, getScale, getEquivalentNote, getInterval, transposeNote
2 changes: 1 addition & 1 deletion rollup.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export default {
},
{
file: pkg.module,
format: 'es',
format: 'esm',
},
],
plugins: [terser(), typescript({ outDir: 'dist' })],
Expand Down
14 changes: 0 additions & 14 deletions src/chords/getChords.ts

This file was deleted.

14 changes: 14 additions & 0 deletions src/chords/getScaleChords.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { majorScaleQualities, modes } from '../consts';
import { offsetArr } from '../helper';
import type { TMode } from '../types';
import { getChord } from './getChord';
import { scaleQualitiesToChordSymbol } from './helpers';

export const getScaleChords = (scale: string[], mode: TMode) => {
const scaleQualities = offsetArr(majorScaleQualities, modes.indexOf(mode));

return scale.map((note, i) => {
const quality = scaleQualitiesToChordSymbol(scaleQualities[i]);
return getChord(`${note}${quality}`);
});
};
10 changes: 10 additions & 0 deletions src/consts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,16 @@ export const majorScaleQualities: TChordQuality[] = [
'diminished',
];

export const majorScaleRomanNumerals = [
'I',
'ii',
'iii',
'IV',
'V',
'vi',
'vii',
];

export const addTypes = ['add2', 'add4', 'add9', 'add11', 'add13'];
export const susTypes = ['sus2', 'sus4'];

Expand Down
27 changes: 19 additions & 8 deletions src/keys/getKey.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,29 @@
import { getChords } from '../chords/getChords';
import { getScaleChords } from '../chords/getScaleChords';
import { majorScales, modes } from '../consts';
import { isMajor, offsetArr } from '../helper';
import { getModeName } from '../modes/getName';
import { isModeName } from '../modes/helpers';
import { extractScaleName } from '../scale/extractName';
import { getMajorFromMode } from '../scale/getMajorFromMode';
import type { TMode } from '../types';
import type { IChord, TMode } from '../types';
import { getRelativeMinorName } from './helpers';

export const getKey = (key: string) => {
type KeyInfo = {
name: string;
notes: string[];
major: {
name: string;
notes: string[];
};
minor: {
name: string;
notes: string[];
};
modes(name: TMode): string[];
chords: IChord[];
};

export const getKey = (key: string): KeyInfo | undefined => {
const [pitch, mode] = extractScaleName(key) || [];

if (mode === undefined || pitch === undefined) {
Expand Down Expand Up @@ -38,10 +53,6 @@ export const getKey = (key: string) => {
modes(name: TMode) {
return offsetArr(majorScale, modes.indexOf(name));
},
chords: getChords(scale, mode),
chords: getScaleChords(scale, mode),
};
};

const possibleVersion = {
name: 'C major',
};
15 changes: 15 additions & 0 deletions src/main.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,18 @@
// Chords
export { getChord } from './chords/getChord';
export { getScaleChords } from './chords/getScaleChords';

// Keys
export { getKey } from './keys/getKey';

// Scales
export { guessScale } from './scale/guessScale';
export { getScale } from './scale/getScale';

// Notes
export { getEquivalentNote } from './notes/getEquivalentNote';
export { getInterval } from './notes/getInterval';
export { transposeNote } from './notes/transpose';

// Consts
export { majorScales } from './consts';
12 changes: 12 additions & 0 deletions src/notes/getScaleDegreeOfNote.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { describe, expect, it } from 'vitest';
import { getScaleDegreeOfNote } from './getScaleDegreeOfNote';

describe('getScaleDegreeOfNote', () => {
it('converts notes to degrees based on a scale', () => {
expect(
['E', 'A', 'C#', 'B'].map((note) =>
getScaleDegreeOfNote(note, ['E', 'F#', 'G#', 'A', 'B', 'C#', 'D#'])
)
).toStrictEqual(['I', 'IV', 'vi', 'V']);
});
});
4 changes: 4 additions & 0 deletions src/notes/getScaleDegreeOfNote.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { majorScaleRomanNumerals } from '../consts';

export const getScaleDegreeOfNote = (note: string, scale: string[]) =>
majorScaleRomanNumerals[scale.indexOf(note)];
31 changes: 0 additions & 31 deletions src/scale/determineScaleFromNotes.test.ts

This file was deleted.

95 changes: 0 additions & 95 deletions src/scale/determineScaleFromNotes.ts

This file was deleted.

49 changes: 49 additions & 0 deletions src/scale/guessScale.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { describe, expect, it } from 'vitest';
import { guessScale } from './guessScale';

describe('guessScale', () => {
const testSongs = [
{
title: 'Dancing Queen',
includedNotes: ['D', 'E', 'F#', 'G#', 'A', 'B'],
excludedNotes: [],
key: 'A major',
},
{
title: "Say It Ain't So",
includedNotes: ['D#', 'F', 'G', 'G#', 'A#', 'C', 'D'],
excludedNotes: [],
key: 'Eb major',
},
{
title: 'Conspiracy',
includedNotes: ['C', 'D', 'E', 'F', 'G', 'A#'],
excludedNotes: [],
key: 'F major',
},
{
title: 'Last Nite',
includedNotes: ['C', 'D', 'E', 'F', 'G', 'A', 'B'],
excludedNotes: [],
key: 'C major',
},
{
title: 'The Dress',
includedNotes: ['C', 'C#', 'D#', 'F', 'G', 'G#', 'A#'],
excludedNotes: [],
key: 'Ab major',
},
{
title: 'Fell in Love Without You',
includedNotes: ['C#', 'D#', 'E'],
excludedNotes: ['C', 'D', 'F', 'G', 'A'],
key: 'B major',
},
];

it.each(testSongs)('$title', ({ includedNotes, excludedNotes, key }) => {
expect(
guessScale(includedNotes, excludedNotes).map((x) => x.name)
).toStrictEqual([key]);
});
});
58 changes: 58 additions & 0 deletions src/scale/guessScale.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { majorScales } from '../consts';
import { getEquivalentNote } from '../notes/getEquivalentNote';

// export const determineTonicFromNotes = (arr: string[]) => {
// const noteFrequency = Object.entries(
// arr.reduce<Record<string, number>>((accum, note) => {
// if (accum[note]) {
// accum[note] += accum[note];
// } else {
// accum[note] = 1;
// }

// return accum;
// }, {})
// ).sort((a, b) => {
// return b[1] - a[1];
// });

// return noteFrequency[0];
// };

const filterScalesFromNotes = (
notes: string[],
scales: string[][],
exclusive = false
) => {
return scales.filter((scale) => {
if (exclusive) {
return !notes.some(
(note) =>
scale.includes(note) || scale.includes(getEquivalentNote(note))
);
} else {
return notes.every(
(note) =>
scale.includes(note) || scale.includes(getEquivalentNote(note))
);
}
});
};

type KeyGuess = { name?: string; scale: string[] };

export const guessScale = (
includedNotes: string[],
excludedNotes: string[]
): KeyGuess[] => {
const allMajors = Object.values(majorScales);
const possibleScales = filterScalesFromNotes(excludedNotes, allMajors, true);
const filteredScales = filterScalesFromNotes(includedNotes, possibleScales);

return filteredScales.map((scale) => {
return {
name: `${scale?.at(0)} major`,
scale,
};
});
};

0 comments on commit e5cd18c

Please sign in to comment.