tonal-tools 6.2.1 → 7.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.
- checksums.yaml +4 -4
- data/lib/tonal/attributions.rb +1 -1
- data/lib/tonal/extensions.rb +87 -21
- data/lib/tonal/ratio.rb +19 -6
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6eb41e5ffdfb2d4e1d6e76f5f69a2c1ad9a81d658af99e8a338211a5deea5d09
|
4
|
+
data.tar.gz: b63cb8bd6081fecdbbd97a2b003d84c2ea6533f9c656a63ba856c9732d021810
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f33625446c980e2a0e92d37efefb6abda13a084f214900af13c2cad9a981e087ff971d3fd62f86e83ec574a1bc9f153f80a5b61001c36cc9fe8eb4fda6fb9336
|
7
|
+
data.tar.gz: 99f81e26f709629654cd54402635d2e504c7075426f5f5807add1a3226736951f37cd459e929fc6c96b101a7290e88a23914b296e5b987212def629455fd9886
|
data/lib/tonal/attributions.rb
CHANGED
data/lib/tonal/extensions.rb
CHANGED
@@ -39,18 +39,27 @@ class Numeric
|
|
39
39
|
#
|
40
40
|
def div_times(factor) = [self / factor, self * factor]
|
41
41
|
|
42
|
-
# @return [Tonal::
|
42
|
+
# @return [Tonal::Ratio] the octave reduced ratio of self
|
43
43
|
# @example
|
44
|
-
# (
|
44
|
+
# (4/5r).to_ratio => 4/5
|
45
|
+
# @param reduced
|
46
|
+
# @param equave
|
45
47
|
#
|
46
|
-
def to_ratio(reduced:
|
48
|
+
def to_ratio(reduced: false, equave: 2/1r) = reduced ? Tonal::ReducedRatio.new(self, equave: equave) : Tonal::Ratio.new(self, equave: equave)
|
47
49
|
alias :ratio :to_ratio
|
48
50
|
|
51
|
+
# @return [Tonal::ReducedRatio]
|
52
|
+
# @example
|
53
|
+
# {4/5r}.to_reduced_ratio => 8/5
|
54
|
+
# @param equave
|
55
|
+
#
|
56
|
+
def to_reduced_ratio(equave: 2/1r) = to_ratio(reduced: true, equave: equave)
|
57
|
+
|
49
58
|
# @return [Float], the degrees on a circle of self
|
50
59
|
# @example
|
51
60
|
# (2**(6.0/12)).period_degrees => 180.0
|
52
61
|
#
|
53
|
-
def period_degrees =
|
62
|
+
def period_degrees = ratio.period_degrees
|
54
63
|
|
55
64
|
# @return [Tonal::Log] the log of self to the given base
|
56
65
|
# @example
|
@@ -82,7 +91,7 @@ class Numeric
|
|
82
91
|
# @example
|
83
92
|
# (3/2r).to_cents => 701.96
|
84
93
|
#
|
85
|
-
def to_cents = self
|
94
|
+
def to_cents = Tonal::Cents.new(ratio: self)
|
86
95
|
|
87
96
|
# @return [Tonal::Hertz] of self
|
88
97
|
#
|
@@ -94,38 +103,41 @@ class Numeric
|
|
94
103
|
# (5/4r).step(12) => 4\12
|
95
104
|
# @param modulo
|
96
105
|
#
|
97
|
-
def step(modulo=12) =
|
106
|
+
def step(modulo=12) = Tonal::Step.new(ratio: self, modulo: modulo)
|
98
107
|
|
99
108
|
# @return [Float] the log product complexity of self
|
100
109
|
# @example
|
101
110
|
# (3/2r).benedetti_height => 6
|
102
111
|
#
|
103
|
-
def benedetti_height =
|
112
|
+
def benedetti_height = ratio.benedetti_height
|
104
113
|
alias :product_complexity :benedetti_height
|
105
114
|
|
106
115
|
# @return [Integer] the product complexity of self
|
107
116
|
# @example
|
108
117
|
# (3/2r).tenney_height => 2.58
|
109
118
|
#
|
110
|
-
def tenney_height =
|
119
|
+
def tenney_height = ratio.tenney_height
|
111
120
|
alias :log_product_complexity :tenney_height
|
112
121
|
|
113
122
|
# @return [Integer] the Weil height
|
114
123
|
# @example
|
115
124
|
# (3/2r).weil_height => 3
|
116
125
|
#
|
117
|
-
def weil_height =
|
126
|
+
def weil_height = ratio.weil_height
|
118
127
|
|
119
128
|
# @return [Tonal::Log2] the log of Weil height
|
120
129
|
# @example
|
121
130
|
# (3/2r).log_weil_height => 1.58
|
122
131
|
#
|
123
|
-
def log_weil_height =
|
132
|
+
def log_weil_height = ratio.log_weil_height
|
124
133
|
|
125
134
|
# @return [Integer] the Wilson height
|
126
135
|
# @example (14/9r).wilson_height => 13
|
136
|
+
# @param reduced
|
137
|
+
# @param equave
|
138
|
+
# @param prime_rejects
|
127
139
|
#
|
128
|
-
def wilson_height(reduced:
|
140
|
+
def wilson_height(reduced: false, equave: 2/1r, prime_rejects: [2]) = ratio(reduced: reduced, equave: equave).wilson_height(prime_rejects: prime_rejects)
|
129
141
|
|
130
142
|
# @return [Float] the cents difference between self and its step in the given modulo
|
131
143
|
# @example
|
@@ -133,21 +145,31 @@ class Numeric
|
|
133
145
|
# @param modulo
|
134
146
|
#
|
135
147
|
# We want the efficiency from the ratio (self)
|
136
|
-
def efficiency(modulo) =
|
148
|
+
def efficiency(modulo, reduced: false) = ratio(reduced: reduced).efficiency(modulo)
|
137
149
|
|
138
150
|
# @return [Tonal::Interval] beween self (upper) and ratio (lower)
|
139
151
|
# @example
|
140
152
|
# (133).interval_with(3/2r) => 133/96 (133/128 / 3/2)
|
141
|
-
# @param
|
153
|
+
# @param other_ratio
|
154
|
+
#
|
155
|
+
def interval_with(other_ratio) = Tonal::Interval.new(ratio, other_ratio)
|
156
|
+
|
157
|
+
# @return [Tonal::Cents] difference between ratio (upper) and self (lower)
|
158
|
+
# @example
|
159
|
+
# (133).cents_difference_with(3/2r)
|
160
|
+
# => 635.62
|
161
|
+
# @param other_ratio
|
142
162
|
#
|
143
|
-
def
|
163
|
+
def cents_difference_with(other_ratio) = interval_with(other_ratio).to_cents
|
144
164
|
|
145
165
|
# @return [Vector], self represented as a prime vector
|
146
166
|
# @example
|
147
167
|
# (3/2r).prime_vector => Vector[-1, 1]
|
168
|
+
# @param reduced
|
148
169
|
#
|
149
|
-
def prime_vector =
|
170
|
+
def prime_vector(reduced: false) = ratio(reduced: reduced).prime_vector
|
150
171
|
alias :monzo :prime_vector
|
172
|
+
alias :prime_exponent_vector :prime_vector
|
151
173
|
|
152
174
|
# @return [Array], self decomposed into its prime factors
|
153
175
|
# @example
|
@@ -174,18 +196,18 @@ class Numeric
|
|
174
196
|
def to_vector = Vector[self.numerator, self.denominator]
|
175
197
|
alias :vector :to_vector
|
176
198
|
|
177
|
-
# @return [Tonal::
|
199
|
+
# @return [Tonal::Ratio], the Ernst Levy negative of self
|
178
200
|
# @example
|
179
201
|
# (7/4r).negative => (12/7)
|
180
202
|
#
|
181
|
-
def negative =
|
203
|
+
def negative = ratio.negative
|
182
204
|
|
183
|
-
# @return [Tonal::
|
205
|
+
# @return [Tonal::Ratio], the ratio rotated on the given axis, default 1/1
|
184
206
|
# @example
|
185
207
|
# (3/2r).mirror => (4/3)
|
186
208
|
# @param axis around which self is mirrored
|
187
209
|
#
|
188
|
-
def mirror(axis=1/1r) =
|
210
|
+
def mirror(axis=1/1r) = ratio.mirror(axis)
|
189
211
|
|
190
212
|
# @return [Integer] the floor of the log (to the given base) of self
|
191
213
|
# @example
|
@@ -268,6 +290,30 @@ class Integer
|
|
268
290
|
end
|
269
291
|
end
|
270
292
|
end
|
293
|
+
|
294
|
+
# @return [Array] of signature of self
|
295
|
+
# @example
|
296
|
+
# 5.signature
|
297
|
+
# => [1]
|
298
|
+
#
|
299
|
+
def prime_signature
|
300
|
+
raise ArgumentError, "applicable only to positive integers" if self <= 0
|
301
|
+
|
302
|
+
n = self
|
303
|
+
exponents = []
|
304
|
+
i = 2
|
305
|
+
while i * i <= n
|
306
|
+
count = 0
|
307
|
+
while n % i == 0
|
308
|
+
n /= i
|
309
|
+
count += 1
|
310
|
+
end
|
311
|
+
exponents << count if count > 0
|
312
|
+
i += 1
|
313
|
+
end
|
314
|
+
exponents << 1 if n > 1 # n is prime at this point
|
315
|
+
exponents.sort
|
316
|
+
end
|
271
317
|
end
|
272
318
|
|
273
319
|
class Array
|
@@ -344,13 +390,33 @@ class Array
|
|
344
390
|
#
|
345
391
|
def mean = self.sum / self.count.to_f
|
346
392
|
|
347
|
-
# @return [Tonal::
|
393
|
+
# @return [Tonal::Ratio] ratio reconstructed from the result of a prime factor decomposition
|
348
394
|
# @example
|
349
395
|
# [[[3, 1]], [[2, 1]]].ratio_from_prime_divisions => (3/2)
|
350
396
|
# @param reduced [Boolean] if a reduced or unreduced ratio is returned
|
351
397
|
#
|
352
398
|
def ratio_from_prime_divisions(reduced: false) = reduced ? Tonal::ReducedRatio.new(Prime.int_from_prime_division(self.first), Prime.int_from_prime_division(self.last)) : Tonal::Ratio.new(Prime.int_from_prime_division(self.first), Prime.int_from_prime_division(self.last))
|
353
399
|
|
400
|
+
# @return [Array] with the EDO and its error best fitting the given ratios contained in self
|
401
|
+
# @example
|
402
|
+
# [3/2r].best_fitting_edo) => [53, 0.07]
|
403
|
+
# [7/4r, 3/2r].best_fitting_edo => [41, 3.46]
|
404
|
+
# @param min_edo [Integer] the mininum edo to search
|
405
|
+
# @param max_edo [Integer] the maximum edo to search
|
406
|
+
#
|
407
|
+
def best_fitting_edo(min_edo: 5, max_edo: 72)
|
408
|
+
(min_edo..max_edo).map do |edo|
|
409
|
+
step_size = 1200.0 / edo
|
410
|
+
|
411
|
+
total_error_for_edo = to_cents.map do |r_cents|
|
412
|
+
quantized = (r_cents / step_size).round * step_size
|
413
|
+
(r_cents - quantized).abs
|
414
|
+
end.sum
|
415
|
+
|
416
|
+
[edo, total_error_for_edo.round(2)]
|
417
|
+
end.min_by{|_, error| error}
|
418
|
+
end
|
419
|
+
|
354
420
|
# @return [Array] translated by value
|
355
421
|
# @example
|
356
422
|
# [0.24184760813024642, 0.49344034900361244, 0.07231824070126536].translate(-0.07231824070126536) = [0.16952936742898106, 0.4211221083023471, 0.0]
|
@@ -403,7 +469,7 @@ class Vector
|
|
403
469
|
# @param reduced
|
404
470
|
# @param equave
|
405
471
|
#
|
406
|
-
def to_ratio(reduced:
|
472
|
+
def to_ratio(reduced: false, equave: 2/1r) = reduced ? Tonal::ReducedRatio.new(*self, equave: equave) : Tonal::Ratio.new(*self, equave: equave)
|
407
473
|
alias :ratio :to_ratio
|
408
474
|
end
|
409
475
|
|
data/lib/tonal/ratio.rb
CHANGED
@@ -336,7 +336,6 @@ class Tonal::Ratio
|
|
336
336
|
# Tonal::Ratio.new(31/30r).prime_divisions => [[[31, 1]], [[2, 1], [3, 1], [5, 1]]]
|
337
337
|
#
|
338
338
|
def prime_divisions
|
339
|
-
return [[[2, 1]], [[2, 1]]] if antecedent == 1
|
340
339
|
[antecedent.prime_division, consequent.prime_division]
|
341
340
|
end
|
342
341
|
|
@@ -346,7 +345,9 @@ class Tonal::Ratio
|
|
346
345
|
#
|
347
346
|
def prime_vector
|
348
347
|
pds = prime_divisions
|
349
|
-
|
348
|
+
return nil if pds.all?(&:empty?)
|
349
|
+
|
350
|
+
max = [pds.first.max{|p| p.first}, pds.last.max{|p| p.first}].compact.max.first
|
350
351
|
|
351
352
|
pds.last.collect!{|i| [i.first, -i.last]}
|
352
353
|
|
@@ -356,6 +357,7 @@ class Tonal::Ratio
|
|
356
357
|
end.to_vector
|
357
358
|
end
|
358
359
|
alias :monzo :prime_vector
|
360
|
+
alias :prime_exponent_vector :prime_vector
|
359
361
|
|
360
362
|
# @return [Integer] the maximum prime factor of self
|
361
363
|
# @example
|
@@ -533,14 +535,25 @@ class Tonal::Ratio
|
|
533
535
|
# @example
|
534
536
|
# Tonal::ReducedRatio.new(133).interval_with(3/2r)
|
535
537
|
# => (192/133) ((3/2) / (133/128))
|
536
|
-
# @param
|
537
|
-
# @param
|
538
|
+
# @param upper ratio
|
539
|
+
# @param lower ratio
|
538
540
|
#
|
539
|
-
def interval_with(
|
540
|
-
r = self.class.new(
|
541
|
+
def interval_with(upper, lower=nil)
|
542
|
+
r = self.class.new(upper, lower)
|
541
543
|
Tonal::Interval.new(self, r)
|
542
544
|
end
|
543
545
|
|
546
|
+
# @return [Tonal::Cents] difference between ratio (upper) and self (lower)
|
547
|
+
# @example
|
548
|
+
# Tonal::ReducedRatio.new(133).cents_difference_with(3/2r)
|
549
|
+
# => 635.62
|
550
|
+
# @param upper ratio
|
551
|
+
# @param lower ratio
|
552
|
+
#
|
553
|
+
def cents_difference_with(upper, lower=nil)
|
554
|
+
interval_with(upper, lower).to_cents
|
555
|
+
end
|
556
|
+
|
544
557
|
# @return [Integer] the difference between antecedent and consequent
|
545
558
|
# @example
|
546
559
|
# Tonal::ReducedRatio.new(3,2).difference => 1
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tonal-tools
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 7.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jose Hales-Garcia
|
8
8
|
bindir: bin
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-
|
10
|
+
date: 2025-08-09 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: yaml
|
@@ -191,7 +191,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
191
191
|
- !ruby/object:Gem::Version
|
192
192
|
version: '3.1'
|
193
193
|
requirements: []
|
194
|
-
rubygems_version: 3.
|
194
|
+
rubygems_version: 3.7.1
|
195
195
|
specification_version: 4
|
196
196
|
summary: Tonal tools
|
197
197
|
test_files: []
|