tonal-tools 5.3.0 → 6.1.1
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 +6 -4
- data/lib/tonal/ratio.rb +70 -51
- 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: 50cbd332f2e7aeb3da776868cd3bd27cd3fd4f25146de194781fa1f8032a3e93
|
4
|
+
data.tar.gz: 3cddb6f9f59e814afface6e739597653442b13f402bf5839784decff633b4662
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 425f07aa55d053031df5bb092495ab88a82741964b3f56295868873b4a96e773ca0af9005352bdb289331d090331c8cb75c05aada7573db858b453002153a1fc
|
7
|
+
data.tar.gz: bb7871f1f9dcdcef36de328f9f839d50c9e9ceba6918b0d6bbd335a85803760461fb4a37a203149a3f7e629d53fcb3f80c56b1bd97d6249a781a0c433fd1ef23
|
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
|
+
# rr(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
@@ -4,6 +4,8 @@ class Tonal::Log
|
|
4
4
|
|
5
5
|
def_delegators :@logarithmand, :ratio, :to_ratio
|
6
6
|
|
7
|
+
PRECISION = 2
|
8
|
+
|
7
9
|
attr_reader :logarithmand, :logarithm, :base
|
8
10
|
|
9
11
|
# @return [Tonal::Log]
|
@@ -52,7 +54,7 @@ class Tonal::Log
|
|
52
54
|
|
53
55
|
# @return [Tonal::Cents] the cents scale logarithm
|
54
56
|
# @example
|
55
|
-
# Tonal::Log.new(logarithmand: 3/2r, base: 2).to_cents => 701.
|
57
|
+
# Tonal::Log.new(logarithmand: 3/2r, base: 2).to_cents => 701.96
|
56
58
|
# @see Tonal::Cents
|
57
59
|
#
|
58
60
|
def to_cents(precision: Tonal::Cents::PRECISION)
|
@@ -61,7 +63,7 @@ class Tonal::Log
|
|
61
63
|
|
62
64
|
# @return [Tonal::Step] the nearest step in the given modulo
|
63
65
|
# @example
|
64
|
-
# Tonal::Log.new(3/2r, base: 2).step(12) => 7\12
|
66
|
+
# Tonal::Log.new(logarithmand: 3/2r, base: 2).step(12) => 7\12
|
65
67
|
#
|
66
68
|
def step(modulo)
|
67
69
|
Tonal::Step.new(modulo: modulo, log: self)
|
@@ -69,10 +71,10 @@ class Tonal::Log
|
|
69
71
|
|
70
72
|
# @return [String] the string representation of Tonal::Log
|
71
73
|
# @example
|
72
|
-
# Tonal::Log.new(3/2r, base: 2).inspect => "0.
|
74
|
+
# Tonal::Log.new(logarithmand: 3/2r, base: 2).inspect => "0.58"
|
73
75
|
#
|
74
76
|
def inspect
|
75
|
-
"#{logarithm}"
|
77
|
+
"#{logarithm.round(PRECISION)}"
|
76
78
|
end
|
77
79
|
|
78
80
|
def <=>(rhs)
|
data/lib/tonal/ratio.rb
CHANGED
@@ -4,6 +4,8 @@ class Tonal::Ratio
|
|
4
4
|
|
5
5
|
def_delegators :@approximation, :neighborhood
|
6
6
|
|
7
|
+
PRECISION = 2
|
8
|
+
|
7
9
|
attr_reader :antecedent, :consequent, :equave, :reduced_antecedent, :reduced_consequent
|
8
10
|
|
9
11
|
# @return [Tonal::Ratio]
|
@@ -81,7 +83,7 @@ class Tonal::Ratio
|
|
81
83
|
|
82
84
|
# @return [Boolean] if pair of ratios are within the given cents limit
|
83
85
|
# @example
|
84
|
-
# Tonal::Ratio.within_cents?(100, 105, 2) =>
|
86
|
+
# Tonal::Ratio.within_cents?(100, 105, 2) => false
|
85
87
|
# @param cents1
|
86
88
|
# @param cents2
|
87
89
|
# @param within
|
@@ -141,7 +143,7 @@ class Tonal::Ratio
|
|
141
143
|
|
142
144
|
# @return [Tonal::Log] Math.log of self in given base
|
143
145
|
# @example
|
144
|
-
# Tonal::Ratio.new(3,2).log(3) => 0.
|
146
|
+
# Tonal::Ratio.new(3,2).log(3) => 0.37
|
145
147
|
# @param base
|
146
148
|
#
|
147
149
|
def to_log(base=2)
|
@@ -151,7 +153,7 @@ class Tonal::Ratio
|
|
151
153
|
|
152
154
|
# @return [Tonal::Log2] Math.log2 of self
|
153
155
|
# @example
|
154
|
-
# Tonal::ReducedRatio.new(3,2).to_log2 => 0.
|
156
|
+
# Tonal::ReducedRatio.new(3,2).to_log2 => 0.58
|
155
157
|
#
|
156
158
|
def to_log2
|
157
159
|
Tonal::Log2.new(logarithmand: to_r)
|
@@ -169,7 +171,7 @@ class Tonal::Ratio
|
|
169
171
|
|
170
172
|
# @return [Integer] the step of self in the given modulo
|
171
173
|
# @example
|
172
|
-
# Tonal::ReducedRatio.new(3,2).step(12) => 7
|
174
|
+
# Tonal::ReducedRatio.new(3,2).step(12) => 7\12
|
173
175
|
#
|
174
176
|
def step(modulo=12)
|
175
177
|
Tonal::Step.new(ratio: to_r, modulo: modulo)
|
@@ -180,7 +182,7 @@ class Tonal::Ratio
|
|
180
182
|
# Tonal::Ratio.new(3,2).period_degrees => 210.59
|
181
183
|
# @param round
|
182
184
|
#
|
183
|
-
def period_degrees(round:
|
185
|
+
def period_degrees(round: PRECISION)
|
184
186
|
(360.0 * Math.log(to_f, equave)).round(round)
|
185
187
|
end
|
186
188
|
|
@@ -189,7 +191,7 @@ class Tonal::Ratio
|
|
189
191
|
# Tonal::Ratio.new(3,2).period_radians => 3.68
|
190
192
|
# @param round
|
191
193
|
#
|
192
|
-
def period_radians(round:
|
194
|
+
def period_radians(round: PRECISION)
|
193
195
|
(2 * Math::PI * Math.log(to_f, equave)).round(round)
|
194
196
|
end
|
195
197
|
|
@@ -254,7 +256,7 @@ class Tonal::Ratio
|
|
254
256
|
|
255
257
|
# @return [Tonal::Ratio] the mirror of self along the axis (default 1/1)
|
256
258
|
# @example
|
257
|
-
# Tonal::
|
259
|
+
# Tonal::ReducedRatio.new(4,3).mirror => (3/2)
|
258
260
|
# @param axis
|
259
261
|
#
|
260
262
|
def mirror(axis=1/1r)
|
@@ -299,7 +301,7 @@ class Tonal::Ratio
|
|
299
301
|
|
300
302
|
# @return [Tonal::Ratio] self sheared by given arguments
|
301
303
|
# @example
|
302
|
-
# Tonal::Ratio.new(3,2).shear(1, 3) => (
|
304
|
+
# Tonal::Ratio.new(3,2).shear(1, 3) => (14/11)
|
303
305
|
# @param a [Numeric]
|
304
306
|
# @param b [Numeric]
|
305
307
|
#
|
@@ -313,7 +315,7 @@ class Tonal::Ratio
|
|
313
315
|
# Tonal::Ratio.new(3,2).planar_degrees => 33.69
|
314
316
|
# @param round
|
315
317
|
#
|
316
|
-
def planar_degrees(round:
|
318
|
+
def planar_degrees(round: PRECISION)
|
317
319
|
(Math.atan2(consequent, antecedent) * 180/Math::PI).round(round)
|
318
320
|
end
|
319
321
|
|
@@ -322,7 +324,7 @@ class Tonal::Ratio
|
|
322
324
|
# Tonal::Ratio.new(3,2).planar_radians => 0.59
|
323
325
|
# @param round
|
324
326
|
#
|
325
|
-
def planar_radians(round:
|
327
|
+
def planar_radians(round: PRECISION)
|
326
328
|
Math.atan2(consequent, antecedent).round(round)
|
327
329
|
end
|
328
330
|
|
@@ -368,8 +370,13 @@ class Tonal::Ratio
|
|
368
370
|
prime_divisions.flatten(1).map(&:first).min
|
369
371
|
end
|
370
372
|
|
371
|
-
|
372
|
-
|
373
|
+
# @return [Boolean] whether self's max prime is within the given number
|
374
|
+
# @example
|
375
|
+
# Tonal::Ratio.new(31/30r).max_prime_within?(7) => false
|
376
|
+
# @param number to compare max prime against
|
377
|
+
#
|
378
|
+
def max_prime_within?(number)
|
379
|
+
max_prime <= number
|
373
380
|
end
|
374
381
|
|
375
382
|
# @return [Integer] the product complexity of self
|
@@ -383,7 +390,7 @@ class Tonal::Ratio
|
|
383
390
|
|
384
391
|
# @return [Tonal::Log2] the log product complexity of self
|
385
392
|
# @example
|
386
|
-
# Tonal::ReducedRatio.new(3/2r).tenney_height => 2.
|
393
|
+
# Tonal::ReducedRatio.new(3/2r).tenney_height => 2.58
|
387
394
|
#
|
388
395
|
def tenney_height
|
389
396
|
Tonal::Log2.new(logarithmand: benedetti_height)
|
@@ -402,7 +409,7 @@ class Tonal::Ratio
|
|
402
409
|
|
403
410
|
# @return [Tonal::Log2] the log of Weil height
|
404
411
|
# @example
|
405
|
-
# Tonal::ReducedRatio.new(3/2r).log_weil_height => 1.
|
412
|
+
# Tonal::ReducedRatio.new(3/2r).log_weil_height => 1.58
|
406
413
|
#
|
407
414
|
def log_weil_height
|
408
415
|
Tonal::Log2.new(logarithmand: weil_height)
|
@@ -418,33 +425,33 @@ class Tonal::Ratio
|
|
418
425
|
|
419
426
|
# @return [Tonal::Cents] the cents difference between self and its step in the given modulo
|
420
427
|
# @example
|
421
|
-
# Tonal::ReducedRatio.new(3,2).efficiency(12) => -1.
|
422
|
-
# @param modulo
|
428
|
+
# Tonal::ReducedRatio.new(3,2).efficiency(12) => -1.96
|
429
|
+
# @param modulo against which the difference of self is compared
|
423
430
|
#
|
424
431
|
def efficiency(modulo)
|
425
|
-
# We want the efficiency from the ratio
|
426
|
-
# If step efficiency is X cents, then ratio efficiency is -X cents.
|
432
|
+
# We want the efficiency from the ratio (self).
|
433
|
+
# If the step efficiency is X cents, then the ratio efficiency is -X cents.
|
427
434
|
step(modulo).efficiency * -1.0
|
428
435
|
end
|
429
436
|
|
430
437
|
# @return [Array] the results of ratio dividing and multiplying self
|
431
438
|
# @example
|
432
439
|
# Tonal::ReducedRatio.new(3/2r).div_times(5/4r) => [(6/5), (15/8)]
|
433
|
-
# @param
|
440
|
+
# @param other_ratio to divide and multiple on self
|
434
441
|
#
|
435
|
-
def div_times(
|
436
|
-
|
437
|
-
[self /
|
442
|
+
def div_times(other_ratio)
|
443
|
+
other_ratio = self.class.new(other_ratio)
|
444
|
+
[self / other_ratio, self * other_ratio]
|
438
445
|
end
|
439
446
|
|
440
447
|
# @return [Array] the results of ratio subtracted and added to self
|
441
448
|
# @example
|
442
449
|
# Tonal::ReducedRatio.new(3/2r).plus_minus(5/4r) => [(1/1), (11/8)]
|
443
|
-
# @param
|
450
|
+
# @param other_ratio to add and subtract from self
|
444
451
|
#
|
445
|
-
def plus_minus(
|
446
|
-
|
447
|
-
[self -
|
452
|
+
def plus_minus(other_ratio)
|
453
|
+
other_ratio = self.class.new(other_ratio)
|
454
|
+
[self - other_ratio, self + other_ratio]
|
448
455
|
end
|
449
456
|
alias :min_plus :plus_minus
|
450
457
|
|
@@ -463,7 +470,7 @@ class Tonal::Ratio
|
|
463
470
|
# Return label, if defined; or,
|
464
471
|
# Return the "antecedent/consequent", if antecedent is less than 7 digits long; or
|
465
472
|
# Return the floating point representation rounded to 2 digits of precision
|
466
|
-
(@label || ((Math.log10(antecedent).to_i + 1) <= 6 ? "#{antecedent}/#{consequent}" : to_f.round(
|
473
|
+
(@label || ((Math.log10(antecedent).to_i + 1) <= 6 ? "#{antecedent}/#{consequent}" : to_f.round(PRECISION))).to_s
|
467
474
|
end
|
468
475
|
|
469
476
|
# @return [String] the string representation of Tonal::Ratio
|
@@ -484,11 +491,11 @@ class Tonal::Ratio
|
|
484
491
|
end
|
485
492
|
|
486
493
|
def *(rhs)
|
487
|
-
|
494
|
+
operate(rhs, :*)
|
488
495
|
end
|
489
496
|
|
490
497
|
def /(rhs)
|
491
|
-
|
498
|
+
operate(rhs, :/)
|
492
499
|
end
|
493
500
|
|
494
501
|
def **(rhs)
|
@@ -519,6 +526,18 @@ class Tonal::Ratio
|
|
519
526
|
[self.denominator, lhs.denominator].lcm
|
520
527
|
end
|
521
528
|
|
529
|
+
# @return [Tonal::Interval] between ratio (upper) and self (lower)
|
530
|
+
# @example
|
531
|
+
# Tonal::ReducedRatio.new(133).interval_with(3/2r)
|
532
|
+
# => (192/133) ((3/2) / (133/128))
|
533
|
+
# @param antecedent
|
534
|
+
# @param consequent
|
535
|
+
#
|
536
|
+
def interval_with(antecedent, consequent=nil)
|
537
|
+
r = self.class.new(antecedent, consequent)
|
538
|
+
Tonal::Interval.new(self, r)
|
539
|
+
end
|
540
|
+
|
522
541
|
# @return [Integer] the difference between antecedent and consequent
|
523
542
|
# @example
|
524
543
|
# Tonal::ReducedRatio.new(3,2).difference => 1
|
@@ -579,32 +598,32 @@ class Tonal::Ratio
|
|
579
598
|
end
|
580
599
|
end
|
581
600
|
|
601
|
+
def coerce(other)
|
602
|
+
[self.class.new(other), self]
|
603
|
+
end
|
604
|
+
|
582
605
|
def operate(rhs, op)
|
606
|
+
klass = (rhs.class == Tonal::ReducedRatio || self.class == Tonal::ReducedRatio) ? Tonal::ReducedRatio : Tonal::Ratio
|
607
|
+
|
583
608
|
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
609
|
when :*
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
end
|
610
|
+
klass.new(antecedent * rhs.antecedent, consequent * rhs.consequent)
|
611
|
+
when :/
|
612
|
+
klass.new(antecedent * rhs.consequent, consequent * rhs.antecedent)
|
613
|
+
when :+, :-
|
614
|
+
lcm = self.denominator.lcm(rhs.denominator)
|
615
|
+
left = (self.to_r * lcm).numerator
|
616
|
+
right = (rhs.to_r * lcm).numerator
|
617
|
+
klass.new((left).send(op, right).abs, lcm)
|
606
618
|
when :**
|
607
|
-
|
619
|
+
klass.new(Rational(antecedent, consequent) ** rhs.to_r)
|
608
620
|
end
|
609
621
|
end
|
610
622
|
end
|
623
|
+
|
624
|
+
module Ratio
|
625
|
+
def self.[](u, l=nil)
|
626
|
+
Tonal::Ratio.new(u, l)
|
627
|
+
end
|
628
|
+
end
|
629
|
+
|
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.1
|
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:
|
11
|
+
date: 2025-01-05 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
|