music-utils 0.5.2 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -2,4 +2,7 @@
2
2
  .redcar/
3
3
 
4
4
  # build directory
5
- pkg/
5
+ pkg/
6
+
7
+ # Gems
8
+ Gemfile.lock
data/CHANGELOG.md CHANGED
@@ -1,3 +1,18 @@
1
+ ## 1.0.0 (May 6, 2011)
2
+
3
+ Features:
4
+
5
+ - Added MusicUtils module
6
+ - New shortcuts for clasify intervals on MusicUtils module
7
+
8
+
9
+ ## 0.5.2 (April 29, 2011)
10
+
11
+ Features:
12
+
13
+ - Extracted some common logic into helper methods
14
+
15
+
1
16
  ## 0.5.1 (April 27, 2011)
2
17
 
3
18
  Features:
data/Gemfile CHANGED
@@ -1,3 +1,2 @@
1
1
  source "http://rubygems.org"
2
- gem "rake", ' ~> 0.8'
3
- gem "rspec", '~> 2.5'
2
+ gemspec
data/README.md CHANGED
@@ -1,30 +1,35 @@
1
1
  music-utils
2
2
  =========
3
3
 
4
- Utils for music. At the moment only one class to classify intervals.
4
+ Utils for music. At the moment only to classify interval.
5
5
 
6
6
  Examples
7
7
  --------
8
8
  Simple intervals:
9
9
 
10
- * Interval.new('do', 'mi', 0).number #=> 3 (3th)
11
- * Interval.new('do', 'mi', 0).semitone #=> 4 (semi-tones)
12
- * Interval.new('do', 'mi', 0).quality #=> M (major)
13
- * Interval.new('do#', 'mi', 0).quality #=> m (minor)
10
+ * MusicUtils.number('do', 'mi') #=> 3 (3th)
11
+ * MusicUtils.semitones('do', 'mi') #=> 4 (semi-tones)
12
+ * MusicUtils.quality('do', 'mi') #=> M (major)
13
+ * MusicUtils.quality('do#', 'mi') #=> m (minor)
14
14
 
15
15
  Compound intervals:
16
16
 
17
- * Interval.new('do', 'mi', 1).number #=> 10 (10th)
18
- * Interval.new('do', 'mi', 1).semitone #=> 16 (semi-tones)
19
- * Interval.new('do', 'mi', 1).quality #=> M (major)
20
- * Interval.new('dob', 'mi#', 1).quality #=> AA (augmented plus)
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)
21
21
 
22
22
  Short Notation:
23
23
 
24
- * Interval.new('do', 're', 0).short #=> M2
25
- * Interval.new('do', 're', 1).short #=> M9
26
- * Interval.new('do#', 'mi', 0).short #=> m3
27
- * Interval.new('do#', 'mi', 1).short #=> m10
24
+ * MusicUtils.short('do', 're') #=> M2
25
+ * MusicUtils.short('do', 're', 1) #=> M9
26
+ * MusicUtils.short('do#', 'mi') #=> m3
27
+ * MusicUtils.short('do#', 'mi', 1) #=> m10
28
+
29
+ Installation
30
+ -----------
31
+
32
+ gem install music-utils
28
33
 
29
34
  To Do
30
35
  -----
data/Rakefile CHANGED
@@ -1,6 +1,3 @@
1
- require 'rubygems'
2
- require 'bundler/setup'
3
-
4
1
  require 'rake'
5
2
  require 'rspec/core/rake_task'
6
3
 
@@ -16,27 +13,8 @@ RSpec::Core::RakeTask.new(:spec) do |spec|
16
13
  end
17
14
 
18
15
  # Gems tasks
19
- desc "Load the gemspec"
20
- task :load_gemspec do
21
- @gemspec = eval(File.read(Dir["*.gemspec"].first))
22
- end
23
-
24
- desc "Validate the gemspec"
25
- task :gemspec => :load_gemspec do
26
- @gemspec.validate
27
- end
28
-
29
- desc "Build gem locally"
30
- task :build => :gemspec do
31
- system "gem build #{@gemspec.name}.gemspec"
32
- FileUtils.mkdir_p "pkg"
33
- FileUtils.mv "#{@gemspec.name}-#{@gemspec.version}.gem", "pkg"
34
- end
35
-
36
- desc "Install gem locally"
37
- task :install => :build do
38
- system "gem install pkg/#{@gemspec.name}-#{@gemspec.version}"
39
- end
16
+ require "bundler"
17
+ Bundler::GemHelper.install_tasks
40
18
 
