-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathcomposition.hpp
210 lines (176 loc) · 5.79 KB
/
composition.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
#ifndef SGR_COMPOSITION_HPP
#define SGR_COMPOSITION_HPP
/**
* @file composition.hpp
* Contains the logic to compose song instances.
*
* @author Gašper Ažman, gasper.azman@gmail.com
* @since 2012-02-05
*/
#include "math.hpp"
#include "units.hpp"
#include <boost/assign/std/vector.hpp>
#include <utility>
#include <map>
namespace sgr {
namespace composition {
/// a chord is a series of tone-offsets relative to a scale.
/// for instance, 0, 2, 4 (1, 3, 5) is the usual chord, that, when played in a
/// major scale, gives a major chord.
typedef std::vector<units::scale_offset> chord;
typedef std::vector<units::interval> intervals_type;
typedef std::vector<units::tone> tones_type;
class scale {
std::vector<units::interval> offsets;
public:
scale()
: offsets() {}
template<typename Arg>
scale(Arg&& offsets)
: offsets(std::forward<Arg>(offsets))
{}
scale(scale&& sc)
: offsets(std::move(sc.offsets))
{}
/**
* Get an interval from a scale.
*
* @param interval the offset within the scale. If you want the basenote,
* put in 0. If you want the second note, put in 1. If you want the last
* note, but one octave down, put in -1.
*
* @return the interval that this scale offset represents.
*/
units::interval
interval(const units::scale_offset& offset) const
{
auto n = offsets.size();
int octaves = offset.value / n;
int r = offset.value % n;
if (r < 0) {
r += n;
octaves -= 1;
}
return units::interval{octaves, offsets[r]};
}
/**
* Accessor for offsets - provides a periodic view of the scale.
* Negative offsets will go from the end of the scale, positive offsets from
* the beginning.
*/
units::scale_offset
offset(const units::scale_offset& offset) const
{
int o = offset.value % int(offsets.size());
if (o < 0) { o += offsets.size(); }
return units::scale_offset{o};
}
/**
* Get intervals from a chord.
*
* @param ch the chord to convert to notes.
*
* @return the intervals.
*/
intervals_type
intervals(const chord& ch)
{
intervals_type t;
for (auto i : ch) {
t.emplace_back(interval(i));
}
return t;
}
size_t size() const { return offsets.size(); }
};
/**
* Returns the nth mode of the scale sc.
*/
scale mode(const scale& sc, const units::scale_offset& n)
{
auto first = sc.interval(n);
auto size = sc.size();
intervals_type newscale;
for (unsigned int i = 0; i < size; ++i) {
newscale.emplace_back(sc.interval(n + units::scale_offset{i}) - first);
}
return scale{std::move(newscale)};
}
//namespace rhythm {
///**
// * Holds a passage of hits.
// */
//struct bar {
// bar() : hits_(), length_(0) {}
// bar& operator<<(const hit& h)
// {
// if (h.start + h.duration > length_) {
// length_ = h.start + h.duration;
// }
// hits_.push_back(h);
// return *this;
// }
// double length() const { return length_; }
// const std::vector<hit>& hits() const { return hits_; }
//private:
// std::vector<hit> hits_;
// double length_;
//};
//} /* end namespace rhythm */
std::vector<units::interval>
to_intervals(const std::initializer_list<double>& offs) {
std::vector<units::interval> sc;
for (auto n : offs) {
sc.emplace_back(units::interval{n});
}
return sc;
}
class resources
{
private:
std::map<std::string, scale> scales_;
std::map<std::string, chord> chords_;
public:
resources()
: scales_()
, chords_()
{
typedef std::vector<double> sc_t;
using units::scale_offset;
using namespace boost::assign; // for operator+=() on vector
// diatonics
scales_["ionian"] = scale(to_intervals({0.,2.,4.,5.,7.,9.,11.}));
scales_["dorian"] = mode(scales_["ionian"], scale_offset{2});
scales_["phrygian"] = mode(scales_["ionian"], scale_offset{3});
scales_["lydian"] = mode(scales_["ionian"], scale_offset{4});
scales_["mixolydian"] = mode(scales_["ionian"], scale_offset{5});
scales_["aeolian"] = mode(scales_["ionian"], scale_offset{6});
scales_["locrian"] = mode(scales_["ionian"], scale_offset{7});
// variations on the minor
// 1 2 3 4 5 6 7
// C D E F G A H
// ionian: 0 2 4 5 7 9 11
// aeolian: 0 2 3 5 7 8 10
scales_["harmonic minor"] = scale(to_intervals({0.,2.,3.,5.,7.,8.,11.}));
scales_["hungarian minor"] = scale(to_intervals({0.,2.,3.,6.,7.,8.,11.}));
scales_["melodic minor"] = scale(to_intervals({0.,2.,3.,5.,7.,9.,11.}));
scales_["double harmonic"] = scale(to_intervals({0.,1.,3.,4.,7.,8.,11.}));
scales_["arabic harmonic"] = scale(to_intervals({0.,0.5,3.,4.,7.,8.,11.5}));
scales_["hungarian gypsy"] = mode(scales_["double harmonic"], scale_offset{4});
scales_["pentatonic minor"] = scale(to_intervals({0.,3.,5.,7.,10.}));
scales_["pentatonic major"] = mode(scales_["pentatonic minor"], scale_offset{2});
scales_["pentatonic egyptian"] = mode(scales_["pentatonic minor"], scale_offset{3});
scales_["pentatonic blues major"]= mode(scales_["pentatonic minor"], scale_offset{4});
scales_["pentatonic blues minor"]= mode(scales_["pentatonic minor"], scale_offset{5});
chords_["trichord"] = chord({scale_offset{0}, scale_offset{2}, scale_offset{4}});
}
inline
const std::map<std::string, scale>&
scales() { return scales_; }
inline
const std::map<std::string, chord>&
chords() { return chords_; }
};
}/* end namespace composition */
}/* end namespace sgr */
#endif