Class: Livecode::Clock

Inherits:
Object
  • Object
show all
Defined in:
lib/livecode/clock.rb

Overview

Clock

Clock is quite literally the beating pulse of Livecode, providing you with a way to sync up blocks of code.

Creating a clock

Clock.new takes two options; :tempo and :resolution. Tempo should be self-explanatory, and is measured in beats per minute (BPM). The default is 120 BPM. Resolution is the number of ticks per beat. The default is 4, which is the equivalent of 16th notes.

clock = Clock.new(:tempo => 120, :resolution => 4)

Control

clock.start    # Starts the clock
clock.stop     # Stops the clock, resets the tick
clock.pause    # Pauses the clock, does not reset the tick
clock.restart  # Restarts the clock
clock.running? # Check if the clock is running

If you lose track of your variables, you can use Clock.stop_all to stop all clocks.

Ticks

The clock is based on ticks, which is simply an incrementing counter. clock.tick will return the current tick, while clock.tick_length will return the length of one tick expressed in seconds.

The modulo operator is quite handy for turning ticks into rythmical structures:

bassdrum.play if clock.tick % 4 == 0 # Plays the bass drum on every beat
snare.play if clock.tick % 8 == 4 # ..and the snare on every other beat

Recipients

A recipient is a callback that will be triggered on every tick. Each recipient must have a unique name, and there’s a few ways to attach them. The following examples all do the same:

clock.recipients.add(:hihat, proc{|clock| hihat.play})
clock.recipients[:hihat] = proc{|clock| hihat.play})
clock.recipients.hihat = proc{|clock| hihat.play}
clock.recipients.hihat{|clock| hihat.play}
clock[:hihat] = proc{|clock| hihat.play}
clock.hihat = proc{|clock| hihat.play}
clock.hihat{|clock| hihat.play}

To remove a recipient, simply unset it:

clock.hihat = false

Furthermore, recipients can be muted, temporarily disabling them:

clock.mute(:bassdrum, :snare)  # Mutes the bass drum and snare
clock.solo(:synth, :bass)      # Solos the synth and bass
clock.enable_all               # Re-enables all recipients

Remember: The callbacks are executed sequentially. If your callback takes more than a split second, you should wrap the code in it’s own thread to allow for parallel processing.

Clock will also try to compensate for the run time of your code in order to stay in sync.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ Clock

Returns a new instance of Clock.



94
95
96
97
98
99
100
101
102
# File 'lib/livecode/clock.rb', line 94

def initialize(options={})
  @tempo      = options[:tempo]      || 120
  @resolution = options[:resolution] || 4
  @tick       = -1
  @thread     = nil
  @running    = false
  @recipients = ClockRecipients.new
  Clock.register(self)
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method_name, *args, &block) ⇒ Object



164
165
166
# File 'lib/livecode/clock.rb', line 164

def method_missing(method_name, *args, &block)
  self.recipients.send(method_name, *args, &block)
end

Instance Attribute Details

#resolutionObject

Returns the value of attribute resolution.



91
92
93
# File 'lib/livecode/clock.rb', line 91

def resolution
  @resolution
end

#tempoObject

Returns the value of attribute tempo.



91
92
93
# File 'lib/livecode/clock.rb', line 91

def tempo
  @tempo
end

#tickObject (readonly)

Returns the value of attribute tick.



92
93
94
# File 'lib/livecode/clock.rb', line 92

def tick
  @tick
end

Class Method Details

.clocksObject

Return all registered clocks.



81
82
83
# File 'lib/livecode/clock.rb', line 81

def clocks
  @@clocks ||= []
end

.register(clock) ⇒ Object

Register a new clock.



76
77
78
# File 'lib/livecode/clock.rb', line 76

def register(clock)
  clocks << clock
end

.stop_allObject

Stop all clocks.



86
87
88
# File 'lib/livecode/clock.rb', line 86

def stop_all
  clocks.each{|clock| clock.stop}
end

Instance Method Details

#pauseObject

Pause the clock.



136
137
138
139
# File 'lib/livecode/clock.rb', line 136

def pause
  @running = false
  self
end

#recipientsObject Also known as: r

Clock recipients



107
# File 'lib/livecode/clock.rb', line 107

def recipients; @recipients; end

#restartObject

Restart the clock.



142
143
144
145
# File 'lib/livecode/clock.rb', line 142

def restart
  @tick = -1
  start
end

#running?Boolean

Returns true if the clock is running.

Returns:

  • (Boolean)


148
149
150
# File 'lib/livecode/clock.rb', line 148

def running?
  @running ? true : false
end

#startObject Also known as: play

Start the clock. Restarts if the clock is already running.



119
120
121
122
123
124
# File 'lib/livecode/clock.rb', line 119

def start
  @running = true
  stop_thread
  start_thread
  self
end

#stopObject

Stop the clock.



128
129
130
131
132
133
# File 'lib/livecode/clock.rb', line 128

def stop
  stop_thread
  @tick = -1
  @running = false
  self
end

#tick!Object

Run next tick.



153
154
155
156
157
158
159
160
161
162
# File 'lib/livecode/clock.rb', line 153

def tick!
  @tick += 1
  recipients.each do |r|; unless r.silenced?
    if r.kind_of?(Proc)
      r.call(self)
    elsif r.respond_to?(:tick)
      r.tick(self)
    end
  end; end
end

#tick_lengthObject Also known as: tl

Length of a single tick (in seconds).



111
112
113
114
115
# File 'lib/livecode/clock.rb', line 111

def tick_length
  tl = (1/(@tempo.to_f/60))/@resolution
  tl = 0.00000001 if tl <= 0
  tl
end