dodecaphony 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2cdb493c58e0f214ef7cc89dac4bafd38d7826b9
4
- data.tar.gz: 807fe2e936382444b1c9612969105a7215bf9307
3
+ metadata.gz: 68d01640c510abfd7e48edade6c57d6dfcb35e07
4
+ data.tar.gz: b285ae148dff3451117edeb016e5f8ef4af039dc
5
5
  SHA512:
6
- metadata.gz: 9662162bdee955579875ba1e37a41b591176ea4cd9e24c92c9c829ef3f211e49fd3c38ce629ca8d570cdaecdc4234746c95ba7cc0b0dbacd088ef2ca17ca6273
7
- data.tar.gz: 06baece067f2ad549ce6808a10c5dba842fef4e924698f56c01f7c1bc69a1d6099b7c31cd5a79cec703847714bfd92ed64b7c85565e285c950b948006187e992
6
+ metadata.gz: 9228481081aa85c962421bfcee1f5e744238f169566b874c42d2b16d0be9e2b8b3f451bfbacef20053a3e4c0f912b624873a80e3d4f97d91a9daa79368e2ee98
7
+ data.tar.gz: 29489b6ba21afca6133b533d0e4c71944f1b48c09b0e0914d70c0124c1de2a3e1a7cc2799484e3689724e59ae1a54a97473f61a625059fe8eba6d75279ddcd7a
data/Readme.md CHANGED
@@ -5,45 +5,58 @@ Dodecaphony calculates twelve tone rows for
5
5
  you. To learn more about what this means, [read
6
6
  this](http://www.tufts.edu/~mdevoto/12TonePrimer.pdf).
7
7
 
8
+ Dodecaphony is a ruby gem. Install with
9
+ ```
10
+ gem install dodecaphony
11
+ ```
12
+
8
13
  Examples
9
14
  ---
10
15
 
11
- Dodecaphony takes an array of twelve strings, one for each pitch in your
12
- twelve tone row.
16
+ First, you'll need a `Dodecaphony::Row` object. `Dodecaphony::Row`
17
+ requires an array of 12 strings, each representing a unique pitch. Each
18
+ pitch must begin with a valid letter name (a through g) and can be
19
+ followed by one or more accidentals. `#`, `+`, `b` and `-` are the four
20
+ valid accidentals.
13
21
 
14
22
  ```ruby
15
- Dodecaphony::Row.new %w[a a# b c c# d d# e f f# g g#]
23
+ my_row = Dodecaphony::Row.new %w[a a# b c c# d d# e f f# g g#]
16
24
  ```
25
+ A row can be converted to either an array of pitch names, or a string with
26
+ pitch names separated by a space.
27
+ ```ruby
28
+ my_row.to_a # ['a', 'a#', 'b', 'c', 'c#', 'd', 'd#', 'e', 'f', 'f#', 'g', 'g#']
17
29
 
18
- Each pitch must begin with a valid letter name (a through g) and can be
19
- followed by one or more accidentals. `#`, `+`, `b` and `-` are the four valid
20
- accidentals.
30
+ my_row.to_s # "a a# b c c# d d# e f f# g g#"
31
+ ```
32
+ You can also ask a row to respell itself, favoring flats or sharps:
33
+ ```ruby
34
+ tone_row = Dodecaphony::Row.new %w[ a f# g ab e f b bb d c# c eb ]
21
35
 
22
- Once you have your row, you can ask it for any prime, inversion, retrograde, or
23
- retrograde inversion like so:
36
+ tone_row.spell_with_sharps # ["A", "F#", "G", "G#", "E", "F", "B", "A#", "D", "C#", "C", "D#"]
24
37
 
38
+ tone_row.spell_with_flats # ["A", "Gb", "G", "Ab", "E", "F", "B", "Bb", "D", "Db", "C", "Eb"]
39
+ ```
40
+ The `Dodecaphony::Calculator` class initializes with a `Dodecaphony::Row`
41
+ object.
25
42
  ```ruby
26
43
  tone_row = Dodecaphony::Row.new %w[ a f# g ab e f b bb d c# c eb ]
27
-
44
+ calc = Dodecaphony::Calculator.new tone_row
45
+ ```
46
+ The calculator can then return any prime, inversion, retrograde, or retrograde
47
+ inversion. Each of these rows is a method of the calculator object, the names
48
+ being the initial of the type of row you want, followed by the number of the
49
+ row you want. Observe:
50
+ ```ruby
28
51
  # "p" followed by 0 through 11 returns the corresponding prime row
29
- tone_row.p0 # ["a", "f#", "g", "ab", "e", "f", "b", "bb", "d", "c#", "c", "eb"]
52
+ calc.p0 # ["a", "f#", "g", "ab", "e", "f", "b", "bb", "d", "c#", "c", "eb"]
30
53
 
31
54
  # "r" followed by 0 through 11 returns the corresponding retrograde
32
- tone_row.r11 # ["d", "b", "c", "c#", "a", "bb", "e", "eb", "g", "f#", "f", "ab"]
55
+ calc.r11 # ["d", "b", "c", "c#", "a", "bb", "e", "eb", "g", "f#", "f", "ab"]
33
56
 
34
57
  # "i" followed by 0 through 11 returns the corresponding inversion
35
- tone_row.i2 # ["b", "d", "c#", "c", "e", "eb", "a", "bb", "f#", "g", "ab", "f"]
58
+ calc.i2 # ["b", "d", "c#", "c", "e", "eb", "a", "bb", "f#", "g", "ab", "f"]
36
59
 
37
60
  # "ri" followed by 0 through 11 returns the corresponding retrograde inversion
38
- tone_row.ri6 # ["a", "c", "b", "bb", "d", "c#", "g", "ab", "e", "f", "f#", "eb"]
39
- ```
40
-
41
- You can also ask a row to respell itself, favoring flats or sharps:
42
- ```ruby
43
- tone_row = Dodecaphony::Row.new %w[ a f# g ab e f b bb d c# c eb ]
44
-
45
- tone_row.spell_with_sharps # ["A", "F#", "G", "G#", "E", "F", "B", "A#", "D", "C#", "C", "D#"]
46
-
47
- tone_row.spell_with_flats # ["A", "Gb", "G", "Ab", "E", "F", "B", "Bb", "D", "Db", "C", "Eb"]
61
+ calc.ri6 # ["a", "c", "b", "bb", "d", "c#", "g", "ab", "e", "f", "f#", "eb"]
48
62
  ```
49
-
@@ -0,0 +1,53 @@
1
+ require_relative 'row'
2
+
3
+ module Dodecaphony
4
+ class Calculator
5
+
6
+ def initialize row
7
+ self.row = row
8
+ end
9
+
10
+ def i0
11
+ row.each_with_object([]) { |pitch, new_row|
12
+ new_row << row.intervals[((row.intervals.key(pitch) - 12).abs)].name
13
+ }
14
+ end
15
+
16
+ (1..11).each do |i|
17
+ define_method "i#{i}".to_sym do
18
+ corresponding_p = self.send("p#{i}").to_a
19
+ new_row = Dodecaphony::Row.new corresponding_p
20
+ (self.class.new new_row).i0
21
+ end
22
+ end
23
+
24
+ (0..11).each do |i|
25
+ define_method "p#{i}".to_sym do
26
+ row.pitches.each_with_object([]) { |pitch, new_row|
27
+ new_row << row.intervals[(transpose i, pitch)].name
28
+ }
29
+ end
30
+
31
+ define_method "r#{i}".to_sym do
32
+ self.send("p#{i}").reverse
33
+ end
34
+
35
+ define_method "ri#{i}".to_sym do
36
+ self.send("i#{i}").reverse
37
+ end
38
+ end
39
+
40
+ private
41
+
42
+ attr_accessor :row
43
+
44
+ def transpose interval, pitch
45
+ (starting_pitch.distance_from(pitch) + interval) % 12
46
+ end
47
+
48
+ def starting_pitch
49
+ row.pitches[0]
50
+ end
51
+
52
+ end
53
+ end
@@ -26,6 +26,13 @@ module Dodecaphony
26
26
  respell :+, "b"
27
27
  end
28
28
 
29
+ def == other
30
+ numbers = (distance_from(other) == 0)
31
+ names = (starting_letter == other.name.upcase.split(//)[0])
32
+
33
+ names && numbers
34
+ end
35
+
29
36
  protected
30
37
 
31
38
  attr_reader :pitch_number
@@ -3,18 +3,27 @@ require 'set'
3
3
 
4
4
  module Dodecaphony
5
5
  class Row
6
+ include Enumerable
6
7
 
7
- attr_reader :original_row
8
+ attr_reader :original_row, :intervals
9
+
10
+ alias_method :pitches, :original_row
8
11
 
9
12
  def initialize tone_row
10
13
  self.original_row = create_row_with_pitches(tone_row)
11
14
  validate_size_of original_row
12
- self.row_with_intervals = create_list_with_intervals(original_row,
15
+ self.intervals = create_list_with_intervals(original_row,
13
16
  starting_pitch)
14
17
  end
15
18
 
16
19
  def to_s
17
- p0.join(" ")
20
+ to_a.join(" ")
21
+ end
22
+
23
+ def to_a
24
+ pitches.each_with_object([]) do |pitch, row|
25
+ row << pitch.name
26
+ end
18
27
  end
19
28
 
20
29
  def spell_with_sharps
@@ -25,49 +34,18 @@ module Dodecaphony
25
34
  normalize_row(:spell_as_flat)
26
35
  end
27
36
 
28
- def i0
29
- original_row.each_with_object([]) do |pitch, row|
30
- row << row_with_intervals[((row_with_intervals.key(pitch) - 12).abs)].name
31
- end
32
- end
33
-
34
- (0..11).each do |i|
35
- define_method "p#{i}".to_sym do
36
- original_row.each_with_object([]) do |pitch, row|
37
- row << row_with_intervals[(transpose i, pitch)].name
38
- end
39
- end
40
- end
41
-
42
- (1..11).each do |i|
43
- define_method "i#{i}".to_sym do
44
- corresponding_p = self.send("p#{i}")
45
- new_row = self.class.new corresponding_p
46
- new_row.i0
37
+ def == other
38
+ (other.pitches).zip(pitches).all? do |pitches|
39
+ pitches[0] == pitches[1]
47
40
  end
48
41
  end
49
42
 
50
- (0..11).each do |i|
51
- define_method "r#{i}".to_sym do
52
- self.send("p#{i}".to_sym).reverse.each_with_object([]) do |pitch, row|
53
- row << pitch
54
- end
55
- end
56
- end
57
-
58
- (0..11).each do |i|
59
- define_method "ri#{i}".to_sym do
60
- self.send("i#{i}").reverse.each_with_object([]) do |pitch, row|
61
- row << pitch
62
- end
63
- end
43
+ def each &block
44
+ pitches.each &block
64
45
  end
65
-
66
46
  private
67
47
 
68
- attr_writer :original_row
69
-
70
- attr_accessor :row_with_intervals
48
+ attr_writer :intervals, :original_row
71
49
 
72
50
  def create_list_with_intervals(row, first_pitch)
73
51
  row_list = row.each_with_object({}) do |pitch, hash|
@@ -112,9 +90,5 @@ module Dodecaphony
112
90
  end
113
91
  end
114
92
 
115
- def transpose interval, pitch
116
- (starting_pitch.distance_from(pitch) + interval) % 12
117
- end
118
-
119
93
  end
120
94
  end
@@ -0,0 +1,84 @@
1
+ require 'calculator'
2
+ require 'ostruct'
3
+
4
+ describe Dodecaphony::Calculator do
5
+
6
+ it "initializes with a row" do
7
+ row = Dodecaphony::Row.new %w[a b b- c c# d d# e f gb g g#]
8
+ calc = Dodecaphony::Calculator.new row
9
+
10
+ expect(calc).to be_kind_of(Dodecaphony::Calculator)
11
+ end
12
+
13
+ it "can provide the original row" do
14
+ row = Dodecaphony::Row.new %w[a b b- c c# d d# e f gb g g#]
15
+ calc = Dodecaphony::Calculator.new row
16
+
17
+ expect(calc.p0).to eq row.to_a
18
+ end
19
+
20
+ it "can provide p1" do
21
+ row = Dodecaphony::Row.new %w[ bb b c c# d f e eb g gb a ab ]
22
+ p1_row = %w[ b c c# d eb gb f e ab g bb a ]
23
+ calc = Dodecaphony::Calculator.new row
24
+
25
+ expect(calc.p1).to eq p1_row.to_a
26
+ end
27
+
28
+ it "can give p7" do
29
+ row = Dodecaphony::Row.new %w[ d c# a b- f eb e c ab g f# b ]
30
+ prime7 = %w[ a ab e f c b- b g eb d c# f# ]
31
+ calc = Dodecaphony::Calculator.new row
32
+
33
+ expect(calc.p7).to eq prime7
34
+ end
35
+
36
+ it "can give i0" do
37
+ row = Dodecaphony::Row.new %w[ A ab a# b c c# d eb e f gb g ]
38
+ new_row = %w[ A a# ab g gb f e eb d c# c b ]
39
+ calc = Dodecaphony::Calculator.new row
40
+
41
+ expect(calc.i0).to eq new_row
42
+ end
43
+
44
+ it "can give i8" do
45
+ row = Dodecaphony::Row.new %w[ A ab a# b c c# d eb e f gb g ]
46
+ new_row = %w[ f gb e eb d c# c b a# A ab g ]
47
+ calc = Dodecaphony::Calculator.new row
48
+
49
+ expect(calc.i8).to eq new_row
50
+ end
51
+
52
+ it "can give r0" do
53
+ row = Dodecaphony::Row.new %w[ a f# g ab e f b bb d c# c eb ]
54
+ new_row = %w[ eb c c# d bb b f e ab g f# a ]
55
+ calc = Dodecaphony::Calculator.new row
56
+
57
+ expect(calc.r0).to eq new_row
58
+ end
59
+
60
+ it "can give r9" do
61
+ row = Dodecaphony::Row.new %w[ a f# g ab e f b bb d c# c eb ]
62
+ new_row = %w[ c a bb b g ab d c# f e eb f# ]
63
+ calc = Dodecaphony::Calculator.new row
64
+
65
+ expect(calc.r9).to eq new_row
66
+ end
67
+
68
+ it "can give ri0" do
69
+ row = Dodecaphony::Row.new %w[ a f# g ab e f b bb d c# c eb ]
70
+ new_row = %w[eb f# f e ab g c# d bb b c a ]
71
+ calc = Dodecaphony::Calculator.new row
72
+
73
+ expect(calc.ri0).to eq new_row
74
+ end
75
+
76
+ it "can give ri11" do
77
+ row = Dodecaphony::Row.new %w[ a f# g ab e f b bb d c# c eb ]
78
+ new_row = %w[ c# e eb d f# f b c ab a bb g ]
79
+ calc = Dodecaphony::Calculator.new row
80
+
81
+ expect(calc.ri10).to eq new_row
82
+ end
83
+
84
+ end
@@ -51,4 +51,25 @@ describe Dodecaphony::Pitch do
51
51
  it "raises an error with an invalid pitch name" do
52
52
  expect {Dodecaphony::Pitch.new "H"}.to raise_error(ArgumentError, 'invalid pitch name')
53
53
  end
54
+
55
+ it "knows when it is not equal to another pitch" do
56
+ p1 = Dodecaphony::Pitch.new "a#"
57
+ p2 = Dodecaphony::Pitch.new "b-"
58
+
59
+ expect(p1).to_not eq p2
60
+ end
61
+
62
+ it "knows when it is equal to another pitch" do
63
+ p1 = Dodecaphony::Pitch.new "a"
64
+ p2 = Dodecaphony::Pitch.new "a"
65
+
66
+ expect(p1).to eq p2
67
+ end
68
+
69
+ it "doesn't factor accidental style into equality" do
70
+ p1 = Dodecaphony::Pitch.new "c#"
71
+ p2 = Dodecaphony::Pitch.new "c+"
72
+
73
+ expect(p1).to eq p2
74
+ end
54
75
  end
@@ -1,4 +1,4 @@
1
- require 'dodecaphony'
1
+ require 'row'
2
2
 
3
3
  describe Dodecaphony::Row do
4
4
 
@@ -6,7 +6,7 @@ describe Dodecaphony::Row do
6
6
  tone_row = %w[ a a# b c db d eb e f f# g g# ]
7
7
  new_dod = Dodecaphony::Row.new tone_row
8
8
 
9
- expect(new_dod.p0).to eq tone_row
9
+ expect(new_dod.to_a).to eq tone_row
10
10
  end
11
11
 
12
12
  it "raises an error for a row with more than 12 pitches" do
@@ -38,59 +38,36 @@ describe Dodecaphony::Row do
38
38
  expect(new_dod.spell_with_flats).to eq %w[ C Db D Eb E F Gb G Ab A Bb B ]
39
39
  end
40
40
 
41
- it "can give p1" do
42
- tone_row = %w[ bb b c c# d f e eb g gb a ab ]
43
- new_dod = Dodecaphony::Row.new tone_row
44
-
45
- expect(new_dod.p1).to eq %w[ b c c# d eb gb f e ab g bb a ]
46
- end
47
-
48
- it "can give p7" do
49
- tone_row = Dodecaphony::Row.new %w[ d c# a b- f eb e c ab g f# b ]
50
-
51
- expect(tone_row.p7).to eq %w[ a ab e f c b- b g eb d c# f# ]
52
- end
53
-
54
- it "can give i0" do
55
- tone_row = Dodecaphony::Row.new %w[ A ab a# b c c# d eb e f gb g ]
56
-
57
- expect(tone_row.i0).to eq %w[ A a# ab g gb f e eb d c# c b ]
58
- end
59
-
60
- it "can give i8" do
61
- tone_row = Dodecaphony::Row.new %w[ A ab a# b c c# d eb e f gb g ]
62
-
63
- expect(tone_row.i8).to eq %w[ f gb e eb d c# c b a# A ab g ]
64
- end
65
-
66
- it "can give r0" do
41
+ it "returns a reasonable string" do
67
42
  tone_row = Dodecaphony::Row.new %w[ a f# g ab e f b bb d c# c eb ]
68
43
 
69
- expect(tone_row.r0).to eq %w[ eb c c# d bb b f e ab g f# a ]
44
+ expect(tone_row.to_s).to eq "a f# g ab e f b bb d c# c eb"
70
45
  end
71
-
72
- it "can give r9" do
73
- tone_row = Dodecaphony::Row.new %w[ a f# g ab e f b bb d c# c eb ]
74
46
 
75
- expect(tone_row.r9).to eq %w[ c a bb b g ab d c# f e eb f# ]
47
+ it "returns an array" do
48
+ tone_row = Dodecaphony::Row.new %w[a f# g ab e f b b- d c# c eb]
49
+
50
+ expect(tone_row.to_a).to eq %w[a f# g ab e f b b- d c# c eb]
76
51
  end
77
52
 
78
- it "can give ri0" do
79
- tone_row = Dodecaphony::Row.new %w[ a f# g ab e f b bb d c# c eb ]
53
+ it "returns its pitches" do
54
+ tone_row = Dodecaphony::Row.new %w[a f# g ab e f b b- d c# c eb]
55
+ first_pitch = Dodecaphony::Pitch.new "a"
80
56
 
81
- expect(tone_row.ri0).to eq %w[eb f# f e ab g c# d bb b c a ]
57
+ expect(tone_row.pitches.to_a[0].name).to eq first_pitch.name
82
58
  end
83
59
 
84
- it "can give ri11" do
85
- tone_row = Dodecaphony::Row.new %w[ a f# g ab e f b bb d c# c eb ]
60
+ it "can check for equality with other rows" do
61
+ row1 = Dodecaphony::Row.new %w[a f# g ab e f b b- d c# c eb]
62
+ row2 = Dodecaphony::Row.new %w[a f# g ab e f b b- d c# c eb]
86
63
 
87
- expect(tone_row.ri10).to eq %w[ c# e eb d f# f b c ab a bb g ]
64
+ expect(row1).to eq row2
88
65
  end
89
66
 
90
- it "converts to a reasonable string" do
91
- tone_row = Dodecaphony::Row.new %w[ a f# g ab e f b bb d c# c eb ]
67
+ it "knows when rows are unequal" do
68
+ row1 = Dodecaphony::Row.new %w[a f# g ab e f b b- d c# c eb]
69
+ row2 = Dodecaphony::Row.new %w[a b b- c d- d e- e f g- g a-]
92
70
 
93
- expect(tone_row.to_s).to eq "a f# g ab e f b bb d c# c eb"
71
+ expect(row1).to_not eq row2
94
72
  end
95
-
96
73
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dodecaphony
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kevin McGladdery
@@ -39,10 +39,12 @@ extra_rdoc_files: []
39
39
  files:
40
40
  - LICENSE
41
41
  - Readme.md
42
- - lib/dodecaphony.rb
42
+ - lib/calculator.rb
43
43
  - lib/pitch.rb
44
- - spec/dodecaphony_spec.rb
44
+ - lib/row.rb
45
+ - spec/calculator_spec.rb
45
46
  - spec/pitch_spec.rb
47
+ - spec/row_spec.rb
46
48
  homepage: http://github.com/runkmc/dodecaphony
47
49
  licenses:
48
50
  - MIT
@@ -63,10 +65,11 @@ required_rubygems_version: !ruby/object:Gem::Requirement
63
65
  version: '0'
64
66
  requirements: []
65
67
  rubyforge_project:
66
- rubygems_version: 2.3.0
68
+ rubygems_version: 2.2.2
67
69
  signing_key:
68
70
  specification_version: 4
69
71
  summary: Tone Row Calculator
70
72
  test_files:
71
- - spec/dodecaphony_spec.rb
73
+ - spec/calculator_spec.rb
72
74
  - spec/pitch_spec.rb
75
+ - spec/row_spec.rb