synthesizer 1.2.0 → 1.3.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: ab192c339eebdc39d867ac206c82454c8b3509f92967e54f4aa4f4660b2e3cdf
4
- data.tar.gz: 86fadad577d12289b652be8bfa4ac55f6a6bad136fa5dc9ce21eac4df3f536e6
3
+ metadata.gz: ba89ee2f086cd7828b8a8f56ac0afaaed912b6140171972ea0a79de35116a8d2
4
+ data.tar.gz: 74ac5e12ea76f79b4d03a3181f24a97901c6381a8f8f7c4f34894f212f234438
5
5
  SHA512:
6
- metadata.gz: ce723ad9a5fd4817ce33f362fb15cdce50132b066c0aff60b203d13e04ab4bef99f947f6e4d871d2a24ad0a66b98aa1b899e72b579d23dbad64245b848ffc94d
7
- data.tar.gz: c42def904f7c6531d2f68d1000c5cd0a4cc2b54088f7af0c3414d3ffa59d1da8750eca6efd961b987953cde385266f187066ca71ba4f41c3bf2798fb0f1fcec3
6
+ metadata.gz: 2fbda5f5c4e4a5f13744ce84f1ba210cc5cf5ae264d4b24b0106650949b8e03d1a2ef24767d832febfd5770dda7805797fccf798a0015be99884371cedb75572
7
+ data.tar.gz: a8aa71eeaca0a941c2b0c7edadaa67610d44084afa7808a4a6488a622be0ab457025339d843854261ad7950f4e03510750feed62fae3083851023d01ca05f982
@@ -0,0 +1,59 @@
1
+ require 'synthesizer'
2
+ require 'audio_stream/core_ext'
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
+ shape: Shape::SquareSawtooth,
18
+ uni_num: ModulationValue.new(4)
19
+ .add(Modulation::Lfo.new(
20
+ )),
21
+ uni_detune: 0.1,
22
+ ),
23
+ ],
24
+ amplifier: Amplifier.new(
25
+ volume: ModulationValue.new(1.0)
26
+ .add(Modulation::Adsr.new(
27
+ attack: 0.05,
28
+ hold: 0.1,
29
+ decay: 0.4,
30
+ sustain: 0.8,
31
+ release: 0.2
32
+ ), depth: 1.0),
33
+ ),
34
+ quality: Quality::LOW,
35
+ soundinfo: soundinfo,
36
+ )
37
+
38
+ se = StepEditor::StGt.new(bpm: 120) {|se|
39
+ se.note(Note.new(60), st: 480, gt: 480*3)
40
+ se.pitch_bend(1, st: 480)
41
+ se.pitch_bend(2, st: 480*2)
42
+ se.complete
43
+ }
44
+
45
+ track1 = AudioInputStepEditor.new(synth, se)
46
+
47
+ stereo_out = AudioOutput.device(soundinfo: soundinfo)
48
+
49
+ track1
50
+ .stream
51
+ .send_to(stereo_out, gain: 0.25)
52
+
53
+
54
+ conductor = Conductor.new(
55
+ input: [track1],
56
+ output: [stereo_out]
57
+ )
58
+ conductor.connect
59
+ conductor.join
@@ -0,0 +1,52 @@
1
+ module AudioStream
2
+ class AudioInputStepEditor < Rx::Subject
3
+ include AudioInput
4
+
5
+ def initialize(synth, step_editor)
6
+ super()
7
+
8
+ @synth = synth
9
+ @step_editor = step_editor
10
+
11
+ @soundinfo = synth.soundinfo
12
+ end
13
+
14
+ def each(&block)
15
+ Enumerator.new do |y|
16
+
17
+ events = Hash.new {|h, k| h[k]=[]}
18
+
19
+ fps = @soundinfo.samplerate.to_f / @soundinfo.window_size
20
+
21
+ @step_editor.events.each {|event|
22
+ pos = event[0]
23
+ events[(pos * fps).to_i] << event
24
+ }
25
+
26
+ catch :break do
27
+ Range.new(0, nil).each {|i|
28
+ if events.has_key?(i)
29
+ events[i].each {|event|
30
+ type = event[1]
31
+
32
+ case type
33
+ when :note_on
34
+ @synth.note_on(event[2], velocity: event[3])
35
+ when :note_off
36
+ @synth.note_off(event[2])
37
+ when :pitch_bend
38
+ @synth.pitch_bend = event[2]
39
+ when :complete
40
+ throw :break
41
+ end
42
+ }
43
+ end
44
+
45
+ buf = @synth.next
46
+ y << buf
47
+ }
48
+ end
49
+ end.each(&block)
50
+ end
51
+ end
52
+ end
data/lib/synthesizer.rb CHANGED
@@ -3,6 +3,8 @@ require 'synthesizer/version'
3
3
  require 'audio_stream'
