basic-sequencer 0.0.4

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 69fcf47b967d669ca28420c35c71dd4a642229da
4
+ data.tar.gz: 96e296ed53e0f27a539dcfb8f32a9ebf461fc519
5
+ SHA512:
6
+ metadata.gz: 79b566c5927160eead43d655a1a06c08eea322f63b6ec12bb1bcbf5ed64cfd48ad75aaa9210107829ef39fac244a42f6350278cd9fe3cc96d4084de9bc03d303
7
+ data.tar.gz: dae58578dc14438b6133954e076679ad6bad8da0606ece4b222cf3488a80b7b934997ca93ffda0693425a8983f0e9286d0267ba5adb47da185e590e8c2286512
data/LICENSE ADDED
@@ -0,0 +1,13 @@
1
+ Copyright 2011-2014 Ari Russo
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
data/README.md ADDED
@@ -0,0 +1,25 @@
1
+ #Sequencer
2
+
3
+ Perform a sequence of events at tempo
4
+
5
+ The tempo clock is MIDI syncable by way of [topaz](http://github.com/arirusso/topaz).
6
+
7
+ This is used by [diamond](http://github.com/arirusso/diamond)
8
+
9
+ ## Installation
10
+
11
+ `gem install basic-sequencer`
12
+
13
+ or with Bundler, add this to your Gemfile
14
+
15
+ `gem "basic-sequencer"`
16
+
17
+ ## Documentation
18
+
19
+ * [rdoc](http://rubydoc.info/github/arirusso/sequencer)
20
+
21
+ ## License
22
+
23
+ Licensed under Apache 2.0, See the file LICENSE
24
+
25
+ Copyright © 2011-2014 Ari Russo
data/lib/sequencer.rb ADDED
@@ -0,0 +1,24 @@
1
+ #
2
+ # Sequencer
3
+ # Perform a sequence of events at tempo
4
+ #
5
+ # (c)2011-2014 Ari Russo
6
+ # Licensed under Apache 2.0
7
+ #
8
+
9
+ # libs
10
+ require "forwardable"
11
+ require "topaz"
12
+
13
+ # classes
14
+ require "sequencer/clock"
15
+ require "sequencer/core"
16
+ require "sequencer/event"
17
+ require "sequencer/event_trigger"
18
+ require "sequencer/loop"
19
+
20
+ module Sequencer
21
+
22
+ VERSION = "0.0.4"
23
+
24
+ end
@@ -0,0 +1,75 @@
1
+ module Sequencer
2
+
3
+ # A light wrapper for Topaz::Tempo that adds some event handling
4
+ class Clock
5
+
6
+ extend Forwardable
7
+
8
+ attr_reader :event
9
+ def_delegators :@clock, :pause, :stop, :unpause
10
+
11
+ # @param [Fixnum, UniMIDI::Input] tempo_or_input
12
+ # @param [Hash] options
13
+ # @option options [Array<UniMIDI::Output>, UniMIDI::Output] :outputs MIDI output device(s)
14
+ def initialize(tempo_or_input, options = {})
15
+ @event = Event.new
16
+ initialize_clock(tempo_or_input, options.fetch(:resolution, 128), :outputs => options[:outputs])
17
+ end
18
+
19
+ # Start the clock
20
+ # @param [Hash] options
21
+ # @option options [Boolean] :blocking Whether to run in the foreground (also :focus, :foreground)
22
+ # @option options [Boolean] :suppress_clock Whether this clock is a sync-slave
23
+ # @return [Boolean]
24
+ def start(options = {})
25
+ clock_options = {}
26
+ clock_options[:background] = ![:blocking, :focus, :foreground].any? { |key| !!options[key] }
27
+ @clock.start(clock_options) unless !!options[:suppress_clock]
28
+ Thread.abort_on_exception = true
29
+ end
30
+
31
+ private
32
+
33
+ # Action taken by the clock on a tick. Fires the tick event
34
+ def on_tick
35
+ @event.do_tick
36
+ end
37
+
38
+ # Instantiate the underlying clock object
39
+ # @param [Fixnum, UniMIDI::Input] tempo_or_input
40
+ # @param [Fixnum] resolution
41
+ # @param [Hash] options
42
+ # @option options [Array<UniMIDI::Output>, UniMIDI::Output] :outputs MIDI output device(s)
43
+ def initialize_clock(tempo_or_input, resolution, options = {})
44
+ @clock = Topaz::Tempo.new(tempo_or_input, :midi => options[:outputs])
45
+ @clock.interval = @clock.interval * (resolution / @clock.interval)
46
+ @clock.on_tick { on_tick }
47
+ end
48
+
49
+ # Clock event callbacks
50
+ class Event
51
+
52
+ def initialize
53
+ @tick = []
54
+ end
55
+
56
+ # Access the tick event callback
57
+ # @param [Proc] block
58
+ # @return [Proc]
59
+ def tick(&block)
60
+ if block_given?
61
+ @tick.clear
62
+ @tick << block
63
+ end
64
+ @tick
65
+ end
66
+
67
+ # Fire the tick event callback
68
+ # @return [Boolean]
69
+ def do_tick
70
+ !@tick.empty? && @tick.map(&:call)
71
+ end
72
+
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,77 @@
1
+ module Sequencer
2
+
3
+ # The core sequencer
4
+ class Core
5
+
6
+ attr_reader :event, :loop, :trigger
7
+ attr_accessor :pointer
8
+
9
+ def initialize
10
+ @event = Event.new
11
+ @loop = Loop.new
12
+ @pointer = 0
13
+ @trigger = EventTrigger.new
14
+ end
15
+
16
+ # Execute a single cycle of sequencing (perform and step)
17
+ # @param [Array] sequence The sequence to execute a single cycle of
18
+ # @return [Boolean] Whether perform and step both finished
19
+ def exec(sequence)
20
+ perform(sequence) && step(sequence)
21
+ end
22
+
23
+ # Step the sequencer and fire the step event
24
+ # @param [Array] sequence
25
+ # @return [Boolean]
26
+ def step(sequence)
27
+ if reset_pointer?(:length => sequence.length)
28
+ reset_pointer
29
+ else
30
+ @pointer += 1
31
+ end
32
+ @event.do_step
33
+ true
34
+ end
35
+
36
+ # If a stop is triggered, stop. Otherwise if reset is triggered, reset. Finally,
37
+ # fire the perform event on the current step of the sequence
38
+ # @param [Array] sequence
39
+ # @return [Boolean] True if perform event was fired
40
+ def perform(sequence)
41
+ data = sequence.at(@pointer)
42
+ @event.do_next(@pointer, data) if @event.next?(@pointer)
43
+ if @trigger.stop?(@pointer, data)
44
+ @event.do_stop
45
+ false
46
+ else
47
+ reset_pointer if @trigger.reset?(@pointer, data)
48
+ @event.do_perform(data)
49
+ true
50
+ end
51
+ end
52
+
53
+ # Set the pointer to the loop start point
54
+ # @return [Fixnum]
55
+ def reset_pointer
56
+ @pointer = @loop.next
57
+ end
58
+
59
+ private
60
+
61
+ # Is the pointer at the point where it needs to be reset?
62
+ # @param [Hash] options
63
+ # @option options [Fixnum] :length The length of the sequence (used when the default loop is active)
64
+ # @return [Boolean]
65
+ def reset_pointer?(options = {})
66
+ !@loop.disabled? && !@loop.in_bounds?(@pointer + 1, :length => options[:length])
67
+ end
68
+
69
+ end
70
+
71
+ # Shortcut to the Core constructor
72
+ # @return [Core]
73
+ def self.new
74
+ Core.new
75
+ end
76
+
77
+ end
@@ -0,0 +1,86 @@
1
+ module Sequencer
2
+
3
+ # Events that are fired by the sequencer
4
+ class Event
5
+
6
+ def initialize
7
+ @next = {}
8
+ @perform = []
9
+ @step = []
10
+ @stop = []
11
+ end
12
+
13
+ def next(pointer = nil, &block)
14
+ if block_given?
15
+ @next[pointer] ||= []
16
+ @next[pointer] << block
17
+ end
18
+ hash
19
+ end
20
+
21
+ def next?(pointer = nil)
22
+ !@next[pointer].nil?
23
+ end
24
+
25
+ def do_next(pointer, data)
26
+ keys = [pointer, nil]
27
+ callbacks = keys.map { |key| @next.delete(key) }.flatten.compact
28
+ callbacks.each(&:call)
29
+ true
30
+ end
31
+
32
+ # Set the step event
33
+ # @param [Proc] block
34
+ # @return [Proc]
35
+ def step(&block)
36
+ if block_given?
37
+ @step.clear
38
+ @step << block
39
+ end
40
+ @step
41
+ end
42
+
43
+ # Fire the step events
44
+ # @return [Boolean]
45
+ def do_step
46
+ !@step.empty? && @step.map(:call)
47
+ end
48
+
49
+ # Access the stop events
50
+ # @param [Proc] block
51
+ # @return [Proc]
52
+ def stop(&block)
53
+ if block_given?
54
+ @stop.clear
55
+ @stop << block
56
+ end
57
+ @stop
58
+ end
59
+
60
+ # Fire the stop event
61
+ # @return [Boolean]
62
+ def do_stop
63
+ @stop.map(&:call)
64
+ end
65
+
66
+ # Set the perform event
67
+ # @param [Proc] block
68
+ # @return [Proc]
69
+ def perform(&block)
70
+ if block_given?
71
+ @perform.clear
72
+ @perform << block
73
+ end
74
+ @perform
75
+ end
76
+
77
+ # Fire the perform event
78
+ # @param [Object] data Data for the current sequence step
79
+ # @return [Boolean]
80
+ def do_perform(data)
81
+ @perform.map { |callback| callback.call(data) }
82
+ end
83
+
84
+ end
85
+
86
+ end
@@ -0,0 +1,78 @@
1
+ module Sequencer
2
+
3
+ # Callbacks that when evaluate to true, will trigger the corresponding sequencer event
4
+ class EventTrigger
5
+
6
+ # Set the reset trigger. When true, the sequence will go back to step 0
7
+ # @param [Proc] block
8
+ # @return [Proc]
9
+ def reset(&block)
10
+ @reset = block
11
+ end
12
+
13
+ # Set the rest trigger. When true, no messages will be outputted during that step
14
+ # @param [Proc] block
15
+ # @return [Proc]
16
+ def rest(&block)
17
+ @rest = block
18
+ end
19
+
20
+ # Whether the reset event should fire
21
+ # @param [Fixnum] pointer The sequencer pointer
22
+ # @param [Object] data Data for the current sequence step
23
+ # @return [Boolean]
24
+ def reset?(pointer, data)
25
+ !@reset.nil? && @reset.call(pointer, data)
26
+ end
27
+
28
+ # Whether the rest event should fire
29
+ # @param [Fixnum] pointer The sequencer pointer
30
+ # @param [Object] data Data for the current sequence step
31
+ # @return [Boolean]
32
+ def rest?(pointer, data)
33
+ !@rest.nil? && @rest.call(pointer, data)
34
+ end
35
+
36
+ # Set the stop trigger. When true, the sequencer will stop
37
+ # @param [Proc] block
38
+ # @return [Proc]
39
+ def stop(&block)
40
+ @stop = block
41
+ end
42
+
43
+ # Whether to fire the stop event
44
+ # @param [Fixnum] pointer The sequencer pointer
45
+ # @param [Object] data Data for the current sequence step
46
+ # @return [Boolean]
47
+ def stop?(pointer, data)
48
+ !@stop.nil? && @stop.call(pointer, data)
49
+ end
50
+
51
+ # Shortcut to trigger a rest event on a given interval of ticks
52
+ # @param [Fixnum, nil] num The number of ticks or nil to cancel existing triggers
53
+ # @return [Fixnum, nil]
54
+ def rest_every(num)
55
+ if num.nil?
56
+ @rest = nil
57
+ else
58
+ rest { |pointer| pointer % num == 0 }
59
+ num
60
+ end
61
+ end
62
+
63
+ # Shortcut to trigger a reset even on a given interval of ticks
64
+ # @param [Fixnum, nil] num The number of ticks or nil to cancel existing triggers
65
+ # @return [Fixnum, nil]
66
+ def reset_every(num)
67
+ if num.nil?
68
+ @reset = nil
69
+ else
70
+ reset { |pointer| pointer % num == 0 }
71
+ num
72
+ end
73
+ end
74
+
75
+ end
76
+
77
+ end
78
+
@@ -0,0 +1,60 @@
1
+ module Sequencer
2
+
3
+ class Loop
4
+
5
+ attr_reader :count, :range
6
+
7
+ def initialize
8
+ @count = 0
9
+ @range = nil
10
+ @is_disabled = false
11
+ end
12
+
13
+ # Set the loop range
14
+ # @param [Array<Fixnum>, FalseClass, Fixnum, Range] value
15
+ # @return [FalseClass, Range]
16
+ def range=(value)
17
+ @range = to_range(value)
18
+ end
19
+
20
+ def start
21
+ default? ? 0 : @range.begin
22
+ end
23
+
24
+ def next
25
+ @count += 1
26
+ start
27
+ end
28
+
29
+ def default?
30
+ @range.nil?
31
+ end
32
+
33
+ def disabled?
34
+ @is_disabled
35
+ end
36
+
37
+ def disable
38
+ @is_disabled = true
39
+ end
40
+
41
+ def in_bounds?(num, options = {})
42
+ length = options[:length]
43
+ range = default? ? 0..(length-1) : @range
44
+ range.include?(num)
45
+ end
46
+
47
+ private
48
+
49
+ # @param [Array<Fixnum>, Fixnum, Range] value
50
+ # @return [FalseClass, Range]
51
+ def to_range(value)
52
+ case value
53
+ when Array then (value[0]..value[1])
54
+ when Fixnum then (0..value)
55
+ when Range then value
56
+ end
57
+ end
58
+
59
+ end
60
+ end
@@ -0,0 +1,51 @@
1
+ require "helper"
2
+
3
+ class Sequencer::ClockTest < Test::Unit::TestCase
4
+
5
+ context "Clock" do
6
+
7
+ setup do
8
+ @clock = Sequencer::Clock.new(120)
9
+ end
10
+
11
+ context "Clock::Event#tick" do
12
+
13
+ setup do
14
+ @flag = false
15
+ @flag2 = false
16
+ end
17
+
18
+ should "assign single callback" do
19
+ @clock.event.tick { @flag = true }
20
+ refute @flag
21
+ @clock.event.do_tick
22
+ assert @flag
23
+ end
24
+
25
+ should "reassign single callback" do
26
+ @clock.event.tick { @flag = true }
27
+ @clock.event.tick { @flag2 = true }
28
+ refute @flag
29
+ refute @flag2
30
+ @clock.event.do_tick
31
+ refute @flag
32
+ assert @flag2
33
+ end
34
+
35
+ should "allow multiple callbacks" do
36
+ @clock.event.tick { @flag = true }
37
+ @clock.event.tick << proc { @flag2 = true }
38
+ refute @flag
39
+ refute @flag2
40
+ @clock.event.do_tick
41
+ assert @flag
42
+ assert @flag2
43
+ end
44
+
45
+ end
46
+
47
+ end
48
+
49
+ end
50
+
51
+
data/test/core_test.rb ADDED
@@ -0,0 +1,133 @@
1
+ require "helper"
2
+
3
+ class Sequencer::CoreTest < Test::Unit::TestCase
4
+
5
+ context "Core" do
6
+
7
+ setup do
8
+ @sequencer = Sequencer::Core.new
9
+ end
10
+
11
+ context "#exec" do
12
+
13
+ setup do
14
+ @sequence = [1,2,3,4]
15
+ end
16
+
17
+ should "move to next" do
18
+ assert_equal 0, @sequencer.pointer
19
+ @sequencer.exec(@sequence)
20
+ assert_equal 1, @sequencer.pointer
21
+ end
22
+
23
+ should "do repeat" do
24
+ @sequencer.pointer = @sequence.length - 1
25
+ @sequencer.exec(@sequence)
26
+ assert_equal 0, @sequencer.pointer
27
+ end
28
+
29
+ should "stop" do
30
+ @sequencer.trigger.expects(:stop?).once.returns(true)
31
+ @sequencer.trigger.expects(:reset?).never
32
+ @sequencer.event.expects(:do_perform).never
33
+ @sequencer.exec(@sequence)
34
+ end
35
+
36
+ should "reset and fire event" do
37
+ @sequencer.pointer = 3
38
+ @sequencer.trigger.expects(:stop?).once.returns(false)
39
+ @sequencer.trigger.expects(:reset?).once.returns(true)
40
+ @sequencer.event.expects(:do_perform).once
41
+ @sequencer.exec(@sequence)
42
+ assert_equal 1, @sequencer.pointer
43
+ end
44
+
45
+ should "fire event" do
46
+ @sequencer.pointer = 2
47
+ @sequencer.trigger.expects(:stop?).once.returns(false)
48
+ @sequencer.trigger.expects(:reset?).once.returns(false)
49
+ @sequencer.event.expects(:do_perform).once
50
+ @sequencer.exec(@sequence)
51
+ assert_equal 3, @sequencer.pointer
52
+ end
53
+
54
+ end
55
+
56
+ context "#step" do
57
+
58
+ setup do
59
+ @sequence = [1,2,3,4]
60
+ @sequencer.event.expects(:do_step).once
61
+ end
62
+
63
+ should "move to next" do
64
+ assert_equal 0, @sequencer.pointer
65
+ @sequencer.step(@sequence)
66
+ assert_equal 1, @sequencer.pointer
67
+ end
68
+
69
+ should "do repeat" do
70
+ @sequencer.pointer = @sequence.length - 1
71
+ @sequencer.step(@sequence)
72
+ assert_equal 0, @sequencer.pointer
73
+ end
74
+
75
+ end
76
+
77
+ context "#perform" do
78
+
79
+ setup do
80
+ @sequence = [1,2,3,4]
81
+ end
82
+
83
+ should "stop" do
84
+ @sequencer.trigger.expects(:stop?).once.returns(true)
85
+ @sequencer.trigger.expects(:reset?).never
86
+ @sequencer.event.expects(:do_perform).never
87
+ @sequencer.perform(@sequence)
88
+ end
89
+
90
+ should "reset and fire event" do
91
+ @sequencer.pointer = 3
92
+ @sequencer.trigger.expects(:stop?).once.returns(false)
93
+ @sequencer.trigger.expects(:reset?).once.returns(true)
94
+ @sequencer.event.expects(:do_perform).once
95
+ @sequencer.perform(@sequence)
96
+ assert_equal 0, @sequencer.pointer
97
+ end
98
+
99
+ should "fire event" do
100
+ @sequencer.pointer = 3
101
+ @sequencer.trigger.expects(:stop?).once.returns(false)
102
+ @sequencer.trigger.expects(:reset?).once.returns(false)
103
+ @sequencer.event.expects(:do_perform).once
104
+ @sequencer.perform(@sequence)
105
+ assert_equal 3, @sequencer.pointer
106
+ end
107
+
108
+ end
109
+
110
+ context "Functional" do
111
+
112
+ setup do
113
+ @clock = Sequencer::Clock.new(120)
114
+ @clock.event.tick { @sequencer.exec(@sequence) }
115
+ @sequencer.event.stop { @clock.stop }
116
+ @sequence = [1,2,3,4]
117
+ @cache = []
118
+ @sequencer.event.perform { | data| @cache << data }
119
+ @sequencer.trigger.stop { @sequencer.loop.count == 1 }
120
+ @clock.start(:focus => true)
121
+ end
122
+
123
+ should "create cache of sequence" do
124
+ assert_equal @sequence, @cache
125
+ end
126
+
127
+ end
128
+
129
+
130
+ end
131
+
132
+ end
133
+
@@ -0,0 +1,89 @@
1
+ require "helper"
2
+
3
+ class Sequencer::EventTriggerTest < Test::Unit::TestCase
4
+
5
+ context "EventTrigger" do
6
+
7
+ setup do
8
+ @trigger = Sequencer::EventTrigger.new
9
+ end
10
+
11
+ context "#reset?" do
12
+
13
+ setup do
14
+ @has_run = false
15
+ @trigger.reset { |p, d| @has_run = d }
16
+ end
17
+
18
+ should "fire stop trigger" do
19
+ assert @trigger.reset?(0, true)
20
+ assert @has_run = true
21
+ end
22
+
23
+ end
24
+
25
+ context "#reset_every" do
26
+
27
+ setup do
28
+ @trigger.reset_every(3)
29
+ end
30
+
31
+ should "reset every three ticks" do
32
+ 3.times do |i|
33
+ assert @trigger.reset?((i * 3) + 0, false)
34
+ refute @trigger.reset?((i * 3) + 1, false)
35
+ refute @trigger.reset?((i * 3) + 2, false)
36
+ end
37
+ end
38
+
39
+ end
40
+
41
+ context "#rest_every" do
42
+
43
+ setup do
44
+ @trigger.rest_every(3)
45
+ end
46
+
47
+ should "reset every three ticks" do
48
+ 3.times do |i|
49
+ assert @trigger.rest?((i * 3) + 0, false)
50
+ refute @trigger.rest?((i * 3) + 1, false)
51
+ refute @trigger.rest?((i * 3) + 2, false)
52
+ end
53
+ end
54
+
55
+ end
56
+
57
+ context "#rest?" do
58
+
59
+ setup do
60
+ @has_run = false
61
+ @trigger.rest { |p, d| @has_run = d }
62
+ end
63
+
64
+ should "fire stop trigger" do
65
+ assert @trigger.rest?(0, true)
66
+ assert @has_run = true
67
+ end
68
+
69
+ end
70
+
71
+ context "#stop?" do
72
+
73
+ setup do
74
+ @has_run = false
75
+ @trigger.stop { |p, d| @has_run = d }
76
+ end
77
+
78
+ should "fire stop trigger" do
79
+ assert @trigger.stop?(0, true)
80
+ assert @has_run = true
81
+ end
82
+
83
+ end
84
+
85
+ end
86
+
87
+ end
88
+
89
+
data/test/helper.rb ADDED
@@ -0,0 +1,15 @@
1
+ dir = File.dirname(File.expand_path(__FILE__))
2
+ $LOAD_PATH.unshift dir + "/../lib"
3
+
4
+ require "test/unit"
5
+ require "mocha/test_unit"
6
+ require "shoulda-context"
7
+ require "sequencer"
8
+
9
+ module TestHelper
10
+
11
+ def self.select_midi_output
12
+ $midi_output = UniMIDI::Output.gets
13
+ end
14
+
15
+ end
data/test/loop_test.rb ADDED
@@ -0,0 +1,89 @@
1
+ require "helper"
2
+
3
+ class Sequencer::LoopTest < Test::Unit::TestCase
4
+
5
+ context "Loop" do
6
+
7
+ setup do
8
+ @loop = Sequencer::Loop.new
9
+ end
10
+
11
+ context "#to_range" do
12
+
13
+ should "convert array" do
14
+ assert_equal 1..6, @loop.send(:to_range, [1, 6])
15
+ end
16
+
17
+ should "convert number" do
18
+ assert_equal 0..9, @loop.send(:to_range, 9)
19
+ end
20
+
21
+ should "pass range" do
22
+ assert_equal 5..8, @loop.send(:to_range, 5..8)
23
+ end
24
+
25
+ end
26
+
27
+ context "#start" do
28
+
29
+ context "default loop" do
30
+
31
+ should "always have 0 as start" do
32
+ assert @loop.default?
33
+ assert_equal 0, @loop.start
34
+ end
35
+
36
+ end
37
+
38
+ context "custom loop" do
39
+
40
+ setup do
41
+ @loop.range = 3..6
42
+ end
43
+
44
+ should "have custom start point" do
45
+ refute @loop.default?
46
+ assert_equal 3, @loop.start
47
+ end
48
+
49
+ end
50
+
51
+ end
52
+
53
+ context "#in_bounds?" do
54
+
55
+ context "default loop" do
56
+
57
+ should "include number in range" do
58
+ assert @loop.in_bounds?(3, :length => 10)
59
+ end
60
+
61
+ should "not include number out of range" do
62
+ refute @loop.in_bounds?(10, :length => 8)
63
+ end
64
+
65
+ end
66
+
67
+ context "custom loop" do
68
+
69
+ setup do
70
+ @loop.range = 0..6
71
+ end
72
+
73
+ should "include number in range" do
74
+ assert @loop.in_bounds?(5)
75
+ end
76
+
77
+ should "not include number out of range" do
78
+ refute @loop.in_bounds?(7)
79
+ end
80
+
81
+ end
82
+
83
+ end
84
+
85
+ end
86
+
87
+ end
88
+
89
+
metadata ADDED
@@ -0,0 +1,97 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: basic-sequencer
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.4
5
+ platform: ruby
6
+ authors:
7
+ - Ari Russo
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-09-15 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: midi-topaz
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 0.0.15
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 0.0.15
33
+ - !ruby/object:Gem::Dependency
34
+ name: unimidi
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '0'
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: 0.2.5
43
+ type: :runtime
44
+ prerelease: false
45
+ version_requirements: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - "~>"
48
+ - !ruby/object:Gem::Version
49
+ version: '0'
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: 0.2.5
53
+ description: Perform a sequence of events at tempo in Ruby
54
+ email:
55
+ - ari.russo@gmail.com
56
+ executables: []
57
+ extensions: []
58
+ extra_rdoc_files: []
59
+ files:
60
+ - LICENSE
61
+ - README.md
62
+ - lib/sequencer.rb
63
+ - lib/sequencer/clock.rb
64
+ - lib/sequencer/core.rb
65
+ - lib/sequencer/event.rb
66
+ - lib/sequencer/event_trigger.rb
67
+ - lib/sequencer/loop.rb
68
+ - test/clock_test.rb
69
+ - test/core_test.rb
70
+ - test/event_trigger_test.rb
71
+ - test/helper.rb
72
+ - test/loop_test.rb
73
+ homepage: http://github.com/arirusso/sequencer
74
+ licenses:
75
+ - Apache 2.0
76
+ metadata: {}
77
+ post_install_message:
78
+ rdoc_options: []
79
+ require_paths:
80
+ - lib
81
+ required_ruby_version: !ruby/object:Gem::Requirement
82
+ requirements:
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ required_rubygems_version: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: 1.3.6
91
+ requirements: []
92
+ rubyforge_project: basic-sequencer
93
+ rubygems_version: 2.2.2
94
+ signing_key:
95
+ specification_version: 4
96
+ summary: Perform a sequence of events at tempo
97
+ test_files: []