Sound Slider - generate the sound() call for programmatic use

Hi All,

If you find a cool sound using the picker and want to modify it programmatically, there are limitations. This program shows all sliders on the screen (thanks szleski for the Hslider class that I modified). It will generate the sound() parameters which you can copy and paste into your project. You might do something like change the StartFrequency like I did to make notes.

http://fredbogg.posterous.com/sound-slider-v01

Good idea @Fred! I had some problems with the sliders though, in the sense that if you move a slider and accidentally moved your finger a but in the vertical direction, you end up with changing the value of the next slider. I took the liberty of updating your program, adding multitouch support, saving the state in local storage, added integer slider for the WaveForm and putting the sliders in a table simplifying the overall program. I hope you approve!

-- Sound Slider
-- original author Fredbogg
-- adapted by Herwig Van Marck
function setup()
    print("double tap to reset sliders")
    print(SOUND_SQUAREWAVE)
    time = 0
    --displayMode( FULLSCREEN)
    x = 1.9
  --  iparameter("waveform",0,3,0)    
    --parameter("volume",0,1,1.0)
    sliders={}
    
    playDelaySlider = HSlider("playDelay",255,WIDTH/x, HEIGHT - 10, 0.1, 5, 2)
    
    table.insert(sliders, HSlider("StartFrequency",255,WIDTH/x, HEIGHT - 50, 0, 1, 0.5))
    table.insert(sliders, HSlider("AttackTime",255,WIDTH/x, HEIGHT - 90, 0, 1, 0))
    table.insert(sliders, HSlider("SustainTime",255,WIDTH/x, HEIGHT - 130, 0, 3, 0.5))
    table.insert(sliders, HSlider("SustainPunch",255,WIDTH/x, HEIGHT - 170, 0, 1, 0))
    table.insert(sliders, HSlider("DecayTime",255,WIDTH/x, HEIGHT - 210, 0, 3, 0))
    table.insert(sliders, HSlider("MinimumFrequency",255,WIDTH/x, HEIGHT - 250, 0, 1, 0))
    table.insert(sliders, HSlider("Slide",255,WIDTH/x, HEIGHT - 290, 0, 1, 0.5))
    table.insert(sliders, HSlider("DeltaSlide",255,WIDTH/x, HEIGHT - 330, 0, 1, 0.5))
    table.insert(sliders, HSlider("VibratoDepth",255,WIDTH/x, HEIGHT - 370, 0, 1, 0.5))
    table.insert(sliders, HSlider("VibratoSpeed",255,WIDTH/x, HEIGHT - 410, 0, 1, 0.5))
    table.insert(sliders, HSlider("ChangeAmount",255,WIDTH/x, HEIGHT - 450, 0, 1, 0.5))
    table.insert(sliders, HSlider("ChangeSpeed",255,WIDTH/x, HEIGHT - 490, 0, 1, 0.5))
    table.insert(sliders, HSlider("SquareDuty",255,WIDTH/x, HEIGHT - 530, 0, 1, 0.5))
    table.insert(sliders, HSlider("DutySweep",255,WIDTH/x, HEIGHT - 570, 0, 1, 0.5))
    table.insert(sliders, HSlider("RepeatSpeed",255,WIDTH/x, HEIGHT - 610, 0, 1, 0.5))
    table.insert(sliders, HSlider("PhaserSweep",255,WIDTH/x, HEIGHT - 650, 0, 1, 0.5))
    table.insert(sliders, HSlider("LowPassFilterCutoff",255,WIDTH/x, HEIGHT - 690, 0, 1, 1))
    table.insert(sliders, HSlider("LowPassFilterCutoffSweep",255,
        WIDTH/x, HEIGHT - 730, 0, 1, 0.5))
    table.insert(sliders, HSlider("LowPassFilterResonance",255,
        WIDTH/(10*x), HEIGHT - 10, 0, 1, 0.5))
    table.insert(sliders, HSlider("HighPassFilterCutoff",255,
        WIDTH/(10*x), HEIGHT - 50, 0, 1, 0.5))
    table.insert(sliders, HSlider("HighPassFilterCutoffSweep",255,
        WIDTH/(10*x), HEIGHT - 90, 0, 1, 0.5))
    table.insert(sliders, HSlider("Waveform",255,WIDTH/(10*x), HEIGHT - 130, 0, 3, 0,
        {"Square","Saw","Sine","Noise"}))
    table.insert(sliders, HSlider("Volume",255,WIDTH/(10*x), HEIGHT - 170, 0, 1, 1))
 
