tonal-tools 6.2.0 → 7.0.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 +69 -16
- data/lib/tonal/ratio.rb +20 -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: '08e71f0a71f06993084a2567211a4106cefc25aaa4d1f28bc941bf737097915b'
|
4
|
+
data.tar.gz: 6fa78c5271fa011906a7de57b9a56f7693bd11f2985d5193b868bd00468d3341
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6509f49a314f5cec9b413617ddf00967e7c57655b9eb86b8b96e56033c3ef8cd8e136ee0a69cffb0e1de413e998b67537671763fd98bb937552bb03dc52316ff
|
7
|
+
data.tar.gz: c99a22e906caaaca500225189a19f7633df2144485ef6c9479faf9bbbaefed01a04a085fd7de0b74cf4549f6b37c8afa919566d561709e66685306d962218863
|
data/lib/tonal/attributions.rb
CHANGED
data/lib/tonal/extensions.rb
CHANGED
@@ -43,14 +43,14 @@ class Numeric
|
|
43
43
|
# @example
|
44
44
|
# (2**(1.0/12)).ratio => (4771397596969315/4503599627370496)
|
45
45
|
#
|
46
|
-
def to_ratio(reduced:
|
46
|
+
def to_ratio(reduced: false, equave: 2/1r) = reduced ? Tonal::ReducedRatio.new(self, equave: equave) : Tonal::Ratio.new(self, equave: equave)
|
47
47
|
alias :ratio :to_ratio
|
48
48
|
|
49
49
|
# @return [Float], the degrees on a circle of self
|
50
50
|
# @example
|
51
51
|
# (2**(6.0/12)).period_degrees => 180.0
|
52
52
|
#
|
53
|
-
def period_degrees =
|
53
|
+
def period_degrees = ratio.period_degrees
|
54
54
|
|
55
55
|
# @return [Tonal::Log] the log of self to the given base
|
56
56
|
# @example
|
@@ -82,7 +82,7 @@ class Numeric
|
|
82
82
|
# @example
|
83
83
|
# (3/2r).to_cents => 701.96
|
84
84
|
#
|
85
|
-
def to_cents = self
|
85
|
+
def to_cents = Tonal::Cents.new(ratio: self)
|
86
86
|
|
87
87
|
# @return [Tonal::Hertz] of self
|
88
88
|
#
|
@@ -94,38 +94,38 @@ class Numeric
|
|
94
94
|
# (5/4r).step(12) => 4\12
|
95
95
|
# @param modulo
|
96
96
|
#
|
97
|
-
def step(modulo=12) =
|
97
|
+
def step(modulo=12) = Tonal::Step.new(ratio: self, modulo: modulo)
|
98
98
|
|
99
99
|
# @return [Float] the log product complexity of self
|
100
100
|
# @example
|
101
101
|
# (3/2r).benedetti_height => 6
|
102
102
|
#
|
103
|
-
def benedetti_height =
|
103
|
+
def benedetti_height = ratio.benedetti_height
|
104
104
|
alias :product_complexity :benedetti_height
|
105
105
|
|
106
106
|
# @return [Integer] the product complexity of self
|
107
107
|
# @example
|
108
108
|
# (3/2r).tenney_height => 2.58
|
109
109
|
#
|
110
|
-
def tenney_height =
|
110
|
+
def tenney_height = ratio.tenney_height
|
111
111
|
alias :log_product_complexity :tenney_height
|
112
112
|
|
113
113
|
# @return [Integer] the Weil height
|
114
114
|
# @example
|
115
115
|
# (3/2r).weil_height => 3
|
116
116
|
#
|
117
|
-
def weil_height =
|
117
|
+
def weil_height = ratio.weil_height
|
118
118
|
|
119
119
|
# @return [Tonal::Log2] the log of Weil height
|
120
120
|
# @example
|
121
121
|
# (3/2r).log_weil_height => 1.58
|
122
122
|
#
|
123
|
-
def log_weil_height =
|
123
|
+
def log_weil_height = ratio.log_weil_height
|
124
124
|
|
125
125
|
# @return [Integer] the Wilson height
|
126
126
|
# @example (14/9r).wilson_height => 13
|
127
127
|
#
|
128
|
-
def wilson_height(reduced:
|
128
|
+
def wilson_height(reduced: false, equave: 2/1r, prime_rejects: [2]) = ratio(reduced: reduced, equave: equave).wilson_height(prime_rejects: prime_rejects)
|
129
129
|
|
130
130
|
# @return [Float] the cents difference between self and its step in the given modulo
|
131
131
|
# @example
|
@@ -133,21 +133,30 @@ class Numeric
|
|
133
133
|
# @param modulo
|
134
134
|
#
|
135
135
|
# We want the efficiency from the ratio (self)
|
136
|
-
def efficiency(modulo) =
|
136
|
+
def efficiency(modulo, reduced: false) = ratio(reduced: reduced).efficiency(modulo)
|
137
137
|
|
138
138
|
# @return [Tonal::Interval] beween self (upper) and ratio (lower)
|
139
139
|
# @example
|
140
140
|
# (133).interval_with(3/2r) => 133/96 (133/128 / 3/2)
|
141
|
-
# @param
|
141
|
+
# @param other_ratio
|
142
142
|
#
|
143
|
-
def interval_with(
|
143
|
+
def interval_with(other_ratio) = Tonal::Interval.new(ratio, other_ratio)
|
144
|
+
|
145
|
+
# @return [Tonal::Cents] difference between ratio (upper) and self (lower)
|
146
|
+
# @example
|
147
|
+
# (133).cents_difference_with(3/2r)
|
148
|
+
# => 635.62
|
149
|
+
# @param other_ratio
|
150
|
+
#
|
151
|
+
def cents_difference_with(other_ratio) = interval_with(other_ratio).to_cents
|
144
152
|
|
145
153
|
# @return [Vector], self represented as a prime vector
|
146
154
|
# @example
|
147
155
|
# (3/2r).prime_vector => Vector[-1, 1]
|
148
156
|
#
|
149
|
-
def prime_vector =
|
157
|
+
def prime_vector(reduced: false) = ratio(reduced: reduced).prime_vector
|
150
158
|
alias :monzo :prime_vector
|
159
|
+
alias :prime_exponent_vector :prime_vector
|
151
160
|
|
152
161
|
# @return [Array], self decomposed into its prime factors
|
153
162
|
# @example
|
@@ -178,14 +187,14 @@ class Numeric
|
|
178
187
|
# @example
|
179
188
|
# (7/4r).negative => (12/7)
|
180
189
|
#
|
181
|
-
def negative =
|
190
|
+
def negative = ratio.negative
|
182
191
|
|
183
192
|
# @return [Tonal::ReducedRatio], the ratio rotated on the given axis, default 1/1
|
184
193
|
# @example
|
185
194
|
# (3/2r).mirror => (4/3)
|
186
195
|
# @param axis around which self is mirrored
|
187
196
|
#
|
188
|
-
def mirror(axis=1/1r) =
|
197
|
+
def mirror(axis=1/1r) = ratio.mirror(axis)
|
189
198
|
|
190
199
|
# @return [Integer] the floor of the log (to the given base) of self
|
191
200
|
# @example
|
@@ -268,6 +277,30 @@ class Integer
|
|
268
277
|
end
|
269
278
|
end
|
270
279
|
end
|
280
|
+
|
281
|
+
# @return [Array] of signature of self
|
282
|
+
# @example
|
283
|
+
# 5.signature
|
284
|
+
# => [1]
|
285
|
+
#
|
286
|
+
def prime_signature
|
287
|
+
raise ArgumentError, "applicable only to positive integers" if self <= 0
|
288
|
+
|
289
|
+
n = self
|
290
|
+
exponents = []
|
291
|
+
i = 2
|
292
|
+
while i * i <= n
|
293
|
+
count = 0
|
294
|
+
while n % i == 0
|
295
|
+
n /= i
|
296
|
+
count += 1
|
297
|
+
end
|
298
|
+
exponents << count if count > 0
|
299
|
+
i += 1
|
300
|
+
end
|
301
|
+
exponents << 1 if n > 1 # n is prime at this point
|
302
|
+
exponents.sort
|
303
|
+
end
|
271
304
|
end
|
272
305
|
|
273
306
|
class Array
|
@@ -351,6 +384,26 @@ class Array
|
|
351
384
|
#
|
352
385
|
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
386
|
|
387
|
+
# @return [Array] with the EDO and its error best fitting the given ratios contained in self
|
388
|
+
# @example
|
389
|
+
# [3/2r].best_fitting_edo) => [53, 0.07]
|
390
|
+
# [7/4r, 3/2r].best_fitting_edo => [41, 3.46]
|
391
|
+
# @param min_edo [Integer] the mininum edo to search
|
392
|
+
# @param max_edo [Integer] the maximum edo to search
|
393
|
+
#
|
394
|
+
def best_fitting_edo(min_edo: 5, max_edo: 72)
|
395
|
+
(min_edo..max_edo).map do |edo|
|
396
|
+
step_size = 1200.0 / edo
|
397
|
+
|
398
|
+
total_error_for_edo = to_cents.map do |r_cents|
|
399
|
+
quantized = (r_cents / step_size).round * step_size
|
400
|
+
(r_cents - quantized).abs
|
401
|
+
end.sum
|
402
|
+
|
403
|
+
[edo, total_error_for_edo.round(2)]
|
404
|
+
end.min_by{|_, error| error}
|
405
|
+
end
|
406
|
+
|
354
407
|
# @return [Array] translated by value
|
355
408
|
# @example
|
356
409
|
# [0.24184760813024642, 0.49344034900361244, 0.07231824070126536].translate(-0.07231824070126536) = [0.16952936742898106, 0.4211221083023471, 0.0]
|
@@ -403,7 +456,7 @@ class Vector
|
|
403
456
|
# @param reduced
|
404
457
|
# @param equave
|
405
458
|
#
|
406
|
-
def to_ratio(reduced:
|
459
|
+
def to_ratio(reduced: false, equave: 2/1r) = reduced ? Tonal::ReducedRatio.new(*self, equave: equave) : Tonal::Ratio.new(*self, equave: equave)
|
407
460
|
alias :ratio :to_ratio
|
408
461
|
end
|
409
462
|
|
data/lib/tonal/ratio.rb
CHANGED
@@ -99,6 +99,7 @@ class Tonal::Ratio
|
|
99
99
|
def ratio
|
100
100
|
self
|
101
101
|
end
|
102
|
+
alias :to_ratio :ratio
|
102
103
|
|
103
104
|
# @return [Tonal::Ratio::Approximation] self's approximation instance
|
104
105
|
#
|
@@ -335,7 +336,6 @@ class Tonal::Ratio
|
|
335
336
|
# Tonal::Ratio.new(31/30r).prime_divisions => [[[31, 1]], [[2, 1], [3, 1], [5, 1]]]
|
336
337
|
#
|
337
338
|
def prime_divisions
|
338
|
-
return [[[2, 1]], [[2, 1]]] if antecedent == 1
|
339
339
|
[antecedent.prime_division, consequent.prime_division]
|
340
340
|
end
|
341
341
|
|
@@ -345,7 +345,9 @@ class Tonal::Ratio
|
|
345
345
|
#
|
346
346
|
def prime_vector
|
347
347
|
pds = prime_divisions
|
348
|
-
|
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
|
349
351
|
|
350
352
|
pds.last.collect!{|i| [i.first, -i.last]}
|
351
353
|
|
@@ -355,6 +357,7 @@ class Tonal::Ratio
|
|
355
357
|
end.to_vector
|
356
358
|
end
|
357
359
|
alias :monzo :prime_vector
|
360
|
+
alias :prime_exponent_vector :prime_vector
|
358
361
|
|
359
362
|
# @return [Integer] the maximum prime factor of self
|
360
363
|
# @example
|
@@ -532,14 +535,25 @@ class Tonal::Ratio
|
|
532
535
|
# @example
|
533
536
|
# Tonal::ReducedRatio.new(133).interval_with(3/2r)
|
534
537
|
# => (192/133) ((3/2) / (133/128))
|
535
|
-
# @param
|
536
|
-
# @param
|
538
|
+
# @param upper ratio
|
539
|
+
# @param lower ratio
|
537
540
|
#
|
538
|
-
def interval_with(
|
539
|
-
r = self.class.new(
|
541
|
+
def interval_with(upper, lower=nil)
|
542
|
+
r = self.class.new(upper, lower)
|
540
543
|
Tonal::Interval.new(self, r)
|
541
544
|
end
|
542
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
|
+
|
543
557
|
# @return [Integer] the difference between antecedent and consequent
|
544
558
|
# @example
|
545
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.0.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.6.
|
194
|
+
rubygems_version: 3.6.8
|
195
195
|
specification_version: 4
|
196
196
|
summary: Tonal tools
|
197
197
|
test_files: []
|