synthesizer 3.1.0 → 3.4.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.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +4 -0
  3. data/examples/{metronome.rb → audio_input_metronome.rb} +8 -2
  4. data/examples/{step_editor.rb → audio_input_step_editor.rb} +10 -2
  5. data/examples/filter_band_pass.rb +73 -0
  6. data/examples/{lpf.rb → filter_serial.rb} +9 -2
  7. data/examples/oscillator_pan.rb +70 -0
  8. data/examples/{formant_vocoder.rb → oscillator_source_formant_vocoder.rb} +10 -3
  9. data/examples/{formant_vocoder_sweep.rb → oscillator_source_formant_vocoder_sweep.rb} +13 -6
  10. data/examples/oscillator_sync.rb +71 -0
  11. data/examples/oscillator_unison.rb +64 -0
  12. data/examples/oscillator_volume.rb +70 -0
  13. data/examples/{mono.rb → synth_mono.rb} +10 -2
  14. data/examples/{poly.rb → synth_poly.rb} +10 -2
  15. data/{examples → jupyter}/adsr.ipynb +20 -17
  16. data/jupyter/curves.ipynb +103 -0
  17. data/jupyter/shapes.ipynb +111 -0
  18. data/lib/audio_stream/audio_input_metronome.rb +1 -1
  19. data/lib/synthesizer/amplifier.rb +4 -1
  20. data/lib/synthesizer/filter/band_pass_filter.rb +3 -3
  21. data/lib/synthesizer/filter/high_pass_filter.rb +3 -3
  22. data/lib/synthesizer/filter/high_shelf_filter.rb +4 -4
  23. data/lib/synthesizer/filter/low_pass_filter.rb +3 -3
  24. data/lib/synthesizer/filter/low_shelf_filter.rb +4 -4
  25. data/lib/synthesizer/filter/parallel.rb +2 -2
  26. data/lib/synthesizer/filter/peaking_filter.rb +5 -5
  27. data/lib/synthesizer/filter/serial.rb +2 -2
  28. data/lib/synthesizer/modulation/adsr.rb +37 -35
  29. data/lib/synthesizer/modulation/curve.rb +3 -0
  30. data/lib/synthesizer/modulation/glide.rb +9 -8
  31. data/lib/synthesizer/modulation/lfo.rb +23 -23
  32. data/lib/synthesizer/modulation_value.rb +5 -5
  33. data/lib/synthesizer/mono_synth.rb +7 -2
  34. data/lib/synthesizer/oscillator.rb +11 -9
  35. data/lib/synthesizer/oscillator_source/base.rb +35 -5
  36. data/lib/synthesizer/oscillator_source/formant_vocoder.rb +27 -19
  37. data/lib/synthesizer/oscillator_source/pulse.rb +11 -3
  38. data/lib/synthesizer/poly_synth.rb +5 -2
  39. data/lib/synthesizer/processor/high.rb +63 -0
  40. data/lib/synthesizer/processor/low.rb +59 -0
  41. data/lib/synthesizer/processor.rb +6 -44
  42. data/lib/synthesizer/quality.rb +6 -0
  43. data/lib/synthesizer/shape.rb +4 -4
  44. data/lib/synthesizer/shape_pos.rb +22 -19
  45. data/lib/synthesizer/unison.rb +28 -16
  46. data/lib/synthesizer/version.rb +1 -1
  47. data/lib/synthesizer.rb +1 -0
  48. data/samples/cinema.rb +730 -0
  49. data/samples/cinema_drum.wav +0 -0
  50. data/samples/daijoubu.rb +811 -0
  51. data/samples/daijoubu_drum.wav +0 -0
  52. data/samples/kira_power.rb +987 -0
  53. data/samples/kira_power_drum.wav +0 -0
  54. data/synthesizer.gemspec +1 -1
  55. metadata +32 -18
  56. data/examples/curves.ipynb +0 -105
  57. 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, framerate)
8
+ def generator(note_perform, samplecount)
9
9
  filter_mods = @filters.map {|filter|
10
- filter.generator(note_perform, framerate)
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, framerate)
10
+ def generator(note_perform, samplecount)
11
11
  soundinfo = note_perform.synth.soundinfo
12
- filter = AudioStream::Fx::LowShelfFilter.new(soundinfo)
12
+ filter = AudioStream::Fx::PeakingFilter.new(soundinfo)
13
13
 
