music-utils 1.0.2 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|