Old 08-26-2020, 06:54 AM   #1
BirdBird
Human being with feelings
 
BirdBird's Avatar
 
Join Date: Mar 2019
Posts: 235
Default Razor Edit Scripts

While the other threads are busy discussing features and implementation details I thought it would be nice to have a thread for experimenting with scripts now that we have access to API.


Here are some wrapper functions around the "basic API" that are hopefully a bit more approachable. (Lua)
This stuff will likely break in the future, but it is nice to have something that makes it easier to play around with razor edits in the meanwhile. Place this at the top of your code:
Code:
function literalize(str)
    return str:gsub("[%(%)%.%%%+%-%*%?%[%]%^%$]", function(c) return "%" .. c end)
end

function GetGUIDFromEnvelope(envelope)
    local ret2, envelopeChunk = reaper.GetEnvelopeStateChunk(envelope, "")
    local GUID = "{" ..  string.match(envelopeChunk, "GUID {(%S+)}") .. "}"
    return GUID
end

function GetItemsInRange(track, areaStart, areaEnd)
    local items = {}
    local itemCount = reaper.CountTrackMediaItems(track)
    for k = 0, itemCount - 1 do 
        local item = reaper.GetTrackMediaItem(track, k)
        local pos = reaper.GetMediaItemInfo_Value(item, "D_POSITION")
        local length = reaper.GetMediaItemInfo_Value(item, "D_LENGTH")
        local itemEndPos = pos+length

        --check if item is in area bounds
        if (itemEndPos > areaStart and itemEndPos <= areaEnd) or
            (pos >= areaStart and pos < areaEnd) or
            (pos <= areaStart and itemEndPos >= areaEnd) then
                table.insert(items,item)
        end
    end

    return items
end

function GetEnvelopePointsInRange(envelopeTrack, areaStart, areaEnd)
    local envelopePoints = {}

    for i = 1, reaper.CountEnvelopePoints(envelopeTrack) do
        local retval, time, value, shape, tension, selected = reaper.GetEnvelopePoint(envelopeTrack, i - 1)

        if time >= areaStart and time <= areaEnd then --point is in range
            envelopePoints[#envelopePoints + 1] = {
                id = i-1 ,
                time = time,
                value = value,
                shape = shape,
                tension = tension,
                selected = selected
            }
        end
    end

    return envelopePoints
end

function SetTrackRazorEdit(track, areaStart, areaEnd, clearSelection)
    if clearSelection == nil then clearSelection = false end
    
    if clearSelection then
        local ret, area = reaper.GetSetMediaTrackInfo_String(track, 'P_RAZOREDITS', '', false)
    
        --parse string, all this string stuff could probably be written better
        local str = {}
        for j in string.gmatch(area, "%S+") do
            table.insert(str, j)
        end
        
        --strip existing selections across the track
        local j = 1
        while j <= #str do
            local GUID = str[j+2]
            if GUID == '""' then 
                str[j] = ''
                str[j+1] = ''
                str[j+2] = ''
            end

            j = j + 3
        end

        --insert razor edit 
        local REstr = tostring(areaStart) .. ' ' .. tostring(areaEnd) .. ' ""'
        table.insert(str, REstr)

        local finalStr = ''
        for i = 1, #str do
            local space = i == 1 and '' or ' '
            finalStr = finalStr .. space .. str[i]
        end

        local ret, area = reaper.GetSetMediaTrackInfo_String(track, 'P_RAZOREDITS', finalStr, true)
        return ret
    else         
        local ret, area = reaper.GetSetMediaTrackInfo_String(track, 'P_RAZOREDITS', '', false)
        local str = area ~= nil and area .. ' ' or ''
        str = str .. tostring(areaStart) .. ' ' .. tostring(areaEnd) .. '  ""'
        
        local ret, area = reaper.GetSetMediaTrackInfo_String(track, 'P_RAZOREDITS', str, true)
        return ret
    end
end

