ruby-mext 0.1.0 → 0.2.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: 773f3e12f73de66842d7642971dcea4b2867739ef6b4cc31cd5817e0ffe4ffe6
4
- data.tar.gz: 15072b30760291f0018672562ab5f3a7b3a72a3e943b63822b2ef334c4a4cbb5
3
+ metadata.gz: f9b816eb8358ac2720a30375f4d7c5c85a8d99b61781efd8eea22ba931e54b5e
4
+ data.tar.gz: fe9a1ad5339a33fc710319bcd9c512538aec99902ebd3ac5bee8e0b617bef013
5
5
  SHA512:
6
- metadata.gz: d90bc088598500d36d74bfecc0dcf56cbc7be5f1e4f9febbbbd954ce2d49da1c3bc6b949729363da5ffe0d8476361ddc10ac66fb4da040efcc7fd6babe44bc3d
7
- data.tar.gz: 66a518a399b40aadaf5e9e318489951859eed2c8412f655336c802f0195bb8713b68aeb25873f91388f8daa960669a91f6f154f01c1c86bca5c384abad75d46b
6
+ metadata.gz: 77455bc326bfe523232abca1f8985ea6ded5a7368c06ca41f2b10f551b541b656c4d402b0e10fcf7946895169ad4e2c6c2ee7c7c9260319602081c71900e2f9c
7
+ data.tar.gz: c02ba1e2882ad0760cb7c217980c92c7d65896f6cb7e42c086f7f428efa57852c0a5f30f2400a181d364fe4ff84ee00f416f876d863dfa90d7a743934dc70340
data/Rakefile CHANGED
@@ -1,6 +1,7 @@
1
1
  require "bundler/gem_tasks"
2
2
  require "rspec/core/rake_task"
3
3
  require 'rdoc/task'
4
+ require 'ruby-mext'
4
5
 
5
6
  RDoc::Task.new do |rdoc|
6
7
  rdoc.main = "README.md"
@@ -10,3 +11,5 @@ end
10
11
  RSpec::Core::RakeTask.new(:spec)
11
12
 
12
13
  task :default => :spec
