In implementations where you want named data, I've noticed that the 
algorithm gets obfuscated by lots of variable names with dots after them. 
For example, here is a basic analog model of a state variable filter used 
as a sine wave generator:

immutable SvfSinOscCoef
    g0::Float64
    g1::Float64
end
immutable SvfSinOsc
    ic1eq::Float64
    ic2eq::Float64
end
function SvfSinOscCoef_Init (;freq=1.0, sr=44100.0)    
    local g::Float64 = tan (2pi*freq/sr)
    local g0 = 1.0/(1.0+g^2)
    SvfSinOscCoef (g0,g*g0)
end
function SvfSinOsc_Init (startphase::Float64)
    SvfSinOsc (cos(startphase), sin(startphase))
end

But the tick function looks a bit messy:

function tick (state::SvfSinOsc, coef::SvfSinOscCoef)
    local v1::Float64 = coef.g0*state.ic1eq - coef.g1*state.ic2eq
    local v2::Float64 = coef.g1*state.ic1eq + coef.g0*state.ic2eq
    SvfSinOsc (2*v1 - state.ic1eq, 2*v2 - state.ic2eq)
end


It would be really cool if there was a way to shorthand the syntax of this 
to something like the following, which is a lot more readable:

function tick (state::SvfSinOsc, coef::SvfSinOscCoef)
    using s, c
    local v1::Float64 = g0*ic1eq - g1*ic2eq
    local v2::Float64 = g1*ic1eq + g0*ic2eq
    SvfSinOsc (2*v1 - ic1eq, 2*v2 - ic2eq)
end


Lots of algorithms have arguments with the same type, but even then you 
could still specify using just the most used argument, but if it doesn't 
help make things more clear or isn't useful then people don't have to use 
it at all.



Another pattern that would be nice to handle cleanly is: fetch state to 
local, compute on local, store local to state. I have written code that 
generates code to handle this since it is such a pain to keep everything in 
sync, but if there was some way to automate this at the language level then 
it would really rock, so here is an example of the longhand way, which 
isn't too bad for this example, but just imagine if there are 20 or so 
variables, and you are writing multiple tick functions:

type SvfSinOsc
    ic1eq::Float64
    ic2eq::Float64
end

function tick (state::SvfSinOsc, coef::SvfSinOscCoef)
    local ic1eq::Float64 = state.ic1eq
    local ic2eq::Float64 = state.ic2eq
    for i = 1:100
        # compute algorithm using local copies of state.ic1eq and 
state.ic2eq
    end
    state.ic1eq = ic1eq
    state.ic2eq = ic2eq
    return state
end


I have a feeling that macros may be able to help out here to result in 
something like:

function tick (state::SvfSinOsc, coef::SvfSinOscCoef)
    @fetch state
    for i = 1:100
        # compute iterative algorithm using local copies of state.ic1eq and 
state.ic2eq
    end
    @store state
    return state
end

But I'm not sure how to code such a beast, I tried something like:

macro fetch(obj::SvfSinOsc)
    return quote
        local ic1eq = obj.ic1eq
        local ic2eq = obj.ic2eq
    end
end

macro store(obj::SvfSinOsc)
    return quote
        obj.ic1eq = ic1eq
        obj.ic2eq = ic2eq
    end
end

dump(osc)
macroexpand (:(@fetch osc))
macroexpand (:(@store osc))

SvfSinOsc 
  ic1eq: Float64 1.0
  ic2eq: Float64 0.0


Out[28]: :($(Expr(:error, 
TypeError(:anonymous,"typeassert",SvfSinOsc,:osc))))







Reply via email to