tonal-tools 1.2.0 → 1.3.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: 691fae166ed9abb7f7bac70c6e28a9a5997faf5c18ac2e18c962763e45b49af7
4
- data.tar.gz: 413a77763276622ff1201f2e9cc0fb49d9486843fbd1f1f84d77cfa84a4f2da6
3
+ metadata.gz: 540d38c024465fdb45af2fbaada5a4fc020857ca03fc9c9e56f6152462e5d38e
4
+ data.tar.gz: 58637a5d53fe59d3a5feab46e587b3ae08c4d8d837aa3410b5b21d684f90fc12
5
5
  SHA512:
6
- metadata.gz: cb1ba05cd9cf96e948f25c9a832bfddd7e2e90ff59fbcdb55caf5172ddb13fc65042835ec494e2c39317d520bae8cace1ae832b182c70ee0815b8d09bb1572bf
7
- data.tar.gz: 7a813d888fe63b98681f5f6f436106f4a9e3e4c43f697ab705835af59740a26b7cba132f4c2df82e91ddb8180c4160015f6aa1839231578e0070d0f88f3b35aa
6
+ metadata.gz: d3e97921221dc86faeeae926b23af4c7ed22da2d2c26bc1377493d6442cb9dcafaa2ab60ee430b5b804e550fbfaa6e4c19c8b2379c2941b1d4407f7000649845
7
+ data.tar.gz: e5850e74a54e375834e7b578e2438146907a6a9107e6b95e72366a531f92cdab734f4d273ac8be48877d0c19ca36940dc2acf9eb3f4ded6baadf4b46eb21c54d
@@ -5,54 +5,61 @@ class Prime
5
5
  # @param lower bound
6
6
  # @param upper bound
7
7
  #
8
- def self.within(lower, upper)
9
- self.each(upper).reject{|p| p < lower}
10
- end
8
+ def self.within(lower=0, upper) = self.each(upper).reject{|p| p < lower}
11
9
  end
12
10
 
13
11
  class Numeric
12
+ # @return [Numeric] translated modularly
13
+ # @example
14
+ # Math::PI.modulo_translate(-3, 3) => -2.858407346410207
15
+ # @param lower the lower bound of the modulo range
16
+ # @param upper the upper bound of the modulo range
17
+ #
18
+ def modulo_translate(lower=0, upper)
19
+ range = (upper - lower) == 0 ? 1 : upper - lower
20
+ (self - lower) % range + lower
21
+ end
22
+
14
23
  # @return [Array] a tuple of self offset positively/negatively
15
24
  # @example
16
25
  # Math::PI.plus_minus(3)
17
26
  # => [6.141592653589793, 0.14159265358979312]
18
27
  # @param offset plus and minus distance from self
19
28
  #
20
- def plus_minus(offset)
21
- [self + offset, self - offset]
22
- end
29
+ def plus_minus(offset) = [self + offset, self - offset]
30
+ alias :min_plus :plus_minus
31
+
32
+ # @return [Array] a tuple of self divided and multiplied by factor
33
+ # @example
34
+ # Math::PI.div_times(3) => [1.0471975511965976, 9.42477796076938]
35
+ # @param [Numeric]
36
+ #
37
+ def div_times(factor) = [self / factor, self * factor]
23
38
 
24
39
  # @return [Tonal::ReducedRatio] the octave reduced ratio of self
25
40
  # @example
26
41
  # (2**(1.0/12)).ratio => (4771397596969315/4503599627370496)
27
42
  #
28
- def to_ratio(reduced: true, equave: 2/1r)
29
- reduced ? Tonal::ReducedRatio.new(self, equave: equave) : Tonal::Ratio.new(self, equave: equave)
30
- end
43
+ def to_ratio(reduced: true, equave: 2/1r) = reduced ? Tonal::ReducedRatio.new(self, equave: equave) : Tonal::Ratio.new(self, equave: equave)
31
44
  alias :ratio :to_ratio
32
45
 
33
46
  # @return [Float], the degrees on a circle of self
34
47
  # @example
35
48
  # (2**(6.0/12)).period_degrees => 180.0
36
49
  #
37
- def period_degrees
38
- self.ratio.period_degrees
39
- end
50
+ def period_degrees = self.ratio.period_degrees
40
51
 
41
52
  # @return [Tonal::Log] the log of self to the given base
