music-utils 1.0.2 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +9 -0
- data/README.md +12 -17
- data/Rakefile +7 -1
- data/benchmark/music-utils_bm.rb +16 -7
- data/lib/music-utils.rb +5 -0
- data/lib/music-utils/interval/interval.rb +22 -29
- data/lib/music-utils/note/note.rb +21 -0
- data/lib/music-utils/scales/scales.rb +104 -31
- data/lib/music-utils/version.rb +1 -1
- data/spec/interval/interval_spec.rb +6 -6
- data/spec/music-utils_spec.rb +268 -17
- metadata +9 -8
data/CHANGELOG.md
CHANGED
@@ -1,8 +1,17 @@
|
|
1
|
+
## 1.1.0 (May 19, 2011)
|
2
|
+
|
3
|
+
Features:
|
4
|
+
|
5
|
+
- Added functionality to create major and minor scales
|
6
|
+
- Minor performance improvement to qualify intervals
|
7
|
+
|
8
|
+
|
1
9
|
## 1.0.2 (May 12, 2011)
|
2
10
|
|
3
11
|
Features:
|
4
12
|
|
5
13
|
- Fixed do-sol bug
|
14
|
+
- Fixed bug on 6th number quality
|
6
15
|
|
7
16
|
|
8
17
|
## 1.0.1 (May 6, 2011)
|
data/README.md
CHANGED
@@ -1,30 +1,25 @@
|
|
1
1
|
music-utils
|
2
2
|
=========
|
3
3
|
|
4
|
-
Utils for music.
|
4
|
+
Utils for music. For now to classify music intervals and create scales.
|
5
5
|
|
6
6
|
Examples
|
7
7
|
--------
|
8
|
-
Simple intervals:
|
8
|
+
Simple and Compound intervals:
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
* MusicUtils.quality('do#', 'mi') #=> m (minor)
|
14
|
-
|
15
|
-
Compound intervals:
|
16
|
-
|
17
|
-
* MusicUtils.number('do', 'mi', 1) #=> 10 (10th)
|
18
|
-
* MusicUtils.semitones('do', 'mi', 1) #=> 16 (semi-tones)
|
19
|
-
* MusicUtils.quality('do', 'mi', 1) #=> M (major)
|
20
|
-
* MusicUtils.quality('dob', 'mi#', 1) #=> AA (augmented plus)
|
10
|
+
MusicUtils.number(:do, :mi) #=> 3 (3th)
|
11
|
+
MusicUtils.semitones(:do, :mi, 1) #=> 16 (semi-tones)
|
12
|
+
MusicUtils.quality(:do, :mi) #=> M (major)
|
21
13
|
|
22
14
|
Short Notation:
|
23
15
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
16
|
+
MusicUtils.short(:do, :re) #=> M2
|
17
|
+
MusicUtils.short(:do, :re, 1) #=> M9
|
18
|
+
|
19
|
+
Create scales:
|
20
|
+
|
21
|
+
MusicUtils.scale(:fa, MusicUtils::MAJ_SCALE) #=> [:fa, :sol, :la, :sib, :do, :re, :mi]
|
22
|
+
|
28
23
|
|
29
24
|
Installation
|
30
25
|
-----------
|
data/Rakefile
CHANGED
@@ -26,4 +26,10 @@ Bundler::GemHelper.install_tasks
|
|
26
26
|
desc "Clean automatically generated files"
|
27
27
|
task :clean do
|
28
28
|
FileUtils.rm_rf "pkg"
|
29
|
-
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# Profiler tasks
|
32
|
+
desc "Run profiler"
|
33
|
+
task :profile do
|
34
|
+
`ruby -w -rprofile benchmark/music-utils_bm.rb 10000`
|
35
|
+
end
|
data/benchmark/music-utils_bm.rb
CHANGED
@@ -4,27 +4,36 @@ require 'music-utils'
|
|
4
4
|
require 'music-utils/scales/scales'
|
5
5
|
require 'benchmark'
|
6
6
|
|
7
|
-
n =
|
7
|
+
n = (ARGV[0].to_i != 0) ? ARGV[0].to_i : 100000
|
8
8
|
label_width = 60
|
9
9
|
|
10
|
+
# Helper method to print benchmarks titles
|
11
|
+
def title(desc, n)
|
12
|
+
puts '-' * 105
|
13
|
+
puts desc + ' ' + n.to_s + ' times: '
|
14
|
+
end
|
15
|
+
|
16
|
+
# Benchmarks
|
17
|
+
|
18
|
+
title 'Classifying do-mi interval', n
|
10
19
|
Benchmark.bm(label_width) do |b|
|
11
|
-
b.report('
|
20
|
+
b.report('with strings (number):') do
|
12
21
|
n.times { MusicUtils.number('do', 'mi') }
|
13
22
|
end
|
14
|
-
b.report('
|
23
|
+
b.report('with strings (quality):') do
|
15
24
|
n.times { MusicUtils.quality('do', 'mi') }
|
16
25
|
end
|
17
|
-
b.report('
|
26
|
+
b.report('with strings (short notation):') do
|
18
27
|
n.times { MusicUtils.short('do', 'mi') }
|
19
28
|
end
|
20
29
|
|
21
|
-
b.report('
|
30
|
+
b.report('with scales (number):') do
|
22
31
|
n.times { MusicUtils.number(Scales::DO, Scales::MI) }
|
23
32
|
end
|
24
|
-
b.report('
|
33
|
+
b.report('with scales (quality):') do
|
25
34
|
n.times { MusicUtils.quality(Scales::DO, Scales::MI) }
|
26
35
|
end
|
27
|
-
b.report('
|
36
|
+
b.report('with scales (short notation):') do
|
28
37
|
n.times { MusicUtils.short(Scales::DO, Scales::MI) }
|
29
38
|
end
|
30
39
|
end
|
data/lib/music-utils.rb
CHANGED
@@ -1,30 +1,18 @@
|
|
1
1
|
require 'music-utils/scales/scales'
|
2
|
+
require 'music-utils/note/note'
|
2
3
|
|
3
|
-
# This class represents a music interval
|
4
4
|
module MusicUtils
|
5
5
|
|
6
|
+
# This class represents a music interval
|
6
7
|
class Interval
|
7
8
|
include Scales
|
8
9
|
|
9
10
|
def initialize(note1, note2, step)
|
10
|
-
|
11
|
-
|
12
|
-
n = 0
|
13
|
-
n += 1 if note1[0..2].to_sym == SOL
|
14
|
-
|
15
|
-
@note1 = note1[0..1 + n].to_sym
|
16
|
-
@note1_alt = note1[2 + n..3 + n]
|
17
|
-
|
18
|
-
# SOL is the only note of length = 3
|
19
|
-
n = 0
|
20
|
-
n += 1 if note2[0..2].to_sym == SOL
|
21
|
-
|
22
|
-
@note2 = note2[0..1 + n].to_sym
|
23
|
-
@note2_alt = note2[2 + n..3 + n]
|
24
|
-
|
11
|
+
@note1, @note1_alt = MusicUtils::Note.parse(note1)
|
12
|
+
@note2, @note2_alt = MusicUtils::Note.parse(note2)
|
25
13
|
@step = step
|
26
14
|
end
|
27
|
-
|
15
|
+
|
28
16
|
# It classifies the diatonic interval
|
29
17
|
def number
|
30
18
|
# initialize counter and index of scale
|
@@ -61,16 +49,20 @@ module MusicUtils
|
|
61
49
|
count = count + (12 * @step) if @step > 0
|
62
50
|
|
63
51
|
# counting notes alterations
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
52
|
+
case @note1_alt
|
53
|
+
when Scales::FLAT ; count += 1
|
54
|
+
when Scales::SHARP ; count -= 1
|
55
|
+
when Scales::DFLAT ; count += 2
|
56
|
+
when Scales::DSHARP ; count -= 2
|
57
|
+
end
|
58
|
+
|
59
|
+
case @note2_alt
|
60
|
+
when Scales::FLAT ; count -= 1
|
61
|
+
when Scales::SHARP ; count += 1
|
62
|
+
when Scales::DFLAT ; count -= 2
|
63
|
+
when Scales::DSHARP ; count += 2
|
64
|
+
end
|
65
|
+
|
74
66
|
count
|
75
67
|
end
|
76
68
|
|
@@ -90,10 +82,11 @@ module MusicUtils
|
|
90
82
|
|
91
83
|
# Common loop to search note 2
|
92
84
|
def until_find_note2(i)
|
85
|
+
length = DIATONIC_SCALE.length
|
93
86
|
# search note2
|
94
87
|
while DIATONIC_SCALE[i] != @note2
|
95
88
|
i += 1
|
96
|
-
if i >
|
89
|
+
if i > length
|
97
90
|
i = 0; next
|
98
91
|
end
|
99
92
|
yield i
|
@@ -112,7 +105,7 @@ module MusicUtils
|
|
112
105
|
def note1_index
|
113
106
|
DIATONIC_SCALE.index(@note1)
|
114
107
|
end
|
115
|
-
|
108
|
+
|
116
109
|
end
|
117
110
|
|
118
111
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module MusicUtils
|
2
|
+
|
3
|
+
# Represents a music note
|
4
|
+
class Note
|
5
|
+
|
6
|
+
# Parse notes to obtaining the raw note and its alterations separately
|
7
|
+
def self.parse(note)
|
8
|
+
n = 0
|
9
|
+
|
10
|
+
# SOL is the only note of length = 3
|
11
|
+
n += 1 if note[0..2].to_sym == MusicUtils::SOL
|
12
|
+
|
13
|
+
note_aux = note[0..1 + n].to_sym
|
14
|
+
note_alt = note[2 + n..3 + n]
|
15
|
+
|
16
|
+
[note_aux, note_alt]
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'music-utils/note/note'
|
2
|
+
|
1
3
|
# Scales module
|
2
4
|
module Scales
|
3
5
|
|
@@ -11,49 +13,54 @@ module Scales
|
|
11
13
|
SI = :si
|
12
14
|
|
13
15
|
DIATONIC_SCALE = [DO, RE, MI, FA, SOL, LA, SI]
|
14
|
-
|
16
|
+
|
15
17
|
# Alterations:
|
16
|
-
FLAT = '
|
18
|
+
FLAT = 'f'
|
17
19
|
DFLAT = FLAT + FLAT
|
18
|
-
SHARP = '
|
20
|
+
SHARP = 's'
|
19
21
|
DSHARP = SHARP + SHARP
|
20
22
|
|
21
23
|
# Altered notes
|
22
|
-
DOF = DO.to_s + FLAT
|
23
|
-
DOFF = DO.to_s + DFLAT
|
24
|
-
DOS = DO.to_s + SHARP
|
25
|
-
DOSS = DO.to_s + DSHARP
|
24
|
+
DOF = (DO.to_s + FLAT).to_sym
|
25
|
+
DOFF = (DO.to_s + DFLAT).to_sym
|
26
|
+
DOS = (DO.to_s + SHARP).to_sym
|
27
|
+
DOSS = (DO.to_s + DSHARP).to_sym
|
26
28
|
|
27
|
-
REF = RE.to_s + FLAT
|
28
|
-
REFF = RE.to_s + DFLAT
|
29
|
-
RES = RE.to_s + SHARP
|
30
|
-
RESS = RE.to_s + DSHARP
|
29
|
+
REF = (RE.to_s + FLAT).to_sym
|
30
|
+
REFF = (RE.to_s + DFLAT).to_sym
|
31
|
+
RES = (RE.to_s + SHARP).to_sym
|
32
|
+
RESS = (RE.to_s + DSHARP).to_sym
|
31
33
|
|
32
|
-
MIF = MI.to_s + FLAT
|
33
|
-
MIFF = MI.to_s + DFLAT
|
34
|
-
MIS = MI.to_s + SHARP
|
35
|
-
MISS = MI.to_s + DSHARP
|
34
|
+
MIF = (MI.to_s + FLAT).to_sym
|
35
|
+
MIFF = (MI.to_s + DFLAT).to_sym
|
36
|
+
MIS = (MI.to_s + SHARP).to_sym
|
37
|
+
MISS = (MI.to_s + DSHARP).to_sym
|
36
38
|
|
37
|
-
FAF = FA.to_s + FLAT
|
38
|
-
FAFF = FA.to_s + DFLAT
|
39
|
-
FAS = FA.to_s + SHARP
|
40
|
-
FASS = FA.to_s + DSHARP
|
39
|
+
FAF = (FA.to_s + FLAT).to_sym
|
40
|
+
FAFF = (FA.to_s + DFLAT).to_sym
|
41
|
+
FAS = (FA.to_s + SHARP).to_sym
|
42
|
+
FASS = (FA.to_s + DSHARP).to_sym
|
41
43
|
|
42
|
-
SOLF
|
43
|
-
SOLFF
|
44
|
-
SOLS
|
45
|
-
SOLSS
|
44
|
+
SOLF = (SOL.to_s + FLAT).to_sym
|
45
|
+
SOLFF = (SOL.to_s + DFLAT).to_sym
|
46
|
+
SOLS = (SOL.to_s + SHARP).to_sym
|
47
|
+
SOLSS = (SOL.to_s + DSHARP).to_sym
|
46
48
|
|
47
|
-
LAF = LA.to_s + FLAT
|
48
|
-
LAFF = LA.to_s + DFLAT
|
49
|
-
LAS = LA.to_s + SHARP
|
50
|
-
LASS = LA.to_s + DSHARP
|
49
|
+
LAF = (LA.to_s + FLAT).to_sym
|
50
|
+
LAFF = (LA.to_s + DFLAT).to_sym
|
51
|
+
LAS = (LA.to_s + SHARP).to_sym
|
52
|
+
LASS = (LA.to_s + DSHARP).to_sym
|
51
53
|
|
52
|
-
SIF = SI.to_s + FLAT
|
53
|
-
SIFF = SI.to_s + DFLAT
|
54
|
-
SIS = SI.to_s + SHARP
|
55
|
-
SISS = SI.to_s + DSHARP
|
54
|
+
SIF = (SI.to_s + FLAT).to_sym
|
55
|
+
SIFF = (SI.to_s + DFLAT).to_sym
|
56
|
+
SIS = (SI.to_s + SHARP).to_sym
|
57
|
+
SISS = (SI.to_s + DSHARP).to_sym
|
56
58
|
|
59
|
+
CROMATIC_SCALE = [[SIS, DO, REFF], [DOS, REF], [DOSS, RE, MIFF], [RES, MIF, FAFF], [RESS, MI, FAF], [MIS, FA, SOLFF], [MISS, FAS, SOLF], [FASS, SOL, LAFF], [SOLS, LAF], [SOLSS, LA, SIFF], [LAS, SIF], [LASS, SI, DOF]]
|
60
|
+
MAJ_SCALE = [2, 2, 1, 2, 2, 2, 1]
|
61
|
+
NATURAL_MIN_SCALE = [2, 1, 2, 2, 1, 2, 2]
|
62
|
+
MELODIC_MIN_SCALE = [2, 1, 2, 2, 1, 2, 1]
|
63
|
+
|
57
64
|
# Qualities
|
58
65
|
PERF = 'P'
|
59
66
|
MAJ = 'M'
|
@@ -73,5 +80,71 @@ module Scales
|
|
73
80
|
7 => {8 => DIMP, 9 => DIM, 10 => MIN, 11 => MAJ, 12 => AUG, 13 => AUGP},
|
74
81
|
8 => {10 => DIMP, 11 => DIM, 12 => PERF, 13 => AUG, 14 => AUGP}
|
75
82
|
}
|
83
|
+
|
84
|
+
# Create scale from a note and scale structure
|
85
|
+
def Scales.scale(from, scale_struct)
|
86
|
+
from = from.to_sym
|
87
|
+
|
88
|
+
i = 0
|
89
|
+
find_it = false
|
90
|
+
CROMATIC_SCALE.each do |e|
|
91
|
+
if e.is_a?(Array)
|
92
|
+
e.each do |ee|
|
93
|
+
find_it = true if from == ee
|
94
|
+
end
|
95
|
+
else
|
96
|
+
find_it = true if from == e
|
97
|
+
end
|
98
|
+
break if find_it
|
99
|
+
i += 1
|
100
|
+
end
|
101
|
+
|
102
|
+
scale = []
|
103
|
+
scale << from
|
104
|
+
|
105
|
+
from_note, from_alter = MusicUtils::Note.parse(from)
|
106
|
+
|
107
|
+
diatonic_scale = diatonic_scale_from(from_note)
|
108
|
+
diatonic_scale.delete(from_note)
|
109
|
+
|
110
|
+
length = CROMATIC_SCALE.length
|
111
|
+
|
112
|
+
scale_struct.each do |shift|
|
113
|
+
if i + shift > length - 1
|
114
|
+
i = (i + shift) - (length)
|
115
|
+
shift = 0
|
116
|
+
end
|
117
|
+
|
118
|
+
CROMATIC_SCALE[i + shift].each do |e|
|
119
|
+
e_note, e_alter = MusicUtils::Note.parse(e)
|
120
|
+
|
121
|
+
if diatonic_scale.first == e_note
|
122
|
+
scale << e
|
123
|
+
diatonic_scale.delete(diatonic_scale.first)
|
124
|
+
break
|
125
|
+
end
|
126
|
+
end
|
127
|
+
i += shift
|
128
|
+
end
|
129
|
+
|
130
|
+
scale
|
131
|
+
end
|
132
|
+
|
133
|
+
# Create a diatonic scale starting with the "from" note
|
134
|
+
def Scales.diatonic_scale_from(from)
|
135
|
+
diatonic_scale = []
|
136
|
+
length = DIATONIC_SCALE.length
|
137
|
+
i = DIATONIC_SCALE.index(from)
|
138
|
+
c = 0
|
139
|
+
while c < length
|
140
|
+
diatonic_scale << DIATONIC_SCALE[i]
|
141
|
+
i += 1
|
142
|
+
c += 1
|
143
|
+
if i > length - 1
|
144
|
+
i = 0
|
145
|
+
end
|
146
|
+
end
|
147
|
+
diatonic_scale
|
148
|
+
end
|
76
149
|
|
77
150
|
end
|
data/lib/music-utils/version.rb
CHANGED
@@ -27,7 +27,7 @@ describe MusicUtils::Interval do
|
|
27
27
|
end
|
28
28
|
|
29
29
|
it "simple interval dob-mi# should be 6 semitones" do
|
30
|
-
i = Interval.new('
|
30
|
+
i = Interval.new('dof', 'mis', 0)
|
31
31
|
i.semitones.should == 6
|
32
32
|
end
|
33
33
|
|
@@ -54,12 +54,12 @@ describe MusicUtils::Interval do
|
|
54
54
|
end
|
55
55
|
|
56
56
|
it "quality of interval do#-mi should be m" do
|
57
|
-
i = Interval.new('
|
57
|
+
i = Interval.new('dos', 'mi', 0)
|
58
58
|
i.quality.should == 'm'
|
59
59
|
end
|
60
60
|
|
61
61
|
it "quality of interval do#-mi should be m" do
|
62
|
-
i = Interval.new('
|
62
|
+
i = Interval.new('dos', 'mi', 0)
|
63
63
|
i.quality.should == 'm'
|
64
64
|
end
|
65
65
|
|
@@ -69,7 +69,7 @@ describe MusicUtils::Interval do
|
|
69
69
|
end
|
70
70
|
|
71
71
|
it "quality of compound interval dob-mi# should be AA" do
|
72
|
-
i = Interval.new('
|
72
|
+
i = Interval.new('dof', 'mis', 1)
|
73
73
|
i.quality.should == 'AA'
|
74
74
|
end
|
75
75
|
|
@@ -92,12 +92,12 @@ describe MusicUtils::Interval do
|
|
92
92
|
end
|
93
93
|
|
94
94
|
it "the short notation of do#-mi interval should be m3" do
|
95
|
-
i = Interval.new('
|
95
|
+
i = Interval.new('dos', 'mi', 0)
|
96
96
|
i.short.should == 'm3'
|
97
97
|
end
|
98
98
|
|
99
99
|
it "the short notation of do#-mi compound interval should be m10" do
|
100
|
-
i = Interval.new('
|
100
|
+
i = Interval.new('dos', 'mi', 1)
|
101
101
|
i.short.should == 'm10'
|
102
102
|
end
|
103
103
|
|
data/spec/music-utils_spec.rb
CHANGED
@@ -6,29 +6,131 @@ describe MusicUtils do
|
|
6
6
|
context "Intervals" do
|
7
7
|
|
8
8
|
context "By number" do
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
9
|
+
context "Diatonic from DO" do
|
10
|
+
it "the number of simple interval do-re should be a 2th" do
|
11
|
+
MusicUtils.number(DO, RE).should == 2
|
12
|
+
end
|
13
|
+
it "the number of do-re compound interval should be a 9th" do
|
14
|
+
MusicUtils.number(DO, RE, 1).should == 9
|
15
|
+
end
|
16
|
+
it "the number of simple interval do-mi should be a 3rd" do
|
17
|
+
MusicUtils.number(DO, MI).should == 3
|
18
|
+
end
|
19
|
+
it "the number of do-mi compound interval should be a 10th" do
|
20
|
+
MusicUtils.number(DO, MI, 1).should == 10
|
21
|
+
end
|
22
|
+
it "the number of simple interval do-fa should be a 4th" do
|
23
|
+
MusicUtils.number(DO, FA).should == 4
|
24
|
+
end
|
25
|
+
it "the number of do-fa compound interval should be a 11th" do
|
26
|
+
MusicUtils.number(DO, FA, 1).should == 11
|
27
|
+
end
|
28
|
+
it "the number of simple interval do-sol should be a 5th" do
|
29
|
+
MusicUtils.number(DO, SOL).should == 5
|
30
|
+
end
|
31
|
+
it "the number of do-sol compound interval should be a 12th" do
|
32
|
+
MusicUtils.number(DO, SOL, 1).should == 12
|
33
|
+
end
|
34
|
+
it "the number of simple interval do-la should be a 6th" do
|
35
|
+
MusicUtils.number(DO, LA).should == 6
|
36
|
+
end
|
37
|
+
it "the number of do-la compound interval should be a 13th" do
|
38
|
+
MusicUtils.number(DO, LA, 1).should == 13
|
39
|
+
end
|
40
|
+
it "the number of simple interval do-si should be a 7th" do
|
41
|
+
MusicUtils.number(DO, SI).should == 7
|
42
|
+
end
|
43
|
+
it "the number of do-si compound interval should be a 14th" do
|
44
|
+
MusicUtils.number(DO, SI, 1).should == 14
|
45
|
+
end
|
46
|
+
it "the number of simple interval do-do should be a 8th" do
|
47
|
+
MusicUtils.number(DO, DO).should == 8
|
48
|
+
end
|
49
|
+
it "the number of do-do compound interval should be a 15th" do
|
50
|
+
MusicUtils.number(DO, DO, 1).should == 15
|
51
|
+
end
|
14
52
|
end
|
15
53
|
end
|
16
54
|
|
17
|
-
context "By semitones" do
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
55
|
+
context "By semitones" do
|
56
|
+
context "Diatonic from DO" do
|
57
|
+
it "simple interval do-re should be 2 semitones" do
|
58
|
+
MusicUtils.semitones(DO, RE).should == 2
|
59
|
+
end
|
60
|
+
it "compound interval do-re should be 14 semitones" do
|
61
|
+
MusicUtils.semitones(DO, RE, 1).should == 14
|
62
|
+
end
|
63
|
+
it "simple interval do-mi should be 4 semitones" do
|
64
|
+
MusicUtils.semitones(DO, MI).should == 4
|
65
|
+
end
|
66
|
+
it "compound interval do-mi should be 16 semitones" do
|
67
|
+
MusicUtils.semitones(DO, MI, 1).should == 16
|
68
|
+
end
|
69
|
+
it "simple interval do-fa should be 5 semitones" do
|
70
|
+
MusicUtils.semitones(DO, FA).should == 5
|
71
|
+
end
|
72
|
+
it "compound interval do-fa should be 17 semitones" do
|
73
|
+
MusicUtils.semitones(DO, FA, 1).should == 17
|
74
|
+
end
|
75
|
+
it "simple interval do-sol should be 7 semitones" do
|
76
|
+
MusicUtils.semitones(DO, SOL).should == 7
|
77
|
+
end
|
78
|
+
it "compound interval do-sol should be 17 semitones" do
|
79
|
+
MusicUtils.semitones(DO, SOL, 1).should == 19
|
80
|
+
end
|
81
|
+
it "simple interval do-la should be 9 semitones" do
|
82
|
+
MusicUtils.semitones(DO, LA).should == 9
|
83
|
+
end
|
84
|
+
it "compound interval do-la should be 21 semitones" do
|
85
|
+
MusicUtils.semitones(DO, LA, 1).should == 21
|
86
|
+
end
|
87
|
+
it "simple interval do-si should be 11 semitones" do
|
88
|
+
MusicUtils.semitones(DO, SI).should == 11
|
89
|
+
end
|
90
|
+
it "compound interval do-si should be 21 semitones" do
|
91
|
+
MusicUtils.semitones(DO, SI, 1).should == 23
|
92
|
+
end
|
23
93
|
end
|
24
94
|
end
|
25
95
|
|
26
|
-
context "By quality" do
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
96
|
+
context "By quality" do
|
97
|
+
context "Diatonic from DO" do
|
98
|
+
it "quality of interval do-re should be M" do
|
99
|
+
MusicUtils.quality(DO, RE).should == 'M'
|
100
|
+
end
|
101
|
+
it "quality of compound interval do-re should be M" do
|
102
|
+
MusicUtils.quality(DO, RE, 1).should == 'M'
|
103
|
+
end
|
104
|
+
it "quality of interval do-mi should be M" do
|
105
|
+
MusicUtils.quality(DO, MI).should == 'M'
|
106
|
+
end
|
107
|
+
it "quality of compound interval do-mi should be M" do
|
108
|
+
MusicUtils.quality(DO, MI, 1).should == 'M'
|
109
|
+
end
|
110
|
+
it "quality of interval do-fa should be P" do
|
111
|
+
MusicUtils.quality(DO, FA).should == 'P'
|
112
|
+
end
|
113
|
+
it "quality of compound interval do-fa should be P" do
|
114
|
+
MusicUtils.quality(DO, FA, 1).should == 'P'
|
115
|
+
end
|
116
|
+
it "quality of interval do-sol should be P" do
|
117
|
+
MusicUtils.quality(DO, SOL).should == 'P'
|
118
|
+
end
|
119
|
+
it "quality of compound interval do-sol should be P" do
|
120
|
+
MusicUtils.quality(DO, SOL, 1).should == 'P'
|
121
|
+
end
|
122
|
+
it "quality of interval do-la should be m" do
|
123
|
+
MusicUtils.quality(DO, LA).should == 'm'
|
124
|
+
end
|
125
|
+
it "quality of compound interval do-la should be m" do
|
126
|
+
MusicUtils.quality(DO, LA, 1).should == 'm'
|
127
|
+
end
|
128
|
+
it "quality of interval do-si should be M" do
|
129
|
+
MusicUtils.quality(DO, SI).should == 'M'
|
130
|
+
end
|
131
|
+
it "quality of compound interval do-si should be M" do
|
132
|
+
MusicUtils.quality(DO, SI, 1).should == 'M'
|
133
|
+
end
|
32
134
|
end
|
33
135
|
end
|
34
136
|
|
@@ -43,4 +145,153 @@ describe MusicUtils do
|
|
43
145
|
|
44
146
|
end
|
45
147
|
|
148
|
+
context "Scales" do
|
149
|
+
context "Major scale" do
|
150
|
+
context "Natural notes" do
|
151
|
+
it "the major scale of DO should be [DO, RE, MI, FA, SOL, LA, SI, DO]" do
|
152
|
+
MusicUtils.scale(DO, MAJ_SCALE).should == [DO, RE, MI, FA, SOL, LA, SI]
|
153
|
+
end
|
154
|
+
it "the major scale of RE should be [RE, MI, FAS, SOL, LA, SI, DOS, RE]" do
|
155
|
+
MusicUtils.scale(RE, MAJ_SCALE).should == [RE, MI, FAS, SOL, LA, SI, DOS]
|
156
|
+
end
|
157
|
+
it "the major scale of MI should be [MI, FAS, SOLS, LA, SI, DOS, RES, MI]" do
|
158
|
+
MusicUtils.scale(MI, MAJ_SCALE).should == [MI, FAS, SOLS, LA, SI, DOS, RES]
|
159
|
+
end
|
160
|
+
it "the major scale of FA should be [FA, SOL, LA, SIF, DO, RE, MI, FA]" do
|
161
|
+
MusicUtils.scale(FA, MAJ_SCALE).should == [FA, SOL, LA, SIF, DO, RE, MI]
|
162
|
+
end
|
163
|
+
it "the major scale of SOL should be [SOL, LA, SI, DO, RE, MI, FAS, SOL]" do
|
164
|
+
MusicUtils.scale(SOL, MAJ_SCALE).should == [SOL, LA, SI, DO, RE, MI, FAS]
|
165
|
+
end
|
166
|
+
it "the major scale of LA should be [LA, SI, DOS, RE, MI, FAS, SOLS, LA]" do
|
167
|
+
MusicUtils.scale(LA, MAJ_SCALE).should == [LA, SI, DOS, RE, MI, FAS, SOLS]
|
168
|
+
end
|
169
|
+
it "the major scale of SI should be [SI, DOS, RES, MI, FAS, SOLS, LAS, SI]" do
|
170
|
+
MusicUtils.scale(SI, MAJ_SCALE).should == [SI, DOS, RES, MI, FAS, SOLS, LAS]
|
171
|
+
end
|
172
|
+
end
|
173
|
+
context "Sharped notes" do
|
174
|
+
it "the major scale of DO# should be [DOS, RES, MIS, FAS, SOLS, LAS, SIS]" do
|
175
|
+
MusicUtils.scale(DOS, MAJ_SCALE).should == [DOS, RES, MIS, FAS, SOLS, LAS, SIS]
|
176
|
+
end
|
177
|
+
it "the major scale of RE# should be [RES, MIS, FASS, SOLS, LAS, SIS, DOSS]" do
|
178
|
+
MusicUtils.scale(RES, MAJ_SCALE).should == [RES, MIS, FASS, SOLS, LAS, SIS, DOSS]
|
179
|
+
end
|
180
|
+
it "the major scale of MI# should be [MIS, FASS, SOLSS, LAS, SIS, DOSS, RESS]" do
|
181
|
+
MusicUtils.scale(MIS, MAJ_SCALE).should == [MIS, FASS, SOLSS, LAS, SIS, DOSS, RESS]
|
182
|
+
end
|
183
|
+
it "the major scale of FA# should be [FAS, SOLS, LAS, SI, DOS, RES, MISS]" do
|
184
|
+
MusicUtils.scale(FAS, MAJ_SCALE).should == [FAS, SOLS, LAS, SI, DOS, RES, MIS]
|
185
|
+
end
|
186
|
+
it "the major scale of SOL# should be [SOLS, LAS, SIS, DOS, RES, MIS, FASS]" do
|
187
|
+
MusicUtils.scale(SOLS, MAJ_SCALE).should == [SOLS, LAS, SIS, DOS, RES, MIS, FASS]
|
188
|
+
end
|
189
|
+
it "the major scale of LA# should be [SOLS, LAS, SIS, DOS, RES, MIS, FASS]" do
|
190
|
+
MusicUtils.scale(LAS, MAJ_SCALE).should == [LAS, SIS, DOSS, RES, MIS, FASS, SOLSS]
|
191
|
+
end
|
192
|
+
it "the major scale of SI# should be [SIS, DOSS, RESS, MIS, FASS, SOLSS, LASS]" do
|
193
|
+
MusicUtils.scale(SIS, MAJ_SCALE).should == [SIS, DOSS, RESS, MIS, FASS, SOLSS, LASS]
|
194
|
+
end
|
195
|
+
end
|
196
|
+
context "Flated notes" do
|
197
|
+
it "the major scale of DOb should be [DOF, REF, MIF, FAF, SOLF, LAF, SIF]" do
|
198
|
+
MusicUtils.scale(DOF, MAJ_SCALE).should == [DOF, REF, MIF, FAF, SOLF, LAF, SIF]
|
199
|
+
end
|
200
|
+
it "the major scale of REb should be [REF, MIF, FA, SOLF, LAF, SIF, DO]" do
|
201
|
+
MusicUtils.scale(REF, MAJ_SCALE).should == [REF, MIF, FA, SOLF, LAF, SIF, DO]
|
202
|
+
end
|
203
|
+
it "the major scale of MIb should be [MIF, FA, SOL, LAF, SIF, DO, RE]" do
|
204
|
+
MusicUtils.scale(MIF, MAJ_SCALE).should == [MIF, FA, SOL, LAF, SIF, DO, RE]
|
205
|
+
end
|
206
|
+
it "the major scale of FAb should be [FAF, SOLF, LAF, SIFF, DOF, REF, MIF]" do
|
207
|
+
MusicUtils.scale(FAF, MAJ_SCALE).should == [FAF, SOLF, LAF, SIFF, DOF, REF, MIF]
|
208
|
+
end
|
209
|
+
it "the major scale of SOLb should be [SOLF, LAF, SIF, DOF, REF, MIF, FA]" do
|
210
|
+
MusicUtils.scale(SOLF, MAJ_SCALE).should == [SOLF, LAF, SIF, DOF, REF, MIF, FA]
|
211
|
+
end
|
212
|
+
it "the major scale of LAb should be [LAF, SIF, DO, REF, MIF, FA, SOL]" do
|
213
|
+
MusicUtils.scale(LAF, MAJ_SCALE).should == [LAF, SIF, DO, REF, MIF, FA, SOL]
|
214
|
+
end
|
215
|
+
it "the major scale of SIb should be [SIF, DO, RE, MIF, FA, SOL, LA]" do
|
216
|
+
MusicUtils.scale(SIF, MAJ_SCALE).should == [SIF, DO, RE, MIF, FA, SOL, LA]
|
217
|
+
end
|
218
|
+
end
|
219
|
+
context "Natural Minor scale" do
|
220
|
+
# [2, 1, 2, 2, 1, 2]
|
221
|
+
context "Natural notes" do
|
222
|
+
it "the natural minor scale of DO should be [DO, RE, MIF, FA, SOL, LAF, SIF]" do
|
223
|
+
MusicUtils.scale(DO, NATURAL_MIN_SCALE).should == [DO, RE, MIF, FA, SOL, LAF, SIF]
|
224
|
+
end
|
225
|
+
it "the natural minor scale of RE should be [RE, MI, FA, SOL, LA, SIF, DO]" do
|
226
|
+
MusicUtils.scale(RE, NATURAL_MIN_SCALE).should == [RE, MI, FA, SOL, LA, SIF, DO]
|
227
|
+
end
|
228
|
+
it "the natural minor scale of MI should be [MI, FAS, SOL, LA, SI, DO, RE]" do
|
229
|
+
MusicUtils.scale(MI, NATURAL_MIN_SCALE).should == [MI, FAS, SOL, LA, SI, DO, RE]
|
230
|
+
end
|
231
|
+
it "the natural minor scale of FA should be [FA, SOL, LAF, SIF, DO, REF, MIF]" do
|
232
|
+
MusicUtils.scale(FA, NATURAL_MIN_SCALE).should == [FA, SOL, LAF, SIF, DO, REF, MIF]
|
233
|
+
end
|
234
|
+
it "the natural minor scale of SOL should be [SOL, LA, SIF, DO, RE, MIF, FA]" do
|
235
|
+
MusicUtils.scale(SOL, NATURAL_MIN_SCALE).should == [SOL, LA, SIF, DO, RE, MIF, FA]
|
236
|
+
end
|
237
|
+
it "the natural minor scale of LA should be [LA, SI, DO, RE, MI, FA, SOL]" do
|
238
|
+
MusicUtils.scale(LA, NATURAL_MIN_SCALE).should == [LA, SI, DO, RE, MI, FA, SOL]
|
239
|
+
end
|
240
|
+
it "the natural minor scale of SI should be [SI, DOS, RES, MI, FAS, SOLS, LAS, SI]" do
|
241
|
+
MusicUtils.scale(SI, NATURAL_MIN_SCALE).should == [SI, DOS, RE, MI, FAS, SOL, LA]
|
242
|
+
end
|
243
|
+
end
|
244
|
+
# [2, 1, 2, 2, 1, 2]
|
245
|
+
context "Sharped notes" do
|
246
|
+
it "the natural minor scale of DO# should be [DO, RE, MIF, FA, SOL, LAF, SIF]" do
|
247
|
+
MusicUtils.scale(DOS, NATURAL_MIN_SCALE).should == [DOS, RES, MI, FAS, SOLS, LA, SI]
|
248
|
+
end
|
249
|
+
it "the natural minor scale of RE# should be [RE, MI, FA, SOL, LA, SIF, DO]" do
|
250
|
+
MusicUtils.scale(RES, NATURAL_MIN_SCALE).should == [RES, MIS, FAS, SOLS, LAS, SI, DOS]
|
251
|
+
end
|
252
|
+
it "the natural minor scale of MI# should be [MI, FAS, SOL, LA, SI, DO, RE]" do
|
253
|
+
MusicUtils.scale(MIS, NATURAL_MIN_SCALE).should == [MIS, FASS, SOLS, LAS, SIS, DOS, RES]
|
254
|
+
end
|
255
|
+
it "the natural minor scale of FA# should be [FA, SOL, LAF, SIF, DO, REF, MIF]" do
|
256
|
+
MusicUtils.scale(FAS, NATURAL_MIN_SCALE).should == [FAS, SOLS, LA, SI, DOS, RE, MI]
|
257
|
+
end
|
258
|
+
it "the natural minor scale of SOL# should be [SOL, LA, SIF, DO, RE, MIF, FA]" do
|
259
|
+
MusicUtils.scale(SOLS, NATURAL_MIN_SCALE).should == [SOLS, LAS, SI, DOS, RES, MI, FAS]
|
260
|
+
end
|
261
|
+
it "the natural minor scale of LA# should be [LA, SI, DO, RE, MI, FA, SOL]" do
|
262
|
+
MusicUtils.scale(LAS, NATURAL_MIN_SCALE).should == [LAS, SIS, DOS, RES, MIS, FAS, SOLS]
|
263
|
+
end
|
264
|
+
it "the natural minor scale of SI# should be [SI, DOS, RES, MI, FAS, SOLS, LAS, SI]" do
|
265
|
+
MusicUtils.scale(SIS, NATURAL_MIN_SCALE).should == [SIS, DOSS, RES, MIS, FASS, SOLS, LAS]
|
266
|
+
end
|
267
|
+
end
|
268
|
+
# [2, 1, 2, 2, 1, 2]
|
269
|
+
context "Flated notes" do
|
270
|
+
it "the natural minor scale of DOb should be [DOF, REF, MIFF, FAF, SOLF, LAFF, SIFF]" do
|
271
|
+
MusicUtils.scale(DOF, NATURAL_MIN_SCALE).should == [DOF, REF, MIFF, FAF, SOLF, LAFF, SIFF]
|
272
|
+
end
|
273
|
+
it "the natural minor scale of REb should be [REF, MIF, FAF, SOLF, LAF, SIFF, DOF]" do
|
274
|
+
MusicUtils.scale(REF, NATURAL_MIN_SCALE).should == [REF, MIF, FAF, SOLF, LAF, SIFF, DOF]
|
275
|
+
end
|
276
|
+
it "the natural minor scale of MIb should be [MIF, FA, SOLF, LAF, SIF, DOF, REF]" do
|
277
|
+
MusicUtils.scale(MIF, NATURAL_MIN_SCALE).should == [MIF, FA, SOLF, LAF, SIF, DOF, REF]
|
278
|
+
end
|
279
|
+
it "the natural minor scale of FAb should be [FAF, SOLF, LAFF, SIFF, DOF, REFF, MIFF]" do
|
280
|
+
MusicUtils.scale(FAF, NATURAL_MIN_SCALE).should == [FAF, SOLF, LAFF, SIFF, DOF, REFF, MIFF]
|
281
|
+
end
|
282
|
+
it "the natural minor scale of SOLb should be [SOLF, LAF, SIFF, DOF, REF, MIFF, FAF]" do
|
283
|
+
MusicUtils.scale(SOLF, NATURAL_MIN_SCALE).should == [SOLF, LAF, SIFF, DOF, REF, MIFF, FAF]
|
284
|
+
end
|
285
|
+
it "the natural minor scale of LAb should be [LAF, SIF, DOF, REF, MIF, FAF, SOLF]" do
|
286
|
+
MusicUtils.scale(LAF, NATURAL_MIN_SCALE).should == [LAF, SIF, DOF, REF, MIF, FAF, SOLF]
|
287
|
+
end
|
288
|
+
it "the natural minor scale of SIb should be [SIF, DO, REF, MIF, FA, SOLF, LAF]" do
|
289
|
+
MusicUtils.scale(SIF, NATURAL_MIN_SCALE).should == [SIF, DO, REF, MIF, FA, SOLF, LAF]
|
290
|
+
end
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
46
297
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: music-utils
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0
|
4
|
+
version: 1.1.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2011-05-
|
12
|
+
date: 2011-05-19 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rake
|
16
|
-
requirement: &
|
16
|
+
requirement: &75690210 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '0.8'
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *75690210
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: bundler
|
27
|
-
requirement: &
|
27
|
+
requirement: &75690020 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :development
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *75690020
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: rspec
|
38
|
-
requirement: &
|
38
|
+
requirement: &75689790 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,7 +43,7 @@ dependencies:
|
|
43
43
|
version: '0'
|
44
44
|
type: :development
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *75689790
|
47
47
|
description: Utils for music. At the moment only to classify intervals.
|
48
48
|
email:
|
49
49
|
- jorgeluis700@gmail.com
|
@@ -60,6 +60,7 @@ files:
|
|
60
60
|
- benchmark/music-utils_bm.rb
|
61
61
|
- lib/music-utils.rb
|
62
62
|
- lib/music-utils/interval/interval.rb
|
63
|
+
- lib/music-utils/note/note.rb
|
63
64
|
- lib/music-utils/scales/scales.rb
|
64
65
|
- lib/music-utils/version.rb
|
65
66
|
- music-utils.gemspec
|