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{
16
22class MusicalScale : public QObject
23{
24 Q_OBJECT
25 Q_PROPERTY (
26 ScaleType scaleType READ scaleType WRITE setScaleType NOTIFY scaleTypeChanged)
27 Q_PROPERTY (
28 zrythm::dsp::MusicalNote rootKey READ rootKey WRITE setRootKey NOTIFY
29 rootKeyChanged)
30 QML_ELEMENT
31 QML_EXTENDED_NAMESPACE (zrythm::dsp)
32
33public:
34 /**
35 * Scale type (name) eg Aeolian.
36 */
37 enum class ScaleType : std::uint8_t
38 {
41
42 /* --- popular scales --- */
43
44 Major,
45
48
50 Ionian,
51
52 Dorian,
53 Phrygian,
54 Lydian,
55 Mixolydian,
56
58 Aeolian,
59
60 Locrian,
61 MelodicMinor,
62 HarmonicMinor,
63 WholeTone,
64 MajorPentatonic,
65 MinorPentatonic,
66 OctatonicHalfWhole,
67 OctatonicWholeHalf,
68
69 /* --- exotic scales --- */
70
73
74 HarmonicMajor,
75 PhrygianDominant,
76 MajorLocrian,
77 Algerian,
78 Augmented,
79 DoubleHarmonic,
80 Chinese,
81 Diminished,
82 DominantDiminished,
83 Egyptian,
84 EightToneSpanish,
85 Enigmatic,
86 Geez,
87 Hindu,
88 Hirajoshi,
89 HungarianGypsy,
90 Insen,
91 NeapolitanMajor,
92 NeapolitanMinor,
93 Oriental,
94 RomanianMinor,
95 Altered,
96 Maqam,
97 Yo,
98 BebopLocrian,
99 BebopDominant,
100 BebopMajor,
101 SuperLocrian,
102 EnigmaticMinor,
103 Composite,
104 Bhairav,
105 HungarianMinor,
106 Persian,
107 Iwato,
108 Kumoi,
109 Pelog,
110 Prometheus,
111 PrometheusNeapolitan,
112 PrometheusLiszt,
113 Balinese,
114 Ragatodi,
115 Japanese1,
116 Japanese2,
117
118 /* --- TODO unimplemented --- */
119
120 Blues,
121 Flamenco,
122 Gypsy,
123 HalfDiminished,
124 In,
125 Istrian,
126 LydianAugmented,
127 Tritone,
128 UkranianDorian,
129 };
130 Q_ENUM (ScaleType)
131
132public:
133 MusicalScale (QObject * parent = nullptr) : QObject (parent) { }
134 MusicalScale (ScaleType type, MusicalNote root, QObject * parent = nullptr)
135 : MusicalScale (parent)
136 {
137 setScaleType (type);
138 setRootKey (root);
139 }
140 Z_DISABLE_COPY_MOVE (MusicalScale)
141 ~MusicalScale () override = default;
142
143 // ========================================================================
144 // QML Interface
145 // ========================================================================
146
147 auto scaleType () const { return type_; }
148 void setScaleType (ScaleType type)
149 {
150 type = std::clamp (type, ScaleType::Chromatic, ScaleType::UkranianDorian);
151 if (type_ != type)
152 {
153 type_ = type;
154 Q_EMIT scaleTypeChanged (type);
155 }
156 }
157 Q_SIGNAL void scaleTypeChanged (ScaleType type);
158
159 auto rootKey () const { return root_key_; }
160 void setRootKey (MusicalNote root_key)
161 {
162 root_key = std::clamp (root_key, MusicalNote::C, MusicalNote::B);
163 if (root_key_ != root_key)
164 {
165 root_key_ = root_key;
166 Q_EMIT rootKeyChanged (root_key);
167 }
168 }
169 Q_SIGNAL void rootKeyChanged (MusicalNote root_key);
170
171 Q_INVOKABLE QString toString () const { return to_string ().to_qstring (); }
172
178 Q_INVOKABLE bool containsNote (MusicalNote note) const;
179
180 // ========================================================================
181
188 static const bool * get_notes_for_type (ScaleType type, bool ascending);
189
199 static std::array<ChordType, 12>
200 get_triad_types_for_type (ScaleType type, bool ascending);
201
202 static utils::Utf8String type_to_string (ScaleType type);
203
208
212 bool contains_chord (const ChordDescriptor &chord) const;
213
217 bool is_accent_in_scale (
218 MusicalNote chord_root,
219 ChordType type,
220 ChordAccent chord_accent) const;
221
222 bool is_same_scale (const MusicalScale &other) const
223 {
224 return type_ == other.type_ && root_key_ == other.root_key_;
225 }
226
227private:
228 static constexpr auto kRootKeyKey = "rootKey"sv;
229 static constexpr auto kTypeKey = "type"sv;
230
231 friend void init_from (
232 MusicalScale &obj,
233 const MusicalScale &other,
234 utils::ObjectCloneType clone_type);
235
236 friend void to_json (nlohmann::json &j, const MusicalScale &s);
237 friend void from_json (const nlohmann::json &j, MusicalScale &s);
238
239private:
242
244 MusicalNote root_key_ = MusicalNote::A;
245
246 BOOST_DESCRIBE_CLASS (MusicalScale, (), (), (), (type_, root_key_))
247};
248
249} // 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:38