42
53
  # @example
43
54
  # (3/2r).log(10) => 0.17609125905568124
44
55
  #
45
- def log(base)
46
- Tonal::Log.new(logarithmand: self, base: base)
47
- end
56
+ def log(base) = Tonal::Log.new(logarithmand: self, base: base)
48
57
 
49
58
  # @return [Tonal::Log2] the log2 of self
50
59
  # @example
51
60
  # (3/2r).log2 => 0.5849625007211562
52
61
  #
53
- def log2
54
- Tonal::Log2.new(logarithmand: self)
55
- end
62
+ def log2 = Tonal::Log2.new(logarithmand: self)
56
63
  alias :to_log2 :log2
57
64
  alias :span :log2
58
65
 
@@ -60,31 +67,23 @@ class Numeric
60
67
  # @example
61
68
  # 700.0.cents => 700.0
62
69
  #
63
- def cents
64
- Tonal::Cents.new(cents: self)
65
- end
70
+ def cents = Tonal::Cents.new(cents: self)
66
71
 
67
72
  # @return [Tonal::Cents] of self interpreted as a cents quantity
68
73
  # @example
69
74
  # 700.0.¢ => 700.0
70
75
  #
71
- def ¢
72
- cents
73
- end
76
+ def ¢ = cents
74
77
 
75
78
  # @return [Tonal::Cents] of self interpreted as a ratio
76
79
  # @example
77
80
  # (3/2r).to_cents => 701.96
78
81
  #
79
- def to_cents
80
- self.log2.to_cents
81
- end
82
+ def to_cents = self.log2.to_cents
82
83
 
83
84
  # @return [Tonal::Hertz] of self
84
85
  #
85
- def hz
86
- Tonal::Hertz.new(self)
87
- end
86
+ def hz = Tonal::Hertz.new(self)
88
87
  alias :to_hz :hz
89
88
 
90
89
  # @return [Step] the step of self in the given modulo
@@ -92,133 +91,89 @@ class Numeric
92
91
  # (5/4r).step(12) => 4\12
93
92
  # @param modulo
94
93
  #
95
- def step(modulo=12)
96
- to_log2.step(modulo)
97
- end
94
+ def step(modulo=12) = to_log2.step(modulo)
98
95
 
99
96
  # @return [Float] the log product complexity of self
100
97
  # @example
101
- # (3/2r).tenney_height => 2.584962500721156
98
+ # (3/2r).benedetti_height => 6
102
99
  #
103
- def benedetti_height
104
- self.ratio.benedetti_height
105
- end
100
+ def benedetti_height = self.ratio.benedetti_height
106
101
  alias :product_complexity :benedetti_height
107
102
 
108
103
  # @return [Integer] the product complexity of self
109
104
  # @example
110
- # (3/2r).benedetti_height => 6
105
+ # (3/2r).tenney_height => 2.584962500721156
111
106
  #
112
- def tenney_height
113
- self.ratio.tenney_height
114
- end
107
+ def tenney_height = self.ratio.tenney_height
115
108
  alias :log_product_complexity :tenney_height
116
109
 
117
110
  # @return [Integer] the Weil height
118
111
  # @example
119
112
  # (3/2r).weil_height => 3
120
113
  #
121
- def weil_height
122
- self.ratio.weil_height
123
- end
114
+ def weil_height = self.ratio.weil_height
124
115
 
125
116
  # @return [Tonal::Log2] the log of Weil height
126
117
  # @example
127
118
  # (3/2r).log_weil_height => 1.5849625007211563
128
119
  #
129
- def log_weil_height
130
- self.ratio.log_weil_height
131
- end
120
+ def log_weil_height = self.ratio.log_weil_height
132
121
 
133
122
  # @return [Integer] the Wilson height
134
123
  # @example (14/9r).wilson_height => 13
135
124
  #
136
- def wilson_height(reduced: true, equave: 2/1r, prime_rejects: [2])
137
- self.ratio(reduced: reduced, equave: equave).wilson_height(prime_rejects: prime_rejects)
138
- end
125
+ def wilson_height(reduced: true, equave: 2/1r, prime_rejects: [2]) = self.ratio(reduced: reduced, equave: equave).wilson_height(prime_rejects: prime_rejects)
139
126
 
140
127
  # @return [Float] the cents difference between self and its step in the given modulo
