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.
@@ -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
@@ -0,0 +1,8 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.5.1
5
+ before_install: gem install bundler -v 1.16.2
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in tone.gemspec
6
+ gemspec
@@ -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
@@ -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.
@@ -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).
@@ -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
@@ -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__)
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,11 @@
1
+ if RUBY_ENGINE == 'opal'
2
+ require 'tone/vendor'
3
+ require 'tone/transport'
4
+ require 'tone/event'
5
+ require 'tone/synth'
6
+ require 'tone/effect'
7
+ else
8
+ require 'opal'
9
+
10
+ Opal.append_path File.expand_path('../', __FILE__).untaint
11
+ end
@@ -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
@@ -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
@@ -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