music_note/scale/
mod.rs

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    /// ```
78    /// use music_note::{midi, Note, Scale};
79    ///
80    /// // C major
81    /// let scale = Scale::major(midi!(C, 4));
82    ///
83    /// assert!(scale.eq([
84    ///     midi!(C, 4),
85    ///     midi!(D, 4),
86    ///     midi!(E, 4),
87    ///     midi!(F, 4),
88    ///     midi!(G, 4),
89    ///     midi!(A, 4),
90    ///     midi!(B, 4),
91    /// ]));
92    /// ```
93    pub fn major(root: T) -> Self {
94        Self::diatonic(root, ScaleIntervals::major())
95    }
96
97    /// ```
98    /// use music_note::{Natural, Note, Scale};
99    ///
100    /// // B natural minor
101    /// let scale = Scale::natural_minor(Note::from(Natural::B));
102    ///
103    /// assert!(scale.eq([
104    ///     Note::from(Natural::B),
105    ///     Note::sharp(Natural::C),
106    ///     Note::from(Natural::D),
107    ///     Note::from(Natural::E),
108    ///     Note::sharp(Natural::F),
109    ///     Note::from(Natural::G),
110    ///     Note::from(Natural::A),
111    /// ]));
112    /// ```
113    pub fn natural_minor(root: T) -> Self {
114        Self::diatonic(root, ScaleIntervals::natural_minor())
115    }
116
117    /// ```
118    /// use music_note::{Natural, Note, Scale};
119    ///
120    /// // A harmonic minor
121    /// let scale = Scale::harmonic_minor(Note::from(Natural::A));
122    ///
123    /// assert!(scale.eq([
124    ///     Note::from(Natural::A),
125    ///     Note::from(Natural::B),
126    ///     Note::from(Natural::C),
127    ///     Note::from(Natural::D),
128    ///     Note::from(Natural::E),
129    ///     Note::from(Natural::F),
130    ///     Note::sharp(Natural::G),
131    /// ]));
132    /// ```
133    pub fn harmonic_minor(root: T) -> Self {
134        Self::diatonic(root, ScaleIntervals::harmonic_minor())
135    }
136
137    /// ```
138    /// use music_note::{Natural, Note, Scale};
139    ///
140    /// // E melodic minor
141    /// let scale = Scale::melodic_minor(Note::from(Natural::E));
142    ///
143    /// assert!(scale.eq([
144    ///     Note::from(Natural::E),
145    ///     Note::sharp(Natural::F),
146    ///     Note::from(Natural::G),
147    ///     Note::from(Natural::A),
148    ///     Note::from(Natural::B),
149    ///     Note::sharp(Natural::C),
150    ///     Note::sharp(Natural::D),
151    /// ]));
152    /// ```
153    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}