119class ChordDescriptor :
public QObject
125 static constexpr std::uint8_t kDefaultBasePitch = 36;
127 ChordDescriptor () =
default;
132 ChordAccent accent = ChordAccent::None,
134 std::optional<MusicalNote> bass = std::nullopt,
135 QObject * parent =
nullptr)
136 : QObject (parent), root_note_ (root), type_ (type), accent_ (accent),
137 inversion_ (std::clamp (inversion, minInversion (), maxInversion ())),
147 zrythm::dsp::chords::MusicalNote rootNote READ rootNote WRITE setRootNote
148 NOTIFY rootNoteChanged)
149 Q_PROPERTY (
bool hasBass READ hasBass WRITE setHasBass NOTIFY hasBassChanged)
151 zrythm::dsp::chords::MusicalNote bassNote READ bassNote WRITE setBassNote
152 NOTIFY bassNoteChanged)
154 zrythm::dsp::chords::ChordType chordType READ chordType WRITE setChordType
155 NOTIFY chordTypeChanged)
157 zrythm::dsp::chords::ChordAccent chordAccent READ chordAccent WRITE
158 setChordAccent NOTIFY chordAccentChanged)
160 int inversion READ inversion WRITE setInversion NOTIFY inversionChanged)
161 Q_PROPERTY (QString displayName READ displayName NOTIFY displayNameChanged)
163 MusicalNote rootNote ()
const {
return root_note_; }
164 void setRootNote (MusicalNote v)
169 Q_EMIT rootNoteChanged (v);
170 Q_EMIT displayNameChanged ();
175 bool hasBass ()
const {
return bass_note_.has_value (); }
176 void setHasBass (
bool v)
180 bass_note_ = v ? std::optional<MusicalNote> (root_note_) : std::nullopt;
181 Q_EMIT hasBassChanged (v);
182 Q_EMIT displayNameChanged ();
187 MusicalNote bassNote ()
const {
return bass_note_.value_or (MusicalNote::C); }
188 void setBassNote (MusicalNote v)
190 bool had = hasBass ();
191 if (!bass_note_.has_value () || *bass_note_ != v)
195 Q_EMIT hasBassChanged (
true);
196 Q_EMIT bassNoteChanged (v);
197 Q_EMIT displayNameChanged ();
202 ChordType chordType ()
const {
return type_; }
203 void setChordType (ChordType v)
208 Q_EMIT chordTypeChanged (v);
209 Q_EMIT displayNameChanged ();
214 ChordAccent chordAccent ()
const {
return accent_; }
215 void setChordAccent (ChordAccent v)
220 Q_EMIT chordAccentChanged (v);
221 Q_EMIT displayNameChanged ();
226 int inversion ()
const {
return inversion_; }
227 void setInversion (
int v)
229 v = std::clamp (v, minInversion (), maxInversion ());
233 Q_EMIT inversionChanged (v);
234 Q_EMIT displayNameChanged ();
239 QString displayName ()
const;
241 Q_SIGNAL
void rootNoteChanged (zrythm::dsp::chords::MusicalNote note);
242 Q_SIGNAL
void hasBassChanged (
bool has);
243 Q_SIGNAL
void bassNoteChanged (zrythm::dsp::chords::MusicalNote note);
244 Q_SIGNAL
void chordTypeChanged (zrythm::dsp::chords::ChordType type);
245 Q_SIGNAL
void chordAccentChanged (zrythm::dsp::chords::ChordAccent accent);
246 Q_SIGNAL
void inversionChanged (
int inversion);
247 Q_SIGNAL
void displayNameChanged ();
248 Q_SIGNAL
void changed ();
254 Q_INVOKABLE
bool isKeyInChord (MusicalNote key)
const;
255 Q_INVOKABLE
bool isKeyBass (MusicalNote key)
const;
257 static constexpr size_t kMaxIntervals = 12;
263 static boost::container::static_vector<int, kMaxIntervals>
270 boost::container::static_vector<int, kMaxIntervals>
getIntervals ()
const;
278 static constexpr size_t kMaxPitches = 8;
279 std::array<std::uint8_t, kMaxPitches> data{};
282 auto begin ()
const {
return data.begin (); }
283 auto end ()
const {
return data.begin () + count; }
284 bool empty ()
const {
return count == 0; }
285 size_t size ()
const {
return count; }
286 std::uint8_t operator[] (
size_t i)
const {
return data[i]; }
297 getMidiPitches (std::uint8_t base_pitch = kDefaultBasePitch)
const;
299 int maxInversion ()
const;
300 int minInversion ()
const {
return -maxInversion (); }
311 bool isEquivalent (
const ChordDescriptor &other)
const;
314 friend void to_json (nlohmann::json &j,
const ChordDescriptor &c);
315 friend void from_json (
const nlohmann::json &j, ChordDescriptor &c);
318 MusicalNote root_note_ = MusicalNote::C;
321 ChordType type_ = ChordType::None;
328 ChordAccent accent_ = ChordAccent::None;
338 std::optional<MusicalNote> bass_note_;
347 std::optional<boost::container::static_vector<int, kMaxIntervals>>