tonal-tools 6.2.1 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8b2ee2750807000bca57c6e3624a3ad589afe4ce01bde9b1a62fc66a565e7ac6
4
- data.tar.gz: '0823e862608da5a193aacd5a582d9094694b36c794e652af39987580f14cf9d7'
3
+ metadata.gz: '08e71f0a71f06993084a2567211a4106cefc25aaa4d1f28bc941bf737097915b'
4
+ data.tar.gz: 6fa78c5271fa011906a7de57b9a56f7693bd11f2985d5193b868bd00468d3341
5
5
  SHA512:
6
- metadata.gz: bfb21cebb86682d76e3f7bd9ac5aafa26307382d8788fad7176ca893aa9edc34074f7b89ae9e32ed4913f84285a388ecf8b3fd32f788d1cee8377fb05237c410
7
- data.tar.gz: ad25d51f865409821b6ae06d2efa74364fa324c13bc3a1e215ed79c289df143e3f117b4396fffd912fbce03642507bd72d3ce2a23dc14cfbb7e6976270415b72
6
+ metadata.gz: 6509f49a314f5cec9b413617ddf00967e7c57655b9eb86b8b96e56033c3ef8cd8e136ee0a69cffb0e1de413e998b67537671763fd98bb937552bb03dc52316ff
7
+ data.tar.gz: c99a22e906caaaca500225189a19f7633df2144485ef6c9479faf9bbbaefed01a04a085fd7de0b74cf4549f6b37c8afa919566d561709e66685306d962218863
@@ -1,4 +1,4 @@
1
1
  module Tonal
2
2
  TOOLS_PRODUCER = "mTonal"
3
- TOOLS_VERSION = "6.2.1"
3
+ TOOLS_VERSION = "7.0.0"
4
4
  end
@@ -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: true, equave: 2/1r) = reduced ? Tonal::ReducedRatio.new(self, equave: equave) : Tonal::Ratio.new(self, equave: equave)
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 = self.ratio.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.log2.to_cents
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) = to_log2.step(modulo)
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 = self.ratio.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 = self.ratio.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 = self.ratio.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 = self.ratio.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: true, equave: 2/1r, prime_rejects: [2]) = self.ratio(reduced: reduced, equave: equave).wilson_height(prime_rejects: prime_rejects)
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) = to_ratio.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 ratio
141
+ # @param other_ratio
142
142
  #
143
- def interval_with(ratio) = Tonal::Interval.new(self.ratio, ratio)
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 = self.ratio.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 = self.ratio.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) = self.ratio.mirror(axis)
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: true, equave: 2/1r) = reduced ? Tonal::ReducedRatio.new(*self, equave: equave) : Tonal::Ratio.new(*self, equave: equave)
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
@@ -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
- max = [pds.first.max{|p| p.first}, pds.last.max{|p| p.first}].max.first
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 antecedent
537
- # @param consequent
538
+ # @param upper ratio
539
+ # @param lower ratio
538
540
  #
539
- def interval_with(antecedent, consequent=nil)
540
- r = self.class.new(antecedent, consequent)
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: 6.2.1
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-01-16 00:00:00.000000000 Z
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.2
194
+ rubygems_version: 3.6.8
195
195
  specification_version: 4
196
196
  summary: Tonal tools
197
197
  test_files: []