end

-- This function gets called once every frame
function draw()
    -- This sets the background color to black
    background(0, 0, 0)

    if CurrentOrientation == PORTRAIT then
        displayMode(FULLSCREEN)
    else 
        displayMode(STANDARD)
    end
    
    drawSliders()
    
    
    -- Do your drawing here

    
    time = time + DeltaTime
    if time > playDelaySlider.v then
        playSound()
        time = 0
    end
    
    
end

function buildSound()
    local str='snd={'
    for i=1,#sliders do
        slider=sliders[i]
        if (i~=1) then
            str = str .. ", "
        end
        str = str .. slider.name .. " = " .. slider.v
    end
    return str.."}"
end

function playSound()
    loadstring(buildSound())()
    sound(snd)
end

function touched(touch)
    for i=1,#sliders do
        sliders[i]:touched(touch)
    end
    playDelaySlider:touched(touch)
    
    if touch.state == ENDED then
        clearOutput()
        if touch.tapCount==2 then
            for i=1,#sliders do
                sliders[i]:reset()
            end
        end
        print("sound("..buildSound()..")\
")
    end
end

function drawSliders()
    for i=1,#sliders do
        sliders[i]:draw()
    end
    playDelaySlider:draw()
end

HSlider = class()

function HSlider:init(name,length,x, y, minv, maxv, v, intLabels)
    -- you can accept and set parameters here
    self.x = x
    self.y = y
    self.minv = minv
    self.maxv = maxv
    self.intLabels=intLabels
    self.default=v
    local val=readLocalData(name)
    if (val) then
        self.v=val
    else
        self.v = v
    end
    self.length = length
    self.name = name
    self.touchID=nil
end

function HSlider:draw()
    -- Codea does not automatically call this method
    pushStyle()
    stroke(255, 255, 255, 255)
    lineCapMode(PROJECT)
    strokeWidth(7)
    self:vtick(0, 5)
    self:vtick(self.length, 5)
    
    if ((self.intLabels) and (self.maxv - self.minv>1))then
        for tx=self.minv+1,self.maxv -1 do
            self:vtick((tx- self.minv) / (self.maxv - self.minv) * self.length,3)
        end
    end
    
    lineCapMode(SQUARE)
    line(self.x, self.y, self.x + self.length, self.y)
    lineCapMode(PROJECT)
    pushStyle()
    stroke(229, 42, 44, 255)
    self:vtick((self.v - self.minv) / (self.maxv - self.minv) * self.length, 7)
    popStyle()
    
    
    -- print the current value to the right
    if (self.intLabels) then
        text(self.intLabels[self.v+1],self.x+self.length+50,self.y)
    else
        text(self.v,self.x+self.length+50,self.y)
    end
    
    -- print the name of the slider to the left
    text(self.name, self.x+(self.length/2),self.y-10)
    popStyle()
end

function HSlider:vtick(x, y)
    if x + self.x >= self.x and x <= self.length then
        line(self.x + x, self.y - y, self.x + x, self.y + y) 
    end
end

function HSlider:reset()
    self.v=self.default
    saveLocalData(self.name,self.v)
end

function HSlider:touched(touch)
    -- Codea does not automatically call this method
    if touch.state == BEGAN then
        if touch.x >= self.x-20 and touch.x <= self.x + self.length + 20
                and math.abs(touch.y - self.y) < 20 then
                    self.touchID=touch.id
        end
    end
    if ((touch.state == MOVING) or (touch.state == BEGAN)) and (self.touchID==touch.id) then
        self.v = (touch.x - self.x) / self.length * (self.maxv - self.minv) + self.minv
        if self.intLabels then
            self.v=math.floor((touch.x - self.x) / self.length * (self.maxv - self.minv) + self.minv)
        else
            self.v = (touch.x - self.x) / self.length * (self.maxv - self.minv) + self.minv
        end
        if self.v > self.maxv then
            self.v = self.maxv
        end
        if self.v < self.minv then
            self.v = self.minv
        end
    end
    if (touch.state == ENDED) and (self.touched) then
        saveLocalData(self.name,self.v)
        self.touchID=nil
    end
end

Looks great, @Herwig! I’ll take it for a spin tonight. Thanks for cleaning up all that longhand! I was hoping someone might.

One of the things to add now would be a randomise feature, which I was simulating by scribbling my finger over the sliders! There is code available from sfxr on how to pseudo randomise it, as there are many combinations that result in silence.