41
19
  desc "Clean automatically generated files"
42
20
  task :clean do
@@ -0,0 +1,109 @@
1
+ require 'music-utils/scales/scales'
2
+
3
+ # This class represents a music interval
4
+ module MusicUtils
5
+
6
+ class Interval
7
+ include Scales
8
+
9
+ def initialize(note1, note2, step)
10
+ @note1 = note1
11
+ @note2 = note2
12
+ @step = step
13
+ end
14
+
15
+ # It classifies the diatonic interval
16
+ def number
17
+ # initialize counter and index of scale
18
+ i = note1_index
19
+ count = 1
20
+
21
+ count, i = no_unison(count, i)
22
+
23
+ # Counting notes
24
+ until_find_note2(i) { count += 1 }
25
+
26
+ count = count + (8 * @step) - 1 if @step > 0
27
+ count
28
+ end
29
+
30
+ # Returns the number of semitones
31
+ def semitones
32
+ # initialize counter and index of scale
33
+ i = note1_index
34
+ count = 0
35
+
36
+ count, i = no_unison(count, i)
37
+
38
+ # counting semi-tones
39
+ until_find_note2(i) do |i|
40
+ # from 'mi' to 'fa' and 'si' to 'do' there 1 semi-tone
41
+ if DIATONIC_SCALE[i] == 'fa' or DIATONIC_SCALE[i] == 'do'
42
+ count += 1
43
+ else
44
+ count += 2
45
+ end
46
+ end
47
+
48
+ count = count + (12 * @step) if @step > 0
49
+
50
+ # counting notes alterations
51
+ alter = @note1[2..3]
52
+
53
+ alter.each_char do |c|
54
+ count += 1 if c == 'b'
55
+ count -= 1 if c == '#'
56
+ end
57
+
58
+ alter = @note2[2..3]
59
+
60
+ alter.each_char do |c|
61
+ count -= 1 if c == 'b'
62
+ count += 1 if c == '#'
63
+ end
64
+
65
+ count
66
+ end
67
+
68
+ # Returns the quality of the interval
69
+ def quality
70
+ s = ( @step > 0 and semitones - (12 * @step) ) || semitones
71
+ n = ( @step > 0 and number - (7 * @step) ) || number
72
+ QUALITIES[n][s]
73
+ end
74
+
75
+ # Returns the class interval in the short notation
76
+ def short
77
+ quality + number.to_s
78
+ end
79
+
80
+ private
81
+
82
+ # Common loop to search note 2
83
+ def until_find_note2(i)
84
+ # search note2
85
+ while DIATONIC_SCALE[i] != @note2[0..1]
86
+ i += 1
87
+ if i > DIATONIC_SCALE.length
88
+ i = 0; next
89
+ end
90
+ yield i
91
+ end
92
+ end
93
+
94
+ # Jumps to the next note if note 1 and note 2 are the same
95
+ def no_unison(count, i)
96
+ if @note1[0..1] == @note2[0..1]
97
+ count += 1; i += 1
98
+ end
99
+ [count, i]
100
+ end
101
+
102
+ # Returns index of note 1
103
+ def note1_index
104
+ DIATONIC_SCALE.index(@note1[0..1])
105
+ end
106
+
107
+ end
108
+
109
+ end
@@ -0,0 +1,13 @@
1
+ # Scales module
2
+ module Scales
3
+ DIATONIC_SCALE = ['do', 're', 'mi', 'fa', 'sol', 'la', 'si']
4
+ QUALITIES = {
5
+ 2 => {0 => 'd', 1 => 'm', 2 => 'M', 3 => 'A', 4 => 'AA'},
6
+ 3 => {1 => 'dd', 2 => 'd', 3 => 'm', 4 => 'M', 5 => 'A', 6 => 'AA'},
7
+ 4 => {3 => 'dd', 4 => 'd', 5 => 'P', 6 => 'A', 7 => 'AA'},
8
+ 5 => {5 => 'dd', 6 => 'd', 7 => 'P', 8 => 'A', 9 => 'AA'},
9
+ 6 => {6 => 'dd', 7 => 'd', 8 => 'm', 9 => 'M', 10 => 'A', 11 => 'AA'},
10
+ 7 => {8 => 'dd', 9 => 'd', 10 => 'm', 11 => 'M', 12 => 'A', 13 => 'AA'},
11
+ 8 => {10 => 'dd', 11 => 'd', 12 => 'P', 13 => 'A', 14 => 'AA'}
12
+ }
13
+ end
@@ -0,0 +1,3 @@
1
+ module MusicUtils
2
+ VERSION = '1.0.0'
3
+ end
@@ -0,0 +1,26 @@
1
+ require 'music-utils/interval/interval'
2
+
3
+ # Music utils
4
+ module MusicUtils
5
+
6
+ # Returns the number of the interval
7
+ def MusicUtils.number(note1, note2, step = 0)
8
+ Interval.new(note1, note2, step).number
9
+ end
10
+
11
+ # Returns semitones of interval
12
+ def MusicUtils.semitones(note1, note2, step = 0)
13
+ Interval.new(note1, note2, step).semitones
14
+ end
15
+
16
+ # Returns the quality of interval
17
+ def MusicUtils.quality(note1, note2, step = 0)
18
+ Interval.new(note1, note2, step).quality
19
+ end
20
+
21
+ # Returns short notation
22
+ def MusicUtils.short(note1, note2, step = 0)
23
+ Interval.new(note1, note2, step).short
24
+ end
25
+
26
+ end
data/music-utils.gemspec CHANGED
@@ -1,22 +1,31 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "music-utils/version"
1
4
 
