post_tonal 0.1.1.pre → 0.2.0.pre
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +13 -6
- data/lib/post_tonal/pitch_class_set.rb +78 -21
- data/lib/post_tonal/version.rb +1 -1
- data/test/unit/pitch_class_set_test.rb +127 -0
- metadata +2 -2
data/CHANGELOG.md
CHANGED
@@ -1,17 +1,24 @@
|
|
1
1
|
#CHANGELOG
|
2
2
|
|
3
|
+
####October 22, 2012 [0.2.0.pre]
|
4
|
+
- Implements prime form
|
5
|
+
- Fixes normal form logic and updates tests
|
6
|
+
|
7
|
+
####October 21, 2012 [0.1.1.pre]
|
8
|
+
- Adds homepage information to gem specification
|
9
|
+
|
3
10
|
####October 21, 2012 [0.1.1.pre]
|
4
|
-
-
|
11
|
+
- Adds homepage information to gem specification
|
5
12
|
|
6
13
|
####October 21, 2012 [0.1.0.pre]
|
7
|
-
-
|
8
|
-
-
|
14
|
+
- Implements transposition in PitchClassSet
|
15
|
+
- Changes normal_form, inversion, and transpose so that they each return a PitchClassSet
|
9
16
|
|
10
17
|
####October 20, 2012 [0.0.3.pre]
|
11
|
-
-
|
18
|
+
- Implements inversion in PitchClassSet
|
12
19
|
|
13
20
|
####October 16, 2012 [0.0.2.pre]
|
14
|
-
-
|
21
|
+
- Implements normal form in PitchClassSet
|
15
22
|
|
16
23
|
####October 15, 2012 [0.0.1.pre]
|
17
|
-
-
|
24
|
+
- Creates PitchClass, PitchClassSet, PitchClassInterval, PitchInterval, and NoteParser
|
@@ -7,8 +7,9 @@ module PostTonal
|
|
7
7
|
|
8
8
|
def initialize(pitch_classes = nil)
|
9
9
|
@pitch_classes = pitch_classes || []
|
10
|
-
@normalized_pitch_classes = pitch_classes ? self.class.to_normal_form(@pitch_classes) : []
|
11
|
-
@inverted_pitch_classes = pitch_classes ? invert(@pitch_classes) : []
|
10
|
+
@normalized_pitch_classes = @pitch_classes.size > 0 ? self.class.to_normal_form(@pitch_classes) : []
|
11
|
+
@inverted_pitch_classes = @pitch_classes.size > 0 ? invert(@pitch_classes) : []
|
12
|
+
@prime_pitch_classes = @pitch_classes.size > 0 ? to_prime_form : []
|
12
13
|
end
|
13
14
|
|
14
15
|
# Add a pitch to the pitch class set
|
@@ -31,16 +32,17 @@ module PostTonal
|
|
31
32
|
@pitch_classes << pc
|
32
33
|
@normalized_pitch_classes = self.class.to_normal_form(@pitch_classes)
|
33
34
|
@inverted_pitch_classes = invert(@pitch_classes)
|
35
|
+
@prime_pitch_classes = to_prime_form
|
34
36
|
end
|
35
37
|
|
36
38
|
pc
|
37
39
|
end
|
38
40
|
|
39
41
|
def eql?(pitch_class_set)
|
40
|
-
return false if @pitch_classes.size != pitch_class_set.pitch_classes.size
|
42
|
+
return false if @pitch_classes.size != pitch_class_set.pitch_classes.size || @pitch_classes.size == 0
|
41
43
|
|
42
|
-
@
|
43
|
-
return false if !pitch_class_set.
|
44
|
+
@pitch_classes.each_with_index do |pitch_class, i|
|
45
|
+
return false if !pitch_class.eql?(pitch_class_set.pitch_classes[i])
|
44
46
|
end
|
45
47
|
|
46
48
|
true
|
@@ -75,19 +77,14 @@ module PostTonal
|
|
75
77
|
if newLen < shortest[:length]
|
76
78
|
shortest = {:array => normal.dup, :length => newLen}
|
77
79
|
elsif newLen == shortest[:length]
|
78
|
-
(normal.size - 1).downto(q) do |r|
|
79
80
|
|
80
|
-
|
81
|
-
|
82
|
-
|
81
|
+
rs = shortest[:array].reverse
|
82
|
+
normal.reverse.each_with_index do |pitch_class, i|
|
83
|
+
this_dist = (pitch_class.value - normal.first.value).abs
|
84
|
+
that_dist = (rs[i].value - rs.last.value).abs
|
83
85
|
|
84
|
-
|
85
|
-
|
86
|
-
sNewLen += 12 if sNewLen == 1 && normal.size > 2
|
87
|
-
|
88
|
-
if newLen < sNewLen
|
89
|
-
shortest = {:array => normal.dup, :length => newLen}
|
90
|
-
break
|
86
|
+
if this_dist < that_dist
|
87
|
+
shortest = {:array => normal, :length => newLen}
|
91
88
|
end
|
92
89
|
end
|
93
90
|
end
|
@@ -106,9 +103,21 @@ module PostTonal
|
|
106
103
|
self.class.new(@normalized_pitch_classes)
|
107
104
|
end
|
108
105
|
|
109
|
-
#
|
106
|
+
# Returns a PitchClassSet of the current PitchClassSet in prime form
|
107
|
+
def prime_form
|
108
|
+
prime1 = normal_form.transpose_to_zero
|
109
|
+
prime2 = inversion.normal_form.transpose_to_zero
|
110
|
+
return prime2 if prime2.is_more_packed_than? prime1
|
111
|
+
prime1
|
112
|
+
end
|
113
|
+
|
114
|
+
# Transposes the set
|
115
|
+
#
|
116
|
+
# degree - The number of steps to transpose. May be positive or negative
|
117
|
+
# reset_octave - If true, resets octave attribute to 0 for all pitch classes
|
118
|
+
#
|
110
119
|
# Returns PitchClassSet of the transposed set
|
111
|
-
def transpose(degree)
|
120
|
+
def transpose(degree, reset_octave = false)
|
112
121
|
transposed = self.class.new
|
113
122
|
|
114
123
|
@pitch_classes.each do |pitch_class|
|
@@ -117,8 +126,12 @@ module PostTonal
|
|
117
126
|
|
118
127
|
val += degree
|
119
128
|
|
120
|
-
|
121
|
-
|
129
|
+
if reset_octave
|
130
|
+
oct = 0
|
131
|
+
else
|
132
|
+
oct += val / 12
|
133
|
+
oct -= 1 if val < 0 && val % 12 == 0
|
134
|
+
end
|
122
135
|
|
123
136
|
transposed.add_pitch(val, oct)
|
124
137
|
end
|
@@ -126,7 +139,34 @@ module PostTonal
|
|
126
139
|
transposed
|
127
140
|
end
|
128
141
|
|
129
|
-
|
142
|
+
def reset_octave
|
143
|
+
ro = []
|
144
|
+
|
145
|
+
@pitch_classes.each do |pitch_class|
|
146
|
+
ro << PitchClass.new(pitch_class.value)
|
147
|
+
end
|
148
|
+
|
149
|
+
self.class.new(ro)
|
150
|
+
end
|
151
|
+
|
152
|
+
# Check if this pitch class set is more tightly packed to the left than the comparison pitch class set.
|
153
|
+
#
|
154
|
+
# Returns false if less tightly packed or if is the same set
|
155
|
+
def is_more_packed_than?(pitch_class_set)
|
156
|
+
return false if (@pitch_classes.size != pitch_class_set.pitch_classes.size || @pitch_classes.size == 0) || eql?(pitch_class_set)
|
157
|
+
|
158
|
+
rpcs = pitch_class_set.pitch_classes.reverse
|
159
|
+
@pitch_classes.reverse.each_with_index do |pitch_class, i|
|
160
|
+
this_dist = (pitch_class.value - @pitch_classes.first.value).abs
|
161
|
+
that_dist = (rpcs[i].value - rpcs.last.value).abs
|
162
|
+
|
163
|
+
return true if this_dist < that_dist
|
164
|
+
end
|
165
|
+
|
166
|
+
false
|
167
|
+
end
|
168
|
+
|
169
|
+
protected
|
130
170
|
|
131
171
|
# Inverts an array of pitch classes. The PitchClass attribute octave may become invalid after inversion.
|
132
172
|
# Returns a PitchClassSet of the inverted pitch classes
|
@@ -141,5 +181,22 @@ module PostTonal
|
|
141
181
|
inverted
|
142
182
|
end
|
143
183
|
|
184
|
+
# Returns the normal form of an array of pitch classes
|
185
|
+
def to_prime_form
|
186
|
+
#prime1 = normal_form.transpose_to_zero.pitch_classes
|
187
|
+
#prime2 = inversion.normal_form.transpose_to_zero
|
188
|
+
|
189
|
+
#return prime1.pitch_classes if prime1.is_more_packed_than? prime2
|
190
|
+
#return prime2.pitch_classes_classes
|
191
|
+
[]
|
192
|
+
end
|
193
|
+
|
194
|
+
def transpose_to_zero
|
195
|
+
dist = 12 - @pitch_classes[0].value
|
196
|
+
"TT0: #{@pitch_classes}, dist: #{dist}"
|
197
|
+
return transpose(dist, true) if dist % 12 != 0
|
198
|
+
self
|
199
|
+
end
|
200
|
+
|
144
201
|
end
|
145
202
|
end
|
data/lib/post_tonal/version.rb
CHANGED
@@ -118,6 +118,20 @@ class PitchClassSetTest < Test::Unit::TestCase
|
|
118
118
|
[6,7,0].each_with_index do |n, i|
|
119
119
|
assert_equal(n, @p7.normal_form.pitch_classes[i].value)
|
120
120
|
end
|
121
|
+
|
122
|
+
@p8 = PostTonal::PitchClassSet.new
|
123
|
+
@p8.add_pitch(0)
|
124
|
+
@p8.add_pitch(3)
|
125
|
+
@p8.add_pitch(8)
|
126
|
+
@p8.add_pitch(9)
|
127
|
+
|
128
|
+
@p8n = PostTonal::PitchClassSet.new
|
129
|
+
@p8n.add_pitch(8)
|
130
|
+
@p8n.add_pitch(9)
|
131
|
+
@p8n.add_pitch(0)
|
132
|
+
@p8n.add_pitch(3)
|
133
|
+
|
134
|
+
assert_equal(@p8n, @p8.normal_form, "Normal form of #{@p8} should be #{@p8n}")
|
121
135
|
end
|
122
136
|
|
123
137
|
def test_inversion
|
@@ -156,4 +170,117 @@ class PitchClassSetTest < Test::Unit::TestCase
|
|
156
170
|
end
|
157
171
|
end
|
158
172
|
|
173
|
+
def test_prime_form
|
174
|
+
@p1 = PostTonal::PitchClassSet.new
|
175
|
+
@p1.add_pitch(0)
|
176
|
+
@p1.add_pitch(1)
|
177
|
+
@p1.add_pitch(4)
|
178
|
+
@p1.add_pitch(7)
|
179
|
+
|
180
|
+
@p1p = PostTonal::PitchClassSet.new
|
181
|
+
@p1p.add_pitch(0)
|
182
|
+
@p1p.add_pitch(1)
|
183
|
+
@p1p.add_pitch(4)
|
184
|
+
@p1p.add_pitch(7)
|
185
|
+
|
186
|
+
assert_equal(@p1p, @p1.prime_form)
|
187
|
+
|
188
|
+
|
189
|
+
@p2 = PostTonal::PitchClassSet.new
|
190
|
+
@p2.add_pitch(6)
|
191
|
+
@p2.add_pitch(7)
|
192
|
+
@p2.add_pitch(8)
|
193
|
+
|
194
|
+
@p2p = PostTonal::PitchClassSet.new
|
195
|
+
@p2p.add_pitch(0)
|
196
|
+
@p2p.add_pitch(1)
|
197
|
+
@p2p.add_pitch(2)
|
198
|
+
|
199
|
+
assert_equal(@p2p, @p2.prime_form)
|
200
|
+
|
201
|
+
@p3 = PostTonal::PitchClassSet.new
|
202
|
+
@p3.add_pitch(0)
|
203
|
+
@p3.add_pitch(3)
|
204
|
+
@p3.add_pitch(8)
|
205
|
+
@p3.add_pitch(9)
|
206
|
+
|
207
|
+
@p3p = PostTonal::PitchClassSet.new
|
208
|
+
@p3p.add_pitch(0)
|
209
|
+
@p3p.add_pitch(1)
|
210
|
+
@p3p.add_pitch(4)
|
211
|
+
@p3p.add_pitch(7)
|
212
|
+
|
213
|
+
assert_equal(@p3p, @p3.prime_form)
|
214
|
+
|
215
|
+
|
216
|
+
@p4 = PostTonal::PitchClassSet.new
|
217
|
+
@p4.add_pitch(1)
|
218
|
+
@p4.add_pitch(5)
|
219
|
+
@p4.add_pitch(6)
|
220
|
+
@p4.add_pitch(7)
|
221
|
+
|
222
|
+
@p4p = PostTonal::PitchClassSet.new
|
223
|
+
@p4p.add_pitch(0)
|
224
|
+
@p4p.add_pitch(1)
|
225
|
+
@p4p.add_pitch(2)
|
226
|
+
@p4p.add_pitch(6)
|
227
|
+
|
228
|
+
assert_equal(@p4p, @p4.prime_form)
|
229
|
+
|
230
|
+
@p5 = PostTonal::PitchClassSet.new
|
231
|
+
@p5.add_pitch(0)
|
232
|
+
@p5.add_pitch(2)
|
233
|
+
@p5.add_pitch(4)
|
234
|
+
@p5.add_pitch(7)
|
235
|
+
@p5.add_pitch(11)
|
236
|
+
|
237
|
+
@p5p = PostTonal::PitchClassSet.new
|
238
|
+
@p5p.add_pitch(0)
|
239
|
+
@p5p.add_pitch(1)
|
240
|
+
@p5p.add_pitch(3)
|
241
|
+
@p5p.add_pitch(5)
|
242
|
+
@p5p.add_pitch(8)
|
243
|
+
|
244
|
+
assert_equal(@p5p, @p5.prime_form)
|
245
|
+
|
246
|
+
@p6 = PostTonal::PitchClassSet.new
|
247
|
+
@p6.add_pitch(3)
|
248
|
+
@p6.add_pitch(6)
|
249
|
+
@p6.add_pitch(7)
|
250
|
+
@p6.add_pitch(8)
|
251
|
+
@p6.add_pitch(9)
|
252
|
+
@p6.add_pitch(10)
|
253
|
+
|
254
|
+
@p6p = PostTonal::PitchClassSet.new
|
255
|
+
@p6p.add_pitch(0)
|
256
|
+
@p6p.add_pitch(1)
|
257
|
+
@p6p.add_pitch(2)
|
258
|
+
@p6p.add_pitch(3)
|
259
|
+
@p6p.add_pitch(4)
|
260
|
+
@p6p.add_pitch(7)
|
261
|
+
|
262
|
+
assert_equal(@p6p, @p6.prime_form)
|
263
|
+
|
264
|
+
@p7 = PostTonal::PitchClassSet.new
|
265
|
+
@p7.add_pitch(0)
|
266
|
+
@p7.add_pitch(2)
|
267
|
+
@p7.add_pitch(5)
|
268
|
+
@p7.add_pitch(6)
|
269
|
+
@p7.add_pitch(7)
|
270
|
+
@p7.add_pitch(9)
|
271
|
+
@p7.add_pitch(10)
|
272
|
+
@p7.add_pitch(11)
|
273
|
+
|
274
|
+
@p7p = PostTonal::PitchClassSet.new
|
275
|
+
@p7p.add_pitch(0)
|
276
|
+
@p7p.add_pitch(1)
|
277
|
+
@p7p.add_pitch(2)
|
278
|
+
@p7p.add_pitch(4)
|
279
|
+
@p7p.add_pitch(5)
|
280
|
+
@p7p.add_pitch(6)
|
281
|
+
@p7p.add_pitch(7)
|
282
|
+
@p7p.add_pitch(9)
|
283
|
+
|
284
|
+
assert_equal(@p7p, @p7.prime_form)
|
285
|
+
end
|
159
286
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: post_tonal
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0.pre
|
5
5
|
prerelease: 6
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-10-
|
12
|
+
date: 2012-10-22 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: shoulda
|