-
Notifications
You must be signed in to change notification settings - Fork 148
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Release Zuljeah v0.1beta1 #1392
Open
hemisphera
wants to merge
3
commits into
ReaTeam:master
Choose a base branch
from
hemisphera:reapack.com_upload-1715952174299
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+395
−0
Open
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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.lua | ||
-- [main] hemisphera_Zuljeah/Zuljeah_PreviousSong.lua | ||
-- @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. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
-- @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 | ||
|
||
--====-- | ||
|
||
setlistTrack = findSetlistTrack() | ||
if (setlistTrack == nil) then | ||
return | ||
end | ||
setlist = buildSetlist(setlistTrack) | ||
modifySelectedIndex(setlist, 1) | ||
reaper.UpdateArrange() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
-- @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 | ||
|
||
--====-- | ||
|
||
setlistTrack = findSetlistTrack() | ||
if (setlistTrack == nil) then | ||
return | ||
end | ||
setlist = buildSetlist(setlistTrack) | ||
modifySelectedIndex(setlist, -1) | ||
reaper.UpdateArrange() |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for the long delay... Tried it out: it crashes on this line (seq is nil) if
P_NOTES
fails to parse as a number.The 'Consolas' font is only pre-installed on Windows.
The user-facing actions should have the author prefix and be named as sentence case (eg. "hemisphera_Zuljeah - Next song.lua") to blend well with other actions.
Since all three Lua files share a lot of code, I recommend putting the common code in one file and loading that from the others instead of duplicating. A good place would be the hemisphera_Zuljeah.lua package file (in which case it needs to be marked for installation, but not listed in the action list).
Is this behavior normal when starting playback after moving the cursor a bit before the regions?
Docker #0 may be anywhere (top/bottom/left/right/floating), so it would be best to persist in which docker the user wants to put the window.