tonal-tools 7.7.0 → 8.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 +4 -4
- data/lib/tonal/approximation.rb +50 -23
- data/lib/tonal/attributions.rb +1 -1
- data/lib/tonal/cents.rb +37 -0
- data/lib/tonal/extensions.rb +42 -27
- data/lib/tonal/hertz.rb +4 -4
- data/lib/tonal/interval.rb +72 -21
- data/lib/tonal/irb_helpers.rb +15 -13
- data/lib/tonal/log.rb +2 -3
- data/lib/tonal/ratio.rb +154 -93
- data/lib/tonal/reduced_ratio.rb +1 -7
- data/lib/tonal/step.rb +95 -93
- metadata +3 -3
data/lib/tonal/ratio.rb
CHANGED
|
@@ -12,7 +12,7 @@ class Tonal::Ratio
|
|
|
12
12
|
|
|
13
13
|
# @return [Tonal::Ratio]
|
|
14
14
|
# @example
|
|
15
|
-
# Tonal::Ratio.new(3,2) =>
|
|
15
|
+
# Tonal::Ratio.new(3,2) => 3/2
|
|
16
16
|
# @param antecedent [Numeric, Tonal::Ratio]
|
|
17
17
|
# @param consequent [Numeric, Tonal::Ratio]
|
|
18
18
|
#
|
|
@@ -28,7 +28,7 @@ class Tonal::Ratio
|
|
|
28
28
|
|
|
29
29
|
# @return [Tonal::Ratio] ratio who's numerator and denominator are seperated by a difference of 1
|
|
30
30
|
# @example
|
|
31
|
-
# Tonal::Ratio.superparticular(100) =
|
|
31
|
+
# Tonal::Ratio.superparticular(100) = 101/100
|
|
32
32
|
# @param n [Integer] number from which the superior part is calculated
|
|
33
33
|
# @param factor [Rational] multiplied into the resulting ratio, default 1/1
|
|
34
34
|
# @param superpart [Symbol] assigning the superior part to the antecedent or consequent
|
|
@@ -39,7 +39,7 @@ class Tonal::Ratio
|
|
|
39
39
|
|
|
40
40
|
# @return [Tonal::Ratio] ratio who's numerator and denominator are separated by a summand difference
|
|
41
41
|
# @example
|
|
42
|
-
# Tonal::Ratio.superpartient(23, summand: 3) =>
|
|
42
|
+
# Tonal::Ratio.superpartient(23, summand: 3) => 26/23
|
|
43
43
|
# @param n [Integer] number from which the superior part is calculated
|
|
44
44
|
# @param summand [Integer] term added to the superior part
|
|
45
45
|
# @param factor [Rational] multiplied into the resulting ratio, default 1/1
|
|
@@ -56,11 +56,12 @@ class Tonal::Ratio
|
|
|
56
56
|
|
|
57
57
|
# @return [Tonal::Ratio] a randomly generated ratio
|
|
58
58
|
# @example
|
|
59
|
-
# Tonal::Ratio.random_ratio =>
|
|
60
|
-
# @param number_of_factors
|
|
61
|
-
# @param within
|
|
59
|
+
# Tonal::Ratio.random_ratio => 169/1
|
|
60
|
+
# @param number_of_factors the number of prime factors to include in the ratio
|
|
61
|
+
# @param within the upper limit for prime factors
|
|
62
|
+
# @param reduced boolean determining whether to use Tonal::ReducedRatio or Tonal::Ratio
|
|
62
63
|
#
|
|
63
|
-
def self.random_ratio(number_of_factors = 2, within: 100, reduced: false)
|
|
64
|
+
def self.random_ratio(number_of_factors = 2, within: 100, reduced: (self == Tonal::ReducedRatio) ? true : false)
|
|
64
65
|
primes = Prime.each(within).to_a
|
|
65
66
|
nums = []
|
|
66
67
|
dens = []
|
|
@@ -73,13 +74,12 @@ class Tonal::Ratio
|
|
|
73
74
|
|
|
74
75
|
# @return [Tonal::Ratio] the ratio of step in the modulo
|
|
75
76
|
# @example
|
|
76
|
-
# Tonal::Ratio.ed(12, 7)
|
|
77
|
-
#
|
|
78
|
-
# @param
|
|
79
|
-
# @param
|
|
80
|
-
# @param equave
|
|
77
|
+
# Tonal::Ratio.ed(12, 7) => 1.5
|
|
78
|
+
# @param modulo the number of steps in the equal division
|
|
79
|
+
# @param step the step number in the equal division of the equave
|
|
80
|
+
# @param equave the interval of equivalence, default 2/1
|
|
81
81
|
#
|
|
82
|
-
def self.ed(
|
|
82
|
+
def self.ed(step, modulo, equave: 2/1r)
|
|
83
83
|
self.new(2**(step.to_f/modulo), equave: equave)
|
|
84
84
|
end
|
|
85
85
|
|
|
@@ -108,7 +108,7 @@ class Tonal::Ratio
|
|
|
108
108
|
end
|
|
109
109
|
|
|
110
110
|
# ==================================
|
|
111
|
-
# Conversions
|
|
111
|
+
# Conversions, mappings and measurements
|
|
112
112
|
# ==================================
|
|
113
113
|
|
|
114
114
|
# @return [Array] antecedent and consequent as elements of Array
|
|
@@ -143,6 +143,7 @@ class Tonal::Ratio
|
|
|
143
143
|
def to_f
|
|
144
144
|
antecedent.to_f / consequent.to_f
|
|
145
145
|
end
|
|
146
|
+
alias :number :to_f
|
|
146
147
|
|
|
147
148
|
# @return [Tonal::Log] Math.log of self in given base
|
|
148
149
|
# @example
|
|
@@ -177,7 +178,7 @@ class Tonal::Ratio
|
|
|
177
178
|
# Tonal::ReducedRatio.new(3,2).step(12) => 7\12
|
|
178
179
|
#
|
|
179
180
|
def step(modulo=12)
|
|
180
|
-
Tonal::Step.new(ratio: to_r, modulo: modulo)
|
|
181
|
+
Tonal::Scale::Step.new(ratio: to_r, modulo: modulo)
|
|
181
182
|
end
|
|
182
183
|
|
|
183
184
|
# @return [Float] degrees
|
|
@@ -200,7 +201,7 @@ class Tonal::Ratio
|
|
|
200
201
|
|
|
201
202
|
# @return [Tonal::Ratio] copy of self rationally reduced
|
|
202
203
|
# @example
|
|
203
|
-
# Tonal::Ratio.new(16,14).fraction_reduce =>
|
|
204
|
+
# Tonal::Ratio.new(16,14).fraction_reduce => 8/7
|
|
204
205
|
# @see to_r
|
|
205
206
|
#
|
|
206
207
|
def fraction_reduce
|
|
@@ -209,7 +210,7 @@ class Tonal::Ratio
|
|
|
209
210
|
|
|
210
211
|
# @return [Tonal::Ratio] copy of self reduced to the given equave
|
|
211
212
|
# @example
|
|
212
|
-
# Tonal::Ratio.new(48,14).equave_reduce(3) =>
|
|
213
|
+
# Tonal::Ratio.new(48,14).equave_reduce(3) => 8/7
|
|
213
214
|
# @param equave Numeric
|
|
214
215
|
#
|
|
215
216
|
def equave_reduce(equave=2/1r)
|
|
@@ -220,7 +221,7 @@ class Tonal::Ratio
|
|
|
220
221
|
|
|
221
222
|
# @return [Tonal::Ratio] self reduced to the given equave
|
|
222
223
|
# @example
|
|
223
|
-
# Tonal::Ratio.new(48,14).equave_reduce!(3) =>
|
|
224
|
+
# Tonal::Ratio.new(48,14).equave_reduce!(3) => 8/7
|
|
224
225
|
# @param equave Numeric
|
|
225
226
|
#
|
|
226
227
|
def equave_reduce!(equave=2/1r)
|
|
@@ -232,7 +233,7 @@ class Tonal::Ratio
|
|
|
232
233
|
|
|
233
234
|
# @return [Tonal::ReducedRatio] of self
|
|
234
235
|
# @example
|
|
235
|
-
# Tonal::Ratio.new(1,9).to_reduced_ratio =>
|
|
236
|
+
# Tonal::Ratio.new(1,9).to_reduced_ratio => 16/9
|
|
236
237
|
#
|
|
237
238
|
def to_reduced_ratio
|
|
238
239
|
Tonal::ReducedRatio.new(reduced_antecedent, reduced_consequent, equave: equave)
|
|
@@ -241,7 +242,7 @@ class Tonal::Ratio
|
|
|
241
242
|
|
|
242
243
|
# @return [Tonal::Ratio] copy of self with the antecedent and precedent switched
|
|
243
244
|
# @example
|
|
244
|
-
# Tonal::Ratio.new(3,2).invert =>
|
|
245
|
+
# Tonal::Ratio.new(3,2).invert => 2/3
|
|
245
246
|
#
|
|
246
247
|
def invert
|
|
247
248
|
self.class.new(consequent, antecedent)
|
|
@@ -251,7 +252,7 @@ class Tonal::Ratio
|
|
|
251
252
|
|
|
252
253
|
# @return [Tonal::Ratio] with antecedent and precedent switched
|
|
253
254
|
# @example
|
|
254
|
-
# Tonal::Ratio.new(3,2).invert! =>
|
|
255
|
+
# Tonal::Ratio.new(3,2).invert! => 2/3
|
|
255
256
|
#
|
|
256
257
|
def invert!
|
|
257
258
|
_initialize(consequent, antecedent, label: label, equave: equave)
|
|
@@ -260,7 +261,7 @@ class Tonal::Ratio
|
|
|
260
261
|
|
|
261
262
|
# @return [Tonal::Ratio] the mirror of self along the axis (default 1/1)
|
|
262
263
|
# @example
|
|
263
|
-
# Tonal::ReducedRatio.new(4,3).mirror =>
|
|
264
|
+
# Tonal::ReducedRatio.new(4,3).mirror => 3/2
|
|
264
265
|
# @param axis
|
|
265
266
|
#
|
|
266
267
|
def mirror(axis=1/1r)
|
|
@@ -269,7 +270,7 @@ class Tonal::Ratio
|
|
|
269
270
|
|
|
270
271
|
# @return [Tonal::ReducedRatio] the Ernst Levy negative of self
|
|
271
272
|
# @example
|
|
272
|
-
# Tonal::ReducedRatio.new(7/4r).negative =>
|
|
273
|
+
# Tonal::ReducedRatio.new(7/4r).negative => 12/7
|
|
273
274
|
#
|
|
274
275
|
def negative
|
|
275
276
|
self.class.new(3/2r) / self
|
|
@@ -281,10 +282,9 @@ class Tonal::Ratio
|
|
|
281
282
|
# denominator mapped on y-axis
|
|
282
283
|
# ==================================
|
|
283
284
|
#
|
|
284
|
-
|
|
285
285
|
# @return [Tonal::Ratio] with the antecedent and consequent translated by x and y
|
|
286
286
|
# @example
|
|
287
|
-
# Tonal::Ratio.new(3,2).translate(3,3) =>
|
|
287
|
+
# Tonal::Ratio.new(3,2).translate(3,3) => 6/5
|
|
288
288
|
# @param x [Numeric]
|
|
289
289
|
# @param y [Numeric]
|
|
290
290
|
#
|
|
@@ -295,7 +295,7 @@ class Tonal::Ratio
|
|
|
295
295
|
|
|
296
296
|
# @return [Tonal::Ratio] self scaled by given arguments
|
|
297
297
|
# @example
|
|
298
|
-
# Tonal::Ratio.new(3,2).scale(2**5) =>
|
|
298
|
+
# Tonal::Ratio.new(3,2).scale(2**5) => 96/64
|
|
299
299
|
# @param a [Numeric]
|
|
300
300
|
# @param b [Numeric]
|
|
301
301
|
#
|
|
@@ -306,7 +306,7 @@ class Tonal::Ratio
|
|
|
306
306
|
|
|
307
307
|
# @return [Tonal::Ratio] self sheared by given arguments
|
|
308
308
|
# @example
|
|
309
|
-
# Tonal::Ratio.new(3,2).shear(1, 3) =>
|
|
309
|
+
# Tonal::Ratio.new(3,2).shear(1, 3) => 14/11
|
|
310
310
|
# @param a [Numeric]
|
|
311
311
|
# @param b [Numeric]
|
|
312
312
|
#
|
|
@@ -377,15 +377,10 @@ class Tonal::Ratio
|
|
|
377
377
|
prime_divisions.flatten(1).map(&:first).min
|
|
378
378
|
end
|
|
379
379
|
|
|
380
|
-
#
|
|
381
|
-
#
|
|
382
|
-
#
|
|
383
|
-
# @param number to compare max prime against
|
|
380
|
+
# =================================
|
|
381
|
+
# Measures of complexity
|
|
382
|
+
# ==================================
|
|
384
383
|
#
|
|
385
|
-
def max_prime_within?(number)
|
|
386
|
-
max_prime.nil? ? false : max_prime <= number
|
|
387
|
-
end
|
|
388
|
-
|
|
389
384
|
# @return [Integer] the product complexity of self
|
|
390
385
|
# @example
|
|
391
386
|
# Tonal::ReducedRatio.new(3/2r).benedetti_height => 6
|
|
@@ -471,6 +466,86 @@ class Tonal::Ratio
|
|
|
471
466
|
cents - other_ratio.ratio.cents
|
|
472
467
|
end
|
|
473
468
|
|
|
469
|
+
# @return [Integer] the least common multiple with self's denominator and the given number's denominator
|
|
470
|
+
# @example
|
|
471
|
+
# Tonal::Ratio.new(3/2r).lcm(5/4r) => 4
|
|
472
|
+
# @param lhs [Numeric, Tonal::Ratio] the number with which the lcm with self is computed
|
|
473
|
+
#
|
|
474
|
+
def lcm(lhs)
|
|
475
|
+
[self.denominator, lhs.denominator].lcm
|
|
476
|
+
end
|
|
477
|
+
|
|
478
|
+
# @return [Tonal::Interval] between self and another ratio
|
|
479
|
+
# @example
|
|
480
|
+
# Tonal::ReducedRatio.new(3,2).interval_with(4/3r)
|
|
481
|
+
# => 9/8 (3/2 / 4/3)
|
|
482
|
+
# @example
|
|
483
|
+
# Tonal::ReducedRatio.new(3,2).interval_with(4/3r, is_lower: false)
|
|
484
|
+
# => 16/9 (4/3 / 3/2)
|
|
485
|
+
# @param other_ratio [Tonal::ReducedRatio, Numeric] the ratio to form the interval with
|
|
486
|
+
# @param is_lower [Boolean] whether other_ratio is the lower ratio of the interval
|
|
487
|
+
#
|
|
488
|
+
def interval_with(other_ratio, is_lower: true)
|
|
489
|
+
other_ratio = self.class.new(other_ratio)
|
|
490
|
+
args = is_lower ? [self, other_ratio] : [other_ratio, self]
|
|
491
|
+
Tonal::Interval.new(*args)
|
|
492
|
+
end
|
|
493
|
+
|
|
494
|
+
# @return [Tonal::Interval] between 1/1 and self
|
|
495
|
+
# @example
|
|
496
|
+
# Tonal::ReducedRatio.new(3,2).to_interval
|
|
497
|
+
# => (3/2) ((3/2) / (1/1))
|
|
498
|
+
#
|
|
499
|
+
def to_interval
|
|
500
|
+
interval_with(1/1r)
|
|
501
|
+
end
|
|
502
|
+
|
|
503
|
+
# @return [Tonal::Cents] difference between ratio (upper) and self (lower)
|
|
504
|
+
# @example
|
|
505
|
+
# Tonal::ReducedRatio.new(3,2).cents_difference_with(4/3r) => 203.91
|
|
506
|
+
# @example
|
|
507
|
+
# Tonal::ReducedRatio.new(3,2).cents_difference_with(4/3r, is_lower: false) => 996.09
|
|
508
|
+
# @param other_ratio [Tonal::ReducedRatio, Numeric] the ratio to compare cents difference with
|
|
509
|
+
#
|
|
510
|
+
def cents_difference_with(other_ratio, is_lower: true)
|
|
511
|
+
interval_with(other_ratio, is_lower:).to_cents
|
|
512
|
+
end
|
|
513
|
+
|
|
514
|
+
# @return [Integer] the difference between antecedent and consequent
|
|
515
|
+
# @example
|
|
516
|
+
# Tonal::ReducedRatio.new(3,2).difference => 1
|
|
517
|
+
#
|
|
518
|
+
def difference
|
|
519
|
+
antecedent - consequent
|
|
520
|
+
end
|
|
521
|
+
alias :diff :difference
|
|
522
|
+
|
|
523
|
+
# @return [Integer] the sum of antecedent and consequent
|
|
524
|
+
# @example
|
|
525
|
+
# Tonal::ReducedRatio.new(3,2).combination => 5
|
|
526
|
+
#
|
|
527
|
+
def combination
|
|
528
|
+
antecedent + consequent
|
|
529
|
+
end
|
|
530
|
+
alias :comb :combination
|
|
531
|
+
|
|
532
|
+
# @return [Tonal::Ratio] self raised to the given power and root
|
|
533
|
+
# @example
|
|
534
|
+
# Tonal::ReducedRatio.new(3,2).power(2) => 9/8
|
|
535
|
+
# @param power [Numeric]
|
|
536
|
+
# @param root [Numeric, nil]
|
|
537
|
+
# @param approximant [Integer] the index of the approximant to use
|
|
538
|
+
# @param by_method [Symbol] the method used to calculate approximation of the root intervalic ratio
|
|
539
|
+
# @param from [Symbol] whether to calculate the root interval from the lower or upper ratio of the interval
|
|
540
|
+
#
|
|
541
|
+
def power(power, root=nil, approximant: 0, by_method: :continued_fraction, from: :lower_ratio)
|
|
542
|
+
to_interval.root_interval(power:, root:, approximant:, by_method:, from:).intervalic_ratio
|
|
543
|
+
end
|
|
544
|
+
|
|
545
|
+
# ==================================
|
|
546
|
+
# Display
|
|
547
|
+
# ==================================
|
|
548
|
+
|
|
474
549
|
# @return [String] symbolic representation of Tonal::Ratio
|
|
475
550
|
#
|
|
476
551
|
def label
|
|
@@ -480,7 +555,7 @@ class Tonal::Ratio
|
|
|
480
555
|
|
|
481
556
|
# @return [String] the string representation of Tonal::Ratio
|
|
482
557
|
# @example
|
|
483
|
-
# Tonal::Ratio.new(3, 2).inspect => "
|
|
558
|
+
# Tonal::Ratio.new(3, 2).inspect => "3/2"
|
|
484
559
|
#
|
|
485
560
|
def inspect
|
|
486
561
|
# Return the "antecedent/consequent", if antecedent is less than 7 digits long; or
|
|
@@ -489,22 +564,51 @@ class Tonal::Ratio
|
|
|
489
564
|
end
|
|
490
565
|
alias :to_s :inspect
|
|
491
566
|
|
|
567
|
+
# ==================================
|
|
568
|
+
# Arithmetic operations
|
|
569
|
+
# ==================================
|
|
570
|
+
|
|
571
|
+
# @return [Tonal::Ratio] result of adding self and rhs
|
|
572
|
+
# @example
|
|
573
|
+
# Tonal::Ratio.new(3,2) + Tonal::Ratio.new(4,3) => (17/12)
|
|
574
|
+
# @param rhs [Numeric, Tonal::Ratio]
|
|
575
|
+
#
|
|
492
576
|
def +(rhs)
|
|
493
577
|
operate(rhs, :+)
|
|
494
578
|
end
|
|
495
579
|
|
|
580
|
+
# @return [Tonal::Ratio] result of subtracting rhs from self
|
|
581
|
+
# @example
|
|
582
|
+
# Tonal::Ratio.new(3,2) - Tonal::Ratio.new(4,3) => (1/6)
|
|
583
|
+
# @param rhs [Numeric, Tonal::Ratio]
|
|
584
|
+
#
|
|
496
585
|
def -(rhs)
|
|
497
586
|
operate(rhs, :-)
|
|
498
587
|
end
|
|
499
588
|
|
|
589
|
+
# @return [Tonal::Ratio] result of multiplying self and rhs
|
|
590
|
+
# @example
|
|
591
|
+
# Tonal::Ratio.new(3,2) * Tonal::Ratio.new(4,3) => (2/1)
|
|
592
|
+
# @param rhs [Numeric, Tonal::Ratio]
|
|
593
|
+
#
|
|
500
594
|
def *(rhs)
|
|
501
595
|
operate(rhs, :*)
|
|
502
596
|
end
|
|
503
597
|
|
|
598
|
+
# @return [Tonal::Ratio] result of dividing self by rhs
|
|
599
|
+
# @example
|
|
600
|
+
# Tonal::Ratio.new(3,2) / Tonal::Ratio.new(4,3) => (9/8)
|
|
601
|
+
# @param rhs [Numeric, Tonal::Ratio]
|
|
602
|
+
#
|
|
504
603
|
def /(rhs)
|
|
505
604
|
operate(rhs, :/)
|
|
506
605
|
end
|
|
507
606
|
|
|
607
|
+
# @return [Tonal::Ratio] result of raising self to the rhs power
|
|
608
|
+
# @example
|
|
609
|
+
# Tonal::Ratio.new(3,2) ** 2 => (9/4)
|
|
610
|
+
# @param rhs [Numeric, Tonal::Ratio]
|
|
611
|
+
#
|
|
508
612
|
def **(rhs)
|
|
509
613
|
operate(rhs, :**)
|
|
510
614
|
end
|
|
@@ -520,64 +624,27 @@ class Tonal::Ratio
|
|
|
520
624
|
alias :mediant :mediant_sum
|
|
521
625
|
alias :farey_sum :mediant_sum
|
|
522
626
|
|
|
523
|
-
#
|
|
524
|
-
# Measurements
|
|
525
|
-
# ==================================
|
|
526
|
-
|
|
527
|
-
# @return [Integer] the least common multiple with self's denominator and the given number's denominator
|
|
528
|
-
# @example
|
|
529
|
-
# Tonal::Ratio.new(3/2r).lcm(5/4r) => 4
|
|
530
|
-
# @param lhs [Numeric, Tonal::Ratio] the number with which the lcm with self is computed
|
|
531
|
-
#
|
|
532
|
-
def lcm(lhs)
|
|
533
|
-
[self.denominator, lhs.denominator].lcm
|
|
534
|
-
end
|
|
535
|
-
|
|
536
|
-
# @return [Tonal::Interval] between ratio (upper) and self (lower)
|
|
537
|
-
# @example
|
|
538
|
-
# Tonal::ReducedRatio.new(133).interval_with(3/2r)
|
|
539
|
-
# => (192/133) ((3/2) / (133/128))
|
|
540
|
-
# @param upper ratio
|
|
541
|
-
# @param lower ratio
|
|
542
|
-
#
|
|
543
|
-
def interval_with(upper, lower=nil)
|
|
544
|
-
r = self.class.new(upper, lower)
|
|
545
|
-
Tonal::Interval.new(self, r)
|
|
546
|
-
end
|
|
547
|
-
|
|
548
|
-
# @return [Tonal::Cents] difference between ratio (upper) and self (lower)
|
|
549
|
-
# @example
|
|
550
|
-
# Tonal::ReducedRatio.new(133).cents_difference_with(3/2r)
|
|
551
|
-
# => 635.62
|
|
552
|
-
# @param upper ratio
|
|
553
|
-
# @param lower ratio
|
|
554
|
-
#
|
|
555
|
-
def cents_difference_with(upper, lower=nil)
|
|
556
|
-
interval_with(upper, lower).to_cents
|
|
557
|
-
end
|
|
558
|
-
|
|
559
|
-
# @return [Integer] the difference between antecedent and consequent
|
|
627
|
+
# @return [Integer] comparison of self to rhs
|
|
560
628
|
# @example
|
|
561
|
-
# Tonal::
|
|
629
|
+
# Tonal::Ratio.new(3,2) <=> Tonal::Ratio.new(4,3) => 1
|
|
630
|
+
# @param rhs [Tonal::Ratio]
|
|
562
631
|
#
|
|
563
|
-
def
|
|
564
|
-
|
|
632
|
+
def <=>(rhs)
|
|
633
|
+
left = consequent == 0 ? Float::INFINITY : Rational(antecedent, consequent)
|
|
634
|
+
right = rhs.denominator == 0 ? Float::INFINITY : Rational(rhs.numerator, rhs.denominator)
|
|
635
|
+
left <=> right
|
|
565
636
|
end
|
|
566
|
-
alias :diff :difference
|
|
567
637
|
|
|
568
|
-
#
|
|
569
|
-
# @example
|
|
570
|
-
# Tonal::ReducedRatio.new(3,2).combination => 5
|
|
638
|
+
# Set uses Hash as storage and equality of elements is determined according to Object#eql? and Object#hash.
|
|
571
639
|
#
|
|
572
|
-
def
|
|
573
|
-
|
|
640
|
+
def eql?(other)
|
|
641
|
+
other.instance_of?(self.class) && to_r == other.to_r
|
|
574
642
|
end
|
|
575
|
-
alias :comb :combination
|
|
576
643
|
|
|
577
|
-
def
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
644
|
+
def hash
|
|
645
|
+
p, q = 17, 37
|
|
646
|
+
p = q * @id.hash
|
|
647
|
+
p = q * @name.hash
|
|
581
648
|
end
|
|
582
649
|
|
|
583
650
|
private
|
|
@@ -638,9 +705,3 @@ class Tonal::Ratio
|
|
|
638
705
|
end
|
|
639
706
|
end
|
|
640
707
|
end
|
|
641
|
-
|
|
642
|
-
module Ratio
|
|
643
|
-
def self.[](u, l=nil)
|
|
644
|
-
Tonal::Ratio.new(u, l)
|
|
645
|
-
end
|
|
646
|
-
end
|
data/lib/tonal/reduced_ratio.rb
CHANGED
|
@@ -3,7 +3,7 @@ class Tonal::ReducedRatio < Tonal::Ratio
|
|
|
3
3
|
|
|
4
4
|
# @return [Tonal::ReducedRatio]
|
|
5
5
|
# @example
|
|
6
|
-
# Tonal::ReducedRatio.new(12,2) =>
|
|
6
|
+
# Tonal::ReducedRatio.new(12,2) => 3/2
|
|
7
7
|
# @param antecedent [Numeric, Tonal::Ratio]
|
|
8
8
|
# @param consequent [Numeric, Tonal::Ratio]
|
|
9
9
|
# @param equave the interval of equivalence, default 2/1
|
|
@@ -35,9 +35,3 @@ class Tonal::ReducedRatio < Tonal::Ratio
|
|
|
35
35
|
self
|
|
36
36
|
end
|
|
37
37
|
end
|
|
38
|
-
|
|
39
|
-
module ReducedRatio
|
|
40
|
-
def self.[](u, l=nil)
|
|
41
|
-
Tonal::ReducedRatio.new(u, l)
|
|
42
|
-
end
|
|
43
|
-
end
|
data/lib/tonal/step.rb
CHANGED
|
@@ -1,112 +1,114 @@
|
|
|
1
|
-
class Tonal::
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
class Tonal::Scale
|
|
2
|
+
class Step
|
|
3
|
+
extend Forwardable
|
|
4
|
+
include Comparable
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
def_delegators :@log, :logarithmand
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
attr_reader :modulo, :log, :step, :ratio, :tempered
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
def initialize(modulo: nil, log: nil, step: nil, ratio: nil)
|
|
11
|
+
raise ArgumentError, "modulo: required" unless modulo
|
|
12
|
+
raise ArgumentError, "One of log:, step: or ratio: must be provided" unless [log, step, ratio].compact.count == 1
|
|
13
|
+
@modulo = modulo.round
|
|
13
14
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
15
|
+
if ratio
|
|
16
|
+
@ratio, @log = derive_ratio_and_log(ratio: ratio)
|
|
17
|
+
elsif step
|
|
18
|
+
@ratio, @log = derive_ratio_and_log(step: step)
|
|
19
|
+
elsif log
|
|
20
|
+
@ratio, @log = derive_ratio_and_log(log: log)
|
|
21
|
+
end
|
|
21
22
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
@step = (modulo * @log).round
|
|
24
|
+
@tempered = 2**(@step.to_f/@modulo)
|
|
25
|
+
end
|
|
25
26
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
def inspect
|
|
28
|
+
"#{step}\\#{modulo}"
|
|
29
|
+
end
|
|
30
|
+
alias :to_s :inspect
|
|
30
31
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
32
|
+
# @return [Tonal::Scale::Step] new step with the ratio mapped to the new modulo
|
|
33
|
+
# @example
|
|
34
|
+
# Tonal::Scale::Step.new(ratio: 3/2r, modulo: 31).convert(12)
|
|
35
|
+
# => 7\12
|
|
36
|
+
#
|
|
37
|
+
def convert(new_modulo)
|
|
38
|
+
self.class.new(log: log, modulo: new_modulo)
|
|
39
|
+
end
|
|
39
40
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
41
|
+
# @return [Rational] of the step
|
|
42
|
+
# @example
|
|
43
|
+
# Tonal::Scale::Step.new(ratio: 3/2r, modulo: 31).step_to_r
|
|
44
|
+
# => (6735213777669305/4503599627370496)
|
|
45
|
+
#
|
|
46
|
+
def step_to_r
|
|
47
|
+
tempered.to_r
|
|
48
|
+
end
|
|
49
|
+
alias :to_r :step_to_r
|
|
49
50
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
51
|
+
# @return [Rational] of the ratio
|
|
52
|
+
# @example
|
|
53
|
+
# Tonal::Scale::Step.new(ratio: 3/2r, modulo: 31).ratio_to_r
|
|
54
|
+
# => (3/2)
|
|
55
|
+
#
|
|
56
|
+
def ratio_to_r
|
|
57
|
+
ratio.to_r
|
|
58
|
+
end
|
|
58
59
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
60
|
+
# @return [Tonal::Cents] measure of step in cents
|
|
61
|
+
# @example
|
|
62
|
+
# Tonal::Scale::Step.new(ratio: 3/2r, modulo: 31).step_to_cents
|
|
63
|
+
# => 696.77
|
|
64
|
+
#
|
|
65
|
+
def step_to_cents
|
|
66
|
+
tempered.to_cents
|
|
67
|
+
end
|
|
68
|
+
alias :to_cents :step_to_cents
|
|
68
69
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
70
|
+
# @return [Tonal::Cents] measure of ratio in cents
|
|
71
|
+
# @example
|
|
72
|
+
# Tonal::Scale::Step.new(ratio: 3/2r, modulo: 31).ratio_to_cents
|
|
73
|
+
# => 701.96
|
|
74
|
+
#
|
|
75
|
+
def ratio_to_cents
|
|
76
|
+
ratio.to_cents
|
|
77
|
+
end
|
|
77
78
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
79
|
+
# @return [Tonal::Cents] the difference between the step and the ratio
|
|
80
|
+
# @example
|
|
81
|
+
# Tonal::Scale::Step.new(ratio: 3/2r, modulo: 31).efficiency
|
|
82
|
+
# => 5.19
|
|
83
|
+
#
|
|
84
|
+
def efficiency
|
|
85
|
+
# We want the efficiency from the step (self).
|
|
86
|
+
ratio_to_cents - step_to_cents
|
|
87
|
+
end
|
|
87
88
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
89
|
+
def +(rhs)
|
|
90
|
+
self.class.new(step: (rhs % modulo), modulo: modulo)
|
|
91
|
+
end
|
|
92
|
+
alias :% :+
|
|
92
93
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
94
|
+
def <=>(rhs)
|
|
95
|
+
rhs.kind_of?(self.class) && modulo <=> rhs.modulo && log <=> rhs.log && step <=> rhs.step
|
|
96
|
+
end
|
|
96
97
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
98
|
+
private
|
|
99
|
+
def derive_ratio_and_log(ratio: nil, log: nil, step: nil)
|
|
100
|
+
if ratio
|
|
101
|
+
[Tonal::ReducedRatio.new(ratio), Tonal::Log2.new(logarithmand: ratio)]
|
|
102
|
+
elsif log
|
|
103
|
+
if log.kind_of?(Tonal::Log)
|
|
104
|
+
[log.logarithmand, log]
|
|
105
|
+
else
|
|
106
|
+
lg = Tonal::Log2.new(logarithm: log)
|
|
107
|
+
[Tonal::ReducedRatio.new(lg.logarithmand), lg]
|
|
108
|
+
end
|
|
109
|
+
elsif step
|
|
110
|
+
[Tonal::ReducedRatio.new(2.0**(step.to_f/@modulo)), Tonal::Log2.new(logarithmand: (2.0 ** (step.to_f/@modulo)))]
|
|
107
111
|
end
|
|
108
|
-
elsif step
|
|
109
|
-
[Tonal::ReducedRatio.new(2.0**(step.to_f/@modulo)), Tonal::Log2.new(logarithmand: (2.0 ** (step.to_f/@modulo)))]
|
|
110
112
|
end
|
|
111
113
|
end
|
|
112
114
|
end
|
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: 8.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Jose Hales-Garcia
|
|
8
8
|
bindir: bin
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date: 2026-01-
|
|
10
|
+
date: 2026-01-27 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: yaml
|
|
@@ -192,7 +192,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
192
192
|
- !ruby/object:Gem::Version
|
|
193
193
|
version: '3.1'
|
|
194
194
|
requirements: []
|
|
195
|
-
rubygems_version:
|
|
195
|
+
rubygems_version: 4.0.4
|
|
196
196
|
specification_version: 4
|
|
197
197
|
summary: Tonal tools
|
|
198
198
|
test_files: []
|