tonal-tools 5.3.0 → 6.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/approximation.rb +4 -4
- data/lib/tonal/attributions.rb +1 -1
- data/lib/tonal/cents.rb +2 -2
- data/lib/tonal/extensions.rb +20 -5
- data/lib/tonal/interval.rb +22 -4
- data/lib/tonal/irb_helpers.rb +45 -0
- data/lib/tonal/log.rb +4 -4
- data/lib/tonal/ratio.rb +63 -46
- data/lib/tonal/reduced_ratio.rb +6 -11
- data/lib/tonal/step.rb +4 -3
- data/lib/tonal/tools.rb +6 -0
- metadata +9 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 398a62afac11715589c7fa92c09f0ac6017ca1edd45758bf6baf90eac7dc3d78
|
4
|
+
data.tar.gz: 16922965bddd3191a4cdefe3ae238d0cd654bd10648fc029362c5bf479a6a513
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 56595c7e2479252bec13c9c2d41775da6077b2a98396a5916b88541d328cc2d20d72cef8628369dc1646a781b47442707d9828a7d601e83be4028ea66d1280b8
|
7
|
+
data.tar.gz: 25c2f3d1ace9a3337140abecfba8e12908274471824c491a099650b96923e820f545c64180850e62838ead9fdf36a8cac6b04bf9386377be9e502c9ddb10554e
|
data/lib/tonal/approximation.rb
CHANGED
@@ -35,7 +35,7 @@ class Tonal::Ratio
|
|
35
35
|
Set.new(ratio: ratio) do |ratios|
|
36
36
|
ContinuedFraction.new(antecedent.to_f/consequent, conv_limit).convergents.each do |convergent|
|
37
37
|
ratio2 = ratio.class.new(convergent.numerator,convergent.denominator)
|
38
|
-
ratios << ratio2 if ratio.class.within_cents?(self_in_cents, ratio2.to_cents, within) && ratio2.
|
38
|
+
ratios << ratio2 if ratio.class.within_cents?(self_in_cents, ratio2.to_cents, within) && ratio2.max_prime_within?(max_prime)
|
39
39
|
break if ratios.length >= depth
|
40
40
|
end
|
41
41
|
end
|
@@ -55,7 +55,7 @@ class Tonal::Ratio
|
|
55
55
|
Set.new(ratio: ratio) do |ratios|
|
56
56
|
FractionTree.node(to_f).path.each do |node|
|
57
57
|
ratio2 = ratio.class.new(node.number)
|
58
|
-
ratios << ratio2 if ratio.class.within_cents?(self_in_cents, ratio2.to_cents, within) && ratio2.
|
58
|
+
ratios << ratio2 if ratio.class.within_cents?(self_in_cents, ratio2.to_cents, within) && ratio2.max_prime_within?(max_prime)
|
59
59
|
break if ratios.length >= depth
|
60
60
|
end
|
61
61
|
end
|
@@ -77,7 +77,7 @@ class Tonal::Ratio
|
|
77
77
|
n = 1
|
78
78
|
while true do
|
79
79
|
ratio2 = ratio.class.superparticular(n, factor: ratio.to_r, superpart:)
|
80
|
-
ratios << ratio2 if ratio.class.within_cents?(self_in_cents, ratio2.to_cents, within) && ratio2.
|
80
|
+
ratios << ratio2 if ratio.class.within_cents?(self_in_cents, ratio2.to_cents, within) && ratio2.max_prime_within?(max_prime) && ratio2 != ratio
|
81
81
|
break if ratios.length >= depth
|
82
82
|
n += 1
|
83
83
|
end
|
@@ -105,7 +105,7 @@ class Tonal::Ratio
|
|
105
105
|
while boundary <= max_boundary
|
106
106
|
vacinity = ratio.respond_to?(:to_basic_ratio) ? to_basic_ratio.scale(scale) : ratio.scale(scale)
|
107
107
|
self.class.neighbors(away: boundary, vacinity: vacinity).each do |neighbor|
|
108
|
-
ratios << neighbor if ratio.class.within_cents?(self_in_cents, neighbor.to_cents, within) && neighbor.
|
108
|
+
ratios << neighbor if ratio.class.within_cents?(self_in_cents, neighbor.to_cents, within) && neighbor.max_prime_within?(max_prime) && neighbor != ratio
|
109
109
|
end
|
110
110
|
boundary += 1
|
111
111
|
end
|
data/lib/tonal/attributions.rb
CHANGED
data/lib/tonal/cents.rb
CHANGED
@@ -70,7 +70,7 @@ class Tonal::Cents
|
|
70
70
|
# @return
|
71
71
|
# [Tonal::Cents] nearest hundredth cent difference
|
72
72
|
# @example
|
73
|
-
# Tonal::Cents.new(701.9550008653874).nearest_hundredth_difference => 1.
|
73
|
+
# Tonal::Cents.new(cents: 701.9550008653874).nearest_hundredth_difference => 1.96
|
74
74
|
#
|
75
75
|
def nearest_hundredth_difference
|
76
76
|
self.class.new(cents: (value - nearest_hundredth))
|
@@ -108,7 +108,7 @@ class Tonal::Cents
|
|
108
108
|
def derive_log(cents: nil, ratio: nil, log: nil)
|
109
109
|
return Tonal::Log2.new(logarithm: cents / CENT_SCALE) if cents
|
110
110
|
return Tonal::Log2.new(logarithmand: ratio) if ratio
|
111
|
-
log.kind_of?(Tonal::
|
111
|
+
log.kind_of?(Tonal::Log) ? log : Tonal::Log2.new(logarithm: log)
|
112
112
|
end
|
113
113
|
|
114
114
|
def derive_ratio(log: nil, ratio: nil)
|
data/lib/tonal/extensions.rb
CHANGED
@@ -9,6 +9,9 @@ class Prime
|
|
9
9
|
end
|
10
10
|
|
11
11
|
class Numeric
|
12
|
+
alias :antecedent :numerator
|
13
|
+
alias :consequent :denominator
|
14
|
+
|
12
15
|
# @return [Numeric] translated modularly
|
13
16
|
# @example
|
14
17
|
# Math::PI.modulo_translate(-3, 3) => -2.858407346410207
|
@@ -102,7 +105,7 @@ class Numeric
|
|
102
105
|
|
103
106
|
# @return [Integer] the product complexity of self
|
104
107
|
# @example
|
105
|
-
# (3/2r).tenney_height => 2.
|
108
|
+
# (3/2r).tenney_height => 2.58
|
106
109
|
#
|
107
110
|
def tenney_height = self.ratio.tenney_height
|
108
111
|
alias :log_product_complexity :tenney_height
|
@@ -115,7 +118,7 @@ class Numeric
|
|
115
118
|
|
116
119
|
# @return [Tonal::Log2] the log of Weil height
|
117
120
|
# @example
|
118
|
-
# (3/2r).log_weil_height => 1.
|
121
|
+
# (3/2r).log_weil_height => 1.58
|
119
122
|
#
|
120
123
|
def log_weil_height = self.ratio.log_weil_height
|
121
124
|
|
@@ -126,10 +129,11 @@ class Numeric
|
|
126
129
|
|
127
130
|
# @return [Float] the cents difference between self and its step in the given modulo
|
128
131
|
# @example
|
129
|
-
# (3/2r).efficiency(12) => -1.
|
132
|
+
# (3/2r).efficiency(12) => -1.96
|
130
133
|
# @param modulo
|
131
134
|
#
|
132
|
-
|
135
|
+
# We want the efficiency from the ratio (self)
|
136
|
+
def efficiency(modulo) = to_ratio.efficiency(modulo)
|
133
137
|
|
134
138
|
# @return [Tonal::Interval] beween self (upper) and ratio (lower)
|
135
139
|
# @example
|
@@ -240,11 +244,11 @@ class Integer
|
|
240
244
|
alias :totient :phi
|
241
245
|
|
242
246
|
# @return [Array] of integers that are n-smooth with self
|
243
|
-
# Adapted from https://rosettacode.org/wiki/N-smooth_numbers#Ruby
|
244
247
|
# @example
|
245
248
|
# 5.nsmooth(25)
|
246
249
|
# => [1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, 16, 18, 20, 24, 25, 27, 30, 32, 36, 40, 45, 48, 50, 54]
|
247
250
|
# @param limit
|
251
|
+
# @note Adapted from https://rosettacode.org/wiki/N-smooth_numbers#Ruby
|
248
252
|
#
|
249
253
|
def nsmooth(limit=2)
|
250
254
|
([0] * limit).tap do |ns|
|
@@ -267,6 +271,11 @@ class Integer
|
|
267
271
|
end
|
268
272
|
|
269
273
|
class Array
|
274
|
+
alias :numerator :first
|
275
|
+
alias :denominator :last
|
276
|
+
alias :antecedent :first
|
277
|
+
alias :consequent :last
|
278
|
+
|
270
279
|
# @return [Array] self replaced by array padded to the right up to n, with value. value default is nil
|
271
280
|
# @example
|
272
281
|
# [3,2].rpad!(3, 12) => [3, 2, 12]
|
@@ -379,6 +388,12 @@ class Array
|
|
379
388
|
(value - lower) % range + lower
|
380
389
|
end
|
381
390
|
end
|
391
|
+
|
392
|
+
# @return [Rational] from first and last element of array. Ideally to be used with tuples.
|
393
|
+
# @example
|
394
|
+
# [4,3].to_r => (4/3)
|
395
|
+
#
|
396
|
+
def to_r = Rational(numerator, denominator)
|
382
397
|
end
|
383
398
|
|
384
399
|
class Vector
|
data/lib/tonal/interval.rb
CHANGED
@@ -8,9 +8,21 @@ class Tonal::Interval
|
|
8
8
|
|
9
9
|
INTERVAL_OF_EQUIVALENCE = 2/1r
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
|
11
|
+
# @return [Tonal::Interval] the interval of the given ratios
|
12
|
+
# @example
|
13
|
+
# Tonal::Interval.new(2,3) => (3/2) ((3/2) / (1/1))
|
14
|
+
# @param args two arguments representing ratios or four arguments representing two pairs of numerator/denominator
|
15
|
+
# @param reduced boolean determining whether to use Tonal::ReducedRatio or Tonal::Ratio
|
16
|
+
#
|
17
|
+
def initialize(*args, reduced: true)
|
18
|
+
klass = reduced ? Tonal::ReducedRatio : Tonal::Ratio
|
19
|
+
raise(ArgumentError, "Two or four arguments required. Either two ratios, or two pairs of numerator, denominator", caller[0]) unless [2, 4].include?(args.size)
|
20
|
+
@lower_ratio, @upper_ratio = case args.size
|
21
|
+
when 2
|
22
|
+
[klass.new(args[0].antecedent, args[0].consequent), klass.new(args[1].antecedent, args[1].consequent)]
|
23
|
+
when 4
|
24
|
+
[klass.new(args[0],args[1]), klass.new(args[2], args[3])]
|
25
|
+
end
|
14
26
|
@interval = @upper_ratio / @lower_ratio
|
15
27
|
end
|
16
28
|
alias :ratio :interval
|
@@ -30,10 +42,16 @@ class Tonal::Interval
|
|
30
42
|
end
|
31
43
|
|
32
44
|
def inspect
|
33
|
-
"#{
|
45
|
+
"#{interval} (#{upper} / #{lower})"
|
34
46
|
end
|
35
47
|
|
36
48
|
def <=>(rhs)
|
37
49
|
interval.to_r <=> rhs.interval.to_r
|
38
50
|
end
|
39
51
|
end
|
52
|
+
|
53
|
+
module Interval
|
54
|
+
def self.[](l, u, reduced=true)
|
55
|
+
Tonal::Interval.new(l, u, reduced:)
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Tonal
|
2
|
+
module IRBHelpers
|
3
|
+
# @return [Tonal::Ratio] an unreduced ratio
|
4
|
+
# @example
|
5
|
+
# r(3,3) => (3/3)
|
6
|
+
# @param arg1 the ratio if only argument provided, or the numerator if two argments are provided
|
7
|
+
# @param arg2 the denominator when two arguments are provided
|
8
|
+
#
|
9
|
+
def r(arg1, arg2=nil)
|
10
|
+
Tonal::Ratio.new(arg1, arg2)
|
11
|
+
end
|
12
|
+
|
13
|
+
# @return [Tonal::ReducedRatio] a reduced ratio
|
14
|
+
# @example
|
15
|
+
# r(3,3) => (1/1)
|
16
|
+
# @param arg1 the ratio if only argument provided, or the numerator if two argments are provided
|
17
|
+
# @param arg2 the denominator when two arguments are provided
|
18
|
+
#
|
19
|
+
def rr(arg1, arg2=nil)
|
20
|
+
Tonal::ReducedRatio.new(arg1, arg2)
|
21
|
+
end
|
22
|
+
|
23
|
+
# @return [Tonal::Interval] the interval between the given args
|
24
|
+
# @example
|
25
|
+
# i(2,3) => (3/2) ((3/2) / (1/1))
|
26
|
+
# @param args two arguments representing ratios or four arguments representing two pairs of numerator/denominator
|
27
|
+
# @param reduced boolean determining whether to use Tonal::ReducedRatio or Tonal::Ratio
|
28
|
+
#
|
29
|
+
def i(*args, reduced: true)
|
30
|
+
Tonal::Interval.new(*args, reduced:)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# @note
|
35
|
+
# Intended for activation from +~/.irbrc+, by placing: +ENV["MTONAL_IRB_HELPERS" ] = "1"+, in the file
|
36
|
+
#
|
37
|
+
# Invoking this command from the IRB will add the helper methods: +r+, +rr+, +i+ in +main+.
|
38
|
+
# These methods represent {Tonal::Ratio}, {Tonal::ReducedRatio} and {Tonal::Interval} respectively.
|
39
|
+
#
|
40
|
+
# @see Tonal::IRBHelpers
|
41
|
+
#
|
42
|
+
def self.include_irb_helpers
|
43
|
+
Object.include(IRBHelpers)
|
44
|
+
end
|
45
|
+
end
|
data/lib/tonal/log.rb
CHANGED
@@ -52,7 +52,7 @@ class Tonal::Log
|
|
52
52
|
|
53
53
|
# @return [Tonal::Cents] the cents scale logarithm
|
54
54
|
# @example
|
55
|
-
# Tonal::Log.new(logarithmand: 3/2r, base: 2).to_cents => 701.
|
55
|
+
# Tonal::Log.new(logarithmand: 3/2r, base: 2).to_cents => 701.96
|
56
56
|
# @see Tonal::Cents
|
57
57
|
#
|
58
58
|
def to_cents(precision: Tonal::Cents::PRECISION)
|
@@ -61,7 +61,7 @@ class Tonal::Log
|
|
61
61
|
|
62
62
|
# @return [Tonal::Step] the nearest step in the given modulo
|
63
63
|
# @example
|
64
|
-
# Tonal::Log.new(3/2r, base: 2).step(12) => 7\12
|
64
|
+
# Tonal::Log.new(logarithmand: 3/2r, base: 2).step(12) => 7\12
|
65
65
|
#
|
66
66
|
def step(modulo)
|
67
67
|
Tonal::Step.new(modulo: modulo, log: self)
|
@@ -69,10 +69,10 @@ class Tonal::Log
|
|
69
69
|
|
70
70
|
# @return [String] the string representation of Tonal::Log
|
71
71
|
# @example
|
72
|
-
# Tonal::Log.new(3/2r, base: 2).inspect => "0.
|
72
|
+
# Tonal::Log.new(logarithmand: 3/2r, base: 2).inspect => "0.58"
|
73
73
|
#
|
74
74
|
def inspect
|
75
|
-
"#{logarithm}"
|
75
|
+
"#{logarithm.round(2)}"
|
76
76
|
end
|
77
77
|
|
78
78
|
def <=>(rhs)
|
data/lib/tonal/ratio.rb
CHANGED
@@ -81,7 +81,7 @@ class Tonal::Ratio
|
|
81
81
|
|
82
82
|
# @return [Boolean] if pair of ratios are within the given cents limit
|
83
83
|
# @example
|
84
|
-
# Tonal::Ratio.within_cents?(100, 105, 2) =>
|
84
|
+
# Tonal::Ratio.within_cents?(100, 105, 2) => false
|
85
85
|
# @param cents1
|
86
86
|
# @param cents2
|
87
87
|
# @param within
|
@@ -141,7 +141,7 @@ class Tonal::Ratio
|
|
141
141
|
|
142
142
|
# @return [Tonal::Log] Math.log of self in given base
|
143
143
|
# @example
|
144
|
-
# Tonal::Ratio.new(3,2).log(3) => 0.
|
144
|
+
# Tonal::Ratio.new(3,2).log(3) => 0.37
|
145
145
|
# @param base
|
146
146
|
#
|
147
147
|
def to_log(base=2)
|
@@ -151,7 +151,7 @@ class Tonal::Ratio
|
|
151
151
|
|
152
152
|
# @return [Tonal::Log2] Math.log2 of self
|
153
153
|
# @example
|
154
|
-
# Tonal::ReducedRatio.new(3,2).to_log2 => 0.
|
154
|
+
# Tonal::ReducedRatio.new(3,2).to_log2 => 0.58
|
155
155
|
#
|
156
156
|
def to_log2
|
157
157
|
Tonal::Log2.new(logarithmand: to_r)
|
@@ -169,7 +169,7 @@ class Tonal::Ratio
|
|
169
169
|
|
170
170
|
# @return [Integer] the step of self in the given modulo
|
171
171
|
# @example
|
172
|
-
# Tonal::ReducedRatio.new(3,2).step(12) => 7
|
172
|
+
# Tonal::ReducedRatio.new(3,2).step(12) => 7\12
|
173
173
|
#
|
174
174
|
def step(modulo=12)
|
175
175
|
Tonal::Step.new(ratio: to_r, modulo: modulo)
|
@@ -254,7 +254,7 @@ class Tonal::Ratio
|
|
254
254
|
|
255
255
|
# @return [Tonal::Ratio] the mirror of self along the axis (default 1/1)
|
256
256
|
# @example
|
257
|
-
# Tonal::
|
257
|
+
# Tonal::ReducedRatio.new(4,3).mirror => (3/2)
|
258
258
|
# @param axis
|
259
259
|
#
|
260
260
|
def mirror(axis=1/1r)
|
@@ -299,7 +299,7 @@ class Tonal::Ratio
|
|
299
299
|
|
300
300
|
# @return [Tonal::Ratio] self sheared by given arguments
|
301
301
|
# @example
|
302
|
-
# Tonal::Ratio.new(3,2).shear(1, 3) => (
|
302
|
+
# Tonal::Ratio.new(3,2).shear(1, 3) => (14/11)
|
303
303
|
# @param a [Numeric]
|
304
304
|
# @param b [Numeric]
|
305
305
|
#
|
@@ -368,8 +368,13 @@ class Tonal::Ratio
|
|
368
368
|
prime_divisions.flatten(1).map(&:first).min
|
369
369
|
end
|
370
370
|
|
371
|
-
|
372
|
-
|
371
|
+
# @return [Boolean] whether self's max prime is within the given number
|
372
|
+
# @example
|
373
|
+
# Tonal::Ratio.new(31/30r).max_prime_within?(7) => false
|
374
|
+
# @param number to compare max prime against
|
375
|
+
#
|
376
|
+
def max_prime_within?(number)
|
377
|
+
max_prime <= number
|
373
378
|
end
|
374
379
|
|
375
380
|
# @return [Integer] the product complexity of self
|
@@ -383,7 +388,7 @@ class Tonal::Ratio
|
|
383
388
|
|
384
389
|
# @return [Tonal::Log2] the log product complexity of self
|
385
390
|
# @example
|
386
|
-
# Tonal::ReducedRatio.new(3/2r).tenney_height => 2.
|
391
|
+
# Tonal::ReducedRatio.new(3/2r).tenney_height => 2.58
|
387
392
|
#
|
388
393
|
def tenney_height
|
389
394
|
Tonal::Log2.new(logarithmand: benedetti_height)
|
@@ -402,7 +407,7 @@ class Tonal::Ratio
|
|
402
407
|
|
403
408
|
# @return [Tonal::Log2] the log of Weil height
|
404
409
|
# @example
|
405
|
-
# Tonal::ReducedRatio.new(3/2r).log_weil_height => 1.
|
410
|
+
# Tonal::ReducedRatio.new(3/2r).log_weil_height => 1.58
|
406
411
|
#
|
407
412
|
def log_weil_height
|
408
413
|
Tonal::Log2.new(logarithmand: weil_height)
|
@@ -418,33 +423,33 @@ class Tonal::Ratio
|
|
418
423
|
|
419
424
|
# @return [Tonal::Cents] the cents difference between self and its step in the given modulo
|
420
425
|
# @example
|
421
|
-
# Tonal::ReducedRatio.new(3,2).efficiency(12) => -1.
|
422
|
-
# @param modulo
|
426
|
+
# Tonal::ReducedRatio.new(3,2).efficiency(12) => -1.96
|
427
|
+
# @param modulo against which the difference of self is compared
|
423
428
|
#
|
424
429
|
def efficiency(modulo)
|
425
|
-
# We want the efficiency from the ratio
|
426
|
-
# If step efficiency is X cents, then ratio efficiency is -X cents.
|
430
|
+
# We want the efficiency from the ratio (self).
|
431
|
+
# If the step efficiency is X cents, then the ratio efficiency is -X cents.
|
427
432
|
step(modulo).efficiency * -1.0
|
428
433
|
end
|
429
434
|
|
430
435
|
# @return [Array] the results of ratio dividing and multiplying self
|
431
436
|
# @example
|
432
437
|
# Tonal::ReducedRatio.new(3/2r).div_times(5/4r) => [(6/5), (15/8)]
|
433
|
-
# @param
|
438
|
+
# @param other_ratio to divide and multiple on self
|
434
439
|
#
|
435
|
-
def div_times(
|
436
|
-
|
437
|
-
[self /
|
440
|
+
def div_times(other_ratio)
|
441
|
+
other_ratio = self.class.new(other_ratio)
|
442
|
+
[self / other_ratio, self * other_ratio]
|
438
443
|
end
|
439
444
|
|
440
445
|
# @return [Array] the results of ratio subtracted and added to self
|
441
446
|
# @example
|
442
447
|
# Tonal::ReducedRatio.new(3/2r).plus_minus(5/4r) => [(1/1), (11/8)]
|
443
|
-
# @param
|
448
|
+
# @param other_ratio to add and subtract from self
|
444
449
|
#
|
445
|
-
def plus_minus(
|
446
|
-
|
447
|
-
[self -
|
450
|
+
def plus_minus(other_ratio)
|
451
|
+
other_ratio = self.class.new(other_ratio)
|
452
|
+
[self - other_ratio, self + other_ratio]
|
448
453
|
end
|
449
454
|
alias :min_plus :plus_minus
|
450
455
|
|
@@ -484,11 +489,11 @@ class Tonal::Ratio
|
|
484
489
|
end
|
485
490
|
|
486
491
|
def *(rhs)
|
487
|
-
|
492
|
+
operate(rhs, :*)
|
488
493
|
end
|
489
494
|
|
490
495
|
def /(rhs)
|
491
|
-
|
496
|
+
operate(rhs, :/)
|
492
497
|
end
|
493
498
|
|
494
499
|
def **(rhs)
|
@@ -519,6 +524,18 @@ class Tonal::Ratio
|
|
519
524
|
[self.denominator, lhs.denominator].lcm
|
520
525
|
end
|
521
526
|
|
527
|
+
# @return [Tonal::Interval] between ratio (upper) and self (lower)
|
528
|
+
# @example
|
529
|
+
# Tonal::ReducedRatio.new(133).interval_with(3/2r)
|
530
|
+
# => (192/133) ((3/2) / (133/128))
|
531
|
+
# @param antecedent
|
532
|
+
# @param consequent
|
533
|
+
#
|
534
|
+
def interval_with(antecedent, consequent=nil)
|
535
|
+
r = self.class.new(antecedent, consequent)
|
536
|
+
Tonal::Interval.new(self, r)
|
537
|
+
end
|
538
|
+
|
522
539
|
# @return [Integer] the difference between antecedent and consequent
|
523
540
|
# @example
|
524
541
|
# Tonal::ReducedRatio.new(3,2).difference => 1
|
@@ -579,32 +596,32 @@ class Tonal::Ratio
|
|
579
596
|
end
|
580
597
|
end
|
581
598
|
|
599
|
+
def coerce(other)
|
600
|
+
[self.class.new(other), self]
|
601
|
+
end
|
602
|
+
|
582
603
|
def operate(rhs, op)
|
604
|
+
klass = (rhs.class == Tonal::ReducedRatio || self.class == Tonal::ReducedRatio) ? Tonal::ReducedRatio : Tonal::Ratio
|
605
|
+
|
583
606
|
case op
|
584
|
-
when :+, :-
|
585
|
-
case rhs
|
586
|
-
when Tonal::Ratio
|
587
|
-
self.class.new((antecedent * rhs.consequent).send(op, rhs.antecedent * consequent).abs, consequent * rhs.consequent)
|
588
|
-
when Rational
|
589
|
-
self.class.new((antecedent * rhs.denominator).send(op, rhs.numerator * consequent).abs, consequent * rhs.denominator)
|
590
|
-
when Array
|
591
|
-
self.class.new((antecedent * rhs[1]).send(op, rhs[0] * consequent), consequent * rhs[1])
|
592
|
-
else
|
593
|
-
r = Rational(rhs)
|
594
|
-
self.class.new((antecedent * r.denominator).send(op, r.numerator * consequent), consequent * r.denominator)
|
595
|
-
end
|
596
607
|
when :*
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
end
|
608
|
+
klass.new(antecedent * rhs.antecedent, consequent * rhs.consequent)
|
609
|
+
when :/
|
610
|
+
klass.new(antecedent * rhs.consequent, consequent * rhs.antecedent)
|
611
|
+
when :+, :-
|
612
|
+
lcm = self.denominator.lcm(rhs.denominator)
|
613
|
+
left = (self.to_r * lcm).numerator
|
614
|
+
right = (rhs.to_r * lcm).numerator
|
615
|
+
klass.new((left).send(op, right).abs, lcm)
|
606
616
|
when :**
|
607
|
-
|
617
|
+
klass.new(Rational(antecedent, consequent) ** rhs.to_r)
|
608
618
|
end
|
609
619
|
end
|
610
620
|
end
|
621
|
+
|
622
|
+
module Ratio
|
623
|
+
def self.[](u, l=nil)
|
624
|
+
Tonal::Ratio.new(u, l)
|
625
|
+
end
|
626
|
+
end
|
627
|
+
|
data/lib/tonal/reduced_ratio.rb
CHANGED
@@ -25,17 +25,6 @@ class Tonal::ReducedRatio < Tonal::Ratio
|
|
25
25
|
Tonal::Ratio.new(antecedent, consequent)
|
26
26
|
end
|
27
27
|
|
28
|
-
# @return [Tonal::Interval] between ratio (upper) and self (lower)
|
29
|
-
# @example
|
30
|
-
# Tonal::ReducedRatio.new(133).interval_with(3/2r)
|
31
|
-
# => 192/133 (3/2 / 133/128)
|
32
|
-
# @param ratio
|
33
|
-
#
|
34
|
-
def interval_with(ratio)
|
35
|
-
r = ratio.is_a?(self.class) ? ratio : self.class.new(ratio)
|
36
|
-
Tonal::Interval.new(r, self)
|
37
|
-
end
|
38
|
-
|
39
28
|
# @return [Tonal::ReducedRatio] with antecedent and precedent switched
|
40
29
|
# @example
|
41
30
|
# Tonal::ReducedRatio.new(3,2).invert! => (4/3)
|
@@ -46,3 +35,9 @@ class Tonal::ReducedRatio < Tonal::Ratio
|
|
46
35
|
self
|
47
36
|
end
|
48
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
@@ -40,7 +40,7 @@ class Tonal::Step
|
|
40
40
|
# @return [Rational] of the step
|
41
41
|
# @example
|
42
42
|
# Tonal::Step.new(ratio: 3/2r, modulo: 31).step_to_r
|
43
|
-
# => 6735213777669305/4503599627370496
|
43
|
+
# => (6735213777669305/4503599627370496)
|
44
44
|
#
|
45
45
|
def step_to_r
|
46
46
|
tempered.to_r
|
@@ -50,7 +50,7 @@ class Tonal::Step
|
|
50
50
|
# @return [Rational] of the ratio
|
51
51
|
# @example
|
52
52
|
# Tonal::Step.new(ratio: 3/2r, modulo: 31).ratio_to_r
|
53
|
-
# => 3/2
|
53
|
+
# => (3/2)
|
54
54
|
#
|
55
55
|
def ratio_to_r
|
56
56
|
ratio.to_r
|
@@ -81,6 +81,7 @@ class Tonal::Step
|
|
81
81
|
# => 5.19
|
82
82
|
#
|
83
83
|
def efficiency
|
84
|
+
# We want the efficiency from the step (self).
|
84
85
|
ratio_to_cents - step_to_cents
|
85
86
|
end
|
86
87
|
|
@@ -98,7 +99,7 @@ class Tonal::Step
|
|
98
99
|
if ratio
|
99
100
|
[Tonal::ReducedRatio.new(ratio), Tonal::Log2.new(logarithmand: ratio)]
|
100
101
|
elsif log
|
101
|
-
if log.kind_of?(Tonal::
|
102
|
+
if log.kind_of?(Tonal::Log)
|
102
103
|
[log.logarithmand, log]
|
103
104
|
else
|
104
105
|
lg = Tonal::Log2.new(logarithm: log)
|
data/lib/tonal/tools.rb
CHANGED
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:
|
4
|
+
version: 6.1.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-
|
11
|
+
date: 2024-12-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: yaml
|
@@ -16,28 +16,28 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '0.
|
19
|
+
version: '0.4'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '0.
|
26
|
+
version: '0.4'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: json
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '2.
|
33
|
+
version: '2.9'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '2.
|
40
|
+
version: '2.9'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: prime
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -114,14 +114,14 @@ dependencies:
|
|
114
114
|
requirements:
|
115
115
|
- - "~>"
|
116
116
|
- !ruby/object:Gem::Version
|
117
|
-
version: '3
|
117
|
+
version: '3'
|
118
118
|
type: :development
|
119
119
|
prerelease: false
|
120
120
|
version_requirements: !ruby/object:Gem::Requirement
|
121
121
|
requirements:
|
122
122
|
- - "~>"
|
123
123
|
- !ruby/object:Gem::Version
|
124
|
-
version: '3
|
124
|
+
version: '3'
|
125
125
|
- !ruby/object:Gem::Dependency
|
126
126
|
name: byebug
|
127
127
|
requirement: !ruby/object:Gem::Requirement
|
@@ -165,6 +165,7 @@ files:
|
|
165
165
|
- lib/tonal/extensions.rb
|
166
166
|
- lib/tonal/hertz.rb
|
167
167
|
- lib/tonal/interval.rb
|
168
|
+
- lib/tonal/irb_helpers.rb
|
168
169
|
- lib/tonal/log.rb
|
169
170
|
- lib/tonal/log2.rb
|
170
171
|
- lib/tonal/ratio.rb
|