├── LICENSE ├── README.md ├── dsh Make or rename region based on prior marker.lua ├── dsh_Decrease item rate by 1 cent.lua ├── dsh_Delete_quiet_clips.lua ├── dsh_Increase item rate by 1 cent.lua ├── dsh_Name_and_number_all_regions.lua ├── dsh_Number all duplicate regions.lua └── dsh_Update_Region_Based_on_Item_Bounds.lua /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 David Hilowitz 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # REAPER-Scripts 2 | Various REAPER scripts that I use in creating sample libraries 3 | 4 | - dsh_Decrease item rate by 1 cent: Decreases item's rate by 1 cent. I map this to Shift+3. 5 | - dsh_Increase item rate by 1 cent: Boosts an item's rate by 1 cent. I map this to Shift+4. 6 | - dsh_Update_Region_Based_on_Item_Bounds: If you've got an item and a region that is almost the same size as the item, run this script and it will resize the region to match the items bounds exactly. 7 | -------------------------------------------------------------------------------- /dsh Make or rename region based on prior marker.lua: -------------------------------------------------------------------------------- 1 | MediaItem = reaper.GetSelectedMediaItem(0, 0) -- the first "0" stands for "current project tab", the second one means "the first of all selected items" 2 | Item_Start_Time = reaper.GetMediaItemInfo_Value(MediaItem, "D_POSITION"); 3 | Item_End_Time = Item_Start_Time + reaper.GetMediaItemInfo_Value(MediaItem, "D_LENGTH") 4 | markeridx, regionidx = reaper.GetLastMarkerAndCurRegion(0, Item_Start_Time) 5 | 6 | if markeridx == NULL then return end 7 | 8 | retval, isrgn, pos, rgnend, markername, markrgnindexnumber = reaper.EnumProjectMarkers(markeridx) 9 | local NewName = markername 10 | 11 | MediaItemTake = reaper.GetActiveTake(MediaItem) 12 | reaper.GetSetMediaItemTakeInfo_String(MediaItemTake , "P_NAME", NewName, true) -- "True" makes the function set a new name ("False" would give you the current name in the function's return) 13 | 14 | 15 | if(regionidx ~= -1) then 16 | retval, isrgn, pos, rgnend, regionname, markrgnindexnumber = reaper.EnumProjectMarkers(regionidx) 17 | reaper.SetProjectMarker(markrgnindexnumber, true, Item_Start_Time, Item_End_Time, NewName) 18 | else 19 | reaper.AddProjectMarker(0, true, Item_Start_Time, Item_End_Time, NewName, -1) 20 | end 21 | 22 | 23 | -------------------------------------------------------------------------------- /dsh_Decrease item rate by 1 cent.lua: -------------------------------------------------------------------------------- 1 | newRate=1.00059463445332746; 2 | 3 | item_count = reaper.CountSelectedMediaItems(0) 4 | 5 | for i=0, item_count do 6 | item = reaper.GetSelectedMediaItem(0, i); 7 | if not item then 8 | break 9 | end 10 | take = reaper.GetActiveTake(item); 11 | if not take then 12 | break 13 | end 14 | rate = reaper.GetMediaItemTakeInfo_Value(take, "D_PLAYRATE"); 15 | reaper.SetMediaItemTakeInfo_Value(take, "D_PLAYRATE", rate/newRate); 16 | end 17 | 18 | reaper.UpdateArrange(); 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /dsh_Delete_quiet_clips.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | * Version: 1.0 3 | * Main: False 4 | --]] 5 | 6 | ---------------------------------------------------------- 7 | -- A function to get the maximum peak value from a take -- 8 | -- (+ an example for how to use the function) -- 9 | ---------------------------------------------------------- 10 | 11 | -- Function description -- 12 | -- retval, maximum peak value, maximum peak pos = get_sample_max_val_and_pos(MediaItem_Take, bool adj_for_take_vol, bool adj_for_item_vol, bool val_is_dB) 13 | 14 | -- Returns false if failed 15 | -- maximum peak value: Peak value is returned in decibels if val_is_dB = true 16 | -- maximum peak pos: Peak sample position in item time 17 | 18 | function get_sample_max_val_and_pos(take, adj_for_take_vol, adj_for_item_vol, val_is_dB) 19 | local ret = false 20 | if take == nil then 21 | return 22 | end 23 | 24 | local item = reaper.GetMediaItemTake_Item(take) -- Get parent item 25 | 26 | if item == nil then 27 | return 28 | end 29 | 30 | local item_pos = reaper.GetMediaItemInfo_Value(item, "D_POSITION") 31 | 32 | -- Get media source of media item take 33 | local take_pcm_source = reaper.GetMediaItemTake_Source(take) 34 | if take_pcm_source == nil then 35 | return 36 | end 37 | 38 | -- Create take audio accessor 39 | local aa = reaper.CreateTakeAudioAccessor(take) 40 | if aa == nil then 41 | return 42 | end 43 | 44 | -- Get the start time of the audio that can be returned from this accessor 45 | local aa_start = reaper.GetAudioAccessorStartTime(aa) 46 | -- Get the end time of the audio that can be returned from this accessor 47 | local aa_end = reaper.GetAudioAccessorEndTime(aa) 48 | 49 | 50 | -- Get the length of the source media. If the media source is beat-based, 51 | -- the length will be in quarter notes, otherwise it will be in seconds. 52 | local take_source_len, length_is_QN = reaper.GetMediaSourceLength(take_pcm_source) 53 | if length_is_QN then 54 | return 55 | end 56 | 57 | -- Get the number of channels in the source media. 58 | local take_source_num_channels = reaper.GetMediaSourceNumChannels(take_pcm_source) 59 | 60 | local channel_data = {} -- max peak values (per channel) are collected to this table 61 | -- Initialize channel_data table 62 | for i=1, take_source_num_channels do 63 | channel_data[i] = { 64 | peak_val = 0, 65 | peak_sample_index = -1 66 | } 67 | end 68 | 69 | -- Get the sample rate. MIDI source media will return zero. 70 | local take_source_sample_rate = reaper.GetMediaSourceSampleRate(take_pcm_source) 71 | if take_source_sample_rate == 0 then 72 | return 73 | end 74 | 75 | -- How many samples are taken from audio accessor and put in the buffer 76 | local samples_per_channel = take_source_sample_rate 77 | 78 | -- Samples are collected to this buffer 79 | local buffer = reaper.new_array(samples_per_channel * take_source_num_channels) 80 | 81 | -- (These are not needed at the moment) 82 | --local take_start_offset = reaper.GetMediaItemTakeInfo_Value(take, "D_STARTOFFS") 83 | --local take_playrate = reaper.GetMediaItemTakeInfo_Value(take, "D_PLAYRATE") 84 | --take_pos = item_pos-start_offs 85 | 86 | local total_samples = math.ceil((aa_end - aa_start) * take_source_sample_rate) 87 | --total_samples = math.floor((aa_end - aa_start) * take_source_sample_rate) 88 | --total_samples = (aa_end - aa_start) * take_source_sample_rate 89 | 90 | local block = 0 91 | local sample_count = 0 92 | local audio_end_reached = false 93 | local offs = aa_start 94 | 95 | local log10 = function(x) return math.log(x, 10) end 96 | local abs = math.abs 97 | --local floor = math.floor 98 | 99 | 100 | -- Loop through samples 101 | while sample_count < total_samples do 102 | if audio_end_reached then 103 | break 104 | end 105 | 106 | -- Get a block of samples from the audio accessor. 107 | -- Samples are extracted immediately pre-FX, 108 | -- and returned interleaved (first sample of first channel, 109 | -- first sample of second channel...). Returns 0 if no audio, 1 if audio, -1 on error. 110 | local aa_ret = 111 | reaper.GetAudioAccessorSamples( 112 | aa, -- AudioAccessor accessor 113 | take_source_sample_rate, -- integer samplerate 114 | take_source_num_channels, -- integer numchannels 115 | offs, -- number starttime_sec 116 | samples_per_channel, -- integer numsamplesperchannel 117 | buffer -- reaper.array samplebuffer 118 | ) 119 | 120 | if aa_ret <= 0 then 121 | --msg("no audio or other error") 122 | --return 123 | end 124 | 125 | for i=1, #buffer, take_source_num_channels do 126 | if sample_count == total_samples then 127 | audio_end_reached = true 128 | break 129 | end 130 | for j=1, take_source_num_channels do 131 | local buf_pos = i+j-1 132 | local curr_val = abs(buffer[buf_pos]) 133 | if curr_val > channel_data[j].peak_val then 134 | -- store current peak value for this channel 135 | channel_data[j].peak_val = curr_val 136 | -- store current peak sample index for this channel 137 | channel_data[j].peak_sample_index = sample_count 138 | end 139 | end 140 | sample_count = sample_count + 1 141 | end 142 | block = block + 1 143 | offs = offs + samples_per_channel / take_source_sample_rate -- new offset in take source (seconds) 144 | end 145 | 146 | reaper.DestroyAudioAccessor(aa) 147 | 148 | local max_peak_val = 0 149 | local channel = 0 150 | local peak_sample_index = -1 151 | 152 | -- Collect data to "peak_values" -table 153 | for i=1, take_source_num_channels do 154 | if channel_data[i].peak_val > max_peak_val then 155 | -- get max peak value from "channel_data" table 156 | max_peak_val = channel_data[i].peak_val 157 | -- get peak sample index from "channel_data" table 158 | peak_sample_index = channel_data[i].peak_sample_index 159 | -- max_peak_val found -> store current channel index 160 | -- channel = i 161 | end 162 | end 163 | 164 | --peak_values[#peak_values + 1] = max_peak_val 165 | --[[ 166 | local cursor_pos = item_pos + peak_sample_index/take_source_sample_rate 167 | reaper.SetEditCurPos(cursor_pos, true, false) 168 | reaper.UpdateArrange() 169 | --]] 170 | 171 | 172 | --reaper.UpdateArrange() 173 | --msg("Getting samples from take " .. tostring(i) .. "/" .. tostring(reaper.CountSelectedMediaItems(0))) 174 | -- end 175 | 176 | 177 | -- Calculate corrections for take/item volume 178 | if adj_for_take_vol then 179 | max_peak_val = max_peak_val * reaper.GetMediaItemTakeInfo_Value(take, "D_VOL") 180 | end 181 | 182 | if adj_for_item_vol then 183 | max_peak_val = max_peak_val * reaper.GetMediaItemInfo_Value(item, "D_VOL") 184 | end 185 | 186 | if val_is_dB then 187 | max_peak_val = 20*log10(max_peak_val) 188 | end 189 | 190 | local peak_sample_pos = peak_sample_index/take_source_sample_rate 191 | 192 | if max_peak_val > 0 then 193 | ret = true 194 | end 195 | 196 | if peak_sample_pos >= 0 then 197 | ret = true 198 | end 199 | 200 | return ret, max_peak_val, peak_sample_pos 201 | end 202 | 203 | -- USER CONFIG AREA ----------------------------------------------------------- 204 | 205 | console = true -- true/false: display debug messages in the console 206 | popup = true 207 | vars = { 208 | silence = -45, 209 | } 210 | 211 | ext_name = "DSH_DeleteQuietItems" 212 | 213 | ------------------------------------------------------- END OF USER CONFIG AREA 214 | 215 | 216 | -- UTILITIES ------------------------------------------------------------- 217 | 218 | -- Save item selection 219 | function AnalyzeSelectedItems () 220 | for i = 0, count_sel_items - 1 do 221 | local entry = {} 222 | entry.item = reaper.GetSelectedMediaItem(0,i) 223 | local take = reaper.GetActiveTake( entry.item ) 224 | if take then 225 | retval,entry.maximum_peak_value, maximum_peak_pos = get_sample_max_val_and_pos(take, false, false, true) 226 | Msg("Item " .. i+1 .. " has peak of " .. entry.maximum_peak_value .. "dBs") 227 | table.insert(init_sel_items, entry) 228 | end 229 | end 230 | end 231 | 232 | 233 | -- Display a message in the console for debugging 234 | function Msg(value) 235 | if console then 236 | reaper.ShowConsoleMsg(tostring(value) .. "\n") 237 | end 238 | end 239 | 240 | function SaveState() 241 | for k, v in pairs( vars ) do 242 | SaveExtState( k, v ) 243 | end 244 | end 245 | 246 | function SaveExtState( var, val) 247 | reaper.SetExtState( ext_name, var, tostring(val), true ) 248 | end 249 | 250 | function GetExtState( var, val ) 251 | if reaper.HasExtState( ext_name, var ) then 252 | local t = type( val ) 253 | val = reaper.GetExtState( ext_name, var ) 254 | if t == "boolean" then val = toboolean( val ) 255 | elseif t == "number" then val = tonumber( val ) 256 | else 257 | end 258 | end 259 | return val 260 | end 261 | 262 | --------------------------------------------------------- END OF UTILITIES 263 | 264 | 265 | -- See if there is items selected 266 | count_sel_items = reaper.CountSelectedMediaItems(0) 267 | 268 | if count_sel_items > 0 then 269 | reaper.ClearConsole() 270 | 271 | for k, v in pairs( vars ) do 272 | vars[k] = GetExtState( k, vars[k] ) 273 | 274 | end 275 | 276 | instructions = { 277 | "Silence Threshold (-90/0, -45)" 278 | } 279 | 280 | default_val = { 281 | vars.silence 282 | } 283 | 284 | retval, retvals_csv = reaper.GetUserInputs( "Delete quiet items", #instructions, table.concat(instructions, ','), table.concat(default_val, ',') ) 285 | 286 | if retvals_csv then 287 | vars.silence = retvals_csv:match("([^,]+)") 288 | vars.silence = tonumber( vars.silence ) 289 | if vars.silence then 290 | vars.silence = math.max( -90, math.min( vars.silence, 0 ) ) 291 | end 292 | 293 | end 294 | 295 | if (not popup or retval) and vars.silence then 296 | 297 | reaper.PreventUIRefresh(1) 298 | 299 | reaper.Undo_BeginBlock() -- Begining of the undo block. Leave it at the top of your main function. 300 | 301 | init_sel_items = {} 302 | AnalyzeSelectedItems(init_sel_items) 303 | 304 | for j, entry in ipairs( init_sel_items ) do 305 | if entry.maximum_peak_value < vars.silence then 306 | reaper.DeleteTrackMediaItem(reaper.GetMediaItemTrack(entry.item), entry.item) 307 | end 308 | end 309 | 310 | reaper.Undo_EndBlock("Delete items with peaks lower than " .. vars.silence .. "dB", -1) -- End of the undo block. Leave it at the bottom of your main function. 311 | 312 | reaper.UpdateArrange() 313 | 314 | reaper.PreventUIRefresh(-1) 315 | end 316 | 317 | end 318 | 319 | -------------------------------------------------------------------------------- /dsh_Increase item rate by 1 cent.lua: -------------------------------------------------------------------------------- 1 | newRate=1.00059463445332746; 2 | 3 | item_count = reaper.CountSelectedMediaItems(0) 4 | 5 | for i=0, item_count do 6 | item = reaper.GetSelectedMediaItem(0, i); 7 | if not item then 8 | break 9 | end 10 | take = reaper.GetActiveTake(item); 11 | if not take then 12 | break 13 | end 14 | rate = reaper.GetMediaItemTakeInfo_Value(take, "D_PLAYRATE"); 15 | reaper.SetMediaItemTakeInfo_Value(take, "D_PLAYRATE", rate*newRate); 16 | end 17 | 18 | reaper.UpdateArrange(); 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /dsh_Name_and_number_all_regions.lua: -------------------------------------------------------------------------------- 1 | num_mrkrgns, num_markers, num_regions = reaper.CountProjectMarkers(0) 2 | 3 | if num_regions == NULL or num_regions == 0 then 4 | return 5 | end 6 | 7 | region_names = {} 8 | 9 | -- For each region 10 | for markeridx =0, num_mrkrgns do 11 | retval, isrgn, pos, rgnend, regionname, rgnindexnumber = reaper.EnumProjectMarkers(markeridx) 12 | if isrgn then 13 | markeridx, regionidx = reaper.GetLastMarkerAndCurRegion(0, pos) 14 | -- TODO: Continue instead of return 15 | if markeridx >= 0 then 16 | retval2, isrgn2, pos2, rgnend2, markername, markrgnindexnumber = reaper.EnumProjectMarkers(markeridx) 17 | -- Check to see whether the region name ends with an underscore followed by a number. if it ends with a number, then we've probably already numbered it so we ignore it 18 | if string.match(markername, ".+_$") then 19 | markername = string.match(markername, "(.+)_$") 20 | end 21 | -- do nothing 22 | 23 | -- Check in our dictionary to see whether or not we've already seen this region name before. 24 | -- If we have, then we look up how many of these we've already seen in the dictionary, 25 | local num_so_far = region_names[markername] 26 | if num_so_far and num_so_far > 0 then 27 | -- add 1 to that number, 28 | num_so_far = num_so_far + 1 29 | -- rename the region 30 | else 31 | num_so_far = 1 32 | end 33 | 34 | -- add the new number to the dictionary 35 | region_names[markername] = num_so_far 36 | 37 | NewName = markername .. "_" .. num_so_far 38 | reaper.SetProjectMarker(rgnindexnumber, isrgn, pos, rgnend, NewName) 39 | -- end 40 | end 41 | end 42 | end 43 | 44 | 45 | -------------------------------------------------------------------------------- /dsh_Number all duplicate regions.lua: -------------------------------------------------------------------------------- 1 | -- MediaItem = reaper.GetSelectedMediaItem(0, 0) -- the first "0" stands for "current project tab", the second one means "the first of all selected items" 2 | -- Item_Start_Time = reaper.GetMediaItemInfo_Value(MediaItem, "D_POSITION"); 3 | -- Item_End_Time = Item_Start_Time + reaper.GetMediaItemInfo_Value(MediaItem, "D_LENGTH") 4 | -- markeridx, regionidx = reaper.GetLastMarkerAndCurRegion(0, Item_Start_Time) 5 | 6 | -- if markeridx == NULL then return end 7 | 8 | -- retval, isrgn, pos, rgnend, markername, markrgnindexnumber = reaper.EnumProjectMarkers(markeridx) 9 | -- local NewName = markername .. "_down" 10 | 11 | -- MediaItemTake = reaper.GetActiveTake(MediaItem) 12 | -- reaper.GetSetMediaItemTakeInfo_String(MediaItemTake , "P_NAME", NewName, true) -- "True" makes the function set a new name ("False" would give you the current name in the function's return) 13 | 14 | 15 | -- if(regionidx ~= -1) then 16 | -- retval, isrgn, pos, rgnend, regionname, markrgnindexnumber = reaper.EnumProjectMarkers(regionidx) 17 | -- reaper.SetProjectMarker(markrgnindexnumber, true, Item_Start_Time, Item_End_Time, NewName) 18 | -- else 19 | -- reaper.AddProjectMarker(0, true, Item_Start_Time, Item_End_Time, NewName, -1) 20 | -- end 21 | 22 | 23 | num_mrkrgns, num_markers, num_regions = reaper.CountProjectMarkers(0) 24 | 25 | if num_regions == NULL or num_regions == 0 then 26 | return 27 | end 28 | 29 | region_names = {} 30 | 31 | -- For each region 32 | for markeridx =0, num_mrkrgns do 33 | retval, isrgn, pos, rgnend, markername, markrgnindexnumber = reaper.EnumProjectMarkers(markeridx) 34 | if isrgn then 35 | -- If the region anme ends with a number, strip it 36 | --markername = string.match(markername, "(.-)_%d*$") 37 | 38 | -- Check to see whether the region name ends with an underscore followed by a number. if it ends with a number, then we've probably already numbered it so we ignore it 39 | if string.match(markername, ".+_[0-9]+$") then 40 | markername = string.match(markername, "(.+)_[0-9]*$") 41 | end 42 | -- do nothing 43 | -- else 44 | -- Check in our dictionary to see whether or not we've already seen this region name before. 45 | -- If we have, then we look up how many of these we've already seen in the dictionary, 46 | local num_so_far = region_names[markername] 47 | if num_so_far and num_so_far > 0 then 48 | -- add 1 to that number, 49 | num_so_far = num_so_far + 1 50 | -- rename the region 51 | else 52 | num_so_far = 1 53 | end 54 | 55 | -- add the new number to the dictionary 56 | 57 | region_names[markername] = num_so_far 58 | NewName = markername .. "_" .. num_so_far 59 | NewName = markername .. num_so_far 60 | reaper.SetProjectMarker(markrgnindexnumber, isrgn, pos, rgnend, NewName) 61 | -- end 62 | end 63 | end 64 | -------------------------------------------------------------------------------- /dsh_Update_Region_Based_on_Item_Bounds.lua: -------------------------------------------------------------------------------- 1 | 2 | MediaItem = reaper.GetSelectedMediaItem(0, 0) -- the first "0" stands for "current project tab", the second one means "the first of all selected items" 3 | Item_Start_Time = reaper.GetMediaItemInfo_Value(MediaItem, "D_POSITION"); 4 | Item_End_Time = Item_Start_Time + reaper.GetMediaItemInfo_Value(MediaItem, "D_LENGTH") 5 | Item_Mid_Point = Item_Start_Time + reaper.GetMediaItemInfo_Value(MediaItem, "D_LENGTH")/2 6 | markeridx, regionidx = reaper.GetLastMarkerAndCurRegion(0, Item_Mid_Point) 7 | 8 | if markeridx == NULL then return end 9 | 10 | retval, isrgn, pos, rgnend, markername, markrgnindexnumber = reaper.EnumProjectMarkers(markeridx) 11 | local NewName = markername 12 | 13 | if(regionidx ~= -1) then 14 | retval, isrgn, pos, rgnend, regionname, markrgnindexnumber = reaper.EnumProjectMarkers(regionidx) 15 | reaper.SetProjectMarker(markrgnindexnumber, true, Item_Start_Time, Item_End_Time, NewName) 16 | else 17 | reaper.AddProjectMarker(0, true, Item_Start_Time, Item_End_Time, NewName, -1) 18 | end 19 | 20 | 21 | --------------------------------------------------------------------------------