synthesizer 3.0.0 → 3.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ed8a308cdf0bcb0baf27daffd40c86c4998c8ca5d49ee90d1c0a2aac7a69c64d
4
- data.tar.gz: 46fbff7561bb5883dac304b083bed46bd6690e840096cd7c4b48f04d32542bac
3
+ metadata.gz: de75bd1dce21cbe4d6fb77b3f7dac7b35a5db994a1e7ee3d4109d660cbb69d68
4
+ data.tar.gz: 6d4f22b0ee34003ce64ab908f39ab9bfdd5df448c738eed516d2cb8312f2dbbe
5
5
  SHA512:
6
- metadata.gz: 9e9444d9132322cb3382e809a77a4803e895f5dd5aedf4de86272f616e27abc525734124d915cd1dd47f24e98e7b9d31716c88783337bc18f47e1b09d4e12ea3
7
- data.tar.gz: 2141b9541d1700616b9d131887218727284210b28488dd9007d08adfd05190320993099145d016b0c84b75cf19a61e74c3bcdf8b0f19249d260d7c05b7e6697d
6
+ metadata.gz: df6f09c4951a5925bc77f6821c53327307f9aeb16d4e273dc440c034c261fb06a35abd0f6c9b19735b3a581267afc30d98e3a05f722829bac9f2aa99e0cd5f34
7
+ data.tar.gz: 17da6f4b246047632d921e15d5b0b6975cc6c4ecda29ce9b1cdbe9231ea1832bef9b3601a91a98fe044711d5eef5a37e67aa74be6ef3691bf102380efc646b46
@@ -0,0 +1,86 @@
1
+ require 'synthesizer'
2
+ require 'audio_stream'
3
+
4
+ include AudioStream
5
+ include Synthesizer
6
+
7
+ soundinfo = SoundInfo.new(
8
+ channels: 2,
9
+ samplerate: 44100,
10
+ window_size: 1024,
11
+ format: RubyAudio::FORMAT_WAV|RubyAudio::FORMAT_PCM_16
12
+ )
13
+
14
+ source = nil
15
+
16
+ synth = PolySynth.new(
17
+ oscillators: [
18
+ Oscillator.new(
19
+ source: source = OscillatorSource::FormantVocoder.new(
20
+ vowels: [:a],
21
+ ),
22
+ phase: 0.0,
23
+ ),
24
+ ],
25
+ amplifier: Amplifier.new(
26
+ volume: ModulationValue.new(1.0)
27
+ .add(Modulation::Adsr.new(
28
+ attack: 0.05,
29
+ hold: 0.1,
30
+ decay: 0.4,
31
+ sustain: 0.8,
32
+ release: 0.2
33
+ ), depth: 1.0),
34
+ ),
35
+ soundinfo: soundinfo,
36
+ )
37
+ bufs = []
38
+ base = 36
39
+
40
+ source.vowels = [:a]
41
+ synth.note_on(Note.new(base))
42
+ bufs += 50.times.map {|_| synth.next}
43
+ synth.note_off(Note.new(base))
44
+ bufs += 20.times.map {|_| synth.next}
45
+
46
+ source.vowels = [:i]
47
+ synth.note_on(Note.new(base))
48
+ bufs += 50.times.map {|_| synth.next}
49
+ synth.note_off(Note.new(base))
50
+ bufs += 20.times.map {|_| synth.next}
51
+
52
+ source.vowels = [:u]
53
+ synth.note_on(Note.new(base))
54
+ bufs += 50.times.map {|_| synth.next}
55
+ synth.note_off(Note.new(base))
56
+ bufs += 20.times.map {|_| synth.next}
57
+
58
+ source.vowels = [:e]
59
+ synth.note_on(Note.new(base))
60
+ bufs += 50.times.map {|_| synth.next}
61
+ synth.note_off(Note.new(base))
62
+ bufs += 20.times.map {|_| synth.next}
63
+
64
+ source.vowels = [:o]
65
+ synth.note_on(Note.new(base))
66
+ bufs += 50.times.map {|_| synth.next}
67
+ synth.note_off(Note.new(base))
68
+
69
+ bufs += 50.times.map {|_| synth.next}
70
+
71
+
72
+ track1 = AudioInput.buffer(bufs)
73
+
74
+ stereo_out = AudioOutput.device(soundinfo: soundinfo)
75
+ #stereo_out = AudioOutput.file("formatvocoder.wav", soundinfo: soundinfo)
76
+
77
+ track1
78
+ .send_to(stereo_out, gain: 1.0)
79
+
80
+
81
+ conductor = Conductor.new(
82
+ input: [track1],
83
+ output: [stereo_out]
84
+ )
85
+ conductor.connect
86
+ conductor.join
@@ -0,0 +1,76 @@
1
+ require 'synthesizer'
2
+ require 'audio_stream'
3
+
4
+ include AudioStream
5
+ include Synthesizer
6
+
7
+ soundinfo = SoundInfo.new(
8
+ channels: 2,
9
+ samplerate: 44100,
10
+ window_size: 1024,
11
+ format: RubyAudio::FORMAT_WAV|RubyAudio::FORMAT_PCM_16
12
+ )
13
+
14
+ synth = PolySynth.new(
15
+ oscillators: [
16
+ Oscillator.new(
17
+ source: OscillatorSource::FormantVocoder.new(
18
+ vowels: [:a, :i, :u, :e, :o],
19
+ #vowels: [:i, :e, :a, :o, :u],
20
+ pronunciation: ModulationValue.new(0)
21
+ .add(Modulation::Lfo.new(
22
+ shape: Shape::ForeverRampUp,
23
+ rate: 2.0,
24
+ )),
25
+ ),
26
+ phase: 0.0,
27
+ ),
28
+ ],
29
+ amplifier: Amplifier.new(
30
+ volume: ModulationValue.new(1.0)
31
+ .add(Modulation::Adsr.new(
32
+ attack: 0.05,
33
+ hold: 0.1,
34
+ decay: 0.4,
35
+ sustain: 0.8,
36
+ release: 0.2
37
+ ), depth: 1.0),
38
+ ),
39
+ soundinfo: soundinfo,
40
+ )
41
+ bufs = []
42
+
43
+ base = 36
44
+ synth.note_on(Note.new(base))
45
+ bufs += 100.times.map {|_| synth.next}
46
+ synth.note_off(Note.new(base))
47
+ bufs += 20.times.map {|_| synth.next}
48
+
49
+ synth.note_on(Note.new(base+4))
50
+ bufs += 100.times.map {|_| synth.next}
51
+ synth.note_off(Note.new(base+4))
52
+ bufs += 20.times.map {|_| synth.next}
53
+
54
+ synth.note_on(Note.new(base+8))
55
+ bufs += 100.times.map {|_| synth.next}
56
+ synth.note_off(Note.new(base+8))
57
+ bufs += 20.times.map {|_| synth.next}
58
+
59
+ bufs += 50.times.map {|_| synth.next}
60
+
61
+
62
+ track1 = AudioInput.buffer(bufs)
63
+
64
+ stereo_out = AudioOutput.device(soundinfo: soundinfo)
65
+ #stereo_out = AudioOutput.file("formatvocoder_sweep.wav", soundinfo: soundinfo)
66
+
67
+ track1
68
+ .send_to(stereo_out, gain: 1.0)
69
+
70
+
71
+ conductor = Conductor.new(
72
+ input: [track1],
73
+ output: [stereo_out]
74
+ )
75
+ conductor.connect
76
+ conductor.join
@@ -14,7 +14,7 @@ soundinfo = SoundInfo.new(
14
14
  synth = PolySynth.new(
15
15
  oscillators: [
16
16
  Oscillator.new(
17
- shape: Shape::WhiteNoise
17
+ source: OscillatorSource::WhiteNoise.instance
18
18
  ),
19
19
  ],
20
20
  filter: Filter::Serial.new(
@@ -49,7 +49,6 @@ synth = PolySynth.new(
49
49
  release: 0.2
50
50
  ), depth: 1.0),
51
51
  ),
52
- quality: Quality::LOW,
53
52
  soundinfo: soundinfo,
54
53
  )
