I am interested in a function where you can pass in a take and the desired source time to convert to real time offset from the item's start position.
This would require taking into account the take's playrate and stretch markers.
I came up with a group of functions to essentially do this, however my results with dealing with sloped stretch markers isn't quite accurate, especially with drastic slopes and slow rates.
Does anyone know of any ways to convert audio source time to real time?
Here's what I've done so far:
Code:
function Reaper.getStretchMarkers(take)
local stretchMarkers = {}
local numStretchMarkers = reaper.GetTakeNumStretchMarkers(take)
for i = 1, numStretchMarkers do
local _, pos, srcPos = reaper.GetTakeStretchMarker(take, i - 1)
stretchMarkers[i] = {
pos = pos,
srcPos = srcPos,
slope = reaper.GetTakeStretchMarkerSlope(take, i - 1)
}
end
for index, marker in ipairs(stretchMarkers) do
local markerRate = 1.0
local markerLength = 0
if index < #stretchMarkers then
local nextMarker = stretchMarkers[index + 1]
markerLength = nextMarker.pos - marker.pos
markerSourceLength = nextMarker.srcPos - marker.srcPos
markerRate = markerSourceLength / markerLength * (1.0 - marker.slope)
end
marker.rate = markerRate
marker.length = markerLength
marker.srcLength = markerSourceLength
end
return stretchMarkers
end
function Reaper.getSourcePosition(take, time)
if time == nil then return nil end
local playrate = reaper.GetMediaItemTakeInfo_Value(take, "D_PLAYRATE")
local tempMarkerIndex = reaper.SetTakeStretchMarker(take, -1, time * playrate)
local _, pos, srcPos = reaper.GetTakeStretchMarker(take, tempMarkerIndex)
reaper.DeleteTakeStretchMarkers(take, tempMarkerIndex)
return srcPos
end
function Reaper.getSourceOffset(take)
return Reaper.getSourcePosition(take, 0.0)
end
function Reaper.getRealPosition(take, sourceTime)
if sourceTime == nil then return nil end
local startOffset = Reaper.getSourceOffset(take)
local playrate = reaper.GetMediaItemTakeInfo_Value(take, "D_PLAYRATE")
local stretchMarkers = Reaper.getStretchMarkers(take)
if #stretchMarkers < 1 then
return (sourceTime - startOffset) / playrate
end
local markerIndex = 0
for index, marker in ipairs(stretchMarkers) do
if sourceTime < marker.srcPos then
markerIndex = index - 1
break
end
if index == #stretchMarkers then
markerIndex = index
end
end
if markerIndex == 0 then
return (sourceTime - startOffset) / playrate
end
local activeMarker = stretchMarkers[markerIndex]
local relativeSourcePosition = sourceTime - activeMarker.srcPos
local actualSlope = 0.0
if activeMarker.srcLength > 0 and activeMarker.length > 0 then
actualSlope = (activeMarker.srcLength / activeMarker.length - activeMarker.rate) / (0.5 * activeMarker.srcLength)
end
local currentMarkerRate = activeMarker.rate + relativeSourcePosition * actualSlope
local averageMarkerRate = (activeMarker.rate + currentMarkerRate) * 0.5
local scaledOffset = relativeSourcePosition / averageMarkerRate
local realTime = activeMarker.pos + scaledOffset
return realTime / playrate
end