Zrythm v2.0.0-alpha.1+31.4967fd053471
a highly automated and intuitive digital audio workstation
Loading...
Searching...
No Matches
musical_scale.h
1// SPDX-FileCopyrightText: © 2018-2022, 2024-2026 Alexandros Theodotou <alex@zrythm.org>
2// SPDX-License-Identifier: LicenseRef-ZrythmLicense
3
4#pragma once
5
6#include <array>
7
8#include "dsp/chord_descriptor.h"
9#include "utils/icloneable.h"
10
11#include <QtQmlIntegration/qqmlintegration.h>
12
13#include <boost/describe.hpp>
14#include <nlohmann/json_fwd.hpp>
15
16namespace zrythm::dsp
17{
18using namespace std::string_view_literals;
19
25class MusicalScale : public QObject
26{
27 Q_OBJECT
28 Q_PROPERTY (
29 ScaleType scaleType READ scaleType WRITE setScaleType NOTIFY scaleTypeChanged)
30 Q_PROPERTY (
31 zrythm::dsp::chords::MusicalNote rootKey READ rootKey WRITE setRootKey
32 NOTIFY rootKeyChanged)
33 QML_ELEMENT
34 QML_EXTENDED_NAMESPACE (zrythm::dsp::chords)
35
36public:
37 /**
38 * Scale type (name) eg Aeolian.
39 */
40 enum class ScaleType : std::uint8_t
41 {
44
45 /* --- popular scales --- */
46
47 Major,
48
51
53 Ionian,
54
55 Dorian,
56 Phrygian,
57 Lydian,
58 Mixolydian,
59
61 Aeolian,
62
63 Locrian,
64 MelodicMinor,
65 HarmonicMinor,
66 WholeTone,
67 MajorPentatonic,
68 MinorPentatonic,
69 OctatonicHalfWhole,
70 OctatonicWholeHalf,
71
72 /* --- exotic scales --- */
73
76
77 HarmonicMajor,
78 PhrygianDominant,
79 MajorLocrian,
80 Algerian,
81 Augmented,
82 DoubleHarmonic,
83 Chinese,
84 Diminished,
85 DominantDiminished,
86 Egyptian,
87 EightToneSpanish,
88 Enigmatic,
89 Geez,
90 Hindu,
91 Hirajoshi,
92 HungarianGypsy,
93 Insen,
94 NeapolitanMajor,
95 NeapolitanMinor,
96 Oriental,
97 RomanianMinor,
98 Altered,
99 Maqam,
100 Yo,
101 BebopLocrian,
102 BebopDominant,
103 BebopMajor,
104 SuperLocrian,
105 EnigmaticMinor,
106 Composite,
107 Bhairav,
108 HungarianMinor,
109 Persian,
110 Iwato,
111 Kumoi,
112 Pelog,
113 Prometheus,
114 PrometheusNeapolitan,
115 PrometheusLiszt,
116 Balinese,
117 Ragatodi,
118 Japanese1,
119 Japanese2,
120
121 /* --- TODO unimplemented --- */
122
123 Blues,
124 Flamenco,
125 Gypsy,
126 HalfDiminished,
127 In,
128 Istrian,
129 LydianAugmented,
130 Tritone,
131 UkranianDorian,
132 };
133 Q_ENUM (ScaleType)
134
135public:
136 MusicalScale (QObject * parent = nullptr) : QObject (parent) { }
137 MusicalScale (ScaleType type, MusicalNote root, QObject * parent = nullptr)
138 : MusicalScale (parent)
139 {
140 setScaleType (type);
141 setRootKey (root);
142 }
143 Q_DISABLE_COPY_MOVE (MusicalScale)
144 ~MusicalScale () override = default;
145
146 // ========================================================================
147 // QML Interface
148 // ========================================================================
149
150 auto scaleType () const { return type_; }
151 void setScaleType (ScaleType type)
152 {
153 type = std::clamp (type, ScaleType::Chromatic, ScaleType::UkranianDorian);
154 if (type_ != type)
155 {
156 type_ = type;
157 Q_EMIT scaleTypeChanged (type);
158 }
159 }
160 Q_SIGNAL void scaleTypeChanged (ScaleType type);
161
162 auto rootKey () const { return root_key_; }
163 void setRootKey (MusicalNote root_key)
164 {
165 root_key = std::clamp (root_key, MusicalNote::C, MusicalNote::B);
166 if (root_key_ != root_key)
167 {
168 root_key_ = root_key;
169 Q_EMIT rootKeyChanged (root_key);
170 }
171 }
172 Q_SIGNAL void rootKeyChanged (MusicalNote root_key);
173
174 Q_INVOKABLE QString toString () const;
175
181 Q_INVOKABLE bool containsNote (MusicalNote note) const;
182
183 Q_INVOKABLE static bool
184 scaleContainsNote (ScaleType type, MusicalNote rootKey, MusicalNote note);
185
186 Q_INVOKABLE static QString noteToString (MusicalNote note);
187
194 Q_INVOKABLE static QStringList allNoteNames ();
195
196 Q_INVOKABLE static QVariantList availableScaleTypes ();
197 Q_INVOKABLE static QVariantList availableScaleTypesExotic ();
198
203 Q_INVOKABLE static QVariantList availableScaleTypesWithTriads ();
204
209 Q_INVOKABLE static QVariantList
210 getDiatonicChords (ScaleType type, MusicalNote rootKey);
211
212 // ========================================================================
213
220 static std::array<bool, 12>
221 get_notes_for_type (ScaleType type, bool ascending);
222
232 static std::array<ChordType, 12>
233 get_triad_types_for_type (ScaleType type, bool ascending);
234
235 /**
236 * @brief A diatonic triad: the root note and chord type for a scale degree.
237 */
238 struct DiatonicTriad
239 {
240 MusicalNote root_note;
241 ChordType chord_type;
242 };
243
254 static boost::container::static_vector<DiatonicTriad, 12>
255 get_diatonic_triads (ScaleType type, MusicalNote root_note);
256
257 static utils::Utf8String type_to_string (ScaleType type);
258
263
267 Q_INVOKABLE bool containsChord (
268 MusicalNote root,
269 ChordType type,
270 ChordAccent accent = ChordAccent::None) const;
271
275 Q_INVOKABLE bool isAccentInScale (
276 MusicalNote chord_root,
277 ChordType type,
278 ChordAccent chord_accent) const;
279
280 bool is_same_scale (const MusicalScale &other) const
281 {
282 return type_ == other.type_ && root_key_ == other.root_key_;
283 }
284
285private:
286 static constexpr auto kRootKeyKey = "rootKey"sv;
287 static constexpr auto kTypeKey = "type"sv;
288
289 friend void init_from (
290 MusicalScale &obj,
291 const MusicalScale &other,
292 utils::ObjectCloneType clone_type);
293
294 friend void to_json (nlohmann::json &j, const MusicalScale &s);
295 friend void from_json (const nlohmann::json &j, MusicalScale &s);
296
297private:
300
302 MusicalNote root_key_ = MusicalNote::A;
303
304 BOOST_DESCRIBE_CLASS (MusicalScale, (), (), (), (type_, root_key_))
305};
306
307} // namespace zrythm::dsp
Musical scale descriptor.
ScaleType
Scale type (name) eg Aeolian.
@ Ionian
Major (same as SCALE_MAJOR).
@ Aeolian
Natural minor (same as Minor).
static Q_INVOKABLE QVariantList availableScaleTypesWithTriads()
Scales with pre-defined triad data in get_triad_types_for_type.
Q_INVOKABLE bool containsNote(MusicalNote note) const
Returns if the given key is in the given MusicalScale.
static Q_INVOKABLE QVariantList getDiatonicChords(ScaleType type, MusicalNote rootKey)
Returns a QVariantList of diatonic chord descriptors for the given scale, each as {display,...
utils::Utf8String to_string() const
Prints the MusicalScale to a string.
static Q_INVOKABLE QStringList allNoteNames()
Returns the display names of all 12 notes in a single octave.
static std::array< bool, 12 > get_notes_for_type(ScaleType type, bool ascending)
Returns the notes in the given scale.
Q_INVOKABLE bool containsChord(MusicalNote root, ChordType type, ChordAccent accent=ChordAccent::None) const
Returns if all of the chord's notes are in the scale.
Q_INVOKABLE bool isAccentInScale(MusicalNote chord_root, ChordType type, ChordAccent chord_accent) const
Returns if the accent is in the scale.
static std::array< ChordType, 12 > get_triad_types_for_type(ScaleType type, bool ascending)
Returns the triads in the given scale.
static boost::container::static_vector< DiatonicTriad, 12 > get_diatonic_triads(ScaleType type, MusicalNote root_note)
Returns the diatonic triads for the given scale and root note.
Lightweight UTF-8 string wrapper with safe conversions.
Definition utf8_string.h:37
A diatonic triad: the root note and chord type for a scale degree.