synthesizer 3.1.0 → 3.4.0

Sign up to get free protection for your applications and to get access to all the features.
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