Collection of custom reaper scripts
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

393 lines
14 KiB

-- Reaper scripted "Big Clock" window with extra functions
-- - Normal time display as in the usual "Big Clock"
-- - Time since last project marker
-- - Time since last region start
-- Author: Ludwig Frühschütz
-- Source: https://www.eleton-audio.de
-- Git: https://files.eleton-audio.de/gitea/Ludwig/Reaper-Scripts.git
-- License: GPL v3.0
-- Requires: Reaper 5 or 6
-- Basic gui stuff by forum user "spk77": https://forum.cockos.com/showthread.php?t=161557
-- Some adjustable settings (startup settings that can be changed in GUI):
local timeSinceProject = true -- EITHER this one is true OR one of the next two
local timeSinceMarker = false
local timeSinceRegion = false
local timeUnitHMS = true -- EITHER this one is true OR one of the next one
local timeUnitMeasures = false
-- Nothing to adjust here anymore...
local script_path
local mouse
local Menu
local gui = {} -- contains some settings for the GUI
local quit = false
local sws_present = false
-- Send a message to the console
function msg(m)
reaper.ShowConsoleMsg(tostring(m) .. "\n")
end
-- Round number
function round(num, numDecimalPlaces)
local mult = 10^(numDecimalPlaces or 0)
return math.floor(num * mult + 0.5) / mult
end
-- Store state to project variables
function storeExtState()
if timeSinceProject then
reaper.SetProjExtState(0, 'bigclock_extra', 'timeSinceProject', '1')
else
reaper.SetProjExtState(0, 'bigclock_extra', 'timeSinceProject', '0')
end
if timeSinceMarker then
reaper.SetProjExtState(0, 'bigclock_extra', 'timeSinceMarker', '1')
else
reaper.SetProjExtState(0, 'bigclock_extra', 'timeSinceMarker', '0')
end
if timeSinceRegion then
reaper.SetProjExtState(0, 'bigclock_extra', 'timeSinceRegion', '1')
else
reaper.SetProjExtState(0, 'bigclock_extra', 'timeSinceRegion', '0')
end
if timeUnitMeasures then
reaper.SetProjExtState(0, 'bigclock_extra', 'timeUnit', 'measures')
else
reaper.SetProjExtState(0, 'bigclock_extra', 'timeUnit', 'hms')
end
reaper.SetProjExtState(0, 'bigclock_extra', 'dockState', gfx.dock(-1))
end
---------------------------
-- functions for graphics...
---------------------------
-- Returns current script's path
function get_script_path()
local info = debug.getinfo(1,'S');
local script_path = info.source:match[[^@?(.*[\/])[^\/]-$]]
return script_path
end
-- gui init stuff, including rightclick-menu
function gui_init()
-- Get "script path"
script_path = get_script_path()
--msg(script_path)
-- Modify "package.path"
package.path = package.path .. ";" .. script_path .. "?.lua"
--msg(package.path)
-- Import files ("classes", functions etc.)--
require "class" -- import "base class"
mouse = require "mouse"
Menu = require "menu class"
-- Create "right click" menu --
-- Create a "Menu" instance
rc_menu = Menu("rc_menu")
-- Add menu items to "rc_menu"
-- ">" at the start spawns a submenu, | at the end creates a spacer
rc_menu:add_item({label = "Time since project start",
toggleable = true,
selected = timeSinceProject})
rc_menu:add_item({label = "Time since previous marker",
toggleable = true,
selected = timeSinceMarker})
rc_menu:add_item({label = "Time since previous region|",
toggleable = true,
selected = timeSinceRegion})
rc_menu:add_item({label = "HH:MM:SS.xxx",
toggleable = true,
selected = timeUnitHMS})
rc_menu:add_item({label = "Measures.Beats.xx|",
toggleable = true,
selected = timeUnitMeasures})
rc_menu:add_item({label = "Quit"})
-- Let's add a command to all created items:
rc_menu.items[1].command = function()
if rc_menu.items[1].selected then
timeSinceProject = true
timeSinceMarker = false
timeSinceRegion = false
rc_menu.items[2].selected = false
rc_menu.items[3].selected = false
else
--dont let user disable option but force selection of other option
rc_menu.items[1].selected = true;
end
storeExtState()
end
rc_menu.items[2].command = function()
if rc_menu.items[2].selected then
timeSinceProject = false
timeSinceMarker = true
timeSinceRegion = false
rc_menu.items[1].selected = false
rc_menu.items[3].selected = false
else
--dont let user disable option but force selection of other option
rc_menu.items[2].selected = true;
end
storeExtState()
end
rc_menu.items[3].command = function()
if rc_menu.items[3].selected then
timeSinceProject = false
timeSinceMarker = false
timeSinceRegion = true
rc_menu.items[1].selected = false
rc_menu.items[2].selected = false
else
--dont let user disable option but force selection of other option
rc_menu.items[3].selected = true;
end
storeExtState()
end
rc_menu.items[4].command = function()
if rc_menu.items[4].selected then
timeUnitHMS = true
timeUnitMeasures = false
rc_menu.items[5].selected = false
else
--dont let user disable option but force selection of other option
rc_menu.items[5].selected = true;
end
storeExtState()
end
rc_menu.items[5].command = function()
if rc_menu.items[5].selected then
timeUnitHMS = false
timeUnitMeasures = true
rc_menu.items[4].selected = false
else
--dont let user disable option but force selection of other option
rc_menu.items[4].selected = true;
end
storeExtState()
end
rc_menu.items[6].command = function() quit = true end
end
-- Draw GUI --
function drawGui()
local retval = 0
local val
local timeRaw
local timeDisplay
local timeDisplayHours
local timeDisplayMinutes
local timeDisplaySeconds
local timeMeasures
local timeBeats
local markerId
local regionId
local isRegion
local markerRegionPos
local regionEnd
local markerRegionName
local markerRegionNumber
-- get time depending on play state
if reaper.GetAllProjectPlayStates(0) == 0 then -- 0: stopped
timeRaw = reaper.GetCursorPosition()
else -- 1: play; 2: pause; 4: record (and their bitwise |)
timeRaw = reaper.GetPlayPosition()
end
-- calculate time since previous marker or region
markerId, regionId = reaper.GetLastMarkerAndCurRegion(0, timeRaw)
if timeSinceMarker then
retval, isRegion, markerRegionPos, regionEnd, markerRegionName, markerRegionNumber = reaper.EnumProjectMarkers(markerId)
elseif timeSinceRegion then
retval, isRegion, markerRegionPos, regionEnd, markerRegionName, markerRegionNumber = reaper.EnumProjectMarkers(regionId)
end
if retval > 0 then timeRaw = timeRaw - markerRegionPos end
-- Construct display string
if timeUnitMeasures then
-- measures and beats: e.g. 07.3.99
timeBeats, timeMeasures, _, _, _ = reaper.TimeMap2_timeToBeats(0, timeRaw)
timeDisplay = timeMeasures+1 .. '.' .. round(timeBeats+1, 2)
else
-- minutes and seconds: MM:SS.xxx (e.g. 27:08.321)
timeDisplayHours = math.floor(timeRaw/3600)
timeRaw = timeRaw%3600
timeDisplayMinutes = math.floor(timeRaw/60)
timeDisplaySeconds = round(timeRaw%60, 3)
if timeDisplayHours > 0 then
timeDisplay = timeDisplayHours .. ":"
if timeDisplayMinutes < 10 then
timeDisplay = timeDisplay .. "0"
end
else
timeDisplay = ""
end
timeDisplay = timeDisplay .. timeDisplayMinutes .. ":"
if timeDisplaySeconds < 10 then
timeDisplay = timeDisplay .. "0"
end
timeDisplay = timeDisplay .. timeDisplaySeconds
end
gfx.clear = 3355443 -- background is dark grey
-- If window is docked, use different scaling
if gfx.dock(-1) > 0 then
-- landscape format
if gfx.w > gfx.h then
gfx.x = 20
gfx.y = ( gfx.h-select(2, gfx.measurestr(timeDisplay)) ) / 2
gui.settings.font_size = gfx.h / 2
gfx.setfont(1,"Arial", gui.settings.font_size)
-- check if string fits into window, if not decrease fontsize a little, check again and loop
while gfx.measurestr(timeDisplay) > (gfx.w - 2*gfx.x) do
gui.settings.font_size = gui.settings.font_size / 1.1
gfx.setfont(1,"Arial", gui.settings.font_size)
end
gfx.printf(timeDisplay)
-- portrait format
else
gfx.x = gfx.w/15
gfx.y = ( gfx.h-select(2, gfx.measurestr(timeDisplay)) ) / 2
gui.settings.font_size = gfx.w / 3
gfx.setfont(1,"Arial", gui.settings.font_size)
gfx.printf(timeDisplay)
end
else -- window is not docked
-- landscape format
if gfx.w > gfx.h then
gfx.x = gfx.w/20
gfx.y = ( gfx.h-select(2, gfx.measurestr(timeDisplay)) ) / 2
gui.settings.font_size = gfx.w / 6
gfx.setfont(1,"Arial", gui.settings.font_size)
-- check if string fits into window, if not decrease fontsize a little, check again and loop
while gfx.measurestr(timeDisplay) > (gfx.w - 2*gfx.x) do
gui.settings.font_size = gui.settings.font_size / 1.1
gfx.setfont(1,"Arial", gui.settings.font_size)
end
gfx.printf(timeDisplay)
-- portrait format
else
gfx.x = gfx.w/20
gfx.y = ( gfx.h-select(2, gfx.measurestr(timeDisplay)) ) / 2
gui.settings.font_size = gfx.w / 3
gfx.setfont(1,"Arial", gui.settings.font_size)
gfx.printf(timeDisplay)
end
end
end
-- Called on script termination. Store stuff...
function onExit()
storeExtState()
end
-- Main init function
function init()
-- check for SWS extensions
if reaper.NamedCommandLookup('_SWS_ABOUT') > 0 then sws_present = true end
-- load settings from rpp
local retval
local val
retval, val = reaper.GetProjExtState(0, 'bigclock_extra', 'timeSinceProject')
if retval > 0 then
if tonumber(val) > 0 then
timeSinceProject = true
else
timeSinceProject = false
end
end
retval, val = reaper.GetProjExtState(0, 'bigclock_extra', 'timeSinceMarker')
if retval > 0 then
if tonumber(val) > 0 then
timeSinceMarker = true
else
timeSinceMarker = false
end
end
retval, val = reaper.GetProjExtState(0, 'bigclock_extra', 'timeSinceRegion')
if retval > 0 then
if tonumber(val) > 0 then
timeSinceRegion = true
else
timeSinceRegion = false
end
end
retval, val = reaper.GetProjExtState(0, 'bigclock_extra', 'timeUnit')
if retval > 0 then
if val == 'measures' then
timeUnitMeasures = true
timeUnitHMS = false
else
timeUnitMeasures = false
timeUnitHMS = true
end
end
-- init stuff...
gui_init()
-- Add stuff to "gui" table
gui.settings = {} -- Add "settings" table to "gui" table
gui.settings.font_size = 50 -- font size
gui.settings.docker_id = 0 -- try 0, 1, 257, 513, 1027 etc.
-- Initialize gfx window --
gfx.init("Big Clock Extra", 350, 100, gui.settings.docker_id)
gfx.setfont(1,"Arial", gui.settings.font_size)
gfx.clear = 3355443 -- background is dark grey
-- Restore docked state
retval, val = reaper.GetProjExtState(0, 'bigclock_extra', 'dockState')
if retval > 0 then
gfx.dock(val)
end
end
-- Main loop --
function mainloop()
-- mouseclicks?
local RMB_state = mouse.cap(mouse.RB)
local LMB_state = mouse.cap(mouse.LB)
local mx = gfx.mouse_x
local my = gfx.mouse_y
if not mouse.last_RMB_state and gfx.mouse_cap&2 == 2 then
-- right click pressed down -> show "right click menu" at mouse cursor
rc_menu:show(mx, my)
if sws_present then
reaper.Main_OnCommand( reaper.NamedCommandLookup('_BR_FOCUS_ARRANGE_WND'), 0 ) -- focus arranger
end
end
if not mouse.last_LMB_state and gfx.mouse_cap&1 == 1 then
-- left click pressed down
if sws_present then
reaper.Main_OnCommand( reaper.NamedCommandLookup('_BR_FOCUS_ARRANGE_WND'), 0 ) -- focus arranger
end
end
mouse.last_RMB_state = RMB_state -- store current right mouse button state
mouse.last_LMB_state = LMB_state -- store current left mouse button state
drawGui()
gfx.update()
if gfx.getchar() >= 0 and not quit then reaper.defer(mainloop) end
end
-- START HERE...
reaper.atexit(onExit)
init()
mainloop()