4
4
  require 'audio_stream/audio_input_synth.rb'
5
5
  require 'audio_stream/audio_input_metronome.rb'
6
+ require 'audio_stream/audio_input_step_editor'
7
+ require 'synthesizer/step_editor'
6
8
 
7
9
  require 'synthesizer/poly_synth'
8
10
  require 'synthesizer/mono_synth'
@@ -45,7 +45,9 @@ module Synthesizer
45
45
  end
46
46
  end
47
47
 
48
- def note_on(note)
48
+ # @param note [Synthesizer::Note]
49
+ # @param velocity [Float] volume percent (0.0~1.0)
50
+ def note_on(note, velocity: 1.0)
49
51
  # Note Off
50
52
  note_off(note)
51
53
 
@@ -54,12 +56,13 @@ module Synthesizer
54
56
  @glide.target = note.num
55
57
  else
56
58
  # Note On
57
- @perform = NotePerform.new(self, note)
59
+ @perform = NotePerform.new(self, note, velocity)
58
60
  @glide.base = note.num
59
61
  end
60
62
  @note_nums << note.num
61
63
  end
62
64
 
65
+ # @param note [Synthesizer::Note]
63
66
  def note_off(note)
64
67
  # Note Off
65
68
  @note_nums.delete_if {|note_num| note_num==note.num}
@@ -3,14 +3,17 @@ module Synthesizer
3
3
 
4
4
  attr_reader :synth
5
5
  attr_reader :note
6
+ attr_reader :velocity
6
7
 
7
- def initialize(synth, note)
8
+ def initialize(synth, note, velocity)
8
9
  @synth = synth
10
+ @note = note
11
+ @velocity = velocity
12
+
9
13
  @processors = synth.oscillators.map {|osc|
10
14
  synth.processor.generator(osc, self)
11
15
  }
12
16
 
13
- @note = note
14
17
  @note_on = true
15
18
  @released = false
16
19
  end
@@ -30,19 +30,21 @@ module Synthesizer
30
30
  end
31
31
 
32
32
  def next
33
+ buf = nil
33
34
  if 0<@performs.length
34
- bufs = @performs.values.map(&:next)
35
+ bufs = @performs.values.map(&:next).compact
35
36
 
36
37
  # delete released note performs
37
38
  @performs.delete_if {|note_num, perform| perform.released? }
38
39
 
39
- bufs.compact.inject(:+)
40
- else
41
- AudioStream::Buffer.float(@soundinfo.window_size, @soundinfo.channels)
40
+ buf = bufs.inject(:+)
42
41
  end
42
+ buf || AudioStream::Buffer.float(@soundinfo.window_size, @soundinfo.channels)
43
43
  end
44
44
 
45
- def note_on(note)
45
+ # @param note [Synthesizer::Note]
46
+ # @param velocity [Float] volume percent (0.0~1.0)
47
+ def note_on(note, velocity: 1.0)
46
48
  # Note Off
47
49
  perform = @performs[note.num]
48
50
  if perform
@@ -50,10 +52,11 @@ module Synthesizer
50
52
  end
51
53
 
52
54
  # Note On
53
- perform = NotePerform.new(self, note)
55
+ perform = NotePerform.new(self, note, velocity)
54
56
  @performs[note.num] = perform
55
57
  end
56
58
 
59
+ # @param note [Synthesizer::Note]
57
60
  def note_off(note)
58
61
  # Note Off
59
62
  perform = @performs[note.num]
@@ -33,7 +33,7 @@ module Synthesizer
33
33
 
