tone.rb 0.1.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 +7 -0
- data/.gitignore +8 -0
- data/.travis.yml +5 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +33 -0
- data/LICENSE.txt +21 -0
- data/README.md +106 -0
- data/Rakefile +14 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/tone.rb +11 -0
- data/lib/tone/effect.rb +157 -0
- data/lib/tone/event.rb +37 -0
- data/lib/tone/synth.rb +100 -0
- data/lib/tone/transport.rb +30 -0
- data/lib/tone/vendor.js +23722 -0
- data/lib/tone/version.rb +3 -0
- data/tone.rb.gemspec +29 -0
- metadata +103 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 843f52bc94240658d10ff26663f3af64ef18b5b41a357a299c40c6e51f5377f8
|
4
|
+
data.tar.gz: c1beef2a831c67e5d51900d8ea3078fe6137fbf886750b979f6c02c6bf940fdb
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 9f148d334a8cbb19f77085c13e2f6c7d990ef07c688b795e1140f09844491fc6cad5205f23a08bcbffede717a073ffabba313d5b9e45747f160535ab8c059209
|
7
|
+
data.tar.gz: 56b17cc4a7129b95c9fc4f35244a0aa2bd6132aab05c828759f49db4584b5e435585802e13ce85c4d5a964a969cc284239fed0a1c72a6c6e043ced205c7379ae
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
tone.rb (0.1.0)
|
5
|
+
opal (>= 0.10.2)
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: https://rubygems.org/
|
9
|
+
specs:
|
10
|
+
ast (2.4.0)
|
11
|
+
hike (1.2.3)
|
12
|
+
minitest (5.11.3)
|
13
|
+
opal (0.11.0)
|
14
|
+
ast (>= 2.3.0)
|
15
|
+
hike (~> 1.2)
|
16
|
+
parser (= 2.3.3.1)
|
17
|
+
sourcemap (~> 0.1.0)
|
18
|
+
parser (2.3.3.1)
|
19
|
+
ast (~> 2.2)
|
20
|
+
rake (10.5.0)
|
21
|
+
sourcemap (0.1.1)
|
22
|
+
|
23
|
+
PLATFORMS
|
24
|
+
ruby
|
25
|
+
|
26
|
+
DEPENDENCIES
|
27
|
+
bundler (~> 1.16)
|
28
|
+
minitest (~> 5.0)
|
29
|
+
rake (~> 10.0)
|
30
|
+
tone.rb!
|
31
|
+
|
32
|
+
BUNDLED WITH
|
33
|
+
1.16.2
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2018 Jose Anasco
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
# Tone.rb
|
2
|
+
|
3
|
+
Ruby wrapper for [Tone.js](https://github.com/feedjira/feedjira). This is used in the live coding environment of [Negasonic](https://negasonic.herokuapp.com/)
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'tone.rb'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle install
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install tone
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
Tone.rb targets version 11 of Tone.js. This are the current implemented modules:
|
24
|
+
|
25
|
+
### Transport
|
26
|
+
|
27
|
+
Handles the global execution of elements in Tone.js
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
# play after 0.1 seconds
|
31
|
+
Tone::Transport.start("+0.1")
|
32
|
+
|
33
|
+
# stop now
|
34
|
+
Tone::Transport.stop
|
35
|
+
```
|
36
|
+
|
37
|
+
### Synth
|
38
|
+
|
39
|
+
Adds basic functionality for handling it as an input node, playing notes, as well as the ability
|
40
|
+
to compare it with other synths
|
41
|
+
|
42
|
+
```ruby
|
43
|
+
# Volume is measured in decibels
|
44
|
+
synth = Tone::Synth::FM.new(volume: 2)
|
45
|
+
|
46
|
+
# Play the E2 note at 0 and release at 0.5 seconds
|
47
|
+
synth.trigger_attack_release('E2', 0.5, 0)
|
48
|
+
|
49
|
+
# Each synths are compared by the volume attribute
|
50
|
+
synth == Tone::Synth::FM.new(volume: 2) #=> true
|
51
|
+
synth == Tone::Synth::FM.new(volume: 3) #=> false
|
52
|
+
synth == Tone::Synth::AM.new(volume: 2) #=> false
|
53
|
+
|
54
|
+
# Connect all effects between each other and connect the synth as the input
|
55
|
+
synth.chain(array_of_effects)
|
56
|
+
```
|
57
|
+
|
58
|
+
### Effect
|
59
|
+
|
60
|
+
Similar to `Synth`, you can compare between effects, as well as remove
|
61
|
+
them trough `Effect#dispose` (good for performance)
|
62
|
+
|
63
|
+
```ruby
|
64
|
+
# each effect has specific attributes
|
65
|
+
vibrato = Tone::Effect::Vibrato.new(frequency: 5, depth: 0.1)
|
66
|
+
vibrato == Tone::Effect::Vibrato.new(frequency: 5, depth: 0.2) #=> false
|
67
|
+
```
|
68
|
+
|
69
|
+
### Event
|
70
|
+
|
71
|
+
Events schedules a group of notes in a certain order across the `Transport`
|
72
|
+
|
73
|
+
```ruby
|
74
|
+
|
75
|
+
# schedules notes in order every 2 seconds
|
76
|
+
Tone::Event::Sequence.new([['E2', 'C1'], 'D2'], 'C2'], 2) do |time, note|
|
77
|
+
Tone::Synth::FM.new.trigger_attack_release note, '1', time
|
78
|
+
end
|
79
|
+
|
80
|
+
# schedules notes in a random order
|
81
|
+
pattern = Tone::Event::Pattern.new(['E2', 'C1', 'D2', 'C2'], :random) do |time, note|
|
82
|
+
Tone::Synth::FM.new.trigger_attack_release note, '1', time
|
83
|
+
end
|
84
|
+
|
85
|
+
# every 2 seconds
|
86
|
+
pattern.interval = 2
|
87
|
+
|
88
|
+
# run it in loop mode
|
89
|
+
pattern.start(0)
|
90
|
+
pattern.loop = true
|
91
|
+
```
|
92
|
+
|
93
|
+
for more info check the [Tone.js Docs](https://tonejs.github.io/docs/)
|
94
|
+
|
95
|
+
## TODO
|
96
|
+
|
97
|
+
* Basic tests
|
98
|
+
* Wrap remaining Tone.js modules
|
99
|
+
|
100
|
+
## Contributing
|
101
|
+
|
102
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/merongivian/tone.rb
|
103
|
+
|
104
|
+
## License
|
105
|
+
|
106
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
Bundler.require
|
3
|
+
Bundler::GemHelper.install_tasks
|
4
|
+
|
5
|
+
require 'open-uri'
|
6
|
+
|
7
|
+
desc 'update js dependencies'
|
8
|
+
task :update_tone_js do
|
9
|
+
js_lib_url = 'https://tonejs.github.io/build/Tone.min.js'
|
10
|
+
js_lib_dest = File.join(File.dirname(__FILE__), './lib/tone/vendor.js')
|
11
|
+
open(js_lib_url) do |f|
|
12
|
+
File.write(js_lib_dest, f.readlines.join)
|
13
|
+
end
|
14
|
+
end
|
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "tone"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
data/lib/tone.rb
ADDED
data/lib/tone/effect.rb
ADDED
@@ -0,0 +1,157 @@
|
|
1
|
+
module Tone
|
2
|
+
module Effect
|
3
|
+
class Base
|
4
|
+
include Native
|
5
|
+
|
6
|
+
alias_native :dispose
|
7
|
+
alias_native :connect
|
8
|
+
alias_native :to_master
|
9
|
+
|
10
|
+
def ==(other)
|
11
|
+
self.class == other.class
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class Chorus < Base
|
16
|
+
attr_reader :frequency, :delay_time, :depth
|
17
|
+
|
18
|
+
def initialize(frequency: 1.5, delay_time: 3.5, depth: 0.7)
|
19
|
+
@frequency = frequency
|
20
|
+
@delay_time = delay_time
|
21
|
+
@depth = depth
|
22
|
+
super `new Tone.Chorus(frequency, delay_time, depth)`
|
23
|
+
end
|
24
|
+
|
25
|
+
def ==(other)
|
26
|
+
super &&
|
27
|
+
frequency == other.frequency &&
|
28
|
+
delay_time == other.delay_time &&
|
29
|
+
depth == other.depth
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
class Vibrato < Base
|
34
|
+
attr_reader :frequency, :depth
|
35
|
+
|
36
|
+
def initialize(frequency: 5, depth: 0.1)
|
37
|
+
@frequency = frequency
|
38
|
+
@depth = depth
|
39
|
+
super `new Tone.Vibrato(frequency, depth)`
|
40
|
+
end
|
41
|
+
|
42
|
+
def ==(other)
|
43
|
+
super &&
|
44
|
+
frequency == other.frequency &&
|
45
|
+
depth == other.depth
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
class Distortion < Base
|
50
|
+
attr_reader :value
|
51
|
+
|
52
|
+
def initialize(value: 0.4)
|
53
|
+
@value = value
|
54
|
+
super `new Tone.Distortion(value)`
|
55
|
+
end
|
56
|
+
|
57
|
+
def ==(other)
|
58
|
+
super && value == other.value
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
class Tremolo < Base
|
63
|
+
attr_reader :frequency, :depth
|
64
|
+
|
65
|
+
def initialize(frequency: 10, depth: 0.5)
|
66
|
+
@frequency = frequency
|
67
|
+
@depth = depth
|
68
|
+
super `new Tone.Tremolo(frequency, depth)`
|
69
|
+
end
|
70
|
+
|
71
|
+
def ==(other)
|
72
|
+
super &&
|
73
|
+
frequency == other.frequency &&
|
74
|
+
depth == other.depth
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
class FeedbackDelay < Base
|
79
|
+
attr_reader :delay_time, :feedback
|
80
|
+
|
81
|
+
def initialize(delay_time: 0.25, feedback: 0.5)
|
82
|
+
@delay_time = delay_time
|
83
|
+
@feedback = feedback
|
84
|
+
super `new Tone.FeedbackDelay(delay_time, feedback)`
|
85
|
+
end
|
86
|
+
|
87
|
+
def ==(other)
|
88
|
+
super &&
|
89
|
+
delay_time == other.delay_time &&
|
90
|
+
feedback == other.feedback
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
class Freeverb < Base
|
95
|
+
attr_reader :room_size, :dampening
|
96
|
+
|
97
|
+
def initialize(room_size: 0.7, dampening: 3000)
|
98
|
+
@room_size = room_size
|
99
|
+
@dampening = dampening
|
100
|
+
super `new Tone.Freeverb(room_size, dampening)`
|
101
|
+
end
|
102
|
+
|
103
|
+
def ==(other)
|
104
|
+
super &&
|
105
|
+
room_size == other.room_size &&
|
106
|
+
dampening == other.dampening
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
class JCReverb < Base
|
111
|
+
attr_reader :room_size
|
112
|
+
|
113
|
+
def initialize(room_size: 0.5)
|
114
|
+
@room_size = room_size
|
115
|
+
super `new Tone.JCReverb(room_size)`
|
116
|
+
end
|
117
|
+
|
118
|
+
def ==(other)
|
119
|
+
super && room_size == other.room_size
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
class Phaser < Base
|
124
|
+
attr_reader :frequency, :octaves, :base_frequency
|
125
|
+
|
126
|
+
def initialize(frequency: 0.5, octaves: 3, base_frequency: 350)
|
127
|
+
@frequency = frequency
|
128
|
+
@octaves = octaves
|
129
|
+
@base_frequency = base_frequency
|
130
|
+
super `new Tone.Phaser(frequency, octaves, base_frequency)`
|
131
|
+
end
|
132
|
+
|
133
|
+
def ==(other)
|
134
|
+
super &&
|
135
|
+
frequency == other.frequency &&
|
136
|
+
octaves == other.octaves &&
|
137
|
+
base_frequency == other.base_frequency
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
class PingPongDelay < Base
|
142
|
+
attr_reader :delay_time, :feedback
|
143
|
+
|
144
|
+
def initialize(delay_time: 0.25, feedback: 1)
|
145
|
+
@delay_time = delay_time
|
146
|
+
@feedback = feedback
|
147
|
+
super `new Tone.PingPongDelay(delay_time, feedback)`
|
148
|
+
end
|
149
|
+
|
150
|
+
def ==(other)
|
151
|
+
super &&
|
152
|
+
delay_time == other.delay_time &&
|
153
|
+
feedback == other.feedback
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
data/lib/tone/event.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
module Tone
|
2
|
+
module Event
|
3
|
+
class Base
|
4
|
+
include Native
|
5
|
+
|
6
|
+
alias_native :start
|
7
|
+
alias_native :dispose
|
8
|
+
native_writer :loop
|
9
|
+
end
|
10
|
+
|
11
|
+
class Pattern < Base
|
12
|
+
native_writer :interval
|
13
|
+
|
14
|
+
def initialize(notes, type, &block)
|
15
|
+
super `new Tone.Pattern(#{block.to_n}, #{notes.to_n}, type)`
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class Part < Base
|
20
|
+
def initialize(definitions, &block)
|
21
|
+
super `new Tone.Part(#{block.to_n}, #{definitions.to_n})`
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class Sequence < Base
|
26
|
+
def initialize(segments, duration, &block)
|
27
|
+
super `new Tone.Sequence(#{block.to_n}, #{segments.to_n}, duration)`
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class Loop < Base
|
32
|
+
def initialize(interval, &block)
|
33
|
+
super `new Tone.Loop(#{block.to_n}, interval)`
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/lib/tone/synth.rb
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
module Tone
|
2
|
+
module Synth
|
3
|
+
class Base
|
4
|
+
include Native
|
5
|
+
|
6
|
+
alias_native :connect
|
7
|
+
alias_native :dispose
|
8
|
+
alias_native :trigger_attack_release, :triggerAttackRelease
|
9
|
+
alias_native :trigger_attack, :triggerAttack
|
10
|
+
alias_native :trigger_release, :triggerRelease
|
11
|
+
|
12
|
+
def chain(*effects)
|
13
|
+
last_node_connected = self
|
14
|
+
|
15
|
+
effects.each do |effect|
|
16
|
+
last_node_connected.connect(effect.to_n)
|
17
|
+
last_node_connected = effect
|
18
|
+
end
|
19
|
+
|
20
|
+
last_node_connected.connect(`Tone.Master`)
|
21
|
+
end
|
22
|
+
|
23
|
+
def initialize(native, volume: 1)
|
24
|
+
@native = native
|
25
|
+
`#@native.volume.value = volume`
|
26
|
+
end
|
27
|
+
|
28
|
+
def volume
|
29
|
+
`#@native.volume.value`
|
30
|
+
end
|
31
|
+
|
32
|
+
def ==(other)
|
33
|
+
volume == other.volume &&
|
34
|
+
self.class == other.class
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
class AM < Base
|
39
|
+
def initialize(**opts)
|
40
|
+
super `new Tone.AMSynth().toMaster()`, **opts
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
class Duo < Base
|
45
|
+
def initialize(**opts)
|
46
|
+
super `new Tone.DuoSynth().toMaster()`, **opts
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
class FM < Base
|
51
|
+
def initialize(**opts)
|
52
|
+
super `new Tone.FMSynth().toMaster()`, **opts
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
class Membrane < Base
|
57
|
+
def initialize(**opts)
|
58
|
+
super `new Tone.MembraneSynth().toMaster()`, **opts
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# TODO
|
63
|
+
class Metal < Base
|
64
|
+
def initialize(**opts)
|
65
|
+
super `new Tone.MetalSynth().toMaster()`, **opts
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
class Mono < Base
|
70
|
+
def initialize(**opts)
|
71
|
+
super `new Tone.MonoSynth().toMaster()`, **opts
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# TODO
|
76
|
+
class Noise < Base
|
77
|
+
def initialize(**opts)
|
78
|
+
super `new Tone.NoiseSynth().toMaster()`, **opts
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
class Pluck < Base
|
83
|
+
def initialize(**opts)
|
84
|
+
super `new Tone.PluckSynth().toMaster()`, **opts
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
class Poly < Base
|
89
|
+
def initialize(**opts)
|
90
|
+
super `new Tone.PolySynth().toMaster()`, **opts
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
class Simple < Base
|
95
|
+
def initialize(**opts)
|
96
|
+
super `new Tone.Synth().toMaster()`, **opts
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|