From c4a900a445219bba629b71ef342f1212fce8248b Mon Sep 17 00:00:00 2001 From: The Dumb Date: Fri, 17 May 2024 15:22:54 +0200 Subject: [PATCH 1/3] Release Zuljeah v0.1beta1 First release --- Various/hemisphera_Zuljeah.lua | 28 ++++ .../hemisphera_Zuljeah/Zuljeah_Monitor.lua | 153 ++++++++++++++++++ Various/hemisphera_Zuljeah/Zuljeah_NextSong | 105 ++++++++++++ .../hemisphera_Zuljeah/Zuljeah_PreviousSong | 105 ++++++++++++ 4 files changed, 391 insertions(+) create mode 100644 Various/hemisphera_Zuljeah.lua create mode 100644 Various/hemisphera_Zuljeah/Zuljeah_Monitor.lua create mode 100644 Various/hemisphera_Zuljeah/Zuljeah_NextSong create mode 100644 Various/hemisphera_Zuljeah/Zuljeah_PreviousSong diff --git a/Various/hemisphera_Zuljeah.lua b/Various/hemisphera_Zuljeah.lua new file mode 100644 index 000000000..da674d06c --- /dev/null +++ b/Various/hemisphera_Zuljeah.lua @@ -0,0 +1,28 @@ +-- @description Zuljeah +-- @author Hemisphera +-- @version 0.1beta1 +-- @changelog First release +-- @metapackage +-- @provides +-- [main] hemisphera_Zuljeah/Zuljeah_Monitor.lua +-- [main] hemisphera_Zuljeah/Zuljeah_NextSong +-- [main] hemisphera_Zuljeah/Zuljeah_PreviousSong +-- @about +-- # Zuljeah Setlist Player +-- +-- Zuljeah is a setlist player for REAPER. You organize your various songs into project regions inside a single REAPER project. Zuljeah then allows you to rearrange the playing order, navigate them and trigger the playback of them. +-- +-- ## How do I prepare my project? +-- +-- 1. You start out by creating your project. Create one or more regions in your project where each region corresponds to a song on your setlist +-- 2. Create one or more "setlist" tracks. A setlist track is any arbitrary track that contains 'SETLIST' (literally, case sensititve) in the name. This track will be used to define the order of your songs. The first setlist track that is found will be used. Muted tracks will be excluded. This way you can create multiple setlists, mute them all and unmute only the one you want to use +-- 3. Create an "Empty Item" for each song that you want to have in your setlist and place it on your setlist track anywhere inside the project region. +-- 4. As content of this empty item insert a numeric value which specifies the sequence of this song on your setlist. It is important that this item does not contain anything but a numeric value. The setlist will be ordered by the numbers you assign here. These numbers can have gaps. +-- +-- ## Alright. And now? +-- +-- 1. Assign shortcuts or keys or MIDI notes to Zuljeah actions. +-- 2. Run the "Zuljeah - Monitor" action which starts Zuljeah. This must always be running to use Zuljeah. You can restart this anytime you make substantial changes to your setlist or songs to refresh Zuljeah. +-- 3. Use the "Next Song" and "Previous Song" to navigate between songs. +-- 4. Hit play to start playback of a song. Zuljeah will automatically stop at the end of the region and move to the next song in the list. + diff --git a/Various/hemisphera_Zuljeah/Zuljeah_Monitor.lua b/Various/hemisphera_Zuljeah/Zuljeah_Monitor.lua new file mode 100644 index 000000000..6444639b3 --- /dev/null +++ b/Various/hemisphera_Zuljeah/Zuljeah_Monitor.lua @@ -0,0 +1,153 @@ +-- @noindex + +local function collectRegions() + local regions = {} + markerCount = reaper.CountProjectMarkers(0) + for i = 0,markerCount-1 do + ok, isRegion, posStart, posEnd, name, id = reaper.EnumProjectMarkers2(0, i) + if (isRegion) then + local r = {} + r["id"] = id + r["name"] = name + r["sequence"] = 0 + r["start"] = posStart + r["end"] = posEnd + regions[i] = r + end + end + return regions +end + +local function findSetlistTrack() + local trackCount = reaper.GetNumTracks() + for i = 0, trackCount - 1 do + local track = reaper.GetTrack(0, i) + local isMuted = reaper.GetMediaTrackInfo_Value(track, 'B_MUTE') + local ok, trackName = reaper.GetTrackName(track) + if (isMuted == 0) and (string.find(trackName, "SETLIST")) then + return track + end + end + return nil +end + +local function buildSetlist(track) + if (track == nil) then + track = findSetlistTrack() + end + if (track == nil) then + return nil + end + + local itemCount = reaper.GetTrackNumMediaItems(track) + local regions = collectRegions() + sq = {} + local sortedRegions = {} + for i = 0, itemCount - 1 do + local mi = reaper.GetTrackMediaItem(track, i) + local ok, take = reaper.GetSetMediaItemInfo_String(mi, "P_NOTES", "", false) + local pos = reaper.GetMediaItemInfo_Value(mi, 'D_POSITION') + local seq = tonumber(tostring(take)) + for k,v in pairs(regions) do + if (v["start"] <= pos) and (v["end"] >= pos) then + v["mediaitem"] = mi + v["selected"] = reaper.IsMediaItemSelected(mi) + sortedRegions[seq] = v + end + end + end + return sortedRegions +end + +local function getSelectedIndex(setlist) + totalItems = 0 + for k,v in pairs(setlist) do + if (v["selected"]) then + selectedIndex = k + end + totalItems = totalItems + 1 + end + return selectedIndex, totalItems +end + +local function setSelectedIndex(setlist, newIndex) + selectedIndex, totalItems = getSelectedIndex(setlist) + + if (newIndex < 1) then + newIndex = totalItems + end + if (newIndex > totalItems) then + newIndex = 1 + end + + if (selectedIndex ~= nil) then + reaper.SetMediaItemSelected(setlist[selectedIndex]["mediaitem"], false) + end + reaper.SetMediaItemSelected(setlist[newIndex]["mediaitem"], true) + reaper.SetEditCurPos(setlist[newIndex]["start"], true, false) +end + +local function modifySelectedIndex(setlist, delta) + selectedIndex, totalItems = getSelectedIndex(setlist) + if (selectedIndex == nil) then + setSelectedIndex(setlist, 1) + else + setSelectedIndex(setlist, selectedIndex + delta) + end +end + +--====-- + +gfx.init("Zuljeah - integrated", 770, 200, 1) +fontSize = 30 +gfx.setfont(1, "Consolas", fontSize) + +lastActiveRegion = 0 + +local function render() + gfx.y = -fontSize + local playPos = reaper.GetPlayPosition() + + local setlistTrack = findSetlistTrack() + if (setlistTrack == nil) then + reaper.ShowConsoleMsg("No setlist track found.\n") + return + end + + local activeRegion = 0 + local setlist = buildSetlist(setlistTrack) + for k,v in pairs(setlist) do + gfx.x = 0 + gfx.y = gfx.y + fontSize + + local isCurrent = (playPos >= v["start"]) and (playPos <= v["end"]) + if (isCurrent) then + activeRegion = k + end + + line = "" + if (isCurrent) then + line = line .. ">>" + else + line = line .. " " + end + line = line .. " " .. v["name"] + if (v["selected"]) then + line = "o " .. line + else + line = " " .. line + end + gfx.drawstr(line .. "\n") + end + + if (lastActiveRegion ~= activeRegion) then + if (activeRegion == 0) then + reaper.OnStopButton() + setSelectedIndex(setlist, lastActiveRegion + 1) + end + lastActiveRegion = activeRegion + end + + reaper.defer(render) +end +render() diff --git a/Various/hemisphera_Zuljeah/Zuljeah_NextSong b/Various/hemisphera_Zuljeah/Zuljeah_NextSong new file mode 100644 index 000000000..00c318759 --- /dev/null +++ b/Various/hemisphera_Zuljeah/Zuljeah_NextSong @@ -0,0 +1,105 @@ +local function collectRegions() + local regions = {} + markerCount = reaper.CountProjectMarkers(0) + for i = 0,markerCount-1 do + ok, isRegion, posStart, posEnd, name, id = reaper.EnumProjectMarkers2(0, i) + if (isRegion) then + local r = {} + r["id"] = id + r["name"] = name + r["sequence"] = 0 + r["start"] = posStart + r["end"] = posEnd + regions[i] = r + end + end + return regions +end + +local function findSetlistTrack() + local trackCount = reaper.GetNumTracks() + for i = 0, trackCount - 1 do + local track = reaper.GetTrack(0, i) + local isMuted = reaper.GetMediaTrackInfo_Value(track, 'B_MUTE') + local ok, trackName = reaper.GetTrackName(track) + if (isMuted == 0) and (string.find(trackName, "SETLIST")) then + return track + end + end + return nil +end + +local function buildSetlist(track) + if (track == nil) then + track = findSetlistTrack() + end + if (track == nil) then + return nil + end + + local itemCount = reaper.GetTrackNumMediaItems(track) + local regions = collectRegions() + sq = {} + local sortedRegions = {} + for i = 0, itemCount - 1 do + local mi = reaper.GetTrackMediaItem(track, i) + local ok, take = reaper.GetSetMediaItemInfo_String(mi, "P_NOTES", "", false) + local pos = reaper.GetMediaItemInfo_Value(mi, 'D_POSITION') + local seq = tonumber(tostring(take)) + for k,v in pairs(regions) do + if (v["start"] <= pos) and (v["end"] >= pos) then + v["mediaitem"] = mi + v["selected"] = reaper.IsMediaItemSelected(mi) + sortedRegions[seq] = v + end + end + end + return sortedRegions +end + +local function getSelectedIndex(setlist) + totalItems = 0 + for k,v in pairs(setlist) do + if (v["selected"]) then + selectedIndex = k + end + totalItems = totalItems + 1 + end + return selectedIndex, totalItems +end + +local function setSelectedIndex(setlist, newIndex) + selectedIndex, totalItems = getSelectedIndex(setlist) + + if (newIndex < 1) then + newIndex = totalItems + end + if (newIndex > totalItems) then + newIndex = 1 + end + + if (selectedIndex ~= nil) then + reaper.SetMediaItemSelected(setlist[selectedIndex]["mediaitem"], false) + end + reaper.SetMediaItemSelected(setlist[newIndex]["mediaitem"], true) + reaper.SetEditCurPos(setlist[newIndex]["start"], true, false) +end + +local function modifySelectedIndex(setlist, delta) + selectedIndex, totalItems = getSelectedIndex(setlist) + if (selectedIndex == nil) then + setSelectedIndex(setlist, 1) + else + setSelectedIndex(setlist, selectedIndex + delta) + end +end + +--====-- + +setlistTrack = findSetlistTrack() +if (setlistTrack == nil) then + return +end +setlist = buildSetlist(setlistTrack) +modifySelectedIndex(setlist, 1) +reaper.UpdateArrange() diff --git a/Various/hemisphera_Zuljeah/Zuljeah_PreviousSong b/Various/hemisphera_Zuljeah/Zuljeah_PreviousSong new file mode 100644 index 000000000..e0e53d964 --- /dev/null +++ b/Various/hemisphera_Zuljeah/Zuljeah_PreviousSong @@ -0,0 +1,105 @@ +local function collectRegions() + local regions = {} + markerCount = reaper.CountProjectMarkers(0) + for i = 0,markerCount-1 do + ok, isRegion, posStart, posEnd, name, id = reaper.EnumProjectMarkers2(0, i) + if (isRegion) then + local r = {} + r["id"] = id + r["name"] = name + r["sequence"] = 0 + r["start"] = posStart + r["end"] = posEnd + regions[i] = r + end + end + return regions +end + +local function findSetlistTrack() + local trackCount = reaper.GetNumTracks() + for i = 0, trackCount - 1 do + local track = reaper.GetTrack(0, i) + local isMuted = reaper.GetMediaTrackInfo_Value(track, 'B_MUTE') + local ok, trackName = reaper.GetTrackName(track) + if (isMuted == 0) and (string.find(trackName, "SETLIST")) then + return track + end + end + return nil +end + +local function buildSetlist(track) + if (track == nil) then + track = findSetlistTrack() + end + if (track == nil) then + return nil + end + + local itemCount = reaper.GetTrackNumMediaItems(track) + local regions = collectRegions() + sq = {} + local sortedRegions = {} + for i = 0, itemCount - 1 do + local mi = reaper.GetTrackMediaItem(track, i) + local ok, take = reaper.GetSetMediaItemInfo_String(mi, "P_NOTES", "", false) + local pos = reaper.GetMediaItemInfo_Value(mi, 'D_POSITION') + local seq = tonumber(tostring(take)) + for k,v in pairs(regions) do + if (v["start"] <= pos) and (v["end"] >= pos) then + v["mediaitem"] = mi + v["selected"] = reaper.IsMediaItemSelected(mi) + sortedRegions[seq] = v + end + end + end + return sortedRegions +end + +local function getSelectedIndex(setlist) + totalItems = 0 + for k,v in pairs(setlist) do + if (v["selected"]) then + selectedIndex = k + end + totalItems = totalItems + 1 + end + return selectedIndex, totalItems +end + +local function setSelectedIndex(setlist, newIndex) + selectedIndex, totalItems = getSelectedIndex(setlist) + + if (newIndex < 1) then + newIndex = totalItems + end + if (newIndex > totalItems) then + newIndex = 1 + end + + if (selectedIndex ~= nil) then + reaper.SetMediaItemSelected(setlist[selectedIndex]["mediaitem"], false) + end + reaper.SetMediaItemSelected(setlist[newIndex]["mediaitem"], true) + reaper.SetEditCurPos(setlist[newIndex]["start"], true, false) +end + +local function modifySelectedIndex(setlist, delta) + selectedIndex, totalItems = getSelectedIndex(setlist) + if (selectedIndex == nil) then + setSelectedIndex(setlist, 1) + else + setSelectedIndex(setlist, selectedIndex + delta) + end +end + +--====-- + +setlistTrack = findSetlistTrack() +if (setlistTrack == nil) then + return +end +setlist = buildSetlist(setlistTrack) +modifySelectedIndex(setlist, -1) +reaper.UpdateArrange() From 92c949168fe5185045846333b2fed0f92660e821 Mon Sep 17 00:00:00 2001 From: The Dumb Date: Fri, 17 May 2024 16:04:17 +0200 Subject: [PATCH 2/3] Fix filenames --- Various/hemisphera_Zuljeah.lua | 4 ++-- .../{Zuljeah_NextSong => Zuljeah_NextSong.lua} | 0 .../{Zuljeah_PreviousSong => Zuljeah_PreviousSong.lua} | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename Various/hemisphera_Zuljeah/{Zuljeah_NextSong => Zuljeah_NextSong.lua} (100%) rename Various/hemisphera_Zuljeah/{Zuljeah_PreviousSong => Zuljeah_PreviousSong.lua} (100%) diff --git a/Various/hemisphera_Zuljeah.lua b/Various/hemisphera_Zuljeah.lua index da674d06c..ae98f3c01 100644 --- a/Various/hemisphera_Zuljeah.lua +++ b/Various/hemisphera_Zuljeah.lua @@ -5,8 +5,8 @@ -- @metapackage -- @provides -- [main] hemisphera_Zuljeah/Zuljeah_Monitor.lua --- [main] hemisphera_Zuljeah/Zuljeah_NextSong --- [main] hemisphera_Zuljeah/Zuljeah_PreviousSong +-- [main] hemisphera_Zuljeah/Zuljeah_NextSong.lua +-- [main] hemisphera_Zuljeah/Zuljeah_PreviousSong.lua -- @about -- # Zuljeah Setlist Player -- diff --git a/Various/hemisphera_Zuljeah/Zuljeah_NextSong b/Various/hemisphera_Zuljeah/Zuljeah_NextSong.lua similarity index 100% rename from Various/hemisphera_Zuljeah/Zuljeah_NextSong rename to Various/hemisphera_Zuljeah/Zuljeah_NextSong.lua diff --git a/Various/hemisphera_Zuljeah/Zuljeah_PreviousSong b/Various/hemisphera_Zuljeah/Zuljeah_PreviousSong.lua similarity index 100% rename from Various/hemisphera_Zuljeah/Zuljeah_PreviousSong rename to Various/hemisphera_Zuljeah/Zuljeah_PreviousSong.lua From 3f6b3fbc13616c1503fe21e6815322f488b8222b Mon Sep 17 00:00:00 2001 From: The Dumb Date: Sat, 18 May 2024 11:55:46 +0200 Subject: [PATCH 3/3] Add noindex to script files --- Various/hemisphera_Zuljeah/Zuljeah_NextSong.lua | 2 ++ Various/hemisphera_Zuljeah/Zuljeah_PreviousSong.lua | 2 ++ 2 files changed, 4 insertions(+) diff --git a/Various/hemisphera_Zuljeah/Zuljeah_NextSong.lua b/Various/hemisphera_Zuljeah/Zuljeah_NextSong.lua index 00c318759..0f9cd2888 100644 --- a/Various/hemisphera_Zuljeah/Zuljeah_NextSong.lua +++ b/Various/hemisphera_Zuljeah/Zuljeah_NextSong.lua @@ -1,3 +1,5 @@ +-- @noindex + local function collectRegions() local regions = {} markerCount = reaper.CountProjectMarkers(0) diff --git a/Various/hemisphera_Zuljeah/Zuljeah_PreviousSong.lua b/Various/hemisphera_Zuljeah/Zuljeah_PreviousSong.lua index e0e53d964..330c6c442 100644 --- a/Various/hemisphera_Zuljeah/Zuljeah_PreviousSong.lua +++ b/Various/hemisphera_Zuljeah/Zuljeah_PreviousSong.lua @@ -1,3 +1,5 @@ +-- @noindex + local function collectRegions() local regions = {} markerCount = reaper.CountProjectMarkers(0)