Skip to content

Commit a6c50a9

Browse files
committed
feat(ChordDictionary): disabled chord
1 parent 472241e commit a6c50a9

27 files changed

+647
-207
lines changed

src/main/store/defaults.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import {
2+
ChordDictionarySettings,
23
ChordDisplaySettings,
34
ChordQuizSettings,
45
CircleOfFifthsSettings,
@@ -75,6 +76,16 @@ export const defaultCircleOfFifthsSettings: CircleOfFifthsSettings = {
7576
displayDegreeLabels: false,
7677
};
7778

79+
export const defaultChordDictionarySettings: ChordDictionarySettings = {
80+
interactive: 'play',
81+
hideDisabled: false,
82+
filterInKey: false,
83+
groupBy: 'none',
84+
defaultNotation: 'short',
85+
disabled: [],
86+
aliases: [['maj', '']],
87+
};
88+
7889
export const defaultNotationSettings: NotationSettings = {
7990
key: 'C',
8091
accidentals: 'flat' as const,
@@ -105,6 +116,7 @@ export const defaults: StoreType = {
105116
chordDisplay: [defaultChordDisplaySettings],
106117
chordQuiz: defaultChordQuizSettings,
107118
circleOfFifths: defaultCircleOfFifthsSettings,
119+
chordDictionary: defaultChordDictionarySettings,
108120
notation: defaultNotationSettings,
109121
server: {
110122
enabled: true,

src/main/types/Settings.schema.json

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,62 @@
11
{
22
"$schema": "http://json-schema.org/draft-07/schema#",
33
"properties": {
4+
"chordDictionary": {
5+
"properties": {
6+
"aliases": {
7+
"items": {
8+
"items": [
9+
{
10+
"type": "string"
11+
},
12+
{
13+
"type": "string"
14+
}
15+
],
16+
"maxItems": 2,
17+
"minItems": 2,
18+
"type": "array"
19+
},
20+
"type": "array"
21+
},
22+
"defaultNotation": {
23+
"enum": [
24+
"long",
25+
"short",
26+
"symbol"
27+
],
28+
"type": "string"
29+
},
30+
"disabled": {
31+
"items": {
32+
"type": "string"
33+
},
34+
"type": "array"
35+
},
36+
"filterInKey": {
37+
"type": "boolean"
38+
},
39+
"groupBy": {
40+
"enum": [
41+
"intervals",
42+
"none",
43+
"quality"
44+
],
45+
"type": "string"
46+
},
47+
"hideDisabled": {
48+
"type": "boolean"
49+
},
50+
"interactive": {
51+
"enum": [
52+
"detect",
53+
"play"
54+
],
55+
"type": "string"
56+
}
57+
},
58+
"type": "object"
59+
},
460
"chordDisplay": {
561
"items": {
662
"properties": {

src/main/types/Settings.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,16 @@ export type CircleOfFifthsSettings = {
6666
displayDegreeLabels: boolean;
6767
};
6868

69+
export type ChordDictionarySettings = {
70+
interactive: 'detect' | 'play';
71+
hideDisabled: boolean;
72+
filterInKey: boolean;
73+
groupBy: 'none' | 'quality' | 'intervals';
74+
defaultNotation: 'long' | 'short' | 'symbol';
75+
disabled: string[];
76+
aliases: Array<[key: string, value: string]>;
77+
};
78+
6979
export type NotationSettings = {
7080
key: string;
7181
accidentals: 'flat' | 'sharp';
@@ -88,6 +98,7 @@ export type Settings = {
8898
chordDisplay: ChordDisplaySettings[];
8999
chordQuiz: ChordQuizSettings;
90100
circleOfFifths: CircleOfFifthsSettings;
101+
chordDictionary: ChordDictionarySettings;
91102
notation: NotationSettings;
92103
server: ServerSettings;
93104
};
Lines changed: 4 additions & 0 deletions
Loading

src/renderer/components/Icon/icons/index.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ export const ICON_NAMES = [
1414
'exclamation',
1515
'github',
1616
'heart',
17+
'hidden',
1718
'info',
1819
'loading',
1920
'midi',
@@ -38,6 +39,7 @@ export const ICON_NAMES = [
3839
'server',
3940
'settings',
4041
'trash',
42+
'visible',
4143
'window',
4244
] as const;
4345

Lines changed: 4 additions & 0 deletions
Loading

src/renderer/helpers/chord-detect.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ function withOmissions(chroma: string, omissionChroma: string): string {
4747

4848
type FindMatchesOptions = {
4949
allowOmissions: boolean;
50+
disabledChords: string[];
5051
};
5152
function findMatches(
5253
notes: string[],
@@ -63,6 +64,10 @@ function findMatches(
6364
allModes.forEach((mode, index) => {
6465
// some chords could have the same chroma but different interval spelling
6566
const chordTypes = chordTypesWithOmissions.filter((chordType) => {
67+
if (options.disabledChords && options.disabledChords.includes(chordType.aliases[0])) {
68+
return false;
69+
}
70+
6671
if (options.allowOmissions) {
6772
const modeWithOmissions = withOmissions(mode, chordType.omissionChroma);
6873
return chordType.chroma === modeWithOmissions;
@@ -100,6 +105,7 @@ function findMatches(
100105

101106
type DetectOptions = {
102107
allowOmissions: boolean;
108+
disabledChords: string[];
103109
};
104110
export function detect(source: string[], options: Partial<DetectOptions> = {}): string[] {
105111
const notes = source.map((n) => note(n).pc).filter((x) => x);

src/renderer/hooks/useNotes.ts

Lines changed: 76 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,15 @@ const getChordInfo = (chord: string, keySignatureNotes: string[]) => {
3737
return null;
3838
};
3939

40-
const getChords = (notes: string[], keySignatureNotes: string[], allowOmissions: boolean) => {
41-
const chords = detect(notes, { allowOmissions }).map((n) => getChordInfo(n, keySignatureNotes));
40+
const getChords = (
41+
notes: string[],
42+
keySignatureNotes: string[],
43+
allowOmissions: boolean,
44+
disabledChords: string[] = []
45+
) => {
46+
const chords = detect(notes, { allowOmissions, disabledChords }).map((n) =>
47+
getChordInfo(n, keySignatureNotes)
48+
);
4249

4350
return chords;
4451
};
@@ -52,6 +59,7 @@ interface Parameters {
5259
allowOmissions: boolean;
5360
useSustain: boolean;
5461
detectOnRelease: boolean;
62+
disabledChords: string[];
5563
}
5664

5765
enum MidiActionTypes {
@@ -71,6 +79,7 @@ enum ParametersActionTypes {
7179
ALLOW_OMISSIONS_CHANGED = 'ALLOW_OMISSIONS_CHANGED',
7280
USE_SUSTAIN_CHANGED = 'USE_SUSTAIN_CHANGED',
7381
DETECT_ON_RELEASE_CHANGED = 'DETECT_ON_RELEASE_CHANGED',
82+
DISABLED_CHORDS_CHANGED = 'DISABLED_CHORDS_CHANGED',
7483
}
7584

7685
interface ParametersAction {
@@ -86,6 +95,7 @@ interface State {
8695
allowOmissions: boolean;
8796
useSustain: boolean;
8897
detectOnRelease: boolean;
98+
disabledChords?: string[];
8999
};
90100
sustainedMidiNotes: number[];
91101
playedMidiNotes: number[];
@@ -110,7 +120,12 @@ function reducer(state: State, action: Action): State {
110120
getNoteInKeySignature(Note.fromMidi(m), keySignature.notes)
111121
);
112122
const pitchClasses = notes.map(Note.pitchClass);
113-
const chords = getChords(notes, keySignature.notes, state.params.allowOmissions);
123+
const chords = getChords(
124+
notes,
125+
keySignature.notes,
126+
state.params.allowOmissions,
127+
state.params.disabledChords
128+
);
114129

115130
return {
116131
...state,
@@ -125,7 +140,12 @@ function reducer(state: State, action: Action): State {
125140
}
126141
case ParametersActionTypes.ALLOW_OMISSIONS_CHANGED: {
127142
const allowOmissions = action.value as typeof state.params.allowOmissions;
128-
const chords = getChords(state.notes, keySignatureNotes, allowOmissions);
143+
const chords = getChords(
144+
state.notes,
145+
keySignatureNotes,
146+
allowOmissions,
147+
state.params.disabledChords
148+
);
129149

130150
return {
131151
...state,
@@ -136,6 +156,24 @@ function reducer(state: State, action: Action): State {
136156
chords,
137157
};
138158
}
159+
case ParametersActionTypes.DISABLED_CHORDS_CHANGED: {
160+
const disabledChords = action.value as typeof state.params.disabledChords;
161+
const chords = getChords(
162+
state.notes,
163+
keySignatureNotes,
164+
state.params.allowOmissions,
165+
disabledChords
166+
);
167+
168+
return {
169+
...state,
170+
params: {
171+
...state.params,
172+
disabledChords,
173+
},
174+
chords,
175+
};
176+
}
139177
case ParametersActionTypes.USE_SUSTAIN_CHANGED: {
140178
const useSustain = action.value as typeof state.params.useSustain;
141179

@@ -144,7 +182,12 @@ function reducer(state: State, action: Action): State {
144182
midiNotes.sort(midiSortCompareFn);
145183
const notes = midiNotes.map(fromMidi);
146184
const pitchClasses = notes.map(Note.pitchClass);
147-
const chords = getChords(notes, keySignatureNotes, state.params.allowOmissions);
185+
const chords = getChords(
186+
notes,
187+
keySignatureNotes,
188+
state.params.allowOmissions,
189+
state.params.disabledChords
190+
);
148191

149192
return {
150193
...state,
@@ -177,7 +220,12 @@ function reducer(state: State, action: Action): State {
177220
midiNotes.sort(midiSortCompareFn);
178221
const notes = midiNotes.map(fromMidi);
179222
const pitchClasses = notes.map(Note.pitchClass);
180-
const chords = getChords(notes, keySignatureNotes, state.params.allowOmissions);
223+
const chords = getChords(
224+
notes,
225+
keySignatureNotes,
226+
state.params.allowOmissions,
227+
state.params.disabledChords
228+
);
181229

182230
return {
183231
...state,
@@ -200,7 +248,12 @@ function reducer(state: State, action: Action): State {
200248
const notes = midiNotes.map(fromMidi);
201249
const pitchClasses = notes.map(Note.pitchClass);
202250
const chords = state.params.detectOnRelease
203-
? getChords(notes, keySignatureNotes, state.params.allowOmissions)
251+
? getChords(
252+
notes,
253+
keySignatureNotes,
254+
state.params.allowOmissions,
255+
state.params.disabledChords
256+
)
204257
: state.chords;
205258

206259
return {
@@ -236,7 +289,12 @@ function reducer(state: State, action: Action): State {
236289
const notes = midiNotes.map(fromMidi);
237290
const pitchClasses = notes.map(Note.pitchClass);
238291
const chords = state.params.detectOnRelease
239-
? getChords(notes, keySignatureNotes, state.params.allowOmissions)
292+
? getChords(
293+
notes,
294+
keySignatureNotes,
295+
state.params.allowOmissions,
296+
state.params.disabledChords
297+
)
240298
: state.chords;
241299

242300
return {
@@ -261,6 +319,7 @@ const defaultState: State = {
261319
allowOmissions: false,
262320
useSustain: true,
263321
detectOnRelease: true,
322+
disabledChords: undefined,
264323
},
265324
sustainedMidiNotes: [],
266325
playedMidiNotes: [],
@@ -276,6 +335,7 @@ export default function useNotes({
276335
key = 'C',
277336
midiChannel = MIDI_CHANNEL_ALL,
278337
allowOmissions = false,
338+
disabledChords = undefined,
279339
useSustain = true,
280340
detectOnRelease = true,
281341
}: Partial<Parameters> = {}) {
@@ -286,6 +346,7 @@ export default function useNotes({
286346
allowOmissions,
287347
useSustain,
288348
detectOnRelease,
349+
disabledChords,
289350
},
290351
});
291352

@@ -303,6 +364,13 @@ export default function useNotes({
303364
});
304365
}, [allowOmissions]);
305366

367+
useEffect(() => {
368+
dispatch({
369+
type: ParametersActionTypes.DISABLED_CHORDS_CHANGED,
370+
value: disabledChords,
371+
});
372+
}, [disabledChords]);
373+
306374
useEffect(() => {
307375
dispatch({
308376
type: ParametersActionTypes.USE_SUSTAIN_CHANGED,

0 commit comments

Comments
 (0)