easy_audio_sequencer 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 509b4bd524d23d7c835a21bddc7868afb2febfc9
4
+ data.tar.gz: 470544ad47c45801b6f6a4feaa25f22003eb6c61
5
+ SHA512:
6
+ metadata.gz: 3e2cbb12f93fa663355bc47541875cbfb7f7f36109840275678376a32dbe64631ced9768363e16051748effe95dd94b02fefa7ca629536cd0e99305e64939b4e
7
+ data.tar.gz: eb761c10294152ff89d3d53beec8bcd889bce505e109056f624cf81294590a45d5ecef866bc9fc0f8c0860bc499226965b030fc2466d7b63be2aa6c4987e7508
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in easy_audio_sequencer.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Jonathan Slate
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,106 @@
1
+ # EasyAudioSequencer
2
+
3
+ I took the sample sequencer code from lsegal's easy_audio gem and created a gem out of it.
4
+
5
+ https://github.com/lsegal/easy_audio/
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ gem 'easy_audio_sequencer'
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install easy_audio_sequencer
20
+
21
+ ## Usage
22
+
23
+ require 'easy_audio'
24
+ require 'easy_audio_sequencer'
25
+
26
+ SNARE = EasyAudioSequencer::Instruments::SNARE
27
+ BASSDRUM = EasyAudioSequencer::Instruments::BASSDRUM
28
+ LEAD = EasyAudioSequencer::Instruments::LEAD
29
+ LEAD2 = EasyAudioSequencer::Instruments::LEAD2
30
+ TRIANGLE = EasyAudioSequencer::Instruments::TRIANGLE
31
+ SQUARELEAD = EasyAudioSequencer::Instruments::SQUARELEAD
32
+ SINE = EasyAudioSequencer::Instruments::SINE
33
+ HIHAT = EasyAudioSequencer::Instruments::HIHAT
34
+ PHASED = EasyAudioSequencer::Instruments::PHASED
35
+ EXP_FALLOFF2 = EasyAudioSequencer::Instruments::EXP_FALLOFF2
36
+
37
+ s = EasyAudioSequencer::Sequencer.new bpm: 43
38
+ s.add_scene :A, [
39
+ [nil, nil, SNARE, nil],
40
+ [EasyAudioSequencer.sn(BASSDRUM, 20), nil, nil, nil],
41
+ [nil, EasyAudioSequencer.sn(SQUARELEAD, 46)] * 4,
42
+ [EasyAudioSequencer.sn(LEAD, 51), nil, nil, EasyAudioSequencer.sn(TRIANGLE,49)],
43
+ [nil, EasyAudioSequencer.sn(SINE,20), nil, nil] * 2,
44
+ ]
45
+ s.add_scene :A2, [
46
+ [nil, nil, SNARE, nil],
47
+ [EasyAudioSequencer.sn(BASSDRUM, 20), nil, nil, nil],
48
+ [nil, EasyAudioSequencer.sn(SQUARELEAD, 46)] * 4,
49
+ [EasyAudioSequencer.sn(LEAD, 51), nil, nil, EasyAudioSequencer.sn(TRIANGLE,54)],
50
+ [nil, EasyAudioSequencer.sn(SINE,26), nil, nil] * 2,
51
+ ]
52
+ s.add_scene :B, [
53
+ [EasyAudioSequencer.sn(HIHAT, 70), nil, nil, nil, EasyAudioSequencer.sn(HIHAT, 70), nil, EasyAudioSequencer.sn(HIHAT, 70), nil] * 2,
54
+ [nil, nil, SNARE, nil],
55
+ [EasyAudioSequencer.sn(BASSDRUM, 20), nil, nil, nil, SNARE, nil, EasyAudioSequencer.sn(BASSDRUM, 20), nil],
56
+ [nil, EasyAudioSequencer.sn(SQUARELEAD, 42)] * 4,
57
+ [EasyAudioSequencer.sn(LEAD, 51), nil, nil, EasyAudioSequencer.sn(TRIANGLE,49)],
58
+ [nil, EasyAudioSequencer.sn(SINE,23), nil, nil] * 2,
59
+ ]
60
+ s.add_scene :C, [
61
+ [EasyAudioSequencer.sn(HIHAT, 70), nil, nil, nil, EasyAudioSequencer.sn(HIHAT, 70), nil, EasyAudioSequencer.sn(HIHAT, 70), nil] * 2,
62
+ [nil, nil, nil, nil, nil, SNARE, nil, nil, nil, nil],
63
+ [nil, EasyAudioSequencer.sn(SQUARELEAD, 49), nil, EasyAudioSequencer.sn(SQUARELEAD, 49), nil, nil, nil, EasyAudioSequencer.sn(-> { e(TRIANGLE) * 0.5 }, 54)],
64
+ [EasyAudioSequencer.sn(BASSDRUM, 20), nil, nil, nil, nil, nil, EasyAudioSequencer.sn(BASSDRUM, 20), nil],
65
+ [EasyAudioSequencer.sn(LEAD, 46), EasyAudioSequencer.sn(LEAD, 46), nil, nil],
66
+ [nil, nil, nil, nil, nil, nil, nil, EasyAudioSequencer.sn(TRIANGLE,42)],
67
+ [nil, nil, nil, nil, EasyAudioSequencer.sn(LEAD2,59), EasyAudioSequencer.sn(LEAD2,59), nil, nil],
68
+ [EasyAudioSequencer.sn(SINE,18)],
69
+ [EasyAudioSequencer.sn(PHASED,20)]
70
+ ]
71
+ s.add_scene :D, [
72
+ [nil, EasyAudioSequencer.sn(SQUARELEAD, 46)] * 4,
73
+ [EasyAudioSequencer.sn(LEAD, 51), nil, nil, EasyAudioSequencer.sn(TRIANGLE,49)],
74
+ ]
75
+ s.add_scene :D2, [
76
+ [nil, EasyAudioSequencer.sn(SQUARELEAD, 46)] * 4,
77
+ [EasyAudioSequencer.sn(TRIANGLE, 51), nil, nil, EasyAudioSequencer.sn(TRIANGLE,46)],
78
+ ]
79
+ s.add_scene :D3, [
80
+ [nil, EasyAudioSequencer.sn(SQUARELEAD, 46)] * 4,
81
+ [EasyAudioSequencer.sn(TRIANGLE, 42), nil, nil, nil],
82
+ ]
83
+ s.add_scene :D4, [
84
+ [nil, EasyAudioSequencer.sn(SQUARELEAD, 46)] * 4,
85
+ ]
86
+
87
+ s.add_scene :D5, [
88
+ [nil, EasyAudioSequencer.sn(-> { e(SQUARELEAD) * e(EXP_FALLOFF2) }, 46)] * 4,
89
+ [EasyAudioSequencer.sn(-> { e(SQUARELEAD) * e(EXP_FALLOFF2) }, 46), nil, nil, nil, nil, nil, nil, nil]
90
+ ]
91
+
92
+ # Play!
93
+ s.play scenes: %w(
94
+ 2:D5
95
+ 1:A 1:A2 2:B 4:C
96
+ 1:A 1:A2 2:B 4:C
97
+ 1:D 1:D2 1:D3 1:D4
98
+ )
99
+
100
+ ## Contributing
101
+
102
+ 1. Fork it ( http://github.com/<my-github-username>/easy_audio_sequencer/fork )
103
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
104
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
105
+ 4. Push to the branch (`git push origin my-new-feature`)
106
+ 5. Create new Pull Request
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,23 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'easy_audio_sequencer/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "easy_audio_sequencer"
8
+ spec.version = EasyAudioSequencer::VERSION
9
+ spec.authors = ["Jonathan Slate"]
10
+ spec.email = ["jslate@patientslikeme.com"]
11
+ spec.summary = %q{A ruby sequencer using easy_audio}
12
+ spec.description = %q{I took the sample sequencer code from lsegal's easy_audio gem and created a gem out of it.}
13
+ spec.homepage = "https://github.com/jslate/easy_audio_sequencer"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.5"
22
+ spec.add_development_dependency "rake", '~> 0'
23
+ end
@@ -0,0 +1,16 @@
1
+ require "easy_audio_sequencer/version"
2
+ require "easy_audio_sequencer/sound"
3
+ require "easy_audio_sequencer/instruments"
4
+ require "easy_audio_sequencer/sequencer"
5
+
6
+ module EasyAudioSequencer
7
+
8
+ def self.freq_for_note(note)
9
+ 2.0 ** ((note-49.0)/12.0) * 440.0
10
+ end
11
+
12
+ def self.sn(fn, note)
13
+ Sound.new(freq: freq_for_note(note), &fn)
14
+ end
15
+
16
+ end
@@ -0,0 +1,26 @@
1
+ module EasyAudioSequencer
2
+ module Instruments
3
+
4
+ SINE = -> { Math.sin(2 * Math::PI * step) * 0.8 }
5
+ SQUARE = -> { step < 0.5 ? -0.8 : 0.8 }
6
+ TRIANGLE = -> { (1 - 4 * (step.round - step).abs) * 0.55 }
7
+ SAW = -> { 2 * (step - step.round) * 0.8 }
8
+
9
+ NOISE = -> { rand - 0.5 }
10
+
11
+ EXP_FALLOFF = -> { [(1 / (frame * 0.002)), 1.0].min }
12
+ EXP_FALLOFF2 = -> { [(1 / (frame * 0.005)), 1.0].min }
13
+ LIN_FALLOFF = -> { (50000.0 - @frame) / 50000.0 }
14
+
15
+ SNARE = -> { e(EXP_FALLOFF) * e(NOISE) * 0.8 }
16
+ BASSDRUM = -> { [1.0,e(EXP_FALLOFF2) * e(NOISE) * 0.1 + e(SINE) * 2 * e(EXP_FALLOFF)].min }
17
+ HIHAT = -> { e(NOISE) * 0.3 * e(EXP_FALLOFF2) + e(SQUARE) * 0.1 * e(EXP_FALLOFF2) }
18
+
19
+ LEAD = -> { e(TRIANGLE) * e(EXP_FALLOFF) }
20
+ LEAD2 = -> { e(SAW) * Math.sin(step * 4.0) * 0.2 * fr(SINE,2*freq*Math.tan(step*0.005)) * 0.4 + e(NOISE) * 0.05 }
21
+ SQUARELEAD = -> { e(SQUARE) * 0.4 * e(EXP_FALLOFF) }
22
+ SQUARELEAD2 = -> { e(SQUARE) * 0.4 * e(EXP_FALLOFF2) }
23
+ PHASED = -> { fr(SINE, Math.sin(@step / 4.0) * (freq / 2.0)) * 0.01 * [1.0,frame.to_f/50000.0].max }
24
+
25
+ end
26
+ end
@@ -0,0 +1,98 @@
1
+ require 'easy_audio'
2
+
3
+ module EasyAudioSequencer
4
+
5
+ class Sequencer
6
+ def initialize(stream: EasyAudio::EasyStream.new(amp: 0.8, frame_size: 4096, latency: 12.0), bpm: 120)
7
+ srand
8
+ @stream = stream
9
+ @stream.fn = method(:next_frame)
10
+ @scene = nil
11
+ @scenes = {}
12
+ @rendered_scenes = {}
13
+ @keyframes = {}
14
+ @tracks = []
15
+ @bpm = bpm.to_f
16
+ @sample = 0
17
+ @kf = 0
18
+ @samples_per_bar = (@stream.sample_rate * 60) / @bpm
19
+ end
20
+
21
+ def next_frame
22
+ if @keyframes[@kf.to_i]
23
+ @scene = @keyframes[@kf.to_i]
24
+ end
25
+ @kf += 1
26
+
27
+ if @rendered_scenes[@scene] && @rendered_scenes[@scene][@sample.to_i]
28
+ result = @rendered_scenes[@scene][@sample.to_i]
29
+ else
30
+ result = calculate_frame(@scene, @sample.to_i)
31
+ end
32
+
33
+ @sample = (@sample + 1) % @samples_per_bar.to_i
34
+ result
35
+ end
36
+
37
+ def add_scene(name = nil, tracks)
38
+ @scenes[name.to_s || 'default'] = tracks.map do |track|
39
+ track.map {|t| Sound === t ? t : t ? Sound.new(&t) : nil }
40
+ end
41
+ end
42
+
43
+ def calculate_frame(name, i)
44
+ @rendered_scenes[name] ||= {}
45
+ total = 0.0
46
+ @scenes[name].each do |track|
47
+ q = @samples_per_bar.to_i / track.length
48
+ n = (i / q).to_i
49
+ step = (i.to_f / @stream.sample_rate) % 1.0
50
+ total += track[n] ? track[n].next_frame(i % q, step) : 0.0
51
+ end
52
+ @rendered_scenes[name][i] = total
53
+ end
54
+
55
+ def render_scenes
56
+ @rendered_scenes = {}
57
+ @keyframes.values.uniq.each do |name|
58
+ reader, writer = IO.pipe
59
+ fork do
60
+ reader.close
61
+ data = @samples_per_bar.to_i.times.map do |i|
62
+ calculate_frame(name, i)
63
+ end
64
+ writer.puts(Marshal.dump(data))
65
+ end
66
+
67
+ writer.close
68
+ data = Marshal.load(reader.read)
69
+ @rendered_scenes[name] = data
70
+ end
71
+ end
72
+
73
+ def play(scenes: ['16:default'])
74
+ @sample = 0
75
+ @kf = 0
76
+ @keyframes = {}
77
+
78
+ last_frame = 0
79
+ scenes.each do |scene|
80
+ bars, name = *scene.split(':')
81
+ @keyframes[last_frame] = name.to_s
82
+ last_frame += (bars.to_i * @samples_per_bar).to_i
83
+ end
84
+
85
+ puts "Rendering scenes in background..."
86
+ Thread.new { render_scenes }
87
+
88
+ puts "Starting audio..."
89
+ @stream.start
90
+ sleep(last_frame.to_f / @stream.sample_rate)
91
+ sleep 0.1 while @kf < last_frame
92
+ end
93
+ end
94
+
95
+ end
96
+
97
+
98
+
@@ -0,0 +1,48 @@
1
+ module EasyAudioSequencer
2
+
3
+ class Sound
4
+ def initialize(freq: 1, &block)
5
+ @freq = freq
6
+ @fn = block
7
+ @frame = 0
8
+ @step = 0
9
+ end
10
+
11
+ attr_accessor :frame, :step, :freq
12
+
13
+ def next_frame(frame, step)
14
+ @frame, @step = frame, step
15
+ calculate_step
16
+ instance_exec(&@fn)
17
+ end
18
+
19
+ def calculate_step
20
+ @step = (step * @freq.to_f) % 1.0
21
+ end
22
+
23
+ def e(fn = nil, &block)
24
+ instance_exec(&(fn || block))
25
+ end
26
+
27
+ def f(fn = nil, note, &block)
28
+ orig_freq, orig_step = @freq, @step
29
+ @freq = freq_for_note(note)
30
+ calculate_step
31
+ result = e(fn || block)
32
+ @freq = orig_freq
33
+ @step = orig_step
34
+ result
35
+ end
36
+
37
+ def fr(fn = nil, freq, &block)
38
+ orig_freq, orig_step = @freq, @step
39
+ @freq = freq
40
+ calculate_step
41
+ result = e(fn || block)
42
+ @freq = orig_freq
43
+ @step = orig_step
44
+ result
45
+ end
46
+ end
47
+
48
+ end
@@ -0,0 +1,3 @@
1
+ module EasyAudioSequencer
2
+ VERSION = "0.0.1"
3
+ end
metadata ADDED
@@ -0,0 +1,85 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: easy_audio_sequencer
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Jonathan Slate
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-11-18 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.5'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.5'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: I took the sample sequencer code from lsegal's easy_audio gem and created
42
+ a gem out of it.
43
+ email:
44
+ - jslate@patientslikeme.com
45
+ executables: []
46
+ extensions: []
47
+ extra_rdoc_files: []
48
+ files:
49
+ - ".gitignore"
50
+ - Gemfile
51
+ - LICENSE.txt
52
+ - README.md
53
+ - Rakefile
54
+ - easy_audio_sequencer.gemspec
55
+ - lib/easy_audio_sequencer.rb
56
+ - lib/easy_audio_sequencer/instruments.rb
57
+ - lib/easy_audio_sequencer/sequencer.rb
58
+ - lib/easy_audio_sequencer/sound.rb
59
+ - lib/easy_audio_sequencer/version.rb
60
+ homepage: https://github.com/jslate/easy_audio_sequencer
61
+ licenses:
62
+ - MIT
63
+ metadata: {}
64
+ post_install_message:
65
+ rdoc_options: []
66
+ require_paths:
67
+ - lib
68
+ required_ruby_version: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: '0'
73
+ required_rubygems_version: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ requirements: []
79
+ rubyforge_project:
80
+ rubygems_version: 2.4.4
81
+ signing_key:
82
+ specification_version: 4
83
+ summary: A ruby sequencer using easy_audio
84
+ test_files: []
85
+ has_rdoc: