OpenAssociatedReaperProject_Script.lua (5584B)
1 --[[ 2 @description OpenAssociatedReaperProject_Script 3 @author Audiokinetic 4 @noindex 5 @provides 6 [nomain] . https://raw.githubusercontent.com/audiokinetic/Reaper-Tools/$commit/OpenAssociatedReaperProject/OpenAssociatedReaperProject_Script.lua 7 @about 8 The script opens up the associated REAPER project of a wav file based on his metadata. 9 @license 10 Copyright (c) 2023 AUDIOKINETIC Inc. 11 12 The script in this file is licensed to use under the license available at: 13 https://raw.githubusercontent.com/audiokinetic/Reaper-Tools/main/License.txt (the "License"). 14 You may not use this file except in compliance with the License. 15 16 Unless required by applicable law or agreed to in writing, software distributed 17 under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 18 CONDITIONS OF ANY KIND, either express or implied. See the License for the 19 specific language governing permissions and limitations under the License. 20 ]]-- 21 22 info = debug.getinfo(1,'S') 23 scriptPath = info.source:match[[^@?(.*[\/])[^\/]-$]] 24 local utils = dofile(scriptPath.."Utilities.lua") 25 26 local tempProject, _ = reaper.EnumProjects( -1, "" ) 27 28 local firstTrack = reaper.GetTrack(utils.CURRENT_PROJECT, 0) 29 30 if not firstTrack then 31 reaper.ShowMessageBox("No audio file sent to REAPER!", "Open Associated REAPER Project: Failed", utils.OK_MESSAGE_BOX) 32 return 33 end 34 35 local mediaItemCount = reaper.CountTrackMediaItems(firstTrack) 36 local mediaItem = reaper.GetTrackMediaItem(firstTrack, 0) 37 local mediaItemTake = reaper.GetActiveTake(mediaItem) 38 local pcmSource = reaper.GetMediaItemTake_Source(mediaItemTake) 39 local filePath = reaper.GetMediaSourceFileName(pcmSource) 40 41 if not reaper.file_exists(filePath) then 42 reaper.ShowMessageBox("Unable to locate file `" .. filePath .. "`", "Open Associated REAPER Project: Failed", utils.OK_MESSAGE_BOX) 43 return 44 end 45 46 -- Read data from wav header -- 47 local pcmSource = reaper.PCM_Source_CreateFromFile(filePath) 48 local projectName = utils.getMetadata(pcmSource, {"IXML:PROJECT", "IXML:Project", "IXML:project", "INFO:INAME"}) 49 local startOffset = utils.getMetadata(pcmSource, {"Generic:StartOffset"}) 50 local trackName = utils.getMetadata(pcmSource, {"IXML:USER:trackName", "IXML:USER:TRACKNAME", "IXML:USER:TrackName", "IXML:USER:trackname"}) 51 52 if startOffset == nil then 53 startOffset = "0:00.000" 54 end 55 56 if not projectName then 57 reaper.ShowMessageBox("IXML:PROJECT header missing or empty in selected file. The script expects the IXML:PROJECT header to contain the associated project name. Make sure 'Embed title/date/time if not provided' and 'Embed start offset' option in the Project Render Metadata are enabled.", "Open Associated REAPER Project: Failed", utils.OK_MESSAGE_BOX) 58 return 59 end 60 61 local projectDirectory = utils.getParentDirectory(filePath) 62 63 local info = debug.getinfo(1, 'S') 64 local scriptPath = info.source:match[[^@?(.*[\/])[^\/]-$]] 65 local reaperProjectsRootPath = scriptPath.."ReaperProjectsRoot.txt" 66 local file, err = io.open(reaperProjectsRootPath, "r") 67 local reaperProjectsRoot = os.getenv("REAPERPROJECTSROOT") 68 if file and not reaperProjectsRoot then 69 reaperProjectsRoot = file:read() 70 file:close() 71 end 72 73 local function findRppFile(dir, rppFile) 74 local i = 0 75 local file = reaper.EnumerateFiles(dir, i) 76 repeat 77 if file ~= nil and file == rppFile then 78 return dir .. utils.SEPARATOR_CHAR .. file 79 end 80 i = i + 1 81 file = reaper.EnumerateFiles(dir, i) 82 until file == nil 83 84 i = 0 85 local subDir = reaper.EnumerateSubdirectories(dir, i) 86 repeat 87 if subDir ~= nil then 88 local ret = findRppFile(dir .. utils.SEPARATOR_CHAR .. subDir, rppFile) 89 if ret ~= nil then 90 return ret 91 end 92 i = i + 1 93 subDir = reaper.EnumerateSubdirectories(dir, i) 94 end 95 until subDir == nil 96 return nil 97 end 98 99 local projectPath = findRppFile(reaperProjectsRoot, projectName .. ".rpp") 100 101 if not projectPath then 102 projectName = string.gsub(projectName, "\n", " ") 103 reaper.ShowMessageBox("Unable to locate project `" .. projectName .. "` in `" .. reaperProjectsRoot .. "`", "Open Associated REAPER Project: Failed", utils.OK_MESSAGE_BOX) 104 return 105 end 106 107 -- Open project and set cursor to start offset -- 108 reaper.Main_OnCommand(41929, 0) -- opens new project tab 109 reaper.Main_openProject("noprompt:" .. projectPath) 110 111 local project, _ = reaper.EnumProjects( -1, "" ) 112 113 local markersAndRegions, _, _ = reaper.CountProjectMarkers(utils.CURRENT_PROJECT) 114 115 local buf = "" 116 for i = 0, markersAndRegions - 1 do 117 local _, isRegion, currentRegionPos, _, currentRegion, index, _ = reaper.EnumProjectMarkers3(0, i) 118 119 if isRegion and reaper.format_timestr(currentRegionPos, buf) == startOffset then 120 reaper.GoToRegion(0, index, true) 121 reaper.adjustZoom(100, 1, true, -1) 122 break 123 end 124 end 125 126 local trackView = reaper.JS_Window_FindChildByID(reaper.GetMainHwnd(), utils.TRACK_VIEW_ID) 127 128 reaper.Main_OnCommand(40297,0) -- deselect all tracks 129 130 if trackName then 131 for i = 0, reaper.CountTracks() - 1 do 132 local currentTrack = reaper.GetTrack(utils.CURRENT_PROJECT, i) 133 local _, currentTrackName = reaper.GetTrackName(currentTrack) 134 135 if currentTrackName == trackName then 136 reaper.SetTrackSelected(currentTrack, true) 137 138 -- Get Y postion of track and then scroll to it 139 local yPosition = reaper.GetMediaTrackInfo_Value(currentTrack, "I_TCPY") 140 reaper.JS_Window_SetScrollPos(trackView, "v", yPosition) 141 break 142 end 143 end 144 end 145 146 reaper.SelectProjectInstance(tempProject) 147 reaper.Main_OnCommand(40860,0) -- close current project tab 148 reaper.SelectProjectInstance(project)