55
54
  bufs = []
@@ -14,20 +14,20 @@ soundinfo = SoundInfo.new(
14
14
  synth = MonoSynth.new(
15
15
  oscillators: [
16
16
  Oscillator.new(
17
- shape: Shape::SquareSawtooth,
17
+ source: OscillatorSource::SquareSawtooth.instance,
18
18
  uni_num: ModulationValue.new(4),
19
19
  #.add(Modulation::Lfo.new(
20
20
  #)),
21
21
  uni_detune: 0.1,
22
22
  ),
23
23
  #Oscillator.new(
24
- # shape: Shape::SquareSawtooth,
24
+ # source: OscillatorSource::SquareSawtooth.instance,
25
25
  # tune_cents: 0.1,
26
26
  # uni_num: 4,
27
27
  # uni_detune: 0.1,
28
28
  #),
29
29
  #Oscillator.new(
30
- # shape: Shape::SquareSawtooth,
30
+ # source: OscillatorSource::SquareSawtooth.instance,
31
31
  # tune_semis: -12,
32
32
  # uni_num: 4,
33
33
  # uni_detune: 0.1,
@@ -44,7 +44,6 @@ synth = MonoSynth.new(
44
44
  ), depth: 1.0),
45
45
  ),
46
46
  glide: 0.2,
47
- quality: Quality::LOW,
48
47
  soundinfo: soundinfo,
49
48
  )
50
49
  bufs = []
