92 static constexpr std::optional<ChordFormula>
94 if (intervals.empty() || intervals.size() >
kMaxNotes || intervals.front() != 0)
99 for (std::size_t i = 0; i < intervals.size(); ++i) {
103 result.intervals_[i] =
static_cast<std::int8_t
>(
interval);
106 result.count_ =
static_cast<std::uint8_t
>(intervals.size());
111 constexpr std::array<std::array<std::int8_t, kMaxNotes>,
kChordQualityCount> intervals{{
125 constexpr std::array<std::uint8_t, kChordQualityCount> counts{{
139 const auto index =
static_cast<std::size_t
>(
quality);
140 if (index >= intervals.size())
143 result.intervals_ = intervals[index];
144 result.count_ = counts[index];
149 constexpr std::size_t
size() const noexcept {
152 constexpr std::optional<int>
interval(std::size_t index)
const noexcept {
155 return static_cast<int>(intervals_[index]);
157 constexpr std::optional<ChordQuality>
quality() const noexcept {
162 constexpr std::array<int, 3> intervals{14, 17, 21};
163 const auto index =
static_cast<std::size_t
>(extension);
164 if (index >= intervals.size())
166 return with_replacement(-1, intervals[index]);
169 constexpr std::optional<ChordFormula>
171 const auto index =
static_cast<std::size_t
>(suspension);
174 const int replacement = index == 0 ? 2 : 5;
175 for (std::size_t note = 1; note < count_; ++note) {
176 const int interval_value = intervals_[note];
179 const int replacement_interval =
180 interval_value -
static_cast<int>(pitch_class) + replacement;
181 return with_replacement(interval_value, replacement_interval);
184 for (std::size_t note = 1; note < count_; ++note) {
185 const int interval_value = intervals_[note];
188 static_cast<int>(pitch_class) != replacement) {
189 const int replacement_interval =
190 interval_value -
static_cast<int>(pitch_class) + replacement;
191 return with_replacement(interval_value, replacement_interval);
194 for (std::size_t note = 1; note < count_; ++note)
195 if (intervals_[note] == replacement)
197 return with_replacement(-1, replacement);
200 constexpr std::optional<ChordFormula>
202 constexpr std::array<int, 6> natural_intervals{7, 7, 14, 14, 17, 21};
203 constexpr std::array<int, 6> altered_intervals{6, 8, 13, 15, 18, 20};
204 const auto index =
static_cast<std::size_t
>(alteration);
205 if (index >= natural_intervals.size())
207 return with_replacement(natural_intervals[index], altered_intervals[index]);
211 std::uint16_t mask = 0;
212 for (std::size_t i = 0; i < count_; ++i)
213 mask =
static_cast<std::uint16_t
>(
221 constexpr std::optional<ChordFormula> with_replacement(
int removed,
int added)
const noexcept {
222 std::array<int, kMaxNotes> values{};
223 std::size_t
size = 0;
224 bool removed_existing =
false;
225 bool added_existing =
false;
226 for (std::size_t note = 0; note < count_; ++note) {
227 const int interval_value = intervals_[note];
228 if (!removed_existing && interval_value == removed) {
229 removed_existing =
true;
232 if (interval_value == added)
233 added_existing =
true;
234 values[
size++] = interval_value;
236 if (!added_existing) {
239 values[
size++] = added;
240 }
else if (!removed_existing) {
243 std::sort(values.begin(), values.begin() +
static_cast<std::ptrdiff_t
>(
size));
247 std::array<std::int8_t, kMaxNotes> intervals_{};
248 std::uint8_t count_ = 0;
249 std::optional<ChordQuality> quality_;
260 result.root_midi_ =
static_cast<std::uint8_t
>(
root_midi);
262 result.inversion_ =
static_cast<std::uint8_t
>(
inversion);
263 result.count_ =
static_cast<std::uint8_t
>(
formula.size());
266 for (std::size_t output = 0; output <
formula.size(); ++output) {
270 while (
pitch <= previous)
274 result.pitches_[output] =
static_cast<std::uint8_t
>(
pitch);
292 constexpr std::size_t
size() const noexcept {
295 constexpr std::optional<int>
pitch(std::size_t index)
const noexcept {
298 return pitches_[index];
302 std::uint16_t mask = 0;
303 for (std::size_t i = 0; i < count_; ++i)
304 mask =
static_cast<std::uint16_t
>(
309 constexpr std::optional<Chord>
transposed(
int semitones)
const noexcept {
310 const auto transposed_root =
static_cast<std::int64_t
>(root_midi_) + semitones;
311 if (transposed_root < 0 || transposed_root > 127)
313 return construct(
static_cast<int>(transposed_root), formula_, inversion_);
320 std::array<std::uint8_t, ChordFormula::kMaxNotes> pitches_{};
321 std::uint8_t root_midi_ = 0;
322 std::uint8_t count_ = 0;
323 std::uint8_t inversion_ = 0;
constexpr const ChordFormula & formula() const noexcept
Definition chord.hpp:286
constexpr PitchClassSet pitch_classes() const noexcept
Definition chord.hpp:301
constexpr std::optional< int > pitch(std::size_t index) const noexcept
Definition chord.hpp:295
constexpr PitchClass root_pitch_class() const noexcept
Definition chord.hpp:283
constexpr auto operator<=>(const Chord &) const =default
static constexpr std::optional< Chord > construct(int root_midi, const ChordFormula &formula, std::size_t inversion=0) noexcept
Definition chord.hpp:254
constexpr std::size_t size() const noexcept
Definition chord.hpp:292
constexpr std::optional< Chord > transposed(int semitones) const noexcept
Definition chord.hpp:309
constexpr int root_midi() const noexcept
Definition chord.hpp:280
constexpr std::size_t inversion() const noexcept
Definition chord.hpp:289
static constexpr std::optional< PitchClassSet > from_mask(std::uint16_t mask) noexcept
Definition pitch.hpp:60
constexpr std::size_t kChordQualityCount
Definition chord.hpp:31
constexpr PitchClass wrap_pitch_class(int index) noexcept
Definition pitch.hpp:44
ChordExtension
Definition chord.hpp:33
@ thirteenth
Definition chord.hpp:36
@ ninth
Definition chord.hpp:34
@ eleventh
Definition chord.hpp:35
constexpr std::array< ChordCompatibilityEntry, 11 > kForgeChordQualities
Definition chord.hpp:73
ChordSuspension
Definition chord.hpp:39
@ second
Definition chord.hpp:40
@ fourth
Definition chord.hpp:41
constexpr int kPitchClassesPerOctave
Definition pitch.hpp:16
PitchClass
Definition pitch.hpp:19
@ d
Definition pitch.hpp:22
@ f
Definition pitch.hpp:25
@ d_sharp
Definition pitch.hpp:23
@ e
Definition pitch.hpp:24
ChordAlteration
Definition chord.hpp:44
@ sharp_ninth
Definition chord.hpp:48
@ flat_thirteenth
Definition chord.hpp:50
@ flat_fifth
Definition chord.hpp:45
@ sharp_fifth
Definition chord.hpp:46
@ sharp_eleventh
Definition chord.hpp:49
@ flat_ninth
Definition chord.hpp:47
constexpr std::array< ChordCompatibilityEntry, 10 > kPulpTimelineChordQualities
Definition chord.hpp:59
ChordQuality
Definition chord.hpp:16
@ diminished
Definition chord.hpp:19
@ suspended2
Definition chord.hpp:25
@ suspended4
Definition chord.hpp:26
@ half_diminished7
Definition chord.hpp:24
@ power
Definition chord.hpp:27
@ augmented
Definition chord.hpp:20
@ octave
Definition chord.hpp:28
@ minor7
Definition chord.hpp:23
@ dominant7
Definition chord.hpp:21
@ minor
Definition chord.hpp:18
@ major7
Definition chord.hpp:22
@ major
Definition chord.hpp:17
ChordQuality quality
Definition chord.hpp:55
std::string_view stored_name
Definition chord.hpp:54