Zrythm v2.0.0-DEV
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 "dsp/chord_descriptor.h"
7#include "utils/icloneable.h"
8
9#include <QtQmlIntegration/qqmlintegration.h>
10
11#include <boost/describe.hpp>
12#include <nlohmann/json_fwd.hpp>
13
14namespace zrythm::dsp
15{
16using namespace std::string_view_literals;
17
23class MusicalScale : public QObject
24{
25 Q_OBJECT
26 Q_PROPERTY (
27 ScaleType scaleType READ scaleType WRITE setScaleType NOTIFY scaleTypeChanged)
28 Q_PROPERTY (
29 zrythm::dsp::MusicalNote rootKey READ rootKey WRITE setRootKey NOTIFY
30 rootKeyChanged)
31 QML_ELEMENT
32 QML_EXTENDED_NAMESPACE (zrythm::dsp)
33
34public:
35 /**
36 * Scale type (name) eg Aeolian.
37 */
38 enum class ScaleType : std::uint8_t
39 {
42
43 /* --- popular scales --- */
44
45 Major,
46
49
51 Ionian,
52
53 Dorian,
54 Phrygian,
55 Lydian,
56 Mixolydian,
57
59 Aeolian,
60
61 Locrian,
62 MelodicMinor,
63 HarmonicMinor,
64 WholeTone,
65 MajorPentatonic,
66 MinorPentatonic,
67 OctatonicHalfWhole,
68 OctatonicWholeHalf,
69
70 /* --- exotic scales --- */
71
74
75 HarmonicMajor,
76 PhrygianDominant,
77 MajorLocrian,
78 Algerian,
79 Augmented,
80 DoubleHarmonic,
81 Chinese,
82 Diminished,
83 DominantDiminished,
84 Egyptian,
85 EightToneSpanish,
86 Enigmatic,
87 Geez,
88 Hindu,
89 Hirajoshi,
90 HungarianGypsy,
91 Insen,
92 NeapolitanMajor,
93 NeapolitanMinor,
94 Oriental,
95 RomanianMinor,
96 Altered,
97 Maqam,
98 Yo,
99 BebopLocrian,
100 BebopDominant,
101 BebopMajor,
102 SuperLocrian,
103 EnigmaticMinor,
104 Composite,
105 Bhairav,
106 HungarianMinor,
107 Persian,
108 Iwato,
109 Kumoi,
110 Pelog,
111 Prometheus,
112 PrometheusNeapolitan,
113 PrometheusLiszt,
114 Balinese,
115 Ragatodi,
116 Japanese1,
117 Japanese2,
118
119 /* --- TODO unimplemented --- */
120
121 Blues,
122 Flamenco,
123 Gypsy,
124 HalfDiminished,
125 In,
126 Istrian,
127 LydianAugmented,
128 Tritone,
129 UkranianDorian,
130 };
131 Q_ENUM (ScaleType)
132
133public:
134 MusicalScale (QObject * parent = nullptr) : QObject (parent) { }
135 MusicalScale (ScaleType type, MusicalNote root, QObject * parent = nullptr)
136 : MusicalScale (parent)
137 {
138 setScaleType (type);
139 setRootKey (root);
140 }
141 Q_DISABLE_COPY_MOVE (MusicalScale)
142 ~MusicalScale () override = default;
143
144 // ========================================================================
145 // QML Interface
146 // ========================================================================
147
148 auto scaleType () const { return type_; }
149 void setScaleType (ScaleType type)
150 {
151 type = std::clamp (type, ScaleType::Chromatic, ScaleType::UkranianDorian);
152 if (type_ != type)
153 {
154 type_ = type;
155 Q_EMIT scaleTypeChanged (type);
156 }
157 }
158 Q_SIGNAL void scaleTypeChanged (ScaleType type);
159
160 auto rootKey () const { return root_key_; }
161 void setRootKey (MusicalNote root_key)
162 {
163 root_key = std::clamp (root_key, MusicalNote::C, MusicalNote::B);
164 if (root_key_ != root_key)
165 {
166 root_key_ = root_key;
167 Q_EMIT rootKeyChanged (root_key);
168 }
169 }
170 Q_SIGNAL void rootKeyChanged (MusicalNote root_key);
171
172 Q_INVOKABLE QString toString () const;
173
179 Q_INVOKABLE bool containsNote (MusicalNote note) const;
180
181 // ========================================================================
182
189 static const bool * get_notes_for_type (ScaleType type, bool ascending);
190
200 static std::array<ChordType, 12>
201 get_triad_types_for_type (ScaleType type, bool ascending);
202
203 static utils::Utf8String type_to_string (ScaleType type);
204
209
213 bool contains_chord (const ChordDescriptor &chord) const;
214
218 bool is_accent_in_scale (
219 MusicalNote chord_root,
220 ChordType type,
221 ChordAccent chord_accent) const;
222
223 bool is_same_scale (const MusicalScale &other) const
224 {
225 return type_ == other.type_ && root_key_ == other.root_key_;
226 }
227
228private:
229 static constexpr auto kRootKeyKey = "rootKey"sv;
230 static constexpr auto kTypeKey = "type"sv;
231
232 friend void init_from (
233 MusicalScale &obj,
234 const MusicalScale &other,
235 utils::ObjectCloneType clone_type);
236
237 friend void to_json (nlohmann::json &j, const MusicalScale &s);
238 friend void from_json (const nlohmann::json &j, MusicalScale &s);
239
240private:
243
245 MusicalNote root_key_ = MusicalNote::A;
246
247 BOOST_DESCRIBE_CLASS (MusicalScale, (), (), (), (type_, root_key_))
248};
249
250} // namespace zrythm::dsp
A ChordDescriptor describes a chord and is not linked to any specific object by itself.
Musical scale descriptor.
ScaleType
Scale type (name) eg Aeolian.
@ Ionian
Major (same as SCALE_MAJOR).
@ Aeolian
Natural minor (same as Minor).
Q_INVOKABLE bool containsNote(MusicalNote note) const
Returns if the given key is in the given MusicalScale.
utils::Utf8String to_string() const
Prints the MusicalScale to a string.
bool contains_chord(const ChordDescriptor &chord) const
Returns if all of the chord's notes are in the scale.
static const bool * get_notes_for_type(ScaleType type, bool ascending)
Returns the notes in the given scale.
bool is_accent_in_scale(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.
Lightweight UTF-8 string wrapper with safe conversions.
Definition utf8_string.h:37