141
128
  # @example
142
129
  # (3/2r).efficiency(12) => -1.955000865387433
143
130
  # @param modulo
144
131
  #
145
- def efficiency(modulo)
146
- (Tonal::Cents::CENT_SCALE * step(modulo).step / modulo.to_f) - to_cents
147
- end
132
+ def efficiency(modulo) = (Tonal::Cents::CENT_SCALE * step(modulo).step / modulo.to_f) - to_cents
148
133
 
149
134
  # @return [Interval] beween self (upper) and ratio (lower)
150
135
  # @example
151
136
  # (133).interval_with(3/2r) => 133/96 (133/128 / 3/2)
152
137
  # @param ratio
153
138
  #
154
- def interval_with(ratio)
155
- Tonal::Interval.new(self.ratio, ratio)
156
- end
139
+ def interval_with(ratio) = Tonal::Interval.new(self.ratio, ratio)
157
140
 
158
141
  # @return [Vector], self represented as a prime vector
159
142
  # @example
160
143
  # (3/2r).prime_vector => Vector[-1, 1]
161
144
  #
162
- def prime_vector
163
- self.ratio.prime_vector
164
- end
145
+ def prime_vector = self.ratio.prime_vector
165
146
  alias :monzo :prime_vector
166
147
 
167
148
  # @return [Array], self decomposed into its prime factors
168
149
  # @example
169
150
  # (31/30r).prime_divisions => [[[31, 1]], [[2, 1], [3, 1], [5, 1]]]
170
151
  #
171
- def prime_divisions
172
- self.ratio.prime_divisions
173
- end
152
+ def prime_divisions = self.ratio.prime_divisions
174
153
 
175
154
  # @return [Integer] the maximum prime factor of self
176
155
  # @example
177
156
  # (31/30r).max_prime => 31
178
157
  #
179
- def max_prime
180
- prime_divisions.flatten(1).map(&:first).max
181
- end
158
+ def max_prime = prime_divisions.flatten(1).map(&:first).max
182
159
 
183
160
  # @return [Integer] the minimum prime factor of self
184
161
  # @example
185
162
  # (31/30r).min_prime => 2
186
163
  #
187
- def min_prime
188
- prime_divisions.flatten(1).map(&:first).min
189
- end
190
-
191
- # @return [Integer] the product complexity of self
192
- # @example
193
- # (3/2r).benedetti_height => 6
194
- #
195
- def benedetti_height
196
- numerator * denominator
197
- end
198
-
199
- # @return [Float] the log product complexity of self
200
- # @example
201
- # (3/2r).tenney_height => 2.584962500721156
202
- #
203
- def tenney_height
204
- Tonal::Log2.new(logarithmand: benedetti_height)
205
- end
164
+ def min_prime = prime_divisions.flatten(1).map(&:first).min
206
165
 
207
166
  # @return [Tonal::ReducedRatio], the Ernst Levy negative of self
208
167
  # @example
209
168
  # (7/4r).negative => (12/7)
210
169
  #
211
- def negative
212
- self.ratio.negative
213
- end
170
+ def negative = self.ratio.negative
214
171
 
215
172
  # @return [Tonal::ReducedRatio], the ratio rotated on the given axis, default 1/1
216
173
  # @example
217
174
  # (3/2r).mirror => (4/3)
218
175
  #
219
- def mirror(axis=1/1r)
220
- self.ratio.mirror(axis)
221
- end
176
+ def mirror(axis=1/1r) = self.ratio.mirror(axis)
222
177
  end
223
178
 
224
179
  class Rational
@@ -226,34 +181,26 @@ class Rational
226
181
  # @example
227
182
  # (3/2r).to_vector => Vector[3, 2]
228
183
  #
229
- def to_vector
230
- Vector[self.numerator, self.denominator]
231
- end
184
+ def to_vector = Vector[self.numerator, self.denominator]
232
185
  alias :vector :to_vector
233
186
 
234
187
  # @return [Array], self decomposed into its prime factors
235
188
  # @example
236
189
  # (31/30r).prime_divisions => [[[31, 1]], [[2, 1], [3, 1], [5, 1]]]
237
190
  #
238
- def prime_divisions
239
- self.ratio.prime_divisions
240
- end
191
+ def prime_divisions = self.ratio.prime_divisions
241
192
 
242
193
  # @return [Integer] the maximum prime factor of self
