synthesizer 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,6 @@
1
+ module Synthesizer
2
+ module Quality
3
+ HIGH = :High
4
+ LOW = :Low
5
+ end
6
+ end
@@ -0,0 +1,35 @@
1
+ module Synthesizer
2
+ module Shape
3
+ # Basic
4
+ Sine = ->(phase) { Math.sin(phase * 2 * Math::PI) }
5
+ Sawtooth = ->(phase) { ((phase + 0.5) % 1) * 2 - 1 }
6
+ Square = ->(phase) { 0.5<=((phase + 0.5) % 1) ? 1.0 : -1.0 }
7
+ Triangle = ->(phase) {
8
+ t = ((phase*4).floor % 4);
9
+ t==0 ? (phase % 0.5)*4 :
10
+ t==1 ? (2-(phase % 0.5)*4) :
11
+ t==2 ? (-(phase % 0.5)*4) : (phase % 0.5)*4-2
12
+ }
13
+
14
+ # Noise
15
+ WhiteNoise = ->(phase) { Random.rand(-1.0...1.0) }
16
+
17
+ # LFO
18
+ RampUp = ->(phase) { (phase % 1) * 2 - 1 }
19
+ RampDown = ->(phase) { (phase % 1) * -2 + 1 }
20
+
21
+ # Complex
22
+ self.constants.tap {|consts|
23
+ consts.each {|a|
24
+ consts.each {|b|
25
+ if a!=b
26
+ eval "#{a}#{b} = ->(phase) {
27
+ (#{a}[phase] + #{b}[phase]) / 2
28
+ }"
29
+ end
30
+ }
31
+ }
32
+ }
33
+
34
+ end
35
+ end
@@ -0,0 +1,29 @@
1
+ module Synthesizer
2
+ class ShapePos
3
+ def initialize(phase: 0.0, sync: nil)
4
+ @init_phase = phase
5
+ @sync = sync
6
+
7
+ @offset = 0
8
+ @phase = 0.0
9
+ end
10
+
11
+ def next(delta)
12
+ @offset += 1
13
+
14
+ if @offset==1
15
+ if @init_phase
16
+ @phase = @init_phase + delta
17
+ else
18
+ @phase = Random.rand + delta
19
+ end
20
+ # TODO: sync
21
+ #elsif @sync && @sync<@offset
22
+ # @offset = 0
23
+ # @phase = @init_phase
24
+ else
25
+ @phase += delta
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,51 @@
1
+ module Synthesizer
2
+ class Unison
3
+ UNI_NUM_MAX = 16
4
+
5
+ def initialize(note_perform, shape, phase)
6
+ @note_perform = note_perform
7
+ @shape = shape
8
+ @poss = UNI_NUM_MAX.times.map {|i|
9
+ ShapePos.new(phase: phase.value)
10
+ }
11
+
12
+ synth = note_perform.synth
13
+ @samplerate = synth.soundinfo.samplerate
14
+ end
15
+
16
+ def next(uni_num, uni_detune, volume, pan, tune_semis, tune_cents)
17
+ if uni_num<1.0
18
+ uni_num = 1.0
19
+ elsif UNI_NUM_MAX<uni_num
20
+ uni_num = UNI_NUM_MAX
21
+ end
22
+
23
+ val_l = 0.0
24
+ val_r = 0.0
25
+
26
+ uni_num.ceil.times {|i|
27
+ pos = @poss[i]
28
+
29
+ uni_volume = 1.0
30
+ if uni_num<i
31
+ uni_volume = uni_num % 1.0
32
+ end
33
+
34
+ sign = i.even? ? 1 : -1
35
+ detune_cents = sign * (i/2) * uni_detune * 100
36
+ diff_pan = sign * (i/2) * uni_detune
37
+
38
+ l_gain, r_gain = Utils.panning(pan + diff_pan)
39
+
40
+ hz = @note_perform.note.hz(semis: tune_semis, cents: tune_cents + detune_cents)
41
+ delta = hz / @samplerate
42
+
43
+ val = @shape[pos.next(delta)] * uni_volume
44
+ val_l += val * l_gain
45
+ val_r += val * r_gain
46
+ }
47
+
48
+ [val_l * volume / uni_num, val_r * volume / uni_num]
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,45 @@
1
+ module Synthesizer
2
+ module Utils
3
+
4
+ def self.panning(pan)
5
+ cp = cross_panning(pan)
6
+
7
+ l_gain = (cp[:l_gain] + cp[:lr_gain]) / cp[:normalize]
8
+ r_gain = (cp[:r_gain] + cp[:rl_gain]) / cp[:normalize]
9
+
10
+ [l_gain, r_gain]
11
+ end
12
+
13
+ def self.cross_panning(pan)
14
+ if pan<-1.0
15
+ pan = -1.0
16
+ elsif 1.0<pan
17
+ pan = 1.0
18
+ end
19
+
20
+ l_gain = 1.0 - pan
21
+ lr_gain = 0.0
22
+ if 1.0<l_gain
23
+ lr_gain = l_gain - 1.0
24
+ l_gain = 1.0
25
+ end
26
+
27
+ r_gain = 1.0 + pan
28
+ rl_gain = 0.0
29
+ if 1.0<r_gain
30
+ rl_gain = r_gain - 1.0
31
+ r_gain = 1.0
32
+ end
33
+
34
+ normalize = [1.0 - pan, 1.0 + pan].max
35
+
36
+ {
37
+ l_gain: l_gain,
38
+ lr_gain: lr_gain,
39
+ r_gain: r_gain,
40
+ rl_gain: rl_gain,
41
+ normalize: normalize
42
+ }
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,3 @@
1
+ module Synthesizer
2
+ VERSION = "1.0.0"
3
+ end
@@ -0,0 +1,39 @@
1
+ lib = File.expand_path("lib", __dir__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require "synthesizer/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "synthesizer"
7
+ spec.version = Synthesizer::VERSION
8
+ spec.authors = ["Yoshida Tetsuya"]
9
+ spec.email = ["yoshida.eth0@gmail.com"]
10
+
11
+ spec.summary = %q{Synthesizer implemented in Ruby.}
12
+ spec.description = %q{Synthesizer implemented in Ruby.}
13
+ spec.homepage = "https://github.com/yoshida-eth0/ruby-synthesizer"
14
+ spec.license = "MIT"
15
+
16
+ spec.metadata["homepage_uri"] = spec.homepage
17
+ spec.metadata["source_code_uri"] = spec.homepage
18
+ spec.metadata["changelog_uri"] = spec.homepage
19
+
20
+ # Specify which files should be added to the gem when it is released.
21
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
22
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
23
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
24
+ end
25
+ spec.bindir = "exe"
26
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
27
+ spec.require_paths = ["lib"]
28
+
29
+ spec.add_development_dependency "bundler", "~> 2.0"
30
+ spec.add_development_dependency "rake", "~> 12.0"
31
+ spec.add_development_dependency "minitest", "~> 5.0"
32
+
33
+ spec.add_dependency "audio_stream", ">= 1.0"
34
+ spec.add_dependency "ruby-audio", ">= 1.6.1"
35
+ spec.add_dependency "coreaudio", ">= 0.0.12"
36
+ spec.add_dependency "ruby-fftw3", ">= 1.0.2"
37
+ spec.add_dependency "rx", ">= 0.0.3"
38
+ spec.add_dependency "rbplotly", ">= 0.1.2"
39
+ end
metadata ADDED
@@ -0,0 +1,209 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: synthesizer
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Yoshida Tetsuya
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2019-07-16 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '12.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '12.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '5.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '5.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: audio_stream
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '1.0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '1.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: ruby-audio
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: 1.6.1
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: 1.6.1
83
+ - !ruby/object:Gem::Dependency
84
+ name: coreaudio
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: 0.0.12
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: 0.0.12
97
+ - !ruby/object:Gem::Dependency
98
+ name: ruby-fftw3
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: 1.0.2
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: 1.0.2
111
+ - !ruby/object:Gem::Dependency
112
+ name: rx
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: 0.0.3
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: 0.0.3
125
+ - !ruby/object:Gem::Dependency
126
+ name: rbplotly
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: 0.1.2
132
+ type: :runtime
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: 0.1.2
139
+ description: Synthesizer implemented in Ruby.
140
+ email:
141
+ - yoshida.eth0@gmail.com
142
+ executables: []
143
+ extensions: []
144
+ extra_rdoc_files: []
145
+ files:
146
+ - ".gitignore"
147
+ - ".travis.yml"
148
+ - Gemfile
149
+ - LICENSE.txt
150
+ - README.md
151
+ - Rakefile
152
+ - bin/console
153
+ - bin/setup
154
+ - examples/adsr.ipynb
155
+ - examples/curves.ipynb
156
+ - examples/mono.rb
157
+ - examples/poly.rb
158
+ - examples/shapes.ipynb
159
+ - lib/audio_stream/audio_input_synth.rb
160
+ - lib/synthesizer.rb
161
+ - lib/synthesizer/amplifier.rb
162
+ - lib/synthesizer/modulation.rb
163
+ - lib/synthesizer/modulation/adsr.rb
164
+ - lib/synthesizer/modulation/curve.rb
165
+ - lib/synthesizer/modulation/glide.rb
166
+ - lib/synthesizer/modulation/lfo.rb
167
+ - lib/synthesizer/modulation_value.rb
168
+ - lib/synthesizer/mono.rb
169
+ - lib/synthesizer/note.rb
170
+ - lib/synthesizer/note_perform.rb
171
+ - lib/synthesizer/oscillator.rb
172
+ - lib/synthesizer/poly.rb
173
+ - lib/synthesizer/processor.rb
174
+ - lib/synthesizer/processor/high.rb
175
+ - lib/synthesizer/processor/low.rb
176
+ - lib/synthesizer/quality.rb
177
+ - lib/synthesizer/shape.rb
178
+ - lib/synthesizer/shape_pos.rb
179
+ - lib/synthesizer/unison.rb
180
+ - lib/synthesizer/utils.rb
181
+ - lib/synthesizer/version.rb
182
+ - synthesizer.gemspec
183
+ homepage: https://github.com/yoshida-eth0/ruby-synthesizer
184
+ licenses:
185
+ - MIT
186
+ metadata:
187
+ homepage_uri: https://github.com/yoshida-eth0/ruby-synthesizer
188
+ source_code_uri: https://github.com/yoshida-eth0/ruby-synthesizer
189
+ changelog_uri: https://github.com/yoshida-eth0/ruby-synthesizer
190
+ post_install_message:
191
+ rdoc_options: []
192
+ require_paths:
193
+ - lib
194
+ required_ruby_version: !ruby/object:Gem::Requirement
195
+ requirements:
196
+ - - ">="
197
+ - !ruby/object:Gem::Version
198
+ version: '0'
199
+ required_rubygems_version: !ruby/object:Gem::Requirement
200
+ requirements:
201
+ - - ">="
202
+ - !ruby/object:Gem::Version
203
+ version: '0'
204
+ requirements: []
205
+ rubygems_version: 3.0.4
206
+ signing_key:
207
+ specification_version: 4
208
+ summary: Synthesizer implemented in Ruby.
209
+ test_files: []