Zrythm
a highly automated and intuitive digital audio workstation
Loading...
Searching...
No Matches
chord_descriptor.h
Go to the documentation of this file.
1// SPDX-FileCopyrightText: © 2018-2022 Alexandros Theodotou <alex@zrythm.org>
2// SPDX-License-Identifier: LicenseRef-ZrythmLicense
3
10#ifndef __AUDIO_CHORD_DESCRIPTOR_H__
11#define __AUDIO_CHORD_DESCRIPTOR_H__
12
13#include <stdint.h>
14
15#include "dsp/position.h"
16#include "utils/yaml.h"
17
24#define CHORD_DESCRIPTOR_SCHEMA_VERSION 2
25
26#define CHORD_DESCRIPTOR_MAX_NOTES 48
27
28typedef enum MusicalNote
29{
30 NOTE_C = 0,
31 NOTE_CS,
32 NOTE_D,
33 NOTE_DS,
34 NOTE_E,
35 NOTE_F,
36 NOTE_FS,
37 NOTE_G,
38 NOTE_GS,
39 NOTE_A,
40 NOTE_AS,
41 NOTE_B
42} MusicalNote;
43
44static const cyaml_strval_t musical_note_strings[] = {
45 {"C", NOTE_C },
46 { "C#", NOTE_CS},
47 { "D", NOTE_D },
48 { "D#", NOTE_DS},
49 { "E", NOTE_E },
50 { "F", NOTE_F },
51 { "F#", NOTE_FS},
52 { "G", NOTE_G },
53 { "G#", NOTE_GS},
54 { "A", NOTE_A },
55 { "A#", NOTE_AS},
56 { "B", NOTE_B },
57};
58
62typedef enum ChordType
63{
64 CHORD_TYPE_NONE,
65 CHORD_TYPE_MAJ,
66 CHORD_TYPE_MIN,
67 CHORD_TYPE_DIM,
68 CHORD_TYPE_SUS4,
69 CHORD_TYPE_SUS2,
70 CHORD_TYPE_AUG,
71 CHORD_TYPE_CUSTOM,
72 NUM_CHORD_TYPES,
73} ChordType;
74
75static const cyaml_strval_t chord_type_strings[] = {
76 {"Invalid", CHORD_TYPE_NONE },
77 { "Maj", CHORD_TYPE_MAJ },
78 { "min", CHORD_TYPE_MIN },
79 { "dim", CHORD_TYPE_DIM },
80 { "sus4", CHORD_TYPE_SUS4 },
81 { "sus2", CHORD_TYPE_SUS2 },
82 { "aug", CHORD_TYPE_AUG },
83 { "custom", CHORD_TYPE_CUSTOM},
84};
85
89typedef enum ChordAccent
90{
91 CHORD_ACC_NONE,
97 /* NOTE: all accents below assume 7 */
112 NUM_CHORD_ACCENTS,
114
115static const cyaml_strval_t chord_accent_strings[] = {
116 {"None", CHORD_ACC_NONE },
117 { "7", CHORD_ACC_7 },
118 { "j7", CHORD_ACC_j7 },
119 { "\u266D9", CHORD_ACC_b9 },
120 { "9", CHORD_ACC_9 },
121 { "\u266F9", CHORD_ACC_S9 },
122 { "11", CHORD_ACC_11 },
123 { "\u266D5/\u266F11", CHORD_ACC_b5_S11},
124 { "\u266F5/\u266D13", CHORD_ACC_S5_b13},
125 { "6/13", CHORD_ACC_6_13 },
126};
127
134typedef struct ChordDescriptor
135{
136 int schema_version;
137
140
142 MusicalNote root_note;
143
145 MusicalNote bass_note;
146
149
156
165 int notes[CHORD_DESCRIPTOR_MAX_NOTES];
166
174
175static const cyaml_schema_field_t chord_descriptor_fields_schema[] = {
176 YAML_FIELD_INT (ChordDescriptor, schema_version),
177 YAML_FIELD_INT (ChordDescriptor, has_bass),
178 YAML_FIELD_ENUM (ChordDescriptor, root_note, musical_note_strings),
179 YAML_FIELD_ENUM (ChordDescriptor, bass_note, musical_note_strings),
180 YAML_FIELD_ENUM (ChordDescriptor, type, chord_type_strings),
181 YAML_FIELD_ENUM (ChordDescriptor, accent, chord_accent_strings),
182 CYAML_FIELD_SEQUENCE_FIXED (
183 "notes",
184 CYAML_FLAG_OPTIONAL,
186 notes,
187 &int_schema,
188 36),
189 YAML_FIELD_INT (ChordDescriptor, inversion),
190
191 CYAML_FIELD_END
192};
193
194static const cyaml_schema_value_t chord_descriptor_schema = {
195 CYAML_VALUE_MAPPING (
196 CYAML_FLAG_POINTER,
198 chord_descriptor_fields_schema),
199};
200
206 MusicalNote root,
207 int has_bass,
208 MusicalNote bass,
209 ChordType type,
210 ChordAccent accent,
211 int inversion);
212
213static inline int
214chord_descriptor_get_max_inversion (const ChordDescriptor * const self)
215{
216 int max_inv = 2;
217 switch (self->accent)
218 {
219 case CHORD_ACC_NONE:
220 break;
221 case CHORD_ACC_7:
222 case CHORD_ACC_j7:
223 case CHORD_ACC_b9:
224 case CHORD_ACC_9:
225 case CHORD_ACC_S9:
226 case CHORD_ACC_11:
227 max_inv = 3;
228 break;
229 case CHORD_ACC_b5_S11:
230 case CHORD_ACC_S5_b13:
231 case CHORD_ACC_6_13:
232 max_inv = 4;
233 break;
234 default:
235 break;
236 }
237
238 return max_inv;
239}
240
241static inline int
242chord_descriptor_get_min_inversion (const ChordDescriptor * const self)
243{
244 return -chord_descriptor_get_max_inversion (self);
245}
246
247static inline int
248chord_descriptor_are_notes_equal (int * notes_a, int * notes_b)
249{
250 /* 36 notes in Chord */
251 for (int i = 0; i < 36; i++)
252 {
253 if (notes_a[i] != notes_b[i])
254 return 0;
255 }
256 return 1;
257}
258
259static inline int
260chord_descriptor_is_equal (ChordDescriptor * a, ChordDescriptor * b)
261{
262 return a->has_bass == b->has_bass && a->root_note == b->root_note
263 && a->bass_note == b->bass_note && a->type == b->type
264 && chord_descriptor_are_notes_equal (a->notes, b->notes)
265 && a->inversion == b->inversion;
266}
267
274bool
276
283bool
285
291
292void
293chord_descriptor_copy (ChordDescriptor * dest, const ChordDescriptor * src);
294
298const char *
300
304const char *
306
310const char *
312
318char *
320
324NONNULL void
325chord_descriptor_to_string (const ChordDescriptor * chord, char * str);
326
331NONNULL void
333
337NONNULL void
339
344#endif
bool chord_descriptor_is_key_in_chord(ChordDescriptor *chord, MusicalNote key)
Returns if the given key is in the chord represented by the given ChordDescriptor.
ChordAccent
Chord accents.
ChordDescriptor * chord_descriptor_clone(const ChordDescriptor *src)
Clones the given ChordDescriptor.
const char * chord_descriptor_note_to_string(MusicalNote note)
Returns the musical note as a string (eg.
NONNULL void chord_descriptor_to_string(const ChordDescriptor *chord, char *str)
Returns the chord in human readable string.
const char * chord_descriptor_chord_accent_to_string(ChordAccent accent)
Returns the chord accent as a string (eg.
ChordDescriptor * chord_descriptor_new(MusicalNote root, int has_bass, MusicalNote bass, ChordType type, ChordAccent accent, int inversion)
Creates a ChordDescriptor.
char * chord_descriptor_to_new_string(const ChordDescriptor *chord)
Returns the chord in human readable string.
const char * chord_descriptor_chord_type_to_string(ChordType type)
Returns the chord type as a string (eg.
NONNULL void chord_descriptor_update_notes(ChordDescriptor *self)
Updates the notes array based on the current settings.
NONNULL void chord_descriptor_free(ChordDescriptor *self)
Frees the ChordDescriptor.
bool chord_descriptor_is_key_bass(ChordDescriptor *chord, MusicalNote key)
Returns if key is the bass or root note of chord.
ChordType
Chord type.
@ CHORD_ACC_b5_S11
6 and 18 semitones.
@ CHORD_ACC_S5_b13
8 and 16 semitones.
@ CHORD_ACC_9
14 semitones.
@ CHORD_ACC_11
17 semitones.
@ CHORD_ACC_S9
15 semitones.
@ CHORD_ACC_6_13
9 and 21 semitones.
@ CHORD_ACC_b9
13 semitones.
@ CHORD_ACC_7
b7 is 10 semitones from chord root, or 9 if the chord is diminished.
@ CHORD_ACC_j7
Maj7 is 11 semitones from the root.
Position struct and API.
A ChordDescriptor describes a chord and is not linked to any specific object by itself.
int notes[CHORD_DESCRIPTOR_MAX_NOTES]
Only used if custom chord.
ChordAccent accent
Chord accent.
MusicalNote bass_note
Bass note 1 octave below.
bool has_bass
Has bass note or not.
int inversion
0 no inversion, less than 0 highest note(s) drop an octave, greater than 0 lowest note(s) receive an ...
MusicalNote root_note
Root note.
ChordType type
Chord type.
YAML utils.