@@ -14,20 +14,20 @@ soundinfo = SoundInfo.new(
14
14
  synth = PolySynth.new(
15
15
  oscillators: [
16
16
  Oscillator.new(
17
- shape: Shape::SquareSawtooth,
17
+ source: OscillatorSource::SquareSawtooth.instance,
18
18
  uni_num: ModulationValue.new(4)
19
19
  .add(Modulation::Lfo.new(
20
20
  )),
21
21
  uni_detune: 0.1,
22
22
  ),
23
23
  #Oscillator.new(
24
- # shape: Shape::SquareSawtooth,
24
+ # source: OscillatorSource::SquareSawtooth.instance,
25
25
  # tune_cents: 0.1,
26
26
  # uni_num: 4,
27
27
  # uni_detune: 0.1,
28
28
  #),
29
29
  #Oscillator.new(
30
- # shape: Shape::SquareSawtooth,
30
+ # source: OscillatorSource::SquareSawtooth.instance,
31
31
  # tune_semis: -12,
32
32
  # uni_num: 4,
33
33
  # uni_detune: 0.1,
@@ -43,7 +43,6 @@ synth = PolySynth.new(
43
43
  release: 0.2
44
44
  ), depth: 1.0),
45
45
  ),
46
- quality: Quality::LOW,
47
46
  soundinfo: soundinfo,
48
47
  )
49
48
  bufs = []
@@ -14,7 +14,7 @@ soundinfo = SoundInfo.new(
14
14
  synth = PolySynth.new(
15
15
  oscillators: [
16
16
  Oscillator.new(
17
- shape: Shape::SquareSawtooth,
17
+ source: OscillatorSource::SquareSawtooth.instance,
18
18
  uni_num: 4,
19
19
  uni_detune: 0.1,
20
20
  ),
@@ -29,7 +29,6 @@ synth = PolySynth.new(
29
29
  release: 0.2
30
30
  ), depth: 1.0),
31
31
  ),
32
- quality: Quality::LOW,
33
32
  soundinfo: soundinfo,
34
33
  )
35
34
 
@@ -11,7 +11,7 @@ module AudioStream
11
11
 
12
12
  @synth = Synthesizer::PolySynth.new(
13
13
  oscillators: Synthesizer::Oscillator.new(
14
- shape: Synthesizer::Shape::Sine,
14
+ source: Synthesizer::OscillatorSource::Sine,
15
15
  phase: 0,
16
16
  ),
17
17
  amplifier: Synthesizer::Amplifier.new(
@@ -24,7 +24,6 @@ module AudioStream
24
24
  release: 0.0
25
25
  ), depth: 1.0),
26
26
  ),
27
- quality: Synthesizer::Quality::LOW,
28
27
  soundinfo: soundinfo,
29
28
  )
30
29
 
@@ -9,6 +9,7 @@ require 'synthesizer/step_editor'
9
9
  require 'synthesizer/poly_synth'
10
10
  require 'synthesizer/mono_synth'
11
11
  require 'synthesizer/oscillator'
12
+ require 'synthesizer/oscillator_source'
12
13
  require 'synthesizer/filter'
13
14
  require 'synthesizer/amplifier'
14
15
  require 'synthesizer/shape'
@@ -19,7 +20,6 @@ require 'synthesizer/note'
19
20
  require 'synthesizer/note_perform'
20
21
  require 'synthesizer/unison'
21
22
  require 'synthesizer/processor'
22
- require 'synthesizer/quality'
23
23
  require 'synthesizer/utils'
24
24
 
25
25
  module Synthesizer
@@ -6,7 +6,6 @@ module Synthesizer
6
6
  attr_reader :amplifier
7
7
  attr_reader :processor
8
8
 
9
- attr_reader :quality
10
9
  attr_reader :soundinfo
11
10
 
12
11
  attr_reader :glide
@@ -15,15 +14,14 @@ module Synthesizer
15
14
  # @param oscillators [Synthesizer::Oscillator] oscillator
16
15
  # @param amplifier [Synthesizer::Amplifier] amplifier
17
16
  # @param soundinfo [AudioStream::SoundInfo]
18
- def initialize(oscillators:, filter: nil, amplifier:, glide: 0.1, quality: Quality::LOW, soundinfo:)
17
+ def initialize(oscillators:, filter: nil, amplifier:, glide: 0.1, soundinfo:)
19
18
  @oscillators = [oscillators].flatten.compact
20
19
  @filter = filter
21
20
  @amplifier = amplifier
22
21
 
23
- @quality = quality
24
22
  @soundinfo = soundinfo
25
23
 
26
- @processor = Processor.create(quality)
24
+ @processor = Processor.new
27
25
  @note_nums = []
28
26
  @perform = nil
29
27
  @glide = Modulation::Glide.new(time: glide)
@@ -1,7 +1,7 @@
1
1
  module Synthesizer
2
2
  class Oscillator
3
3
 
4
- attr_reader :shape
4
+ attr_reader :source
5
5
  attr_reader :volume
6
6
  attr_reader :pan
7
7
  attr_reader :tune_semis
@@ -12,7 +12,7 @@ module Synthesizer
12
12
  attr_reader :uni_num
13
13
  attr_reader :uni_detune
14
14
 
15
- # @param shape [Synthesizer::Shape] oscillator waveform shape
15
+ # @param source [Synthesizer::OscillatorSource] oscillator waveform source
16
16
  # @param volume [Float] oscillator volume. mute=0.0 max=1.0