function SetEnvelopeRazorEdit(envelope, areaStart, areaEnd, clearSelection, GUID)
    local GUID = GUID == nil and GetGUIDFromEnvelope(envelope) or GUID
    local track = reaper.Envelope_GetParentTrack(envelope)

    if clearSelection then
        local ret, area = reaper.GetSetMediaTrackInfo_String(track, 'P_RAZOREDITS', '', false)
    
        --parse string
        local str = {}
        for j in string.gmatch(area, "%S+") do
            table.insert(str, j)
        end
        
        --strip existing selections across the envelope
        local j = 1
        while j <= #str do
            local envGUID = str[j+2]
            if GUID ~= '""' and envGUID:sub(2,-2) == GUID then 
                str[j] = ''
                str[j+1] = ''
                str[j+2] = ''
            end

            j = j + 3
        end

        --insert razor edit
        local REstr = tostring(areaStart) .. ' ' .. tostring(areaEnd) .. ' ' .. GUID
        table.insert(str, REstr)

        local finalStr = ''
        for i = 1, #str do
            local space = i == 1 and '' or ' '
            finalStr = finalStr .. space .. str[i]
        end

        local ret, area = reaper.GetSetMediaTrackInfo_String(track, 'P_RAZOREDITS', finalStr, true)
        return ret
    else         
        local ret, area = reaper.GetSetMediaTrackInfo_String(track, 'P_RAZOREDITS', '', false)

        local str = area ~= nil and area .. ' ' or ''
        str = str .. tostring(areaStart) .. ' ' .. tostring(areaEnd) .. ' ' .. GUID
        
        local ret, area = reaper.GetSetMediaTrackInfo_String(track, 'P_RAZOREDITS', str, true)
        return ret
    end
end

function GetRazorEdits()
    local trackCount = reaper.CountTracks(0)
    local areaMap = {}
    for i = 0, trackCount - 1 do
        local track = reaper.GetTrack(0, i)
        local ret, area = reaper.GetSetMediaTrackInfo_String(track, 'P_RAZOREDITS', '', false)
        if area ~= '' then
            --PARSE STRING
            local str = {}
            for j in string.gmatch(area, "%S+") do
                table.insert(str, j)
            end
        
            --FILL AREA DATA
            local j = 1
            while j <= #str do
                --area data
                local areaStart = tonumber(str[j])
                local areaEnd = tonumber(str[j+1])
                local GUID = str[j+2]
                local isEnvelope = GUID ~= '""'

                --get item/envelope data
                local items = {}
                local envelopeName, envelope
                local envelopePoints
                
                if not isEnvelope then
                    items = GetItemsInRange(track, areaStart, areaEnd)
                else
                    envelope = reaper.GetTrackEnvelopeByChunkName(track, GUID:sub(2, -2))
                    local ret, envName = reaper.GetEnvelopeName(envelope)

                    envelopeName = envName
                    envelopePoints = GetEnvelopePointsInRange(envelope, areaStart, areaEnd)
                end

                local areaData = {
                    areaStart = areaStart,
                    areaEnd = areaEnd,
                    
                    track = track,
                    items = items,
                    
                    --envelope data
                    isEnvelope = isEnvelope,
                    envelope = envelope,
                    envelopeName = envelopeName,
                    envelopePoints = envelopePoints,
                    GUID = GUID:sub(2, -2)
                }

                table.insert(areaMap, areaData)

                j = j + 3
            end
        end
    end

    return areaMap
end

function SplitRazorEdits(razorEdits)
    local areaItems = {}
    local tracks = {}
    reaper.PreventUIRefresh(1)
    for i = 1, #razorEdits do
        local areaData = razorEdits[i]
        if not areaData.isEnvelope then
            local items = areaData.items
            
            --recalculate item data for tracks with previous splits
            if tracks[areaData.track] ~= nil then 
                items = GetItemsInRange(areaData.track, areaData.areaStart, areaData.areaEnd)
            end
            
            for j = 1, #items do 
                local item = items[j]
                --split items 
                local newItem = reaper.SplitMediaItem(item, areaData.areaStart)
                if newItem == nil then
                    reaper.SplitMediaItem(item, areaData.areaEnd)
                    table.insert(areaItems, item)
                else
                    reaper.SplitMediaItem(newItem, areaData.areaEnd)
                    table.insert(areaItems, newItem)
                end
            end

            tracks[areaData.track] = 1
        end
    end
    reaper.PreventUIRefresh(-1)
    
    return areaItems