2
5
  Gem::Specification.new do |s|
3
6
  # Basic Info
4
- s.name = 'music-utils'
5
- s.version = '0.5.2'
6
- s.summary = 'music-utils'
7
- s.description = 'Utils for music. At the moment only one class to classify intervals.'
7
+ s.name = "music-utils"
8
+ s.version = MusicUtils::VERSION
8
9
  s.platform = Gem::Platform::RUBY
9
- s.authors = ['Jorge Luis Pérez']
10
- s.email = ['jorgeluis700@gmail.com']
11
- s.homepage = 'http://github.com/jorgeluis700/music-utils'
12
- s.license = 'MIT'
13
-
14
- # Files and Paths
15
- s.files = `git ls-files`.split("\n")
16
- s.require_path = 'lib'
10
+ s.authors = ["Jorge Luis Pérez"]
11
+ s.email = ["jorgeluis700@gmail.com"]
12
+ s.homepage = "http://github.com/jorgeluis700/music-utils"
13
+ s.summary = %q{Utils for music}
14
+ s.description = %q{Utils for music. At the moment only to classify intervals.}
15
+ s.license = %q{MIT}
16
+
17
+ # Files
18
+ s.files = `git ls-files`.split("\n")
19
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
20
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
21
+ s.require_paths = ["lib"]
17
22
 
18
- # Dependencies
19
- s.add_development_dependency('rspec')
23
+ # Ruby Gems Version
20
24
  s.required_rubygems_version = ">= 1.3.6"
21
25
 
26
+ # Dependencies
27
+ s.add_development_dependency "rake", ">= 0.8"
28
+ s.add_development_dependency "bundler"
29
+ s.add_development_dependency "rspec"
30
+
22
31
  end
@@ -1,6 +1,7 @@
1
- require 'interval'
1
+ require 'music-utils/interval/interval'
2
2
 
3
- describe Interval do
3
+ describe MusicUtils::Interval do
4
+ include MusicUtils
4
5
 
5
6
  context "Number of intervals" do
6
7
  it "the number of simple interval do-mi should be a 3rd" do
@@ -22,22 +23,22 @@ describe Interval do
22
23
  context "Number of semitones of intervals" do
23
24
  it "simple interval do-mi should be 4 semitones" do
24
25
  i = Interval.new('do', 'mi', 0)
25
- i.semitone.should == 4
26
+ i.semitones.should == 4
26
27
  end
27
28
 
28
29
  it "simple interval dob-mi# should be 6 semitones" do
29
30
  i = Interval.new('dob', 'mi#', 0)
30
- i.semitone.should == 6
31
+ i.semitones.should == 6
31
32
  end
32
33
 
33
34
  it "simple interval do-do should be 12 semitones" do
34
35
  i = Interval.new('do', 'do', 0)
35
- i.semitone.should == 12
36
+ i.semitones.should == 12
36
37
  end
37
38
 
38
39
  it "compound interval do-mi should be 16 semitones" do
39
40
  i = Interval.new('do', 'mi', 1)
40
- i.semitone.should == 16
41
+ i.semitones.should == 16
41
42
  end
42
43
  end
43
44
 