17
17
  # @param pan [Float] oscillator pan. left=-1.0 center=0.0 right=1.0 (-1.0~1.0)
18
18
  # @param tune_semis [Integer] oscillator pitch semitone
@@ -22,8 +22,8 @@ module Synthesizer
22
22
  # @param sync [Integer] TODO not implemented
23
23
  # @param uni_num [Float] oscillator voicing number (1.0~16.0)
24
24
  # @param uni_detune [Float] oscillator voicing detune percent. 0.01=1cent 1.0=semitone (0.0~1.0)
25
- def initialize(shape: Shape::Sine, volume: 1.0, pan: 0.0, tune_semis: 0, tune_cents: 0, sym: 0, phase: nil, sync: 0, uni_num: 1.0, uni_detune: 0.0)
26
- @shape = shape
25
+ def initialize(source: OscillatorSource::Sine, volume: 1.0, pan: 0.0, tune_semis: 0, tune_cents: 0, sym: 0, phase: nil, sync: 0, uni_num: 1.0, uni_detune: 0.0)
26
+ @source = source
27
27
 
28
28
  @volume = ModulationValue.create(volume)
29
29
  @pan = ModulationValue.create(pan)
@@ -0,0 +1,5 @@
1
+ require 'synthesizer/shape'
2
+ require 'synthesizer/oscillator_source/base'
3
+ require 'synthesizer/oscillator_source/basic'
4
+ require 'synthesizer/oscillator_source/pulse'
5
+ require 'synthesizer/oscillator_source/formant_vocoder'
@@ -0,0 +1,36 @@
1
+ module Synthesizer
2
+ module OscillatorSource
3
+ class Base
4
+ def initialize
5
+ end
6
+
7
+ def next(context, delta, l_gain, r_gain)
8
+ channels = context.channels
9
+ window_size = context.window_size
10
+ pos = context.pos
11
+
12
+ dst = window_size.times.map {|i|
13
+ sample(context, pos.next(delta))
14
+ }
15
+ dst = Vdsp::DoubleArray.create(dst)
16
+
17
+ case channels
18
+ when 1
19
+ Buffer.new(dst * l_gain)
20
+ when 2
21
+ Buffer.new(dst * l_gain, dst * r_gain)
22
+ end
23
+ end
24
+
25
+ def sample(context, phase)
26
+ raise Error, "not implemented abstruct method: #{self.class.name}.sample(context, phase)"
27
+ end
28
+
29
+ def generate_context(soundinfo, note_perform, phase)
30
+ Context.new(soundinfo.window_size, soundinfo.channels, ShapePos.new(phase: phase))
31
+ end
32
+
33
+ Context = Struct.new("Context", :window_size, :channels, :pos)
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,13 @@
1
+ module Synthesizer
2
+ module OscillatorSource
3
+ Shape.constants.each {|a|
4
+ eval "class #{a} < Base
5
+ include Singleton
6
+
7
+ def sample(context, phase)
8
+ Shape::#{a}[phase]
9
+ end
10
+ end"
11
+ }
12
+ end
13
+ end
@@ -0,0 +1,107 @@
1
+ module Synthesizer
2
+ module OscillatorSource
3
+ class FormantVocoder
4
+ attr_reader :vowels
5
+ attr_reader :pronunciation
6
+
7
+ @@f = {
8
+ i: [110.0, 250.0, 2100.0, 2900.0, 3700.0],
9
+ e: [160.0, 450.0, 1900.0, 2650.0, 3800.0],
10
+ a: [110.0, 700.0, 1250.0, 2500.0, 3900.0],
11
+ o: [110.0, 500.0, 1050.0, 2700.0, 3700.0],
12
+ u: [110.0, 330.0, 1500.0, 2400.0, 3650.0],
13
+ x: [110.0, 335.0, 1550.0, 2450.0, 3800.0],
14
+ }
15
+ @@gain = [50.0, 70.0, 110.0, 200.0, 200.0].map {|x| Math::PI * x}
16
+
17
+ def initialize(vowels: [:i, :e, :a, :o, :u], pronunciation: 0)
18
+ self.vowels = vowels
19
+ self.pronunciation = pronunciation
20
+ @pulse = Pulse.instance
21
+ end
22
+
23
+ def vowels=(vowels)
24
+ vowels = vowels + [vowels[0]]
25
+ @vowels = vowels.map {|v| @@f[v]}
26
+ @vowels_len = @vowels.length
27
+ end
28
+
29
+ def pronunciation=(pronunciation)
30
+ @pronunciation = ModulationValue.create(pronunciation)
31
+ end
32
+
33
+ def next(context, delta, l_gain, r_gain)
34
+ channels = context.channels
35
+ window_size = context.window_size
36
+ samplerate = context.samplerate
37
+ tmpbufs = context.tmpbufs
38
+ pronunciation_mod = context.pronunciation_mod
39
+
40
+ @pulse_context ||= @pulse.generate_context(context.soundinfo, context.note_perform, context.phase)
41
+ pulse = @pulse.next(@pulse_context, delta, 0.5, 0.5).streams[0]
42
+
43
+ r_index = pronunciation_mod[]
44
+ index = r_index.to_i
45
+
46
+ dst = 5.times.map {|i|
47
+ #dst = (1...5).each.map {|i|
48
+ tmpbuf = tmpbufs[i]
49
+ freq = @vowels[index % @vowels_len][i]+(@vowels[(index+1) % @vowels_len][i]-@vowels[index % @vowels_len][i])*(r_index-index)
50
+ w = Math::PI * 2 * freq
51
+ resfil(pulse, tmpbufs[i], @@gain[i], w, 1.0/samplerate, window_size)
52
+ }.inject(:+)
53
+
54
+ case channels
55
+ when 1
56
+ Buffer.new(dst * l_gain)
57
+ when 2
58
+ Buffer.new(dst * l_gain, dst * r_gain)
59
+ end
60
+ end
61
+
62
+ def resfil(x, v, a, w, dt, len)
63
+ b = 2.0 * (Math::E ** (-a*dt)) * Math.cos(w*dt)
64
+ c = Math::E ** (-2.0 * a * dt)
65
+ d = ((a*a+w*w)/w) * (Math::E ** (-a*dt)) * Math.sin(w*dt)
66
+
67
+ #v[0] = v[len-2]
68
+ #v[1] = v[len-1]
69
+ #v[0] += 1.0
70
+
71
+ #Vdsp::UnsafeDouble.vsmsma(v, 1, 1, b, v, 0, 1, -c, v, 2, 1, len)
72
+ #v * (d / 25000.to_f)
73
+
74
+ v[0] = v[len-2]
75
+ v[1] = v[len-1]
76
+
77
+ y = len.times.map {|i|
78
+ v[i+2] = b * v[i+1] - c * v[i] + x[i]
79
+ v[i+1] * (d / 25000.to_f)
80
+ }
81
+
82
+ Vdsp::DoubleArray.create(y)
83
+ end
84
+
85
+ def generate_context(soundinfo, note_perform, phase)
86
+ pronunciation_mod = ModulationValue.balance_generator(note_perform, soundinfo.framerate, @pronunciation)
87
+ tmpbufs = Array.new(5) {|i| Vdsp::DoubleArray.new(soundinfo.window_size+2)}
88
+
89
+ FvContext.new(soundinfo, note_perform, phase, tmpbufs, pronunciation_mod)
90
+ end
91
+
92
+ FvContext = Struct.new("FvContext", :soundinfo, :note_perform, :phase, :tmpbufs, :pronunciation_mod) do
93
+ def window_size
94
+ soundinfo.window_size
95
+ end
96
+
97
+ def channels
98
+ soundinfo.channels
99
+ end
100
+
101
+ def samplerate
102
+ soundinfo.samplerate
103
+ end
104
+ end
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,23 @@
1
+ module Synthesizer
2
+ module OscillatorSource
3
+ class Pulse < Square
4
+ include Singleton
5
+
6
+ def initialize
7
+ end
8
+
9
+ def sample(context, phase)
10
+ val = super(context, phase)
11
+ result = context.prev<0.0 && 0.0<val ? 1.0 : 0.0
12
+ context.prev = val
13
+ result
14
+ end
15
+
16
+ def generate_context(soundinfo, note_perform, phase)
17
+ PulseContext.new(soundinfo.window_size, soundinfo.channels, phase, ShapePos.new(phase: phase), -1.0)
18
+ end
19
+
20
+ PulseContext = Struct.new("PulseContext", :window_size, :channels, :phase, :pos, :prev)
21
+ end
22
+ end
23
+ end
@@ -6,7 +6,6 @@ module Synthesizer
6
6
  attr_reader :amplifier
