1use crate::set::Set;
2use crate::Interval;
3use core::ops::Add;
4
5mod degree;
6pub use degree::Degree;
7
8pub type ScaleIntervals = Set<Interval, u16>;
9
10impl ScaleIntervals {
11 pub fn major() -> Self {
12 Self::from_iter([
13 Interval::UNISON,
14 Interval::MAJOR_SECOND,
15 Interval::MAJOR_THIRD,
16 Interval::PERFECT_FOURTH,
17 Interval::PERFECT_FIFTH,
18 Interval::MAJOR_SIXTH,
19 Interval::MAJOR_SEVENTH,
20 ])
21 }
22
23 pub fn natural_minor() -> Self {
24 Self::from_iter([
25 Interval::UNISON,
26 Interval::MAJOR_SECOND,
27 Interval::MINOR_THIRD,
28 Interval::PERFECT_FOURTH,
29 Interval::PERFECT_FIFTH,
30 Interval::MINOR_SIXTH,
31 Interval::MINOR_SEVENTH,
32 ])
33 }
34
35 pub fn harmonic_minor() -> Self {
36 Self::from_iter([
37 Interval::UNISON,
38 Interval::MAJOR_SECOND,
39 Interval::MINOR_THIRD,
40 Interval::PERFECT_FOURTH,
41 Interval::PERFECT_FIFTH,
42 Interval::MINOR_SIXTH,
43 Interval::MAJOR_SEVENTH,
44 ])
45 }
46
47 pub fn melodic_minor() -> Self {
48 Self::from_iter([
49 Interval::UNISON,
50 Interval::MAJOR_SECOND,
51 Interval::MINOR_THIRD,
52 Interval::PERFECT_FOURTH,
53 Interval::PERFECT_FIFTH,
54 Interval::MAJOR_SIXTH,
55 Interval::MAJOR_SEVENTH,
56 ])
57 }
58
59 pub fn blues() -> Self {
60 Self::from_iter([
61 Interval::UNISON,
62 Interval::MINOR_THIRD,
63 Interval::PERFECT_FOURTH,
64 Interval::TRITONE,
65 Interval::PERFECT_FIFTH,
66 Interval::MINOR_SEVENTH,
67 ])
68 }
69}
70
71pub type DiatonicScale<T> = Scale<T, Diatonic<T, ScaleIntervals>>;
72
73impl<T> DiatonicScale<T>
74where
75 T: Degree + Clone,
76{
77 pub fn major(root: T) -> Self {
94 Self::diatonic(root, ScaleIntervals::major())
95 }
96
97 pub fn natural_minor(root: T) -> Self {
114 Self::diatonic(root, ScaleIntervals::natural_minor())
115 }
116
117 pub fn harmonic_minor(root: T) -> Self {
134 Self::diatonic(root, ScaleIntervals::harmonic_minor())
135 }
136
137 pub fn melodic_minor(root: T) -> Self {
154 Self::diatonic(root, ScaleIntervals::melodic_minor())
155 }
156}
157
158pub struct Diatonic<T: Degree, U> {
159 state: T::State,
160 intervals: U,
161}
162
163impl<T, U> Diatonic<T, U>
164where
165 T: Degree,
166{
167 pub fn new(root: T, intervals: U) -> Self {
168 Self {
169 state: root.state(),
170 intervals,
171 }
172 }
173}
174
175pub struct Scale<T, U> {
176 root: T,
177 intervals: U,
178}
179
180impl<T, U> Scale<T, U> {
181 pub fn new(root: T, intervals: U) -> Self {
182 Self { root, intervals }
183 }
184}
185
186impl<T, U> Scale<T, Diatonic<T, U>>
187where
188 T: Degree + Clone,
189{
190 pub fn diatonic(root: T, intervals: U) -> Self {
191 Self::new(root.clone(), Diatonic::new(root, intervals))
192 }
193}
194
195impl<T> Scale<T, ScaleIntervals> {
196 pub fn blues(root: T) -> Self {
197 Self::new(root, ScaleIntervals::blues())
198 }
199}
200
201impl<T, U> Iterator for Scale<T, U>
202where
203 T: Add<Interval> + Clone,
204 U: Iterator<Item = Interval>,
205{
206 type Item = T::Output;
207
208 fn next(&mut self) -> Option<Self::Item> {
209 self.intervals
210 .next()
211 .map(|interval| self.root.clone() + interval)
212 }
213}
214
215impl<T, U> Iterator for Scale<T, Diatonic<T, U>>
216where
217 T: Degree + Clone,
218 U: Iterator<Item = Interval>,
219{
220 type Item = T;
221
222 fn next(&mut self) -> Option<Self::Item> {
223 self.intervals.intervals.next().map(|interval| {
224 self.root
225 .clone()
226 .degree(&mut self.intervals.state, interval)
227 })
228 }
229}
230
231#[cfg(test)]
232mod tests {
233 use crate::{Natural, Note, Scale};
234
235 #[test]
236 fn test_g_flat_major() {
237 let scale = Scale::major(Note::flat(Natural::G));
238
239 assert!(scale.eq([
240 Note::flat(Natural::G),
241 Note::flat(Natural::A),
242 Note::flat(Natural::B),
243 Note::flat(Natural::C),
244 Note::flat(Natural::D),
245 Note::flat(Natural::E),
246 Note::from(Natural::F),
247 ]))
248 }
249
250 #[test]
251 fn test_f_sharp_major() {
252 let scale = Scale::major(Note::sharp(Natural::F));
253
254 assert!(scale.eq([
255 Note::sharp(Natural::F),
256 Note::sharp(Natural::G),
257 Note::sharp(Natural::A),
258 Note::from(Natural::B),
259 Note::sharp(Natural::C),
260 Note::sharp(Natural::D),
261 Note::sharp(Natural::E),
262 ]))
263 }
264
265 #[test]
266 fn test_c_sharp_major() {
267 let scale = Scale::major(Note::sharp(Natural::C));
268
269 assert!(scale.eq([
270 Note::sharp(Natural::C),
271 Note::sharp(Natural::D),
272 Note::sharp(Natural::E),
273 Note::sharp(Natural::F),
274 Note::sharp(Natural::G),
275 Note::sharp(Natural::A),
276 Note::sharp(Natural::B),
277 ]))
278 }
279}