end
Moved the explanations/examples over to this post as they no longer fit here: https://forum.cockos.com/showpost.ph...9&postcount=73

Last edited by BirdBird; 09-01-2020 at 04:03 PM.
BirdBird is offline   Reply With Quote
Old 08-26-2020, 02:47 PM   #2
X-Raym
Human being with feelings
 
X-Raym's Avatar
 
Join Date: Apr 2013
Location: France
Posts: 7,210
Default

meo-mespotine will like this code snippets for sure :P




Thanks for sharing !
X-Raym is offline   Reply With Quote
Old 08-27-2020, 12:55 AM   #3
sonictim
Human being with feelings
 
sonictim's Avatar
 
Join Date: Feb 2020
Location: Los Angeles
Posts: 353
Default

I just wrote a very simple one that returns true or false if a Razor Edit exists anywhere in your session....... I don't know how you get those cool code snippet windows. Fortunately my script is short....

Code:
 
function RazorEditSelectionExists()

    for i=0, reaper.CountTracks(0)-1 do

        local retval, x = reaper.GetSetMediaTrackInfo_String(reaper.GetTrack(0,i), "P_RAZOREDITS", "string", false)

        if x ~= "" then return true end

    end--for
    
    return false

end--RazorEditSelectionExists()

Last edited by sonictim; 10-30-2020 at 09:12 AM. Reason: code brackets
sonictim is offline   Reply With Quote
Old 08-27-2020, 02:03 AM   #4
sonictim
Human being with feelings
 
sonictim's Avatar
 
Join Date: Feb 2020
Location: Los Angeles
Posts: 353
Default Link Razor Edit with Item Selection

BirdBird! Thank you...

Using your code, and the code I just posted, I just wrote a quick defer function that will link area selection with item selection. Now I'm using my Razor Edit also as a Marquee Selection! I'm a novice coder (was my first time using defer) so if anyone notices any problems with it, please let me know

Code:
 
function Main()

if RazorEditSelectionExists() then

      local selections = GetRazorEdits()
      for i = 1, #selections do
          local areaData = selections[i]
          local items = areaData.items
          for j = 1, #items do reaper.SetMediaItemSelected(items[j], true) end
      end
end--if

reaper.defer(Main)


end--Main()


Main()
Attached Files
File Type: lua TJF LINK Razor Edit and Item Selection.lua (3.7 KB, 87 views)

Last edited by sonictim; 08-27-2020 at 02:36 PM. Reason: updating code
sonictim is offline   Reply With Quote
Old 08-27-2020, 06:47 AM   #5
X-Raym
Human being with feelings
 
X-Raym's Avatar
 
Join Date: Apr 2013
Location: France
Posts: 7,210
Default

@sonictim


to emebed mua code on fprum post use [ code][ /code] syntax without spaces. :P
X-Raym is offline   Reply With Quote
Old 08-27-2020, 09:03 AM   #6
foxAsteria
Human being with feelings
 
foxAsteria's Avatar
 
Join Date: Dec 2009
Location: Oblivion
Posts: 7,870
Default

I can't find other threads discussing the feature...what is razor edit?
__________________
My Wyyyrd Music
foxAsteria is online now   Reply With Quote
Old 08-27-2020, 06:47 AM   #7
Meo-Ada Mespotine
Human being with feelings
 
Meo-Ada Mespotine's Avatar
 
Join Date: Apr 2020
Location: Leipzig
Posts: 2,117
Default

Quote:
Originally Posted by X-Raym View Post
meo-mespotine will like this code snippets for sure :P




Thanks for sharing !
How did you know that?


@sonictim

please put [CODE] brackets arounds your code. Just select the code and hit the #-button in the editor. Otherwise, the forum's layouting could break things.
And it's better readable that way.
__________________
Use you/she/her, when contacting me, please. Thanks :) Not mentoring via PMs, sorry.
Ultraschall-API - 1385 ReaScript functions for Reaper - Reaper Internals - Developerdocs4Reaper - Donate, if you wish
Meo-Ada Mespotine is offline   Reply With Quote
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -7. The time now is 08:41 AM.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2021, vBulletin Solutions Inc.