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 +4 -4
- data/examples/step_editor.rb +59 -0
- data/lib/audio_stream/audio_input_step_editor.rb +52 -0
- data/lib/synthesizer.rb +2 -0
- data/lib/synthesizer/mono_synth.rb +5 -2
- data/lib/synthesizer/note_perform.rb +5 -2
- data/lib/synthesizer/poly_synth.rb +9 -6
- data/lib/synthesizer/processor/high.rb +2 -2
- data/lib/synthesizer/processor/low.rb +2 -2
- data/lib/synthesizer/step_editor.rb +6 -0
- data/lib/synthesizer/step_editor/st_gt.rb +55 -0
- data/lib/synthesizer/version.rb +1 -1
- data/synthesizer.gemspec +1 -1
- metadata +8 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ba89ee2f086cd7828b8a8f56ac0afaaed912b6140171972ea0a79de35116a8d2
|
4
|
+
data.tar.gz: 74ac5e12ea76f79b4d03a3181f24a97901c6381a8f8f7c4f34894f212f234438
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
|
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.
|
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
|
-
|
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,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
|
data/lib/synthesizer/version.rb
CHANGED
data/synthesizer.gemspec
CHANGED
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.
|
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-
|
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.
|
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.
|
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
|