7
7
  attr_reader :processor
8
8
 
9
- attr_reader :quality
10
9
  attr_reader :soundinfo
11
10
 
12
11
  attr_reader :glide
@@ -16,15 +15,14 @@ module Synthesizer
16
15
  # @param filter [Synthesizer::Filter] filter
17
16
  # @param amplifier [Synthesizer::Amplifier] amplifier
18
17
  # @param soundinfo [AudioStream::SoundInfo]
19
- def initialize(oscillators:, filter: nil, amplifier:, quality: Quality::LOW, soundinfo:)
18
+ def initialize(oscillators:, filter: nil, amplifier:, soundinfo:)
20
19
  @oscillators = [oscillators].flatten.compact
21
20
  @filter = filter
22
21
  @amplifier = amplifier
23
22
 
24
- @quality = quality
25
23
  @soundinfo = soundinfo
26
24
 
27
- @processor = Processor.create(quality)
25
+ @processor = Processor.new
28
26
  @performs = {}
29
27
  @pitch_bend = 0.0
30
28
  end
@@ -1,10 +1,48 @@
1
- require 'synthesizer/processor/low'
2
- require 'synthesizer/processor/high'
3
-
4
1
  module Synthesizer
5
- module Processor
6
- def self.create(quality)
7
- const_get(quality, false).new
2
+ class Processor
3
+ def generator(osc, note_perform)
4
+ synth = note_perform.synth
5
+ filter = synth.filter
6
+ amp = synth.amplifier
7
+ window_size = synth.soundinfo.window_size
8
+ framerate = synth.soundinfo.samplerate.to_f / window_size
9
+
10
+ # Oscillator, Amplifier
11
+ volume_mod = ModulationValue.amp_generator(note_perform, framerate, osc.volume, amp.volume)
12
+ pan_mod = ModulationValue.balance_generator(note_perform, framerate, osc.pan, amp.pan)
13
+ tune_semis_mod = ModulationValue.balance_generator(note_perform, framerate, osc.tune_semis, amp.tune_semis, synth.glide&.to_modval)
14
+ tune_cents_mod = ModulationValue.balance_generator(note_perform, framerate, osc.tune_cents, amp.tune_cents)
15
+
16
+ uni_num_mod = ModulationValue.balance_generator(note_perform, framerate, osc.uni_num, amp.uni_num, center: 1.0)
17
+ uni_detune_mod = ModulationValue.balance_generator(note_perform, framerate, osc.uni_detune, amp.uni_detune)
18
+ unison = Unison.new(note_perform, osc.source, osc.phase)
19
+
20
+ # Filter
21
+ filter_mod = nil
22
+ if filter
23
+ filter_mod = filter.generator(note_perform, framerate)
24
+ end
25
+
26
+ -> {
27
+ # Oscillator, Amplifier
28
+ volume = volume_mod[] * note_perform.velocity
29
+ pan = pan_mod[]
30
+ tune_semis = tune_semis_mod[] + synth.pitch_bend
31
+ tune_cents = tune_cents_mod[]
32
+
33
+ uni_num = uni_num_mod[]
34
+ uni_detune = uni_detune_mod[]
35
+
36
+ buf = unison.next(uni_num, uni_detune, volume, pan, tune_semis, tune_cents)
37
+
38
+ # Filter
39
+ if filter_mod
40
+ filter_fx = filter_mod[]
41
+ buf = filter_fx.process(buf)
42
+ end
43
+
44
+ buf
45
+ }
8
46
  end