14
+
15
+ Dir.glob(File.expand_path(File.join('..', 'lib', 'tasks', '**', '*.rake'), __FILE__)).each { |f| load f }
@@ -0,0 +1,88 @@
1
+ require 'cmath'
2
+
3
+ module Math
4
+
5
+ class Expon
6
+
7
+ attr_reader :y_start, :y_end, :x_start, :x_end, :tau
8
+ attr_reader :a, :b, :c
9
+
10
+ #
11
+ # +DEFAULT_TAU+: default exponential curvature factor for +expon()+
12
+ #
13
+ DEFAULT_TAU = 0.01
14
+
15
+ #
16
+ # +Math::Expon.new(ystart, yend, xstart, xend, tau = DEFAULT_TAU)+:
17
+ #
18
+ # exponential curve `y = e^(a*x + b) + c` where:
19
+ #
20
+ # `c = yend + tau`
21
+ #
22
+ # Arguments are:
23
+ #
24
+ # +ystart+, +yend+: start/end y values required
25
+ # +xstart+, +xend+: start/end x values
26
+ # +tau+: the curvature factor
27
+ #
28
+ #:nodoc:
29
+ def initialize(ys, ye, xs, xe, tau = DEFAULT_TAU)
30
+ @y_start = ys
31
+ @y_end = ye
32
+ @x_start = xs
33
+ @x_end = xe
34
+ @tau = tau
35
+ setup
36
+ end
37
+
38
+ #:doc:
39
+ #
40
+ # +y(x)+:
41
+ #
42
+ # Returns a real value (forcing any complex result to its modulus) for any
43
+ # given x
44
+ #
45
+ #:nodoc:
46
+ def y(x)
47
+ (CMath::exp(self.a*x + self.b) + self.c).abs # we want a real number result, no complex please
48
+ end
49
+
50
+ #:doc:
51
+ #
52
+ # +xy(step)+
53
+ #
54
+ # Returns a full deployment of the function evaluated with a step of
55
+ # +step+. It is returned in two arrays - one for the +x+ values and the
56
+ # other for the +y+ values.
57
+ #
58
+ # This method is mainly for testing purposes with the dataxy method of +gruff+
59
+ #
60
+ #:nodoc:
61
+ def xy(s)
62
+ resx = []
63
+ resy = []
64
+ self.x_start.step(x_end, s) do
65
+ |x|
66
+ resx << x
67
+ resy << self.y(x)
68
+ end
69
+ [resx, resy]
70
+ end
71
+
72
+ private
73
+
74
+ def setup
75
+ @c = self.y_end + self.tau
76
+
77
+ exp_sv = self.y_start - self.c # start value of the exponential
78
+ exp_ev = self.y_end - self.c # end value of the exponential
79
+ x_length = self.x_end - self.x_start
80
+
81
+ @a = (CMath::log(exp_ev) - CMath::log(exp_sv)) / x_length;
82
+ @b= CMath::log(exp_sv) - (self.a * x_start);
83
+
84
+ end
85
+
86
+ end
87
+
88
+ end
data/lib/mext/math.rb ADDED
@@ -0,0 +1,9 @@
1
+ module Mext
2
+
3
+ MATH_PATH = File.join(Mext::PATH, 'math')
4
+
5
+ end
6
+
7
+ %w(
8
+ expon
9
+ ).each { |f| require File.join(Mext::MATH_PATH, f) }
@@ -0,0 +1,18 @@
1
+ class Numeric
2
+
3
+ #
4
+ # +cpspch+: frequency to pitch class converter
5
+ #
6
+ # interprets its receiver as frequency and returns its corresponing pitch class
7
+ #
8
+ #:nodoc:
9
+
10
+ def cpspch
11
+ raise NegativeNumeric if self <= 0.0
12
+
13
+ midi_note = self.ftom
14
+
15
+ midi_note.mtopch
16
+ end
17
+
18
+ end
@@ -0,0 +1,20 @@
1
+ class Numeric
2
+
3
+ #
4
+ # +mtopch+: MIDI note to pitch class converter
5
+ #
6
+ # interprets its receiver as a MIDI note and returns its corresponing pitch class
7
+ #
8
+ #:nodoc:
9
+
10
+ def mtopch
11
+
12
+ intv = (self - MIDI_MIDDLE_C) / CHROMATIC_NOTES_PER_OCTAVE
13
+
14
+ intv_octave = intv.to_i
15
+ intv_semi = (intv - intv_octave) * CHROMATIC_NOTES_PER_OCTAVE;
16
+
17
+ PITCH_MIDDLE_C + intv_octave + (intv_semi/100.0);
18
+ end
19
+
20
+ end
@@ -0,0 +1,16 @@
1
+ class Numeric
2
+
3
+ #
4
+ # +pchcps+: pitch class converter to frequency
5
+ #
6
+ # interprets its receiver as pitch class and returns its corresponing frequency
7
+ #
8
+ #:nodoc:
9
+
10
+ def pchcps
11
+ m_note = self.pchtom
12
+
13
+ m_note.mtof
14
+ end
15
+
16
+ end
@@ -0,0 +1,26 @@
1
+ class Numeric
2
+
3
+ #
4
+ # +pchtom+: pitch class to MIDI note converter
5
+ #
6
+ # interprets its receiver as a pitch class and returns its corresponing MIDI note
7
+ #
8
+ #:nodoc:
9
+ MIDI_MIDDLE_C = 60
10
+ PITCH_MIDDLE_C = 8.0
11
+ CHROMATIC_NOTES_PER_OCTAVE = 12.0
12
+
13
+ def pchtom
14
+ p_octave = self.to_i
15
+ p_note = (self - p_octave) * 100
16
+ ref = self < 0.0 ? -CHROMATIC_NOTES_PER_OCTAVE : CHROMATIC_NOTES_PER_OCTAVE
17
+
18
+ p_octave += (p_note / CHROMATIC_NOTES_PER_OCTAVE).to_i # cater for octave wrapping
19
+ p_note = (p_note % ref); # reduce note in a 0-11 space (keeping track of sign)
20
+
21
+ m_octave = ((p_octave - PITCH_MIDDLE_C)*CHROMATIC_NOTES_PER_OCTAVE) + MIDI_MIDDLE_C; # find the appropriate midi octave
22
+
23
+ m_octave + p_note
24
+ end
25
+
26
+ end
@@ -0,0 +1,32 @@
1
+ class Numeric
2
+
3
+ #
4
+ # +rrand(upper)+: random number generator
5
+ #
6
+ # returns a random number in the range receiver-upper bound
7
+ #
8
+ # If any of the numbers (the receiver +or+ the argument) are +Float+s
9
+ # the method will return a +Float+. If both arguments are integers then an
10
+ # +Integer+ will be returned.
11
+ #
12
+ # (this method is present in the SuperCollider sclang interpreter)
13
+ #
14
+ #:nodoc:
15
+
16
+ def rrand(upper)
17
+ lobound = self.to_f
18
+ rng = upper.to_f - lobound
19
+
20
+ (rand()*rng) + lobound
21
+ end
22
+
23
+ end
24
+
25
+ class Integer
26
+
27
+ def rrand(upper)
28
+ res = super(upper)
29
+ upper.is_a?(Integer) ? res.round : res
30
+ end
31
+
32
+ end
data/lib/mext/numeric.rb CHANGED
@@ -11,4 +11,9 @@ end
11
11
  ftom
12
12
  ampdb
13
13
  dbamp
14
+ pchtom
15
+ mtopch
16
+ cpspch
17
+ pchcps
18
+ rrand
14
19
  ).each { |f| require File.join(Mext::NUMERIC_PATH, f) }
data/lib/mext.rb CHANGED
@@ -6,4 +6,5 @@ end
6
6
 
7
7
  %w(
8
8
  numeric
9
+ math
9
10
  ).each { |f| require File.join(Mext::PATH, f) }
