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