Skip to content

Commit

Permalink
Simplified env mechanics.
Browse files Browse the repository at this point in the history
  • Loading branch information
Jeremy Voorhis committed Nov 2, 2008
1 parent deb3522 commit c5f9ba1
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 26 deletions.
4 changes: 2 additions & 2 deletions lib/music/env.rb
Expand Up @@ -4,8 +4,8 @@ def initialize(&fn)
@fn = fn
end

def apply(name, val, context)
@fn.call(val, context.phase)
def apply(val, phase)
@fn.call(val, phase)
end
end
end
67 changes: 44 additions & 23 deletions lib/music/interpreter.rb
Expand Up @@ -6,7 +6,8 @@ def self.eval(music)
new.eval(music)
end

def eval(music, context = Context.default(music.duration))
def eval(music, context = nil)
context ||= Context.init( Scope.new(0, music.duration, {}) )
music.eval(self, context)
end

Expand All @@ -18,43 +19,63 @@ def eval_section(music, context)
end

class Context
attr_reader :time, :attributes
attr_reader :time

def self.default(duration)
new(0, { :section_start => 0, :section_duration => duration})
def self.init(scope)
new(0, [scope])
end

def initialize(time, attrs)
@time, @attributes = time, attrs
def initialize(time, scopes)
@time, @scopes = time, scopes
end

def [](name) attributes[name] end
def keys
@keys ||= @scopes.inject([]) { |ns, s| ns | s.attributes.keys }
end

def attributes
@attributes ||= begin
@scopes.inject({}) do |as, scope|
keys.inject(as) do |as_, key|
a1 = scope.attributes[key]
a2 = as_[key]
as_.merge key => case a1
when Env: a1.apply(a2, phase)
else a1 || a2
end
end
end
end
end

def [](key) attributes[key] end

def phase
(@time - @attributes[:section_start]) / @attributes[:section_duration].to_f
(@time - top.offset) / top.duration.to_f
end

def advance(dur)
self.class.new(time + dur, attributes)
self.class.new(time + dur, @scopes)
end

def push(a0)
a1 = attributes.merge(a0)
self.class.new(time, a1)
def push(scope)
self.class.new(time, [scope, *@scopes])
end

def accept(a0)
names = a0.keys | self.attributes.keys
push(names.inject({}) { |a1, name|
a1.merge name => case new = self.attributes[name]
# If a0 yields a Gen, apply it
when Env: new.apply(name, a0[name], self)
# otherwise, inherit the attribute value from a0 if
# we haven't defined it
else self.attributes[name] || a0[name]
end
})
def accept(attributes)
push(Scope.new(top.offset, top.duration, attributes))
end

private
def top; @scopes.first end
end
end

class Scope
attr_reader :offset, :duration, :attributes

def initialize(offset, duration, attributes)
@offset, @duration, @attributes = offset, duration, attributes
end
end
end
2 changes: 1 addition & 1 deletion lib/music/score.rb
Expand Up @@ -207,7 +207,7 @@ def reverse
end

def eval(interpreter, c0)
c1 = c0.push(attributes.merge(:section_start => c0.time, :section_duration => duration))
c1 = c0.push(Scope.new(c0.time, duration, attributes))
m = score.eval(interpreter, c1)
interpreter.eval_section(m, c0)
end
Expand Down

0 comments on commit c5f9ba1

Please sign in to comment.