@@ -0,0 +1,5 @@
1
+ require 'rake/clean'
2
+
3
+ CLEAN.include('tmp')
4
+ CLEAN.include('html')
5
+ CLEAN.include('pkg')
@@ -0,0 +1,20 @@
1
+ require 'fileutils'
2
+ require File.expand_path(File.join(['..'] * 4, 'spec', 'fixtures', 'expon_dataset'), __FILE__)
3
+ require File.expand_path(File.join('..', 'gruff_plot'), __FILE__)
4
+
5
+ namespace :plot do
6
+
7
+ task :create_output_dir do
8
+ unless Dir.exists?(Mext::Gruff::Plotter::OUTPUT_PATH)
9
+ mkdir_p Mext::Gruff::Plotter::OUTPUT_PATH
10
+ end
11
+ end
12
+
13
+ desc 'plot the Expon dataset'
14
+ task :expon => :create_output_dir do
15
+ ranges = [ Range.new(0, 2), Range.new(3,3) ]
16
+ p = Mext::Gruff::Plotter.new('expon_dataset', 800, Mext::Spec::Fixtures::Math::EXPON_DATASETS, ranges)
17
+ p.plot
18
+ end
19
+
20
+ end
@@ -0,0 +1,3 @@
1
+
2
+ desc 'plot all plots'
3
+ task :plot => ['plot:expon']
@@ -0,0 +1,39 @@
1
+ require 'gruff'
2
+
3
+ module Mext
4
+ module Gruff
5
+
6
+ class Plotter
7
+ attr_reader :title, :size, :datasets, :ranges
8
+
9
+ OUTPUT_PATH = File.expand_path(File.join(['..'] * 4, 'tmp', 'output'), __FILE__)
10
+
11
+ def initialize(t, s, ds, r = nil)
12
+ @title = t
13
+ @size = s
14
+ @datasets = ds
15
+ @ranges = r
16
+ end
17
+
18
+ def plot
19
+ @ranges = [Range.new(0, self.datasets-1)] unless self.ranges
20
+ idx = 0
21
+ self.ranges.each do
22
+ |range|
23
+ g = ::Gruff::Line.new(self.size)
24
+ g.title = self.title + " (#{idx})"
25
+ self.datasets[range].each do
26
+ |args|
27
+ (ys, ye, xs, xe, tau, xmid, ymid) = args
28
+ f = Math::Expon.new(ys, ye, xs, xe, tau)
29
+ (xdata, ydata) = f.xy(0.1)
30
+ g.dataxy("tau: #{f.tau}", xdata, ydata)
31
+ end
32
+ g.write(File.join(Mext::Gruff::Plotter::OUTPUT_PATH, self.title.gsub(/\s+/, '_') + "_#{idx}.png"))
33
+ idx += 1
34
+ end
35
+ end
36
+
37
+ end
38
+ end
39
+ end
data/lib/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Mext
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
data/ruby-mext.gemspec CHANGED
@@ -34,5 +34,6 @@ Gem::Specification.new do |spec|
34
34
  spec.add_development_dependency 'rspec', '~> 3.0'
35
35
  spec.add_development_dependency 'rdoc'
36
36
  spec.add_development_dependency 'byebug'
37
+ spec.add_development_dependency 'gruff'
37
38
 
38
39
  end
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.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nicola Bernardini
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-04-20 00:00:00.000000000 Z
11
+ date: 2019-04-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -80,6 +80,20 @@ dependencies:
80
80
  - - ">="
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: gruff
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
83
97
  description: 'ruby-mext: musical extensions for the Ruby language.'
84
98
  email:
85
99
  - nicb@sme-ccppd.org
@@ -100,14 +114,25 @@ files:
100
114
  - bin/console
101
115
  - bin/setup
102
116
  - lib/mext.rb
117
+ - lib/mext/math.rb
118
+ - lib/mext/math/expon.rb
103
119
  - lib/mext/numeric.rb
104
120
  - lib/mext/numeric/ampdb.rb
121
+ - lib/mext/numeric/cpspch.rb
105
122
  - lib/mext/numeric/dbamp.rb
106
123
  - lib/mext/numeric/exceptions.rb
107
124
  - lib/mext/numeric/ftom.rb
108
125
  - lib/mext/numeric/mtof.rb
126
+ - lib/mext/numeric/mtopch.rb
127
+ - lib/mext/numeric/pchcps.rb
128
+ - lib/mext/numeric/pchtom.rb
109
129
  - lib/mext/numeric/pitch_fork.rb
130
+ - lib/mext/numeric/rrand.rb
110
131
  - lib/ruby-mext.rb
132
+ - lib/tasks/clean.rake
133
+ - lib/tasks/gruff/expon.rake
134
+ - lib/tasks/gruff/gruff.rake
135
+ - lib/tasks/gruff/gruff_plot.rb
111
136
  - lib/version.rb
112
137
  - ruby-mext.gemspec
113
138
  homepage: https://github.com/nicb/ruby-mext