14
- freq_mod = ModulationValue.balance_generator(note_perform, framerate, @freq)
15
- bandwidth_mod = ModulationValue.balance_generator(note_perform, framerate, @bandwidth)
16
- gain_mod = ModulationValue.balance_generator(note_perform, framerate, @gain)
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, framerate)
8
+ def generator(note_perform, samplecount)
9
9
  filter_mods = @filters.map {|filter|
10
- filter.generator(note_perform, framerate)
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 sec (0.0~)
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(framerate, sustain: false, &block)
24
+ def note_on_envelope(soundinfo, samplecount, sustain: false, &block)
25
25
  Enumerator.new do |yld|
26
26
  # attack
27
- rate = @attack * framerate
28
- rate.to_i.times {|i|
29
- x = i.to_f / rate
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
- rate = @hold * framerate
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
- rate = @decay * framerate
42
- rate.to_i.times {|i|
43
- x = i.to_f / rate
44
- y = 1.0 - @sustain_curve[x] * (1.0 - @sustain)
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(framerate, sustain: false, &block)
56
+ def note_off_envelope(soundinfo, samplecount, sustain: false, &block)
58
57
  Enumerator.new do |yld|
59
58
  # release
60
- rate = @release * framerate
61
- rate.to_i.times {|i|
62
- x = i.to_f / rate
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, framerate, release_sustain:)
77
- note_on = note_on_envelope(framerate, sustain: true)
78
- note_off = note_off_envelope(framerate, sustain: release_sustain)
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, framerate, depth, &block)
92
+ def amp_generator(note_perform, samplecount, depth, &block)
92
93
  bottom = 1.0 - depth
93
- gen = generator(note_perform, framerate, release_sustain: 0.0<bottom)
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, framerate, depth, &block)
101
- gen = generator(note_perform, framerate, release_sustain: true)
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(framerate: 44100)
109
- note_on = note_on_envelope(framerate, sustain: false)
110
- note_off = note_off_envelope(framerate, sustain: false)
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(framerate: 44100)
131
- data = plot_data(framerate: framerate)
132
+ def plot(soundinfo)
133
+ data = plot_data(soundinfo)
132
134
  Plotly::Plot.new(data: [data])
133
135
  end
134
136
  end
@@ -4,6 +4,9 @@ module Synthesizer
4
4
  Straight = ->(x) { x }
5
5
  EaseIn = ->(x) { x ** 2 }
6
6
  EaseOut = ->(x) { x * (2 - x) }
7
+
8
+ EaseIn2 = ->(x) { x ** 3 }
9
+ EaseOut2 = ->(x) { 1.0 - EaseIn2[1.0 - x]}
7
10
  end
8
11
  end
9
12
  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.to_f
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, samplerate)
30
- rate = @time * samplerate
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.note_on?
36
+ if !note_perform.released?
36
37
  # Note On
37
- if 0<@time && @target!=@current
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, samplerate, depth)
64
- gen = generator(note_perform, samplerate)
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.5)
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, framerate, &block)
21
- Enumerator.new do |yld|
22
- delta = @rate / framerate
20
+ def generator(note_perform, samplecount, &block)
21
+ soundinfo = note_perform.synth.soundinfo
22
+ hz = @rate.freq(soundinfo)
23
23
 
24
- pos = ShapePos.new(phase: @phase)
24
+ Enumerator.new do |yld|
25
+ pos = ShapePos.new(soundinfo.samplerate / samplecount, @phase)
25
26
 
26
27
  # delay
27
- rate = @delay * framerate
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
- rate = @attack * framerate
34
- rate.to_i.times {|i|
35
- x = i.to_f / rate
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(delta)] * y
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(delta)]
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, framerate, depth, &block)
48
+ def amp_generator(note_perform, samplecount, depth, &block)
49
49
  bottom = 1.0 - depth
50
- gen = generator(note_perform, framerate)
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, framerate, depth, &block)
59
- gen = generator(note_perform, framerate)
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, framerate, *modvals)
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, framerate, depth)
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, framerate, *modvals, center: 0)
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, framerate, depth)
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.new
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] TODO not implemented
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
- 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)
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, delta, l_gain, r_gain)
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(delta))
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, phase)
30
- Context.new(soundinfo.window_size, soundinfo.channels, ShapePos.new(phase: phase))
31
+ def generate_context(soundinfo, note_perform, init_phase)
32
+ Context.new(soundinfo, note_perform, init_phase)
31
33
  end
32
34
 
33
- Context = Struct.new("Context", :window_size, :channels, :pos)
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, delta, l_gain, r_gain)
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
- @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
+ 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 = @vowels[index % @vowels_len][i]+(@vowels[(index+1) % @vowels_len][i]-@vowels[index % @vowels_len][i])*(r_index-index)
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, 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)
95
+ def generate_context(soundinfo, note_perform, init_phase)
96
+ Context.new(soundinfo, note_perform, init_phase, @pronunciation)
90
97
  end
91
98
 
92
- FvContext = Struct.new("FvContext", :soundinfo, :note_perform, :phase, :tmpbufs, :pronunciation_mod) do
93
- def window_size
94
- soundinfo.window_size
95
- end
99
+ class Context < Base::Context
100
+ attr_reader :pronunciation_mod
101
+ attr_reader :tmpbufs
102
+ attr_reader :pulse_context
96
103
 
97
- def channels
98
- soundinfo.channels
99
- end
104
+ def initialize(soundinfo, note_perform, init_phase, pronunciation)
105
+ super(soundinfo, note_perform, init_phase)
100
106
 
101
- def samplerate
102
- soundinfo.samplerate
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, phase)
17
- PulseContext.new(soundinfo.window_size, soundinfo.channels, phase, ShapePos.new(phase: phase), -1.0)
16
+ def generate_context(soundinfo, note_perform, init_phase)
17
+ Context.new(soundinfo, note_perform, init_phase)
18
18
  end
19
19
 
20
- PulseContext = Struct.new("PulseContext", :window_size, :channels, :phase, :pos, :prev)
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.new
28
+ @processor = Processor.create(quality)
26
29
  @performs = {}
27
30
  @pitch_bend = 0.0
28
31
  end