Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

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

edited February 2012 in Code Sharing Posts: 384

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

Tagged:

Comments

  • Posts: 118

    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()..")\n")
        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
    
    
  • Posts: 384

    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.

Sign In or Register to comment.