tone.rb 0.1.0

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