tonal-tools 8.6.0 → 8.8.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: 25126d841103214bbe0a1fe1dcd861460ff4bf7b108ac3e0854032e037f64ab1
4
- data.tar.gz: 3f3941c9a097f937d08f5c0b9fc1edec5df331b45d12599b0dcedfaa275ed6b4
3
+ metadata.gz: ad355622f7095fece5a99d754e0769935e66757f5d0fdae60ca21f9edfed35f3
4
+ data.tar.gz: 6b1ac2a795e4650a2dfc28634a05db3501e76cea05ff999b3958cebe63a37094
5
5
  SHA512:
6
- metadata.gz: 4c8828863ca77987db6837fbbff67a8f74029d8b817418596a3a0ce6959fbd09ffb174a7dc4142a1d67ed8fadc5d85e3694ee87155c1ea064b6760cf73d3baae
7
- data.tar.gz: 54122f26528a2fa0866abc7e9c2e23ffee7dbb64a8d9ed192c48c205b233b365b9064847d667a7e95cfd90b23f0424bc9799ff098426e27b4be727d45cc6c489
6
+ metadata.gz: 39fbd7a2445f7290f446f808e185c7291b6d7edf889e57cc5a6a8c7925a51940f9e374de6041dd92b03d244f65a1921b93d532e0fee211e467f6ce26dd926252
7
+ data.tar.gz: adcd55527c91b82f3723f32df38163c747aea3c492eb67d57a8a245a2565302f96cf1c84de2e91a33d533442da8ce88bf07c223789b957f48a965dc4deba926b
@@ -1,4 +1,4 @@
1
1
  module Tonal
2
2
  TOOLS_PRODUCER = "mTonal"
3
- TOOLS_VERSION = "8.6.0"
3
+ TOOLS_VERSION = "8.8.0"
4
4
  end
data/lib/tonal/hertz.rb CHANGED
@@ -1,6 +1,8 @@
1
1
  class Tonal::Hertz
2
2
  include Comparable
3
3
 
4
+ REFERENCE_FREQUENCY = 440.0
5
+
4
6
  attr_reader :value
5
7
 
6
8
  # @return [Tonal::Hertz]
@@ -18,7 +20,7 @@ class Tonal::Hertz
18
20
  # Tonal::Hertz.reference => 440.0 Hz
19
21
  #
20
22
  def self.reference
21
- self.new(440.0)
23
+ self.new(REFERENCE_FREQUENCY)
22
24
  end
23
25
 
24
26
  # @return [Rational] self as a rational
@@ -50,9 +52,10 @@ class Tonal::Hertz
50
52
  # @example
51
53
  # Tonal::Hertz.new(440).to_midi => 69.0 MIDI
52
54
  # @param reference [Tonal::Hertz, Numeric] the reference frequency to compare to
55
+ # @param modulo [Integer] the modulo to use for the MIDI note calculation
53
56
  #
54
- def to_midi_note
55
- Tonal::Midi::Note.new(frequency: to_f)
57
+ def to_midi_note(modulo: Tonal::Midi::Note::DEFAULT_MODULO)
58
+ Tonal::Midi::Note.new(frequency: to_f, modulo: modulo)
56
59
  end
57
60
  alias :to_midi :to_midi_note
58
61
 
data/lib/tonal/midi.rb CHANGED
@@ -2,37 +2,54 @@ module Tonal::Midi
2
2
  class Note
3
3
  include Comparable
4
4
 
5
- REFERENCE_FREQUENCY = 440.0
6
5
  A4_MIDI_NUMBER = 69
6
+ C4_MIDI_NUMBER = 60
7
+ DEFAULT_MODULO = 12
7
8
 
8
- attr_reader :number, :frequency
9
+ attr_reader :number, :modulo
9
10
 
10
11
  # @return [Tonal::Midi::Note]
11
12
  # @example
12
- # Tonal::Midi::Note.new(number:60) => 60.0 MIDI
13
- # @param arg [Numeric, Tonal::Midi::Note]
13
+ # Tonal::Midi::Note.new(number: 60) => 60 MIDI
14
+ # Tonal::Midi::Note.new(frequency: 261.63) => 60 MIDI
15
+ # @param number [Integer, nil] the MIDI note number. Mutually exclusive with frequency:
16
+ # @param frequency [Numeric, Tonal::Hertz, nil] the frequency in Hz. Mutually exclusive with number:
17
+ # @param modulo [Integer] the number of steps per octave
14
18
  #
15
- def initialize(number: A4_MIDI_NUMBER, frequency: nil)
19
+ def initialize(number: nil, frequency: nil, modulo: DEFAULT_MODULO)
20
+ raise ArgumentError, "Provide either number: or frequency:, not both" if number && frequency
21
+
22
+ @modulo = modulo
16
23
  if frequency
17
24
  raise ArgumentError, "Frequency argument is not Numeric or Tonal::Hertz" unless frequency.kind_of?(Numeric) || frequency.kind_of?(Tonal::Hertz)
18
25
  @frequency = Tonal::Hertz.new(frequency)
