dodecaphony 0.1.0 → 0.2.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.
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