synthesizer 3.0.0 → 3.1.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: 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