@@ -0,0 +1,45 @@
1
+ require 'music-utils'
2
+
3
+ describe MusicUtils do
4
+
5
+ context "Intervals" do
6
+
7
+ context "By number" do
8
+ it "the number of simple interval do-mi should be a 3rd" do
9
+ MusicUtils.number('do', 'mi').should == 3
10
+ end
11
+ it "the number of do-mi compound interval should be a 10th" do
12
+ MusicUtils.number('do', 'mi', 1).should == 10
13
+ end
14
+ end
15
+
16
+ context "By semitones" do
17
+ it "simple interval do-mi should be 4 semitones" do
18
+ MusicUtils.semitones('do', 'mi').should == 4
19
+ end
20
+ it "compound interval do-mi should be 16 semitones" do
21
+ MusicUtils.semitones('do', 'mi', 1).should == 16
22
+ end
23
+ end
24
+
25
+ context "By quality" do
26
+ it "quality of interval do-mi should be M" do
27
+ MusicUtils.quality('do', 'mi').should == 'M'
28
+ end
29
+ it "quality of compound interval do-mi should be M" do
30
+ MusicUtils.quality('do', 'mi', 1).should == 'M'
31
+ end
32
+ end
33
+
34
+ context "By short notation" do
35
+ it "the short notation of do#-mi interval should be m3" do
36
+ MusicUtils.short('do#', 'mi').should == 'm3'
37
+ end
38
+ it "the short notation of do#-mi compound interval should be m10" do
39
+ MusicUtils.short('do#', 'mi', 1).should == 'm10'
40
+ end
41
+ end
42
+
43
+ end
44
+
45
+ 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: 0.5.2
4
+ version: 1.0.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,33 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-04-29 00:00:00.000000000Z
12
+ date: 2011-05-06 00:00:00.000000000Z
13
13
  dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rake
16
+ requirement: &20979048 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0.8'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *20979048
25
+ - !ruby/object:Gem::Dependency
26
+ name: bundler
27
+ requirement: &20978820 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *20978820
14
36
  - !ruby/object:Gem::Dependency
15
37
  name: rspec
16
- requirement: &24028992 !ruby/object:Gem::Requirement
38
+ requirement: &20978544 !ruby/object:Gem::Requirement
17
39
  none: false
18
40
  requirements:
19
41
  - - ! '>='
@@ -21,8 +43,8 @@ dependencies:
21
43
  version: '0'
22
44
  type: :development
23
45
  prerelease: false
24
- version_requirements: *24028992
25
- description: Utils for music. At the moment only one class to classify intervals.
46
+ version_requirements: *20978544
47
+ description: Utils for music. At the moment only to classify intervals.
26
48
  email:
27
49
  - jorgeluis700@gmail.com
28
50
  executables: []
@@ -32,13 +54,16 @@ files:
32
54
  - .gitignore
33
55
  - CHANGELOG.md
34
56
  - Gemfile
35
- - Gemfile.lock
36
57
  - LICENSE
37
58
  - README.md
38
59
  - Rakefile
39
- - lib/interval.rb
60
+ - lib/music-utils.rb
61
+ - lib/music-utils/interval/interval.rb
62
+ - lib/music-utils/scales/scales.rb
63
+ - lib/music-utils/version.rb
40
64
  - music-utils.gemspec
41
- - spec/interval_spec.rb
65
+ - spec/interval/interval_spec.rb
66
+ - spec/music-utils_spec.rb
42
67
  homepage: http://github.com/jorgeluis700/music-utils
43
68
  licenses:
44
69
  - MIT
@@ -52,9 +77,6 @@ required_ruby_version: !ruby/object:Gem::Requirement
52
77
  - - ! '>='
53
78
  - !ruby/object:Gem::Version
54
79
  version: '0'
55
- segments:
56
- - 0
57
- hash: 934369633
58
80
  required_rubygems_version: !ruby/object:Gem::Requirement
59
81
  none: false
60
82
  requirements:
@@ -66,5 +88,5 @@ rubyforge_project:
66
88
  rubygems_version: 1.7.2
67
89
  signing_key:
68
90
  specification_version: 3
69
- summary: music-utils
91
+ summary: Utils for music
70
92
  test_files: []
