synthesizer 3.1.0 → 3.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +4 -0
- data/examples/{metronome.rb → audio_input_metronome.rb} +8 -2
- data/examples/{step_editor.rb → audio_input_step_editor.rb} +10 -2
- data/examples/filter_band_pass.rb +73 -0
- data/examples/{lpf.rb → filter_serial.rb} +9 -2
- data/examples/oscillator_pan.rb +70 -0
- data/examples/{formant_vocoder.rb → oscillator_source_formant_vocoder.rb} +10 -3
- data/examples/{formant_vocoder_sweep.rb → oscillator_source_formant_vocoder_sweep.rb} +13 -6
- data/examples/oscillator_sync.rb +71 -0
- data/examples/oscillator_unison.rb +64 -0
- data/examples/oscillator_volume.rb +70 -0
- data/examples/{mono.rb → synth_mono.rb} +10 -2
- data/examples/{poly.rb → synth_poly.rb} +10 -2
- data/{examples → jupyter}/adsr.ipynb +20 -17
- data/jupyter/curves.ipynb +103 -0
- data/jupyter/shapes.ipynb +111 -0
- data/lib/audio_stream/audio_input_metronome.rb +1 -1
- data/lib/synthesizer/amplifier.rb +4 -1
- data/lib/synthesizer/filter/band_pass_filter.rb +3 -3
- data/lib/synthesizer/filter/high_pass_filter.rb +3 -3
- data/lib/synthesizer/filter/high_shelf_filter.rb +4 -4
- data/lib/synthesizer/filter/low_pass_filter.rb +3 -3
- data/lib/synthesizer/filter/low_shelf_filter.rb +4 -4
- data/lib/synthesizer/filter/parallel.rb +2 -2
- data/lib/synthesizer/filter/peaking_filter.rb +5 -5
- data/lib/synthesizer/filter/serial.rb +2 -2
- data/lib/synthesizer/modulation/adsr.rb +37 -35
- data/lib/synthesizer/modulation/curve.rb +3 -0
- data/lib/synthesizer/modulation/glide.rb +9 -8
- data/lib/synthesizer/modulation/lfo.rb +23 -23
- data/lib/synthesizer/modulation_value.rb +5 -5
- data/lib/synthesizer/mono_synth.rb +7 -2
- data/lib/synthesizer/oscillator.rb +11 -9
- data/lib/synthesizer/oscillator_source/base.rb +35 -5
- data/lib/synthesizer/oscillator_source/formant_vocoder.rb +27 -19
- data/lib/synthesizer/oscillator_source/pulse.rb +11 -3
- data/lib/synthesizer/poly_synth.rb +5 -2
- data/lib/synthesizer/processor/high.rb +63 -0
- data/lib/synthesizer/processor/low.rb +59 -0
- data/lib/synthesizer/processor.rb +6 -44
- data/lib/synthesizer/quality.rb +6 -0
- data/lib/synthesizer/shape.rb +4 -4
- data/lib/synthesizer/shape_pos.rb +22 -19
- data/lib/synthesizer/unison.rb +28 -16
- data/lib/synthesizer/version.rb +1 -1
- data/lib/synthesizer.rb +1 -0
- data/samples/cinema.rb +730 -0
- data/samples/cinema_drum.wav +0 -0
- data/samples/daijoubu.rb +811 -0
- data/samples/daijoubu_drum.wav +0 -0
- data/samples/kira_power.rb +987 -0
- data/samples/kira_power_drum.wav +0 -0
- data/synthesizer.gemspec +1 -1
- metadata +32 -18
- data/examples/curves.ipynb +0 -105
- data/examples/shapes.ipynb +0 -116
@@ -5,9 +5,9 @@ module Synthesizer
|
|
5
5
|
@filters = filters
|
6
6
|
end
|
7
7
|
|
8
|
-
def generator(note_perform,
|
8
|
+
def generator(note_perform, samplecount)
|
9
9
|
filter_mods = @filters.map {|filter|
|
10
|
-
filter.generator(note_perform,
|
10
|
+
filter.generator(note_perform, samplecount)
|
11
11
|
}
|
12
12
|
|
13
13
|
-> {
|
@@ -7,13 +7,13 @@ module Synthesizer
|
|
7
7
|
@gain = ModulationValue.create(gain)
|
8
8
|
end
|
9
9
|
|
10
|
-
def generator(note_perform,
|
10
|
+
def generator(note_perform, samplecount)
|
11
11
|
soundinfo = note_perform.synth.soundinfo
|
12
|
-
filter = AudioStream::Fx::
|
12
|
+
filter = AudioStream::Fx::PeakingFilter.new(soundinfo)
|
13
13
|
|
14
|
-
freq_mod = ModulationValue.balance_generator(note_perform,
|
15
|
-
bandwidth_mod = ModulationValue.balance_generator(note_perform,
|
16
|
-
gain_mod = ModulationValue.balance_generator(note_perform,
|
14
|
+
freq_mod = ModulationValue.balance_generator(note_perform, samplecount, @freq)
|
15
|
+
bandwidth_mod = ModulationValue.balance_generator(note_perform, samplecount, @bandwidth)
|
16
|
+
gain_mod = ModulationValue.balance_generator(note_perform, samplecount, @gain)
|
17
17
|
|
18
18
|
-> {
|
19
19
|
filter.update_coef(freq: freq_mod[], bandwidth: bandwidth_mod[], gain: gain_mod[])
|
@@ -5,9 +5,9 @@ module Synthesizer
|
|
5
5
|
@filters = filters
|
6
6
|
end
|
7
7
|
|
8
|
-
def generator(note_perform,
|
8
|
+
def generator(note_perform, samplecount)
|
9
9
|
filter_mods = @filters.map {|filter|
|
10
|
-
filter.generator(note_perform,
|
10
|
+
filter.generator(note_perform, samplecount)
|
11
11
|
}
|
12
12
|
|
13
13
|
-> {
|
@@ -2,46 +2,45 @@ module Synthesizer
|
|
2
2
|
module Modulation
|
3
3
|
class Adsr
|
4
4
|
|
5
|
-
# @param attack [Float] attack sec (0.0~)
|
5
|
+
# @param attack [AudioStream::Rate | Float] attack sec (0.0~)
|
6
6
|
# @param attack_curve [Synthesizer::Curve]
|
7
|
-
# @param hold [Float] hold sec (0.0~)
|
8
|
-
# @param decay [Float] decay sec (0.0~)
|
7
|
+
# @param hold [AudioStream::Rate | Float] hold sec (0.0~)
|
8
|
+
# @param decay [AudioStream::Rate | Float] decay sec (0.0~)
|
9
9
|
# @param sustain_curve [Synthesizer::Curve]
|
10
|
-
# @param sustain [Float] sustain
|
11
|
-
# @param release [Float] release sec (0.0~)
|
10
|
+
# @param sustain [Float] sustain level (0.0~1.0)
|
11
|
+
# @param release [AudioStream::Rate | Float] release sec (0.0~)
|
12
12
|
# @param release_curve [Synthesizer::Curve]
|
13
13
|
def initialize(attack:, attack_curve: Curve::EaseOut, hold: 0.0, decay:, sustain_curve: Curve::EaseOut, sustain:, release:, release_curve: Curve::EaseOut)
|
14
|
-
@attack = attack
|
14
|
+
@attack = AudioStream::Rate.sec(attack)
|
15
15
|
@attack_curve = attack_curve
|
16
|
-
@hold = hold
|
17
|
-
@decay = decay
|
16
|
+
@hold = AudioStream::Rate.sec(hold)
|
17
|
+
@decay = AudioStream::Rate.sec(decay)
|
18
18
|
@sustain_curve = sustain_curve
|
19
19
|
@sustain = sustain
|
20
|
-
@release = release
|
20
|
+
@release = AudioStream::Rate.sec(release)
|
21
21
|
@release_curve = release_curve
|
22
22
|
end
|
23
23
|
|
24
|
-
def note_on_envelope(
|
24
|
+
def note_on_envelope(soundinfo, samplecount, sustain: false, &block)
|
25
25
|
Enumerator.new do |yld|
|
26
26
|
# attack
|
27
|
-
|
28
|
-
|
29
|
-
x = i.to_f /
|
27
|
+
attack_len = (@attack.sample(soundinfo) / samplecount).to_i
|
28
|
+
attack_len.times {|i|
|
29
|
+
x = i.to_f / attack_len
|
30
30
|
y = @attack_curve[x]
|
31
31
|
yld << y
|
32
32
|
}
|
33
33
|
|
34
34
|
# hold
|
35
|
-
|
36
|
-
rate.to_i.times {|i|
|
35
|
+
(@hold.sample(soundinfo) / samplecount).to_i.times {|i|
|
37
36
|
yld << 1.0
|
38
37
|
}
|
39
38
|
|
40
39
|
# decay
|
41
|
-
|
42
|
-
|
43
|
-
x = i.to_f /
|
44
|
-
y = 1.0 - @sustain_curve[x]
|
40
|
+
decay_len = (@decay.sample(soundinfo) / samplecount).to_i
|
41
|
+
decay_len.times {|i|
|
42
|
+
x = i.to_f / decay_len
|
43
|
+
y = 1.0 - @sustain_curve[x] * (1.0 - @sustain)
|
45
44
|
yld << y
|
46
45
|
}
|
47
46
|
|
@@ -54,12 +53,12 @@ module Synthesizer
|
|
54
53
|
end.each(&block)
|
55
54
|
end
|
56
55
|
|
57
|
-
def note_off_envelope(
|
56
|
+
def note_off_envelope(soundinfo, samplecount, sustain: false, &block)
|
58
57
|
Enumerator.new do |yld|
|
59
58
|
# release
|
60
|
-
|
61
|
-
|
62
|
-
x = i.to_f /
|
59
|
+
release_len = (@release.sample(soundinfo) / samplecount).to_i
|
60
|
+
release_len.times {|i|
|
61
|
+
x = i.to_f / release_len
|
63
62
|
y = 1.0 - @release_curve[x]
|
64
63
|
yld << y
|
65
64
|
}
|
@@ -73,9 +72,11 @@ module Synthesizer
|
|
73
72
|
end.each(&block)
|
74
73
|
end
|
75
74
|
|
76
|
-
def generator(note_perform,
|
77
|
-
|
78
|
-
|
75
|
+
def generator(note_perform, samplecount, release_sustain:)
|
76
|
+
soundinfo = note_perform.synth.soundinfo
|
77
|
+
|
78
|
+
note_on = note_on_envelope(soundinfo, samplecount, sustain: true)
|
79
|
+
note_off = note_off_envelope(soundinfo, samplecount, sustain: release_sustain)
|
79
80
|
last = 0.0
|
80
81
|
|
81
82
|
-> {
|
@@ -88,26 +89,27 @@ module Synthesizer
|
|
88
89
|
end
|
89
90
|
|
90
91
|
|
91
|
-
def amp_generator(note_perform,
|
92
|
+
def amp_generator(note_perform, samplecount, depth, &block)
|
92
93
|
bottom = 1.0 - depth
|
93
|
-
gen = generator(note_perform,
|
94
|
+
gen = generator(note_perform, samplecount, release_sustain: 0.0<bottom)
|
94
95
|
|
95
96
|
-> {
|
96
97
|
gen[] * depth + bottom
|
97
98
|
}
|
98
99
|
end
|
99
100
|
|
100
|
-
def balance_generator(note_perform,
|
101
|
-
gen = generator(note_perform,
|
101
|
+
def balance_generator(note_perform, samplecount, depth, &block)
|
102
|
+
gen = generator(note_perform, samplecount, release_sustain: true)
|
102
103
|
|
103
104
|
-> {
|
104
105
|
gen[] * depth
|
105
106
|
}
|
106
107
|
end
|
107
108
|
|
108
|
-
def plot_data(
|
109
|
-
|
110
|
-
|
109
|
+
def plot_data(soundinfo)
|
110
|
+
samplecount = soundinfo.window_size.to_f
|
111
|
+
note_on = note_on_envelope(soundinfo, samplecount, sustain: false)
|
112
|
+
note_off = note_off_envelope(soundinfo, samplecount, sustain: false)
|
111
113
|
last = 0.0
|
112
114
|
|
113
115
|
xs = []
|
@@ -127,8 +129,8 @@ module Synthesizer
|
|
127
129
|
{x: xs, y: ys}
|
128
130
|
end
|
129
131
|
|
130
|
-
def plot(
|
131
|
-
data = plot_data(
|
132
|
+
def plot(soundinfo)
|
133
|
+
data = plot_data(soundinfo)
|
132
134
|
Plotly::Plot.new(data: [data])
|
133
135
|
end
|
134
136
|
end
|
@@ -2,9 +2,9 @@ module Synthesizer
|
|
2
2
|
module Modulation
|
3
3
|
class Glide
|
4
4
|
|
5
|
-
# @param time [Float] glide time sec (0.0~)
|
5
|
+
# @param time [AudioStream::Rate | Float] glide time sec (0.0~)
|
6
6
|
def initialize(time:)
|
7
|
-
@time = time
|
7
|
+
@time = AudioStream::Rate.sec(time)
|
8
8
|
|
9
9
|
@base = 0.0
|
10
10
|
@current = 0.0
|
@@ -26,15 +26,16 @@ module Synthesizer
|
|
26
26
|
@diff = target - @current
|
27
27
|
end
|
28
28
|
|
29
|
-
def generator(note_perform,
|
30
|
-
|
29
|
+
def generator(note_perform, samplecount)
|
30
|
+
soundinfo = note_perform.synth.soundinfo
|
31
|
+
rate = @time.sample(soundinfo) / samplecount
|
31
32
|
|
32
33
|
-> {
|
33
34
|
ret = nil
|
34
35
|
|
35
|
-
if note_perform.
|
36
|
+
if !note_perform.released?
|
36
37
|
# Note On
|
37
|
-
if 0
|
38
|
+
if 0<rate && @target!=@current
|
38
39
|
# Gliding
|
39
40
|
x = @diff / rate
|
40
41
|
if x.abs<(@target-@current).abs
|
@@ -60,8 +61,8 @@ module Synthesizer
|
|
60
61
|
}
|
61
62
|
end
|
62
63
|
|
63
|
-
def balance_generator(note_perform,
|
64
|
-
gen = generator(note_perform,
|
64
|
+
def balance_generator(note_perform, samplecount, depth)
|
65
|
+
gen = generator(note_perform, samplecount)
|
65
66
|
|
66
67
|
-> {
|
67
68
|
gen[] * depth
|
@@ -3,51 +3,51 @@ module Synthesizer
|
|
3
3
|
class Lfo
|
4
4
|
|
5
5
|
# @param shape [Synthesizer::Shape]
|
6
|
-
# @param delay [Float] delay sec (0.0~)
|
7
|
-
# @param attack [Float] attack sec (0.0~)
|
6
|
+
# @param delay [AudioStream::Rate | Float] delay sec (0.0~)
|
7
|
+
# @param attack [AudioStream::Rate | Float] attack sec (0.0~)
|
8
8
|
# @param attack_curve [Synthesizer::Curve]
|
9
9
|
# @param phase [Float] phase percent (0.0~1.0)
|
10
|
-
# @param rate [Float] wave freq (0.0~)
|
11
|
-
def initialize(shape: Shape::Sine, delay: 0.0, attack: 0.0, attack_curve: Curve::Straight, phase: 0.0, rate: 3
|
10
|
+
# @param rate [AudioStream::Rate | Float] wave freq (0.0~)
|
11
|
+
def initialize(shape: Shape::Sine, delay: 0.0, attack: 0.0, attack_curve: Curve::Straight, phase: 0.0, rate: 0.3)
|
12
12
|
@shape = shape
|
13
|
-
@delay = delay
|
14
|
-
@attack = attack
|
13
|
+
@delay = AudioStream::Rate.sec(delay)
|
14
|
+
@attack = AudioStream::Rate.sec(attack)
|
15
15
|
@attack_curve = attack_curve
|
16
|
-
@phase = phase
|
17
|
-
@rate = rate
|
16
|
+
@phase = phase.to_f
|
17
|
+
@rate = AudioStream::Rate.sec(rate)
|
18
18
|
end
|
19
19
|
|
20
|
-
def generator(note_perform,
|
21
|
-
|
22
|
-
|
20
|
+
def generator(note_perform, samplecount, &block)
|
21
|
+
soundinfo = note_perform.synth.soundinfo
|
22
|
+
hz = @rate.freq(soundinfo)
|
23
23
|
|
24
|
-
|
24
|
+
Enumerator.new do |yld|
|
25
|
+
pos = ShapePos.new(soundinfo.samplerate / samplecount, @phase)
|
25
26
|
|
26
27
|
# delay
|
27
|
-
|
28
|
-
rate.to_i.times {|i|
|
28
|
+
(@delay.sample(soundinfo) / samplecount).to_i.times {|i|
|
29
29
|
yld << 0.0
|
30
30
|
}
|
31
31
|
|
32
32
|
# attack
|
33
|
-
|
34
|
-
|
35
|
-
x = i.to_f /
|
33
|
+
attack_len = (@attack.sample(soundinfo) / samplecount).to_i
|
34
|
+
attack_len.times {|i|
|
35
|
+
x = i.to_f / attack_len
|
36
36
|
y = @attack_curve[x]
|
37
|
-
yld << @shape[pos.next(
|
37
|
+
yld << @shape[pos.next(hz, 0.0, 0.0)] * y
|
38
38
|
}
|
39
39
|
|
40
40
|
# sustain
|
41
41
|
loop {
|
42
|
-
val = @shape[pos.next(
|
42
|
+
val = @shape[pos.next(hz, 0.0, 0.0)]
|
43
43
|
yld << val
|
44
44
|
}
|
45
45
|
end.each(&block)
|
46
46
|
end
|
47
47
|
|
48
|
-
def amp_generator(note_perform,
|
48
|
+
def amp_generator(note_perform, samplecount, depth, &block)
|
49
49
|
bottom = 1.0 - depth
|
50
|
-
gen = generator(note_perform,
|
50
|
+
gen = generator(note_perform, samplecount)
|
51
51
|
|
52
52
|
-> {
|
53
53
|
val = (gen.next + 1) / 2
|
@@ -55,8 +55,8 @@ module Synthesizer
|
|
55
55
|
}
|
56
56
|
end
|
57
57
|
|
58
|
-
def balance_generator(note_perform,
|
59
|
-
gen = generator(note_perform,
|
58
|
+
def balance_generator(note_perform, samplecount, depth, &block)
|
59
|
+
gen = generator(note_perform, samplecount)
|
60
60
|
|
61
61
|
-> {
|
62
62
|
gen.next * depth
|
@@ -9,7 +9,7 @@ module Synthesizer
|
|
9
9
|
@mods = []
|
10
10
|
|
11
11
|
mods.each {|mod, depth|
|
12
|
-
add(mod, depth: depth)
|
12
|
+
add(mod, depth: depth || 1.0)
|
13
13
|
}
|
14
14
|
end
|
15
15
|
|
@@ -35,7 +35,7 @@ module Synthesizer
|
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
38
|
-
def self.amp_generator(note_perform,
|
38
|
+
def self.amp_generator(note_perform, samplecount, *modvals)
|
39
39
|
modvals = modvals.flatten.compact
|
40
40
|
|
41
41
|
# value
|
@@ -45,7 +45,7 @@ module Synthesizer
|
|
45
45
|
mods = []
|
46
46
|
modvals.each {|modval|
|
47
47
|
modval.mods.each {|mod, depth|
|
48
|
-
mods << mod.amp_generator(note_perform,
|
48
|
+
mods << mod.amp_generator(note_perform, samplecount, depth)
|
49
49
|
}
|
50
50
|
}
|
51
51
|
|
@@ -55,7 +55,7 @@ module Synthesizer
|
|
55
55
|
}
|
56
56
|
end
|
57
57
|
|
58
|
-
def self.balance_generator(note_perform,
|
58
|
+
def self.balance_generator(note_perform, samplecount, *modvals, center: 0)
|
59
59
|
modvals = modvals.flatten.compact
|
60
60
|
|
61
61
|
# value
|
@@ -66,7 +66,7 @@ module Synthesizer
|
|
66
66
|
mods = []
|
67
67
|
modvals.each {|modval|
|
68
68
|
modval.mods.each {|mod, depth|
|
69
|
-
mods << mod.balance_generator(note_perform,
|
69
|
+
mods << mod.balance_generator(note_perform, samplecount, depth)
|
70
70
|
}
|
71
71
|
}
|
72
72
|
|
@@ -6,22 +6,27 @@ module Synthesizer
|
|
6
6
|
attr_reader :amplifier
|
7
7
|
attr_reader :processor
|
8
8
|
|
9
|
+
attr_reader :quality
|
9
10
|
attr_reader :soundinfo
|
10
11
|
|
11
12
|
attr_reader :glide
|
12
13
|
attr_accessor :pitch_bend
|
13
14
|
|
14
15
|
# @param oscillators [Synthesizer::Oscillator] oscillator
|
16
|
+
# @param filter [Synthesizer::Filter] filter
|
15
17
|
# @param amplifier [Synthesizer::Amplifier] amplifier
|
18
|
+
# @param glide [AudioStream::Rate] glide time sec (0.0~)
|
19
|
+
# @param quality [Synthesizer::Quality] processor quality
|
16
20
|
# @param soundinfo [AudioStream::SoundInfo]
|
17
|
-
def initialize(oscillators:, filter: nil, amplifier:, glide: 0.1, soundinfo:)
|
21
|
+
def initialize(oscillators:, filter: nil, amplifier:, glide: AudioStream::Rate.sec(0.1), quality: Quality::LOW, soundinfo:)
|
18
22
|
@oscillators = [oscillators].flatten.compact
|
19
23
|
@filter = filter
|
20
24
|
@amplifier = amplifier
|
21
25
|
|
26
|
+
@quality = quality
|
22
27
|
@soundinfo = soundinfo
|
23
28
|
|
24
|
-
@processor = Processor.
|
29
|
+
@processor = Processor.create(quality)
|
25
30
|
@note_nums = []
|
26
31
|
@perform = nil
|
27
32
|
@glide = Modulation::Glide.new(time: glide)
|
@@ -11,18 +11,20 @@ module Synthesizer
|
|
11
11
|
attr_reader :sync
|
12
12
|
attr_reader :uni_num
|
13
13
|
attr_reader :uni_detune
|
14
|
+
attr_reader :uni_stereo
|
14
15
|
|
15
16
|
# @param source [Synthesizer::OscillatorSource] oscillator waveform source
|
16
|
-
# @param volume [Float] oscillator volume. mute=0.0 max=1.0
|
17
|
-
# @param pan [Float] oscillator pan. left=-1.0 center=0.0 right=1.0 (-1.0~1.0)
|
18
|
-
# @param tune_semis [Integer] oscillator pitch semitone
|
19
|
-
# @param tune_cents [Integer] oscillator pitch cent
|
17
|
+
# @param volume [ModulationValue | Float] oscillator volume. mute=0.0 max=1.0
|
18
|
+
# @param pan [ModulationValue | Float] oscillator pan. left=-1.0 center=0.0 right=1.0 (-1.0~1.0)
|
19
|
+
# @param tune_semis [ModulationValue | Integer] oscillator pitch semitone
|
20
|
+
# @param tune_cents [ModulationValue | Integer] oscillator pitch cent
|
20
21
|
# @param sym [nil] TODO not implemented
|
21
|
-
# @param phase [Float] oscillator waveform shape start phase percent (0.0~1.0,nil) nil=random
|
22
|
-
# @param sync [Integer]
|
23
|
-
# @param uni_num [Float] oscillator voicing number (1.0~16.0)
|
24
|
-
# @param uni_detune [Float] oscillator voicing detune percent. 0.01=1cent 1.0=semitone (0.0~1.0)
|
25
|
-
|
22
|
+
# @param phase [ModulationValue | Float] oscillator waveform shape start phase percent (0.0~1.0,nil) nil=random
|
23
|
+
# @param sync [ModulationValue | Integer] oscillator sync pitch 1.0=semitone 12.0=octave (0.0~48.0)
|
24
|
+
# @param uni_num [ModulationValue | Float] oscillator voicing number (1.0~16.0)
|
25
|
+
# @param uni_detune [ModulationValue | Float] oscillator voicing detune percent. 0.01=1cent 1.0=semitone (0.0~1.0)
|
26
|
+
# @param uni_stereo [ModulationValue | Float] oscillator voicing spread pan. -1.0=full inv 0.0=mono 1.0=full (-1.0~1.0)
|
27
|
+
def initialize(source: OscillatorSource::Sine.instance, 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, uni_stereo: 0.0)
|
26
28
|
@source = source
|
27
29
|
|
28
30
|
@volume = ModulationValue.create(volume)
|
@@ -4,13 +4,15 @@ module Synthesizer
|
|
4
4
|
def initialize
|
5
5
|
end
|
6
6
|
|
7
|
-
def next(context,
|
7
|
+
def next(context, rate, sym, sync, l_gain, r_gain)
|
8
|
+
soundinfo = context.soundinfo
|
8
9
|
channels = context.channels
|
9
10
|
window_size = context.window_size
|
10
11
|
pos = context.pos
|
12
|
+
hz = rate.freq(soundinfo)
|
11
13
|
|
12
14
|
dst = window_size.times.map {|i|
|
13
|
-
sample(context, pos.next(
|
15
|
+
sample(context, pos.next(hz, sym, sync))
|
14
16
|
}
|
15
17
|
dst = Vdsp::DoubleArray.create(dst)
|
16
18
|
|
@@ -26,11 +28,39 @@ module Synthesizer
|
|
26
28
|
raise Error, "not implemented abstruct method: #{self.class.name}.sample(context, phase)"
|
27
29
|
end
|
28
30
|
|
29
|
-
def generate_context(soundinfo, note_perform,
|
30
|
-
Context.new(soundinfo
|
31
|
+
def generate_context(soundinfo, note_perform, init_phase)
|
32
|
+
Context.new(soundinfo, note_perform, init_phase)
|
31
33
|
end
|
32
34
|
|
33
|
-
|
35
|
+
class Context
|
36
|
+
attr_reader :soundinfo
|
37
|
+
attr_reader :note_perform
|
38
|
+
attr_reader :init_phase
|
39
|
+
attr_reader :pos
|
40
|
+
|
41
|
+
def initialize(soundinfo, note_perform, init_phase)
|
42
|
+
@soundinfo = soundinfo
|
43
|
+
@note_perform = note_perform
|
44
|
+
@init_phase = init_phase
|
45
|
+
@pos = ShapePos.new(@soundinfo.samplerate, init_phase)
|
46
|
+
end
|
47
|
+
|
48
|
+
def window_size
|
49
|
+
@window_size ||= soundinfo.window_size
|
50
|
+
end
|
51
|
+
|
52
|
+
def channels
|
53
|
+
@channels ||= soundinfo.channels
|
54
|
+
end
|
55
|
+
|
56
|
+
def samplerate
|
57
|
+
@samplerate ||= soundinfo.samplerate
|
58
|
+
end
|
59
|
+
|
60
|
+
def framerate
|
61
|
+
@framerate ||= soundinfo.framerate
|
62
|
+
end
|
63
|
+
end
|
34
64
|
end
|
35
65
|
end
|
36
66
|
end
|
@@ -21,7 +21,7 @@ module Synthesizer
|
|
21
21
|
end
|
22
22
|
|
23
23
|
def vowels=(vowels)
|
24
|
-
vowels = vowels + [vowels[0]]
|
24
|
+
#vowels = vowels + [vowels[0]]
|
25
25
|
@vowels = vowels.map {|v| @@f[v]}
|
26
26
|
@vowels_len = @vowels.length
|
27
27
|
end
|
@@ -30,15 +30,25 @@ module Synthesizer
|
|
30
30
|
@pronunciation = ModulationValue.create(pronunciation)
|
31
31
|
end
|
32
32
|
|
33
|
-
def next(context,
|
33
|
+
def next(context, rate, sym, sync, l_gain, r_gain)
|
34
|
+
soundinfo = context.soundinfo
|
34
35
|
channels = context.channels
|
35
36
|
window_size = context.window_size
|
36
37
|
samplerate = context.samplerate
|
37
38
|
tmpbufs = context.tmpbufs
|
38
39
|
pronunciation_mod = context.pronunciation_mod
|
40
|
+
pulse_context = context.pulse_context
|
39
41
|
|
40
|
-
|
41
|
-
|
42
|
+
pulse = Pulse.instance.next(pulse_context, rate, sym, sync, 0.5, 0.5).streams[0]
|
43
|
+
|
44
|
+
notediff = Math.log2(rate.freq(soundinfo) / 440.0) * 12 + 69 - 36
|
45
|
+
if notediff<0.0
|
46
|
+
notediff = 0.0
|
47
|
+
end
|
48
|
+
notediff = Math.sqrt(notediff)
|
49
|
+
vowels = @vowels.map {|vowel|
|
50
|
+
vowel.map{|f| f * (ShapePos::SEMITONE_RATIO ** notediff)}
|
51
|
+
}
|
42
52
|
|
43
53
|
r_index = pronunciation_mod[]
|
44
54
|
index = r_index.to_i
|
@@ -46,7 +56,7 @@ module Synthesizer
|
|
46
56
|
dst = 5.times.map {|i|
|
47
57
|
#dst = (1...5).each.map {|i|
|
48
58
|
tmpbuf = tmpbufs[i]
|
49
|
-
freq =
|
59
|
+
freq = vowels[index % @vowels_len][i]+(vowels[(index+1) % @vowels_len][i]-vowels[index % @vowels_len][i])*(r_index-index)
|
50
60
|
w = Math::PI * 2 * freq
|
51
61
|
resfil(pulse, tmpbufs[i], @@gain[i], w, 1.0/samplerate, window_size)
|
52
62
|
}.inject(:+)
|
@@ -82,24 +92,22 @@ module Synthesizer
|
|
82
92
|
Vdsp::DoubleArray.create(y)
|
83
93
|
end
|
84
94
|
|
85
|
-
def generate_context(soundinfo, note_perform,
|
86
|
-
|
87
|
-
tmpbufs = Array.new(5) {|i| Vdsp::DoubleArray.new(soundinfo.window_size+2)}
|
88
|
-
|
89
|
-
FvContext.new(soundinfo, note_perform, phase, tmpbufs, pronunciation_mod)
|
95
|
+
def generate_context(soundinfo, note_perform, init_phase)
|
96
|
+
Context.new(soundinfo, note_perform, init_phase, @pronunciation)
|
90
97
|
end
|
91
98
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
99
|
+
class Context < Base::Context
|
100
|
+
attr_reader :pronunciation_mod
|
101
|
+
attr_reader :tmpbufs
|
102
|
+
attr_reader :pulse_context
|
96
103
|
|
97
|
-
def
|
98
|
-
soundinfo
|
99
|
-
end
|
104
|
+
def initialize(soundinfo, note_perform, init_phase, pronunciation)
|
105
|
+
super(soundinfo, note_perform, init_phase)
|
100
106
|
|
101
|
-
|
102
|
-
soundinfo.
|
107
|
+
synth = note_perform.synth
|
108
|
+
@pronunciation_mod = ModulationValue.balance_generator(note_perform, synth.soundinfo.window_size.to_f, pronunciation)
|
109
|
+
@tmpbufs = Array.new(5) {|i| Vdsp::DoubleArray.new(soundinfo.window_size+2)}
|
110
|
+
@pulse_context = Pulse.instance.generate_context(soundinfo, note_perform, init_phase)
|
103
111
|
end
|
104
112
|
end
|
105
113
|
end
|
@@ -13,11 +13,19 @@ module Synthesizer
|
|
13
13
|
result
|
14
14
|
end
|
15
15
|
|
16
|
-
def generate_context(soundinfo, note_perform,
|
17
|
-
|
16
|
+
def generate_context(soundinfo, note_perform, init_phase)
|
17
|
+
Context.new(soundinfo, note_perform, init_phase)
|
18
18
|
end
|
19
19
|
|
20
|
-
|
20
|
+
class Context < Base::Context
|
21
|
+
attr_accessor :prev
|
22
|
+
|
23
|
+
def initialize(soundinfo, note_perform, init_phase)
|
24
|
+
super(soundinfo, note_perform, init_phase)
|
25
|
+
|
26
|
+
@prev = -1.0
|
27
|
+
end
|
28
|
+
end
|
21
29
|
end
|
22
30
|
end
|
23
31
|
end
|
@@ -6,6 +6,7 @@ module Synthesizer
|
|
6
6
|
attr_reader :amplifier
|
7
7
|
attr_reader :processor
|
8
8
|
|
9
|
+
attr_reader :quality
|
9
10
|
attr_reader :soundinfo
|
10
11
|
|
11
12
|
attr_reader :glide
|
@@ -14,15 +15,17 @@ module Synthesizer
|
|
14
15
|
# @param oscillators [Synthesizer::Oscillator] Oscillator
|
15
16
|
# @param filter [Synthesizer::Filter] filter
|
16
17
|
# @param amplifier [Synthesizer::Amplifier] amplifier
|
18
|
+
# @param quality [Synthesizer::Quality] processor quality
|
17
19
|
# @param soundinfo [AudioStream::SoundInfo]
|
18
|
-
def initialize(oscillators:, filter: nil, amplifier:, soundinfo:)
|
20
|
+
def initialize(oscillators:, filter: nil, amplifier:, quality: Quality::LOW, soundinfo:)
|
19
21
|
@oscillators = [oscillators].flatten.compact
|
20
22
|
@filter = filter
|
21
23
|
@amplifier = amplifier
|
22
24
|
|
25
|
+
@quality = quality
|
23
26
|
@soundinfo = soundinfo
|
24
27
|
|
25
|
-
@processor = Processor.
|
28
|
+
@processor = Processor.create(quality)
|
26
29
|
@performs = {}
|
27
30
|
@pitch_bend = 0.0
|
28
31
|
end
|