19
- @number = (A4_MIDI_NUMBER + 12 * Math.log2(frequency.to_f / REFERENCE_FREQUENCY)).round
26
+ @number = (A4_MIDI_NUMBER + modulo * Math.log2(frequency.to_f / Tonal::Hertz::REFERENCE_FREQUENCY)).round
20
27
  else
28
+ number = A4_MIDI_NUMBER if number.nil?
21
29
  raise ArgumentError, "Number argument is not Integer" unless number.kind_of?(Integer)
22
- @number = number.kind_of?(self.class) ? number.inspect : number
23
- @frequency = Tonal::Hertz.new(REFERENCE_FREQUENCY * (2 ** ((number - A4_MIDI_NUMBER) / 12.0)))
30
+ @number = number
31
+ @frequency = Tonal::Hertz.new(Tonal::Hertz::REFERENCE_FREQUENCY * (2 ** ((number - A4_MIDI_NUMBER) / modulo.to_f)))
24
32
  end
25
33
  end
26
34
 
27
35
  alias :value :number
28
36
 
37
+ # @return [Float] the frequency corresponding to the MIDI note number
38
+ # @example
39
+ # Tonal::Midi::Note.new(number:60).frequency => 261.6255653005986
40
+ # @param round [Integer, nil] the number of decimal places to round the frequency to, or nil for no rounding
41
+ #
42
+ def frequency(round: nil)
43
+ round ? @frequency.to_f.round(round) : @frequency.to_f
44
+ end
45
+
29
46
  # @return [String] representation of self
30
47
  def inspect
31
48
  "#{number} MIDI"
32
49
  end
33
50
 
34
51
  def <=>(other)
35
- number <=> other.number
52
+ number <=> (other.kind_of?(self.class) ? other.number : other)
36
53
  end
37
54
  end
38
55
  end
data/lib/tonal/ratio.rb CHANGED
@@ -174,6 +174,25 @@ class Tonal::Ratio
174
174
  end
175
175
  alias :cents :to_cents
176
176
 
177
+ # @return [Tonal::Hertz] the hertz of self with respect to a reference frequency
178
+ # @example
179
+ # Tonal::Ratio.new(3,2).to_hertz => 660.0
180
+ # @param reference [Numeric] the reference frequency
181
+ #
182
+ def to_hertz(reference: Tonal::Hertz.reference)
183
+ Tonal::Hertz.new(reference.to_f * to_f)
184
+ end
185
+
186
+ # @return [Tonal::Midi::Note] the midi representation of self with respect to a reference frequency
187
+ # @example
188
+ # Tonal::Ratio.new(3,2).to_midi => 76 MIDI
189
+ # @param reference [Numeric] the reference frequency
190
+ # @param modulo [Integer] the modulo for the MIDI note
191
+ #
192
+ def to_midi(reference: Tonal::Hertz.reference, modulo: Tonal::Midi::Note::DEFAULT_MODULO)
193
+ to_hertz(reference: reference).to_midi(modulo: modulo)
194
+ end
195
+
177
196
  # @return [Integer] the step of self in the given modulo
178
197
  # @example
179
198
  # Tonal::ReducedRatio.new(3,2).step(12) => 7\12
data/lib/tonal/step.rb CHANGED
@@ -58,6 +58,22 @@ class Tonal::Scale
58
58
  Tonal::Ratio.new(step, modulo)
59
59
  end
60
60
 
61
+ # @return the [Tonal::Midi::Note] representation of the step
62
+ #
63
+ # @example
64
+ # Tonal::Scale::Step.new(ratio: 3/2r, modulo: 31).step_to_midi
65
+ # => 78
66
+ # Tonal::Scale::Step.new(ratio: 3/2r, modulo: 12).step_to_midi
67
+ # => 67
68
+ # Tonal::Scale::Step.new(ratio: 3/2r, modulo: 12).step_to_midi(midi_root: Tonal::Midi::Note::A4_MIDI_NUMBER)
69
+ # => 76
70
+ #
71
+ # @param midi_root [Integer] the MIDI number that corresponds to the 0 step of the scale. Default is C4 (60 MIDI).
72
+ #
73
+ def step_to_midi(midi_root: Tonal::Midi::Note::C4_MIDI_NUMBER)
74
+ Tonal::Midi::Note.new(number: step + midi_root)
75
+ end
76
+
61
77
  # @return the [Rational] representation of the ratio of self
62
78
  # @example
63
79
  # Tonal::Scale::Step.new(ratio: 3/2r, modulo: 31).ratio_to_r
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: 8.6.0
4
+ version: 8.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jose Hales-Garcia
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2026-05-26 00:00:00.000000000 Z
10
+ date: 2026-07-02 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: yaml
@@ -193,7 +193,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
193
193
  - !ruby/object:Gem::Version
194
194
  version: '3.1'
195
195
  requirements: []
196
- rubygems_version: 4.0.11
196
+ rubygems_version: 4.0.14
197
197
  specification_version: 4
198
198
  summary: Tonal tools
199
199
  test_files: []