9
47
  end
10
48
  end
@@ -15,8 +15,14 @@ module Synthesizer
15
15
  WhiteNoise = ->(phase) { Random.rand(-1.0...1.0) }
16
16
 
17
17
  # LFO
18
- RampUp = ->(phase) { (phase % 1) * 2 - 1 }
19
- RampDown = ->(phase) { (phase % 1) * -2 + 1 }
18
+ RampUp = ->(phase) { (phase % 1.0) * 2 - 1 }
19
+ RampDown = ->(phase) { (phase % 1.0) * -2 + 1 }
20
+
21
+ PositiveRampUp = ->(phase) { phase % 1.0}
22
+ PositiveRampDown = ->(phase) { (phase % 1.0) * -1 + 1}
23
+
24
+ ForeverRampUp = ->(phase) { phase}
25
+ ForeverRampDown = ->(phase) { -phase}
20
26
 
21
27
  # Complex
22
28
  self.constants.tap {|consts|
@@ -30,6 +36,5 @@ module Synthesizer
30
36
  }
31
37
  }
32
38
  }
33
-
34
39
  end
35
40
  end
@@ -2,15 +2,15 @@ module Synthesizer
2
2
  class Unison
3
3
  UNI_NUM_MAX = 16
4
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
-
5
+ def initialize(note_perform, source, phase)
12
6
  synth = note_perform.synth
13
7
  @samplerate = synth.soundinfo.samplerate
8
+
9
+ @note_perform = note_perform
10
+ @source = source
11
+ @source_contexts = UNI_NUM_MAX.times.map {|i|
12
+ source.generate_context(synth.soundinfo, note_perform, phase.value)
13
+ }
14
14
  end
15
15
 
16
16
  def next(uni_num, uni_detune, volume, pan, tune_semis, tune_cents)
@@ -20,11 +20,8 @@ module Synthesizer
20
20
  uni_num = UNI_NUM_MAX
21
21
  end
22
22
 
23
- val_l = 0.0
24
- val_r = 0.0
25
-
26
- uni_num.ceil.times {|i|
27
- pos = @poss[i]
23
+ uni_num.ceil.times.map {|i|
24
+ context = @source_contexts[i]
28
25
 
29
26
  uni_volume = 1.0
30
27
  if uni_num<i
@@ -40,12 +37,8 @@ module Synthesizer
40
37
  hz = @note_perform.note.hz(semis: tune_semis, cents: tune_cents + detune_cents)
41
38
  delta = hz / @samplerate
42
39
 
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]
40
+ @source.next(context, delta, l_gain * volume * uni_volume / uni_num, r_gain * volume * uni_volume / uni_num)
41
+ }.inject(:+)
49
42
  end
50
43
  end
51
44
  end
@@ -1,3 +1,3 @@
1
1
  module Synthesizer
