Zrythm v2.0.0-alpha.1
a highly automated and intuitive digital audio workstation
Loading...
Searching...
No Matches
chord_suggestion.h
1// SPDX-FileCopyrightText: © 2026 Alexandros Theodotou <alex@zrythm.org>
2// SPDX-License-Identifier: LicenseRef-ZrythmLicense
3
4#pragma once
5
6#include <optional>
7#include <vector>
8
9#include "dsp/chord_descriptor.h"
10#include "dsp/musical_scale.h"
11
12namespace zrythm::dsp::chords
13{
14
15// ============================================================================
16// Enums
17// ============================================================================
18
20enum class ChordCandidateCategory : uint32_t
21{
22 DiatonicTriads = 1 << 0,
23 DiatonicSevenths = 1 << 1,
24 SecondaryDominants = 1 << 2,
25 BorrowedChords = 1 << 3,
26 LeadingTone = 1 << 4,
27};
28
29inline ChordCandidateCategory
30operator| (ChordCandidateCategory a, ChordCandidateCategory b) noexcept
31{
32 return static_cast<ChordCandidateCategory> (
33 static_cast<uint32_t> (a) | static_cast<uint32_t> (b));
34}
35
36inline ChordCandidateCategory
37operator& (ChordCandidateCategory a, ChordCandidateCategory b) noexcept
38{
39 return static_cast<ChordCandidateCategory> (
40 static_cast<uint32_t> (a) & static_cast<uint32_t> (b));
41}
42
43inline ChordCandidateCategory &
44operator|= (ChordCandidateCategory &a, ChordCandidateCategory b) noexcept
45{
46 a = a | b;
47 return a;
48}
49
51enum class HarmonicFunction
52{
53 Tonic,
54 Predominant,
55 Dominant,
56 Other,
57};
58
60enum class CandidateType
61{
62 DiatonicTriad,
63 DiatonicSeventh,
64 SecondaryDominant,
65 BorrowedChord,
66 LeadingTone,
67};
68
69// ============================================================================
70// Structs
71// ============================================================================
72
78{
79 MusicalNote root_note = MusicalNote::C;
80 ChordType type = ChordType::Major;
81 ChordAccent accent = ChordAccent::None;
82
83 bool operator== (const ChordKey &other) const
84 {
85 return root_note == other.root_note && type == other.type
86 && accent == other.accent;
87 }
88
91 {
92 return ChordDescriptor (root_note, type, accent);
93 }
94};
95
98{
99 ChordKey chord_key{};
100 CandidateType type = CandidateType::DiatonicTriad;
101 int scale_degree = -1;
102 std::optional<int> secondary_dominant_target_degree{};
103};
104
107{
108 ChordKey chord_key{};
109 CandidateType candidate_type = CandidateType::DiatonicTriad;
110 float overall_score = 0.0f;
111 float functional_score = 0.0f;
112 float root_motion_score = 0.0f;
113 float voice_leading_score = 0.0f;
114 int scale_degree = -1;
115 HarmonicFunction function = HarmonicFunction::Other;
116 int rank = 0;
117};
118
119// ============================================================================
120// Public API
121// ============================================================================
122
124bool
125is_minor_type (const MusicalScale &scale);
126
128int
129get_scale_degree (MusicalNote root, const MusicalScale &scale);
130
132float
133score_root_motion (MusicalNote prev_root, MusicalNote next_root);
134
136float
137score_voice_leading (const ChordKey &prev, const ChordKey &next);
138
140float
141score_diatonic_membership (const ChordKey &chord, const MusicalScale &scale);
142
144float
145score_functional_compatibility (
146 const ChordKey &prev,
147 const ChordKey &candidate,
148 const MusicalScale &scale);
149
152float
153score_seventh_resolution (
154 const ChordKey &prev,
155 const ChordKey &next,
156 const MusicalScale &scale);
157
159float
160score_secondary_dominant (
161 const CandidateChord &prev,
162 const CandidateChord &candidate,
163 const MusicalScale &scale);
164
166float
167score_leading_tone_resolution (
168 const ChordKey &prev,
169 const ChordKey &candidate,
170 const MusicalScale &scale);
171
179float
180score_borrowed_chord (const CandidateChord &candidate, const MusicalScale &scale);
181
183std::vector<CandidateChord>
184generate_candidates (
185 const MusicalScale &scale,
186 ChordCandidateCategory categories);
187
189std::vector<ChordSuggestion>
190suggest_next_chords (
191 const ChordKey &current_chord,
192 const MusicalScale &scale,
193 ChordCandidateCategory categories,
194 int max_results = 3);
195
196} // namespace zrythm::dsp::chords
Describes a musical chord by its root note, type, accent, inversion, and optional bass note.
Musical scale descriptor.
A candidate chord with metadata about how it was generated.
Lightweight POD storing just the chord identity (no QObject overhead).
ChordDescriptor make_descriptor() const
Constructs a temporary ChordDescriptor for method calls.
The result of scoring one candidate chord.