243
194
  # @example
244
195
  # (31/30r).max_prime => 31
245
196
  #
246
- def max_prime
247
- self.ratio.max_prime
248
- end
197
+ def max_prime = self.ratio.max_prime
249
198
 
250
199
  # @return [Integer] the minimum prime factor of self
251
200
  # @example
252
201
  # (31/30r).min_prime => 2
253
202
  #
254
- def min_prime
255
- self.ratio.min_prime
256
- end
203
+ def min_prime = self.ratio.min_prime
257
204
  end
258
205
 
259
206
  class Integer
@@ -263,34 +210,26 @@ class Integer
263
210
  # @example
264
211
  # 72.max_prime => 3
265
212
  #
266
- def max_prime
267
- self.prime_division.map(&:first).max
268
- end
213
+ def max_prime = self.prime_division.map(&:first).max
269
214
 
270
215
  # @return [Integer] the minimum prime factor of self
271
216
  # @example
272
217
  # 72.min_prime => 2
273
218
  #
274
- def min_prime
275
- self.prime_division.map(&:first).min
276
- end
219
+ def min_prime = self.prime_division.map(&:first).min
277
220
 
278
221
  # @return [Integer] the factorial of self
279
222
  # @example
280
223
  # 5.factorial => 120
281
224
  #
282
- def factorial
283
- (2..self).reduce(1, :*)
284
- end
225
+ def factorial = (2..self).reduce(1, :*)
285
226
 
286
227
  # @return [Boolean] if self is coprime with i
287
228
  # @example
288
229
  # 25.coprime?(7) => true
289
230
  # 25.coprime?(5) => false
290
231
  #
291
- def coprime?(i)
292
- self.gcd(i) == 1
293
- end
232
+ def coprime?(i) = self.gcd(i) == 1
294
233
 
295
234
  # @return [Array] list of integers that are coprime with self, up to the value of self
296
235
  # @example
@@ -308,9 +247,7 @@ class Integer
308
247
  # @example
309
248
  # 10.phi => 4
310
249
  #
311
- def phi
312
- coprimes.count
313
- end
250
+ def phi = coprimes.count
314
251
  alias :totient :phi
315
252
 
316
253
  # @return [Array] of integers that are n-smooth with self
@@ -358,43 +295,33 @@ class Array
358
295
  # @param min_size
359
296
  # @param value
360
297
  #
361
- def rpad(min_size, value = nil)
362
- self.dup.rpad!(min_size, value)
363
- end
298
+ def rpad(min_size, value = nil) = self.dup.rpad!(min_size, value)
364
299
 
365
300
  # @return [Vector] self converted to a vector
366
301
  # @example
367
302
  # [3,2].to_vector => Vector[3, 2]
368
303
  #
369
- def to_vector
370
- Vector[*self]
371
- end
304
+ def to_vector = Vector[*self]
372
305
  alias :vector :to_vector
373
306
 
374
307
  # @return [Integer] least common multiple of integer elements of self
375
308
  # @example
376
309
  # [3, 2, 7].lcm => 42
377
310
  #
378
- def lcm
379
- self.reduce(1, :lcm)
380
- end
311
+ def lcm = self.reduce(1, :lcm)
381
312
 
382
313
  # @return [Array] of numerators of elements of self
383
314
  # @example
384
315
  # [3/2r, 5/4r].numerators => [3, 5]
385
316
  #
386
- def numerators
387
- self.map(&:numerator)
388
- end
317
+ def numerators = self.map(&:numerator)
389
318
  alias :antecedents :numerators
390
319
 
391
320
  # @return [Array] of denominators of elements of self
392
321
  # @example
393
322
  # [Tonal::Ratio.new(3,2), Tonal::Ratio.new(5,4)].denominators => [2, 4]
394
323
  #
395
- def denominators
396
- self.map(&:denominator)
397
- end
324
+ def denominators = self.map(&:denominator)
398
325
  alias :consequents :denominators
399
326
 
400
327
  # @return [Array] an array of normalized ratios
@@ -410,25 +337,57 @@ class Array
410
337
  # @example
411
338
  # [3/2r, 4/3r].to_cents => [701.96, 498.04]
412
339
  #
413
- def to_cents
414
- self.map{|r| r.to_cents}
415
- end
340
+ def to_cents = self.map{|r| r.to_cents}
416
341
  alias :cents :to_cents