2
- VERSION = "3.0.0"
2
+ VERSION = "3.1.0"
3
3
  end
@@ -30,5 +30,5 @@ Gem::Specification.new do |spec|
30
30
  spec.add_development_dependency "rake", "~> 12.0"
31
31
  spec.add_development_dependency "minitest", "~> 5.0"
32
32
 
33
- spec.add_dependency "audio_stream", ">= 3.0.0"
33
+ spec.add_dependency "audio_stream", ">= 3.2.0"
34
34
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: synthesizer
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.0
4
+ version: 3.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yoshida Tetsuya
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-10-02 00:00:00.000000000 Z
11
+ date: 2019-11-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -58,14 +58,14 @@ dependencies:
58
58
  requirements:
59
59
  - - ">="
60
60
  - !ruby/object:Gem::Version
61
- version: 3.0.0
61
+ version: 3.2.0
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - ">="
67
67
  - !ruby/object:Gem::Version
68
- version: 3.0.0
68
+ version: 3.2.0
69
69
  description: Synthesizer implemented in Ruby.
70
70
  email:
71
71
  - yoshida.eth0@gmail.com
@@ -83,6 +83,8 @@ files:
83
83
  - bin/setup
84
84
  - examples/adsr.ipynb
85
85
  - examples/curves.ipynb
86
+ - examples/formant_vocoder.rb
87
+ - examples/formant_vocoder_sweep.rb
86
88
  - examples/lpf.rb
87
89
  - examples/metronome.rb
88
90
  - examples/mono.rb
@@ -113,11 +115,13 @@ files:
113
115
  - lib/synthesizer/note.rb
114
116
  - lib/synthesizer/note_perform.rb
115
117
  - lib/synthesizer/oscillator.rb
118
+ - lib/synthesizer/oscillator_source.rb
119
+ - lib/synthesizer/oscillator_source/base.rb
120
+ - lib/synthesizer/oscillator_source/basic.rb
121
+ - lib/synthesizer/oscillator_source/formant_vocoder.rb
122
+ - lib/synthesizer/oscillator_source/pulse.rb
116
123
  - lib/synthesizer/poly_synth.rb
117
124
  - lib/synthesizer/processor.rb
118
- - lib/synthesizer/processor/high.rb
119
- - lib/synthesizer/processor/low.rb
120
- - lib/synthesizer/quality.rb
121
125
  - lib/synthesizer/shape.rb
122
126
  - lib/synthesizer/shape_pos.rb
123
127
  - lib/synthesizer/step_editor.rb
@@ -148,7 +152,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
148
152
  - !ruby/object:Gem::Version
149
153
  version: '0'
150
154
  requirements: []
151
- rubygems_version: 3.0.4
155
+ rubygems_version: 3.0.3
152
156
  signing_key:
153
157
  specification_version: 4
154
158
  summary: Synthesizer implemented in Ruby.