34
34
  window_size.times.each {|i|
35
35
  # Oscillator, Amplifier
36
- volume = volume_mod.next
36
+ volume = volume_mod.next * note_perform.velocity
37
37
  tune_semis = tune_semis_mod.next + synth.pitch_bend
38
38
  tune_cents = tune_cents_mod.next
39
39
 
@@ -60,7 +60,7 @@ module Synthesizer
60
60
 
61
61
  window_size.times.each {|i|
62
62
  # Oscillator, Amplifier
63
- volume = volume_mod.next
63
+ volume = volume_mod.next * note_perform.velocity
64
64
  pan = pan_mod.next
65
65
  tune_semis = tune_semis_mod.next + synth.pitch_bend
66
66
  tune_cents = tune_cents_mod.next
@@ -32,7 +32,7 @@ module Synthesizer
32
32
  buf = AudioStream::Buffer.float(window_size, channels)
33
33
 
34
34
  # Oscillator, Amplifier
35
- volume = volume_mod.next
35
+ volume = volume_mod.next * note_perform.velocity
36
36
  tune_semis = tune_semis_mod.next + synth.pitch_bend
37
37
  tune_cents = tune_cents_mod.next
38
38
 
@@ -57,7 +57,7 @@ module Synthesizer
57
57
  buf = AudioStream::Buffer.float(window_size, channels)
58
58
 
59
59
  # Oscillator, Amplifier
60
- volume = volume_mod.next
60
+ volume = volume_mod.next * note_perform.velocity
61
61
  pan = pan_mod.next
62
62
  tune_semis = tune_semis_mod.next + synth.pitch_bend
63
63
  tune_cents = tune_cents_mod.next
@@ -0,0 +1,6 @@
1
+ require 'synthesizer/step_editor/st_gt'
2
+
3
+ module Synthesizer
4
+ module StepEditor
5
+ end
6
+ end
@@ -0,0 +1,55 @@
1
+ module Synthesizer
2
+ module StepEditor
3
+ class StGt
4
+
5
+ attr_reader :ppq
6
+ attr_reader :events
7
+
8
+ def initialize(bpm:, ppq: 480, &block)
9
+ @ppq = ppq
10
+ @seek = 0.0
11
+ @location = 0
12
+ @events = []
13
+ self.bpm = bpm
14
+
15
+ if block_given?
16
+ yield self
17
+ end
18
+ end
19
+
20
+ def bpm=(bpm)
21
+ @ppq_rate = 60.0 / (@ppq.to_f * bpm)
22
+ end
23
+
24
+ def step(st)
25
+ @location += st
26
+ @seek += st * @ppq_rate
27
+ end
28
+
29
+ def location(beats: 4)
30
+ tick = @location % @ppq
31
+ location = (@location - tick) / @ppq
32
+ beat = location % beats
33
+ location = location - beat
34
+ measure = location / beats
35
+
36
+ "#{measure+1}. #{beat+1}. #{tick}"
37
+ end
38
+
39
+ def note(note, st: 0, gt:, vel: 1.0, dev: 0)
40
+ @events << [@seek + dev * @ppq_rate, :note_on, note, vel]
41
+ @events << [@seek + (gt + dev) * @ppq_rate, :note_off, note]
42
+ step(st)
43
+ end
44
+
45
+ def pitch_bend(semis, st: 0, dev: 0)
46
+ @events << [@seek + dev * @ppq_rate, :pitch_bend, semis]
47
+ step(st)
48
+ end
49
+
50
+ def complete
51
+ @events << [@seek, :complete]
52
+ end
53
+ end
54
+ end
55
+ end
@@ -1,3 +1,3 @@
1
1
  module Synthesizer
2
- VERSION = "1.2.0"
2
+ VERSION = "1.3.0"
3
3
  end
data/synthesizer.gemspec CHANGED
@@ -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", ">= 1.2.1"
33
+ spec.add_dependency "audio_stream", ">= 1.2.2"
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: 1.2.0
4
+ version: 1.3.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-07-18 00:00:00.000000000 Z
11
+ date: 2019-07-19 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: 1.2.1
61
+ version: 1.2.2
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: 1.2.1
68
+ version: 1.2.2
69
69
  description: Synthesizer implemented in Ruby.
70
70
  email:
71
71
  - yoshida.eth0@gmail.com
@@ -88,7 +88,9 @@ files:
88
88
  - examples/mono.rb
89
89
  - examples/poly.rb
90
90
  - examples/shapes.ipynb
91
+ - examples/step_editor.rb
91
92
  - lib/audio_stream/audio_input_metronome.rb
93
+ - lib/audio_stream/audio_input_step_editor.rb
92
94
  - lib/audio_stream/audio_input_synth.rb
93
95
  - lib/synthesizer.rb
94
96
  - lib/synthesizer/amplifier.rb
@@ -118,6 +120,8 @@ files:
118
120
  - lib/synthesizer/quality.rb
119
121
  - lib/synthesizer/shape.rb
120
122
  - lib/synthesizer/shape_pos.rb
123
+ - lib/synthesizer/step_editor.rb
124
+ - lib/synthesizer/step_editor/st_gt.rb
121
125
  - lib/synthesizer/unison.rb
122
126
  - lib/synthesizer/utils.rb
123
127
  - lib/synthesizer/version.rb