417
342
 
418
343
  # @return [Float] the mean of the elements of self
419
344
  # @example
420
345
  # [1, 2].mean => 1.5
421
346
  #
422
- def mean
423
- self.sum / self.count.to_f
424
- end
347
+ def mean = self.sum / self.count.to_f
425
348
 
426
349
  # @return [Tonal::ReducedRatio] ratio reconstructed from the result of a prime factor decomposition
427
350
  # @example
428
351
  # [[[3, 1]], [[2, 1]]].ratio_from_prime_divisions => (3/2)
429
352
  #
430
- def ratio_from_prime_divisions
431
- Tonal::Ratio.new(Prime.int_from_prime_division(self.first), Prime.int_from_prime_division(self.last))
353
+ def ratio_from_prime_divisions = Tonal::Ratio.new(Prime.int_from_prime_division(self.first), Prime.int_from_prime_division(self.last))
354
+
355
+ # @return [Array] translated by value
356
+ # @example
357
+ # [0.24184760813024642, 0.49344034900361244, 0.07231824070126536].translate(-0.07231824070126536) = [0.16952936742898106, 0.4211221083023471, 0.0]
358
+ # @param value [Numeric] the value that is translating self
359
+ #
360
+ def translate(value) = self.map{|e| e + value}
361
+
362
+
363
+ # @return [Array] rescaled by new minimum and new maximum
364
+ # @example
365
+ # [0.47943068514319154, 0.7161083818132802, 0.19855867360591783].rescale(0,3)
366
+ # => [1.6280871600341376, 3.0, 0.0]
367
+ # @param new_min
368
+ # @param new_max
369
+ #
370
+ def rescale(new_min=0, new_max)
371
+ old_min = min
372
+ old_max = max
373
+
374
+ self.map do |x|
375
+ new_min + ((x - old_min) * (new_max - new_min)) / (old_max - old_min)
376
+ end
377
+ end
378
+
379
+ # @return [Array] translated modularly
380
+ # @example
381
+ # [-6.617469071022061, 4.755369851099594, 7.588140911919945, -6.49706614430203].modulo_translate(-3, 5)
382
+ # => [2.382530928977939, 4.755369851099594, -1.411859088080055, 2.50293385569797]
383
+ # @param lower the lower bound of the modulo range
384
+ # @param upper the upper bound of the modulo range
385
+ #
386
+ def modulo_translate(lower=0, upper)
387
+ range = upper - lower + 1
388
+ map do |value|
389
+ (value - lower) % range + lower
390
+ end
432
391
  end
433
392
  end
434
393
 
@@ -439,9 +398,7 @@ class Vector
439
398
  # @param reduced
440
399
  # @param equave
441
400
  #
442
- def to_ratio(reduced: true, equave: 2/1r)
443
- reduced ? Tonal::ReducedRatio.new(*self, equave: equave) : Tonal::Ratio.new(*self, equave: equave)
444
- end
401
+ def to_ratio(reduced: true, equave: 2/1r) = reduced ? Tonal::ReducedRatio.new(*self, equave: equave) : Tonal::Ratio.new(*self, equave: equave)
445
402
  alias :ratio :to_ratio
446
403
  end
447
404
 
@@ -451,9 +408,7 @@ module Math
451
408
  # Math.factorial(10) => 3628800
452
409
  # @param limit
453
410
  #
454
- def self.factorial(limit)
455
- (2..limit).reduce(1, :*)
456
- end
411
+ def self.factorial(limit) = (2..limit).reduce(1, :*)
457
412
 
458
413
  PHI = (1 + 5**(1.0/2))/2
459
414
  end
data/lib/tonal/ratio.rb CHANGED
@@ -456,6 +456,7 @@ class Tonal::Ratio
456
456
  ratio = ratio.ratio
457
457
  [self - ratio, self + ratio]
458
458
  end
459
+ alias :min_plus :plus_minus
459
460
 
460
461
  # @return [Cents] cent difference between self and other ratio
461
462
  # @example
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tonal-tools
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jose Hales-Garcia
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-01-16 00:00:00.000000000 Z
11
+ date: 2024-01-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  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.5.3
194
+ rubygems_version: 3.5.4
195
195
  signing_key:
196
196
  specification_version: 4
197
197
  summary: Tonal tools