data/Gemfile.lock DELETED
@@ -1,21 +0,0 @@
1
- GEM
2
- remote: http://rubygems.org/
3
- specs:
4
- diff-lcs (1.1.2)
5
- rake (0.8.7)
6
- rspec (2.5.0)
7
- rspec-core (~> 2.5.0)
8
- rspec-expectations (~> 2.5.0)
9
- rspec-mocks (~> 2.5.0)
10
- rspec-core (2.5.1)
11
- rspec-expectations (2.5.0)
12
- diff-lcs (~> 1.1.2)
13
- rspec-mocks (2.5.0)
14
-
15
- PLATFORMS
16
- ruby
17
- x86-mingw32
18
-
19
- DEPENDENCIES
20
- rake (~> 0.8)
21
- rspec (~> 2.5)
data/lib/interval.rb DELETED
@@ -1,117 +0,0 @@
1
- # Scales module
2
- module Scales
3
- DIATONIC_SCALE = ['do', 're', 'mi', 'fa', 'sol', 'la', 'si']
4
- QUALITIES = {
5
- 2 => {0 => 'd', 1 => 'm', 2 => 'M', 3 => 'A', 4 => 'AA'},
6
- 3 => {1 => 'dd', 2 => 'd', 3 => 'm', 4 => 'M', 5 => 'A', 6 => 'AA'},
7
- 4 => {3 => 'dd', 4 => 'd', 5 => 'P', 6 => 'A', 7 => 'AA'},
8
- 5 => {5 => 'dd', 6 => 'd', 7 => 'P', 8 => 'A', 9 => 'AA'},
9
- 6 => {6 => 'dd', 7 => 'd', 8 => 'm', 9 => 'M', 10 => 'A', 11 => 'AA'},
10
- 7 => {8 => 'dd', 9 => 'd', 10 => 'm', 11 => 'M', 12 => 'A', 13 => 'AA'},
11
- 8 => {10 => 'dd', 11 => 'd', 12 => 'P', 13 => 'A', 14 => 'AA'}
12
- }
13
- end
14
-
15
- # This class represents a music interval
16
- class Interval
17
- include Scales
18
-
19
- def initialize(note1, note2, step)
20
- @note1 = note1
21
- @note2 = note2
22
- @step = step
23
- end
24
-
25
- # It classifies the diatonic interval
26
- def number
27
- # initialize counter and index of scale
28
- i = note1_index
29
- count = 1
30
-
31
- count, i = no_unison(count, i)
32
-
33
- # Counting notes
34
- until_find_note2(i) { count += 1 }
35
-
36
- count = count + (8 * @step) - 1 if @step > 0
37
- count
38
- end
39
-
40
- # Returns the number of semitones
41
- def semitone
42
- # initialize counter and index of scale
43
- i = note1_index
44
- count = 0
45
-
46
- count, i = no_unison(count, i)
47
-
48
- # counting semi-tones
49
- until_find_note2(i) do |i|
50
- # from 'mi' to 'fa' and 'si' to 'do' there 1 semi-tone
51
- if DIATONIC_SCALE[i] == 'fa' or DIATONIC_SCALE[i] == 'do'
52
- count += 1
53
- else
54
- count += 2
55
- end
56
- end
57
-
58
- count = count + (12 * @step) if @step > 0
59
-
60
- # counting notes alterations
61
- alter = @note1[2..3]
62
-
63
- alter.each_char do |c|
64
- count += 1 if c == 'b'
65
- count -= 1 if c == '#'
66
- end
67
-
68
- alter = @note2[2..3]
69
-
70
- alter.each_char do |c|
71
- count -= 1 if c == 'b'
72
- count += 1 if c == '#'
73
- end
74
-
75
- count
76
- end
77
-
78
- # Returns the quality of the interval
79
- def quality
80
- s = ( @step > 0 and semitone - (12 * @step) ) || semitone
81
- n = ( @step > 0 and number - (7 * @step) ) || number
82
- QUALITIES[n][s]
83
- end
84
-
85
- # Returns the class interval in the short notation
86
- def short
87
- quality + number.to_s
88
- end
89
-
90
- private
91
-
92
- # Common loop to search note 2
93
- def until_find_note2(i)
94
- # search note2
95
- while DIATONIC_SCALE[i] != @note2[0..1]
96
- i += 1
97
- if i > DIATONIC_SCALE.length
98
- i = 0; next
99
- end
100
- yield i
101
- end
102
- end
103
-
104
- # Jumps to the next note if note 1 and note 2 are the same
105
- def no_unison(count, i)
106
- if @note1[0..1] == @note2[0..1]
107
- count += 1; i += 1
108
- end
109
- [count, i]
110
- end
111
-
112
- # Returns index of note 1
113
- def note1_index
114
- DIATONIC_SCALE.index(@note1[0..1])
115
- end
116
-
117
- end