@@ -1,91 +0,0 @@
1
- module Synthesizer
2
- module Processor
3
- class High
4
- def generator(osc, note_perform)
5
- synth = note_perform.synth
6
- filter = synth.filter
7
- amp = synth.amplifier
8
- channels = synth.soundinfo.channels
9
- window_size = synth.soundinfo.window_size
10
- framerate = synth.soundinfo.samplerate.to_f
11
-
12
- # Oscillator, Amplifier
13
- volume_mod = ModulationValue.amp_generator(note_perform, framerate, osc.volume, amp.volume)
14
- pan_mod = ModulationValue.balance_generator(note_perform, framerate, osc.pan, amp.pan)
15
- tune_semis_mod = ModulationValue.balance_generator(note_perform, framerate, osc.tune_semis, amp.tune_semis, synth.glide&.to_modval)
16
- tune_cents_mod = ModulationValue.balance_generator(note_perform, framerate, osc.tune_cents, amp.tune_cents)
17
-
18
- uni_num_mod = ModulationValue.balance_generator(note_perform, framerate, osc.uni_num, amp.uni_num, center: 1.0)
19
- uni_detune_mod = ModulationValue.balance_generator(note_perform, framerate, osc.uni_detune, amp.uni_detune)
20
- unison = Unison.new(note_perform, osc.shape, osc.phase)
21
-
22
- # Filter
23
- filter_mod = nil
24
- if filter
25
- filter_mod = filter.generator(note_perform, framerate / window_size)
26
- end
27
-
28
- case channels
29
- when 1
30
- -> {
31
- buf = AudioStream::Buffer.create_mono(window_size)
32
- dst0 = buf.streams[0]
33
-
34
- window_size.times.each {|i|
35
- # Oscillator, Amplifier
36
- volume = volume_mod[] * note_perform.velocity
37
- tune_semis = tune_semis_mod[] + synth.pitch_bend
38
- tune_cents = tune_cents_mod[]
39
-
40
- uni_num = uni_num_mod[]
41
- uni_detune = uni_detune_mod[]
42
-
43
- sval = unison.next(uni_num, uni_detune, volume, 0.0, tune_semis, tune_cents)
44
- mval = (sval[0] + sval[1]) / 2.0
45
-
46
- dst0[i] = mval
47
- }
48
-
49
- # Filter
50
- if filter_mod
51
- filter_fx = filter_mod[]
52
- buf = filter_fx.process(buf)
53
- end
54
-
55
- buf
56
- }
57
- when 2
58
- -> {
59
- buf = AudioStream::Buffer.create_stereo(window_size)
60
- dst0 = buf.streams[0]
61
- dst1 = buf.streams[1]
62
-
63
- window_size.times.each {|i|
64
- # Oscillator, Amplifier
65
- volume = volume_mod[] * note_perform.velocity
66
- pan = pan_mod[]
67
- tune_semis = tune_semis_mod[] + synth.pitch_bend
68
- tune_cents = tune_cents_mod[]
69
-
70
- uni_num = uni_num_mod[]
71
- uni_detune = uni_detune_mod[]
72
-
73
- sval = unison.next(uni_num, uni_detune, volume, pan, tune_semis, tune_cents)
74
-
75
- dst0[i] = sval[0]
76
- dst1[i] = sval[1]
77
- }
78
-
79
- # Filter
80
- if filter_mod
81
- filter_fx = filter_mod[]
82
- buf = filter_fx.process(buf)
83
- end
84
-
85
- buf
86
- }
87
- end
88
- end
89
- end
90
- end
91
- end
@@ -1,88 +0,0 @@
1
- module Synthesizer
2
- module Processor
3
- class Low
4
- def generator(osc, note_perform)
5
- synth = note_perform.synth
6
- filter = synth.filter
7
- amp = synth.amplifier
8
- channels = synth.soundinfo.channels
9
- window_size = synth.soundinfo.window_size
10
- framerate = synth.soundinfo.samplerate.to_f / window_size
11
-
12
- # Oscillator, Amplifier
13
- volume_mod = ModulationValue.amp_generator(note_perform, framerate, osc.volume, amp.volume)
14
- pan_mod = ModulationValue.balance_generator(note_perform, framerate, osc.pan, amp.pan)
15
- tune_semis_mod = ModulationValue.balance_generator(note_perform, framerate, osc.tune_semis, amp.tune_semis, synth.glide&.to_modval)
16
- tune_cents_mod = ModulationValue.balance_generator(note_perform, framerate, osc.tune_cents, amp.tune_cents)
17
-
18
- uni_num_mod = ModulationValue.balance_generator(note_perform, framerate, osc.uni_num, amp.uni_num, center: 1.0)
19
- uni_detune_mod = ModulationValue.balance_generator(note_perform, framerate, osc.uni_detune, amp.uni_detune)
20
- unison = Unison.new(note_perform, osc.shape, osc.phase)
21
-
22
- # Filter
23
- filter_mod = nil
24
- if filter
25
- filter_mod = filter.generator(note_perform, framerate)
26
- end
27
-
28
- case channels
29
- when 1
30
- -> {
31
- buf = AudioStream::Buffer.create_mono(window_size)
32
- dst0 = buf.streams[0]
33
-
34
- # Oscillator, Amplifier
35
- volume = volume_mod[] * note_perform.velocity
36
- tune_semis = tune_semis_mod[] + synth.pitch_bend
37
- tune_cents = tune_cents_mod[]
38
-
39
- uni_num = uni_num_mod[]
40
- uni_detune = uni_detune_mod[]
41
-
42
- window_size.times.each {|i|
43
- val = unison.next(uni_num, uni_detune, volume, 0.0, tune_semis, tune_cents)
44
- dst0[i] = (val[0] + val[1]) / 2.0
45
- }
46
-
47
- # Filter
48
- if filter_mod
49
- filter_fx = filter_mod[]
50
- buf = filter_fx.process(buf)
51
- end
52
-
53
- buf
54
- }
55
- when 2
56
- -> {
57
- buf = AudioStream::Buffer.create_stereo(window_size)
58
- dst0 = buf.streams[0]
59
- dst1 = buf.streams[1]
60
-
61
- # Oscillator, Amplifier
62
- volume = volume_mod[] * note_perform.velocity
63
- pan = pan_mod[]
64
- tune_semis = tune_semis_mod[] + synth.pitch_bend
65
- tune_cents = tune_cents_mod[]
66
-
67
- uni_num = uni_num_mod[]
68
- uni_detune = uni_detune_mod[]
69
-
70
- window_size.times.each {|i|
71
- val = unison.next(uni_num, uni_detune, volume, pan, tune_semis, tune_cents)
72
- dst0[i] = val[0]
73
- dst1[i] = val[1]
74
- }
75
-
76
- # Filter
77
- if filter_mod
78
- filter_fx = filter_mod[]
79
- buf = filter_fx.process(buf)
80
- end
81
-
82
- buf
83
- }
84
- end
85
- end
86
- end
87
- end
88
- end
@@ -1,6 +0,0 @@
1
- module Synthesizer
2
- module Quality
3
- HIGH = :High
4
- LOW = :Low
5
- end
6
- end