Sample Start/End in Macro Page?

“Thanks for the reply! I’ve tried several methods, but none seem to work quite right. The best approach I have so far involves using the plus/minus buttons to snap the start and end points to the grid. This code works perfectly for the StartStepPlus and StartStepMinus buttons—the start point snaps precisely to the grid, even when I change the tempo. However, as soon as I use the EndStepMinus and EndStepPlus buttons, everything gets messed up. The EndStepPlus button also doesn’t work at all.
Does anyone know why it’s working perfectly for the Start buttons but not for the End buttons?”

local layer = this.parent
local zones = this.parent:findZones()

zoneNames = {}
for i = 1, #zones do
    zoneNames[i] = zones[i].name
end

function zoneSelectChanged()
    getSampleLength()
    scope = "@0:Layer 01/@0:"..zones[ZoneSelect].name.."/"
end

defineParameter("ZoneSelect", nil, 1, zoneNames, zoneSelectChanged)
defineParameter("scope", nil, "")
defineParameter("SampleStart", nil, 0, 0, 0x7fffffff, 1)
defineParameter("SampleEnd", nil, 0, 0, 0x7fffffff, 1)
defineParameter("Filename", nil, "", function() onFilenameChanged() end)
-- New parameters for plus/minus switches
defineParameter("StartStepPlus", "Start +1/16", false, nil, function() stepStart(1) end)
defineParameter("StartStepMinus", "Start -1/16", false, nil, function() stepStart(-1) end)
defineParameter("EndStepPlus", "End +1/16", false, nil, function() stepEnd(1) end)
defineParameter("EndStepMinus", "End -1/16", false, nil, function() stepEnd(-1) end)

-- Calculate the size of one 1/16th step
function getGridStep(totalLength)
    return math.max(1, math.floor(totalLength / 16))
end

-- Function to step the start position
function stepStart(direction)
    local zone = zones[ZoneSelect]
    local totalLength = zone:getParameter("SampleOsc.SampleEnd")
    local gridStep = getGridStep(totalLength)
    
    -- Calculate new position
    local newStart = SampleStart + (gridStep * direction)
    
    -- Ensure we stay within bounds
    newStart = math.max(0, newStart)
    newStart = math.min(newStart, SampleEnd)
    
    -- Update parameters
    SampleStart = newStart
    zone:setParameter("SampleOsc.SampleStart", SampleStart)
    zone:setParameter("SampleOsc.SustainLoopStartA", SampleStart)
end

-- Function to step the end position
function stepEnd(direction)
    local zone = zones[ZoneSelect]
    local totalLength = zone:getParameter("SampleOsc.SampleEnd")
    local gridStep = getGridStep(totalLength)
    
    -- Calculate new position for SampleEnd
    local newEnd = SampleEnd + (gridStep * direction)
    
    -- Ensure we stay within bounds
    newEnd = math.max(SampleStart, newEnd) -- End point shouldn't be before start
    newEnd = math.min(newEnd, totalLength)  -- End point shouldn't exceed sample length
    
    -- Update parameters
    SampleEnd = newEnd
    zone:setParameter("SampleOsc.SampleEnd", SampleEnd)
    zone:setParameter("SampleOsc.SustainLoopEndA", SampleEnd)
end

function onFilenameChanged()
    local zone = zones[ZoneSelect]
    local sample = AudioFile.open(Filename)
    if sample.valid then
        zone:setParameter("SampleOsc.Filename", sample.fileName)
        zone:setParameter("SampleOsc.SampleStart", 0)
        zone:setParameter("SampleOsc.SampleEnd", sample.length)
        
        -- Define sample start and end parameters
        defineParameter("SampleStart", nil, 0, 0, sample.length, 1)
        defineParameter("SampleEnd", nil, sample.length, 0, sample.length, 1)
        SampleStart = 0
        SampleEnd = sample.length
        
        -- Set the sustain loop points
        zone:setParameter("SampleOsc.SustainLoopStartA", SampleStart)
        zone:setParameter("SampleOsc.SustainLoopEndA", SampleEnd)
    end
end

function getSampleLength()
    local zone = zones[ZoneSelect]
    local fn = zone:getParameter("SampleOsc.Filename")
    local sample = AudioFile.open(fn)
    if sample.valid then
        defineParameter("SampleStart", nil, 0, 0, sample.length, 1)
        defineParameter("SampleEnd", nil, sample.length, 0, sample.length, 1)
        
        SampleStart = zone:getParameter("SampleOsc.SampleStart")
        SampleEnd = zone:getParameter("SampleOsc.SampleEnd")
    end
end

function onLoad()
    zoneSelectChanged()
end

function onNote(e)
    playNote(e.note, e.velocity, -1, zones[ZoneSelect])
end