ruby-mext 0.21.1 → 0.21.6

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: af5724f948e0ea3cdfd938e89f37c4daf105d42d3c114faa68385269907ced28
4
- data.tar.gz: 17886d733497b5553741ee31022f13378a3f38d0043182b10391abebdc9fd511
3
+ metadata.gz: 7d543e0e00be11dea0f00c0ce6d9679d4a4c75763f4ff106eee0a262e1a0405c
4
+ data.tar.gz: 68ec005980d394bc22d3a17f3ab4c62706d02fc795a90b731b9393556ab338e9
5
5
  SHA512:
6
- metadata.gz: 833603ff9cf2f2845fb5e3757fb5c7cef2679650439c65d3e2ea3cc7506fbea5cbd37920f56ecc067dff3820f35fba4b6a9afb0c9339b8286fc404012142fc90
7
- data.tar.gz: 109db15f348ca299e959d3bd61d6371ac5f1d553e56ab9d0f5ddd8e8269f44a5e9b63a2bb9ba80667a06eee6f959f7649d3b21c91bcd113b1bb7c19fc6dc7798
6
+ metadata.gz: 69bd963b1dcfa608bf0735b2b7c568e949621c591146f495456866fec37688398ebc9a712905e5af8ac9c597e8408845f7ed96c50d1edc3e353522d286ccced9
7
+ data.tar.gz: 271c3f54fbcf26341fbf1ab681b0c04742eae5fd00fd2ec05b92118e990a85415ec7f1b90c3a13717f38132b9146d892671b2fa9400beb7064db7e9abc8d36f7
data/README.md CHANGED
@@ -10,6 +10,11 @@ These are extensions of usual idiomatic `ruby` objects (i.e. `Numeric`,
10
10
  It is the usual unfinished ever-expanding project. Feel free to contribute to
11
11
  it in the form of pull requests if you are so inclined.
12
12
 
13
+ ## Requirements
14
+
15
+ Some `Function`s (notably: `Mext::Math::Polynomial`) require [`octave`](https://octave.org) to be
16
+ installed and running on the same computer.
17
+
13
18
  ## Installation
14
19
 
15
20
  Add this line to your application's Gemfile:
data/lib/mext/math.rb CHANGED
@@ -10,4 +10,5 @@ end
10
10
  expon
11
11
  log
12
12
  stepwise
13
+ polynomial
13
14
  ).each { |f| require File.join(Mext::MATH_PATH, f) }
@@ -0,0 +1,95 @@
1
+ module Math
2
+
3
+ class Polynomial < Function
4
+
5
+ #
6
+ # +:values+
7
+ #
8
+ # is an array of pairs (+x+, +y+)
9
+ #
10
+ attr_reader :values, :factors
11
+
12
+ #
13
+ # +Math::Polynomial.new(values = [])+
14
+ #
15
+ # stepwise function
16
+ #
17
+ # Arguments are:
18
+ #
19
+ # +values+: an array of (+x+, +y+) pairs
20
+ #
21
+ #:nodoc:
22
+ def initialize(vs = [])
23
+ setup(vs)
24
+ end
25
+
26
+ #:doc:
27
+ #
28
+ # +y(x)+:
29
+ #
30
+ # Returns a value for any given x
31
+ #
32
+ #:nodoc:
33
+ def y(x)
34
+ calculate(x)
35
+ end
36
+
37
+ def label
38
+ 'polynomial function'
39
+ end
40
+
41
+ class << self
42
+
43
+ #
44
+ # +from_yaml(yaml_hash)+:
45
+ #
46
+ # creates a Math::Polynomial class from a yaml file which must have the
47
+ # relevant fields:
48
+ #
49
+ # +values+: an array of duples [x, y]
50
+ #
51
+ def from_yaml(yh)
52
+ new(yh['values'])
53
+ end
54
+
55
+ end
56
+
57
+ private
58
+
59
+ def calculate(x)
60
+ result = 0
61
+ idx = self.factors.size-1
62
+ fidx = 0
63
+ idx.downto(0) do
64
+ |n|
65
+ result += (self.factors[fidx]*(x**(n)))
66
+ fidx += 1
67
+ end
68
+ result
69
+ end
70
+
71
+ #
72
+ # +setup+
73
+ #
74
+ # calls +octave+'s +polyfit+ function to load the factors of the
75
+ # polynomial
76
+ #
77
+ #:nodoc:
78
+ def setup(vs)
79
+ @values = []
80
+ sorted = vs.sort { |a, b| a[0] <=> b[0] }
81
+ @values.concat(sorted)
82
+ xs = self.values.map { |v| v[0] }
83
+ ys = self.values.map { |v| v[1] }
84
+ porder = vs.size
85
+ @factors = ::Octave::Io::polyfit(xs, ys, porder)
86
+ #
87
+ # keep in mind that vs might be empty
88
+ #
89
+ @x_start = self.values.first ? self.values.first.first : self.values.first
90
+ @x_end = self.values.last ? self.values.last.first : self.values.last
91
+ end
92
+
93
+ end
94
+
95
+ end
data/lib/mext/music.rb CHANGED
@@ -6,4 +6,7 @@ end
6
6
 
7
7
  %w(
8
8
  pitch_class
9
+ meter
10
+ note_name
11
+ note_names
9
12
  ).each { |f| require File.join(Mext::MUSIC_PATH, f) }
@@ -1,5 +1,5 @@
1
1
  module Mext
2
- module Numeric
2
+ module Music
3
3
 
4
4
  #
5
5
  # +Meter+:
@@ -20,6 +20,7 @@ module Mext
20
20
  end
21
21
 
22
22
  def to_r
23
+ raise ZeroDivisionError, "#{self.numerator}/#{self.divisor} provokes a zero-division error" unless self.divisor != 0
23
24
  Rational(self.numerator, self.divisor)
24
25
  end
25
26
 
@@ -30,13 +31,22 @@ module Mext
30
31
  # we use the logic of +Rational+ to perform logic on +Meter+
31
32
  #
32
33
  [:==, :<, :<=, :>, :>=, :<=>, :===].each { |m| define_method(m) { |other| common_logic(m, other) } }
34
+ #
35
+ # we use the arithmetic of +Rational+ to perform arithmetic on +Meter+
36
+ #
37
+ [:+, :-, :*, :/, :**, :^, ].each { |m| define_method(m) { |other| common_arithmetic(m, other) } }
38
+
33
39
 
34
40
  private
35
41
 
36
42
  def common_logic(method, other)
37
- raise ArgumentError unless other.kind_of?(Meter) || other.kind_of?(Rational)
43
+ raise ArgumentError, "#{other} is neither a #{self.class} nor a Rational (#{other.class})" unless other.kind_of?(Meter) || other.kind_of?(Rational)
38
44
  self.to_r.send(method, other.to_r)
39
45
  end
46
+
47
+ def common_arithmetic(method, other)
48
+ self.to_r.send(method, other.to_r).to_meter
49
+ end
40
50
 
41
51
  end
42
52
 
@@ -47,7 +57,7 @@ end
47
57
  # +Meter(n, d)+ is defined to actually mimick a +Rational()+
48
58
  #
49
59
  def Meter(n, d)
50
- Mext::Numeric::Meter.new(n,d)
60
+ Mext::Music::Meter.new(n,d)
51
61
  end
52
62
 
53
63
  #
@@ -65,3 +75,28 @@ class String
65
75
  end
66
76
 
67
77
  end
78
+
79
+ #
80
+ # we extend the +Rational+ class to carry a +to_meter+ which
81
+ # will convert a into a Meter class
82
+ #
83
+ class Rational
84
+
85
+ def to_meter
86
+ Meter(self.numerator, self.denominator)
87
+ end
88
+
89
+ end
90
+
91
+ #
92
+ # we extend the +Numeric+ class to carry a +to_meter+ which
93
+ # will convert a into a Meter class
94
+ #
95
+ class Numeric
96
+
97
+ def to_meter
98
+ r = self.to_r
99
+ Meter(r.numerator, r.denominator)
100
+ end
101
+
102
+ end
@@ -0,0 +1,43 @@
1
+ module Mext
2
+ module Music
3
+ #
4
+ # +Mext::Music::NoteName+
5
+ #
6
+ # produces all the conversions from a named note to +pitch frequency+,
7
+ # +pitch class+, +LilyPond notation+, etc.
8
+ #
9
+ # In these conversions we assume that 8 is the central octave.
10
+ #
11
+ class NotALilypondName < StandardError; end
12
+ class NoteName
13
+
14
+ DEFAULT_NOTE_NAME_OFFSET = 9 # central 'A' 440 is 8.09, isn't it?
15
+ LILY_NOTE_NAMES = %w( a b c d e f )
16
+
17
+ attr_reader :name, :index
18
+
19
+ def initialize(name, idx)
20
+ @name = name
21
+ @index = idx
22
+ end
23
+
24
+ def to_lily(octave = 8, other = '') # 8 is the central octave
25
+ nn = self.name.sub(/\A\s*(.).*$/, '\1').downcase
26
+ raise NotALilypondName, "\"#{self.name}\" does not contain a note" unless LILY_NOTE_NAMES.include?(nn)
27
+ sharps = (self.name.match?(/\A\s*\w#/) && self.name.sub(/\A\s*\w(#+).*$/, '\1').gsub(/#/, 'is')) || nil
28
+ flats = (self.name.match?(/\A\s*\w[Ff]/) && self.name.sub(/\A\s*\w([Ff]+).*$/, '\1').gsub(/[Ff]/, 'es')) || nil
29
+ accs = sharps ? sharps : (flats ? flats : '')
30
+ "#{nn}#{accs}#{octave}#{other}"
31
+ end
32
+
33
+ def to_pitch_class(octave = 8) # 8 is the central octave
34
+ octave + (self.index/100.0)
35
+ end
36
+
37
+ def to_frequency(octave = 8)
38
+ self.to_pitch_class(octave).pchcps
39
+ end
40
+
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,8 @@
1
+ module Mext
2
+ module Music
3
+
4
+ DEFAULT_ANGLO_NAMES = %w(A B C D E F G)
5
+ DEFAULT_ITA_NAMES = %w(Do Re Mi Fa Sol La Si)
6
+
7
+ end
8
+ end
data/lib/mext/numeric.rb CHANGED
@@ -24,7 +24,6 @@ module Mext
24
24
  NON_VECTORIZABLE_METHODS = %w(
25
25
  constants
26
26
  pitch_fork
27
- meter
28
27
  )
29
28
  ADDED_METHODS = NON_VECTORIZABLE_METHODS + VECTORIZABLE_METHODS
30
29
 
data/lib/octave.rb ADDED
@@ -0,0 +1,12 @@
1
+ module Mext
2
+ module Octave
3
+
4
+ PATH = File.expand_path(File.join('..', 'octave'), __FILE__)
5
+
6
+ end
7
+ end
8
+
9
+ %w(
10
+ io
11
+ polyfit
12
+ ).each { |f| require File.join(Mext::Octave::PATH, f) }
data/lib/octave/io.rb ADDED
@@ -0,0 +1,29 @@
1
+ module Octave
2
+
3
+ module Io
4
+
5
+ class << self
6
+
7
+ OCTAVE_EXE='/usr/bin/env octave -q'
8
+ #
9
+ # +Octave::Io.command(command_string)+
10
+ #
11
+ # send a command to Octave in a pipe and return the results.
12
+ # The results are returned as arrays of float values
13
+ #
14
+ def command(command_string)
15
+ res = []
16
+ decorated_command_string = "echo \"#{command_string}\" | #{OCTAVE_EXE}"
17
+ IO.popen(decorated_command_string) do
18
+ |octave_result|
19
+ out = octave_result.readlines.map { |l| l.chomp }
20
+ out.each { |line| res << line.to_f if line.match?(/\s*\d+/) }
21
+ end
22
+ res
23
+ end
24
+
25
+ end
26
+
27
+ end
28
+
29
+ end
@@ -0,0 +1,22 @@
1
+ module Octave
2
+
3
+ module Io
4
+
5
+ class << self
6
+
7
+ #
8
+ # +Octave::Io.polyfit(x, y, n)+
9
+ #
10
+ # get the coefficients of an n-degree polynomial
11
+ # using +octave+'s +polyfit+ function
12
+ #
13
+ def polyfit(x, y, n)
14
+ command_string = "a = polyfit(#{x}, #{y}, #{n}); a'"
15
+ ::Octave::Io.command(command_string)
16
+ end
17
+
18
+ end
19
+
20
+ end
21
+
22
+ end
data/lib/ruby-mext.rb CHANGED
@@ -8,5 +8,6 @@ end
8
8
 
9
9
  %w(
10
10
  ruby
11
+ octave
11
12
  mext
12
13
  ).each { |f| require File.join(Mext::ROOT, f) }
@@ -1,6 +1,6 @@
1
1
 
2
2
  desc 'plot all plots'
3
- task :plot => ['plot:expon', 'plot:line', 'plot:stepwise']
3
+ task :plot => ['plot:expon', 'plot:line', 'plot:stepwise', 'plot:polynomial']
4
4
 
5
5
  namespace :plot do
6
6
 
@@ -0,0 +1,17 @@
1
+ require 'fileutils'
2
+ require File.expand_path(File.join(['..'] * 4, 'spec', 'fixtures', 'polynomial_dataset'), __FILE__)
3
+ require File.expand_path(File.join('..', 'gruff_plot'), __FILE__)
4
+
5
+ namespace :plot do
6
+
7
+ desc 'plot the Polynomial dataset'
8
+ task :polynomial => :create_output_dir do
9
+ ranges = [ Range.new(0, 0) ]
10
+ p = Mext::Gruff::Plotter.new('polynomial_dataset', 800, Mext::Spec::Fixtures::Math::POLYNOMIAL_DATASET, ranges)
11
+ p.plot do
12
+ |args|
13
+ Math::Polynomial.new(args)
14
+ end
15
+ end
16
+
17
+ end
data/lib/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Mext
2
- VERSION = '0.21.1'
2
+ VERSION = '0.21.6'
3
3
  end
data/ruby-mext.gemspec CHANGED
@@ -7,11 +7,11 @@ Gem::Specification.new do |spec|
7
7
  spec.name = 'ruby-mext'
8
8
  spec.version = Mext::VERSION
9
9
  spec.authors = ['Nicola Bernardini']
10
- spec.email = ['nicb@sme-ccppd.org']
10
+ spec.email = ['nicola.bernardini.rome@gmail.com']
11
11
 
12
12
  spec.summary = %q{ruby-mext: musical extensions for the Ruby language.}
13
13
  spec.description = %q{ruby-mext: musical extensions for the Ruby language.}
14
- spec.homepage = 'https://github.com/nicb/ruby-mext'
14
+ spec.homepage = 'https://git.smerm.org/nicb/ruby-mext'
15
15
 
16
16
  # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
17
17
  # to allow pushing to a single host or delete this section to allow pushing to any host.
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-mext
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.21.1
4
+ version: 0.21.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nicola Bernardini
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-05-01 00:00:00.000000000 Z
11
+ date: 2021-05-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: wavefile
@@ -124,7 +124,7 @@ dependencies:
124
124
  version: '0'
125
125
  description: 'ruby-mext: musical extensions for the Ruby language.'
126
126
  email:
127
- - nicb@sme-ccppd.org
127
+ - nicola.bernardini.rome@gmail.com
128
128
  executables: []
129
129
  extensions: []
130
130
  extra_rdoc_files: []
@@ -157,8 +157,12 @@ files:
157
157
  - lib/mext/math/function.rb
158
158
  - lib/mext/math/line.rb
159
159
  - lib/mext/math/log.rb
160
+ - lib/mext/math/polynomial.rb
160
161
  - lib/mext/math/stepwise.rb
161
162
  - lib/mext/music.rb
163
+ - lib/mext/music/meter.rb
164
+ - lib/mext/music/note_name.rb
165
+ - lib/mext/music/note_names.rb
162
166
  - lib/mext/music/pitch_class.rb
163
167
  - lib/mext/numeric.rb
164
168
  - lib/mext/numeric/addsemi.rb
@@ -169,7 +173,6 @@ files:
169
173
  - lib/mext/numeric/dbamp.rb
170
174
  - lib/mext/numeric/ftom.rb
171
175
  - lib/mext/numeric/gold.rb
172
- - lib/mext/numeric/meter.rb
173
176
  - lib/mext/numeric/mmtot.rb
174
177
  - lib/mext/numeric/mround.rb
175
178
  - lib/mext/numeric/mtof.rb
@@ -185,6 +188,9 @@ files:
185
188
  - lib/mext/sound.rb
186
189
  - lib/mext/sound/info.rb
187
190
  - lib/mext/utilities.rb
191
+ - lib/octave.rb
192
+ - lib/octave/io.rb
193
+ - lib/octave/polyfit.rb
188
194
  - lib/ruby-mext.rb
189
195
  - lib/ruby.rb
190
196
  - lib/ruby/extensions.rb
@@ -194,10 +200,11 @@ files:
194
200
  - lib/tasks/gruff/gruff.rake
195
201
  - lib/tasks/gruff/gruff_plot.rb
196
202
  - lib/tasks/gruff/line.rake
203
+ - lib/tasks/gruff/polynomial.rake
197
204
  - lib/tasks/gruff/stepwise.rake
198
205
  - lib/version.rb
199
206
  - ruby-mext.gemspec
200
- homepage: https://github.com/nicb/ruby-mext
207
+ homepage: https://git.smerm.org/nicb/ruby-mext
201
208
  licenses: []
202
209
  metadata:
203
210
  allowed_push_host: https://rubygems.org
@@ -216,7 +223,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
216
223
  - !ruby/object:Gem::Version
217
224
  version: '0'
218
225
  requirements: []
219
- rubygems_version: 3.1.2
226
+ rubygems_version: 3.2.2
220
227
  signing_key:
221
228
  specification_version: 4
222
229
  summary: 'ruby-mext: musical extensions for the Ruby language.'