Ensuring only one toggle is active in a profile
2 posters
Page 1 of 1
Ensuring only one toggle is active in a profile
I have a scripting question. I am working on a video-player with Troikatronx Isadora and am using the Streamdeck XL for this.
I have a series of toggle buttons that will activate a specified video file on a given "video track". Each track is an individual profile. Each profile has 9 pages of 16 buttons that will trigger video clips. I start on page 2 as page 1 is reserved for streamdeck navigation. The video-player buttons for each track are 3-6, 11-14, 19-22, and 27-30. The other buttons are used for control and not a part of my question here. Each button has a CH#, CC# scheme that can be calculated mathematically.
In a given track (profile) there can only be one clip active at a time. I may go from one page to another and select a clip from different page.
In my host application, I am storing the controller values for each button in a JSON for distribution though the various modules I am creating. This works well in some circumstances as I can extract specific key values for a function. This does not work well for the video-player as the logic and overhead of either comparing JSONs or outputting all the values in onerous.
I could rewrite the JSON packaging with some logic to ensure there is only one video-player toggle active in a track, but I wonder if there is a simple way of doing this with a background script or global variables in the midi plugin itself.
Is there a way to script the buttons or create a global script that ensures that only one video-player button is active at a time or would it be best to go back and rewrite my host application logic to do this?
I would appreciate any input here. Thanks. - J
I have a series of toggle buttons that will activate a specified video file on a given "video track". Each track is an individual profile. Each profile has 9 pages of 16 buttons that will trigger video clips. I start on page 2 as page 1 is reserved for streamdeck navigation. The video-player buttons for each track are 3-6, 11-14, 19-22, and 27-30. The other buttons are used for control and not a part of my question here. Each button has a CH#, CC# scheme that can be calculated mathematically.
In a given track (profile) there can only be one clip active at a time. I may go from one page to another and select a clip from different page.
- Code:
For completeness, here is the math to calculate the button ch# and cc#:
Button values cycle from 1-96 every 3 pages - 2-4, 5-7, 8-10
Button CH# = ((Page_Number - 2) % 3) * 32 + Page_Button_Number
Channel numbers ascend every 96 buttons over the 4 tracks(profiles)
Channel# = ((TRACK-1)*3)+CEILING((PAGE-1)/3)
for example track 2 pages have CH#4 for pages 2-4, CH#5 for pages 5-7 and CH#6 for pages 8-10
In my host application, I am storing the controller values for each button in a JSON for distribution though the various modules I am creating. This works well in some circumstances as I can extract specific key values for a function. This does not work well for the video-player as the logic and overhead of either comparing JSONs or outputting all the values in onerous.
I could rewrite the JSON packaging with some logic to ensure there is only one video-player toggle active in a track, but I wonder if there is a simple way of doing this with a background script or global variables in the midi plugin itself.
Is there a way to script the buttons or create a global script that ensures that only one video-player button is active at a time or would it be best to go back and rewrite my host application logic to do this?
I would appreciate any input here. Thanks. - J
jtints- Posts : 37
Join date : 2024-01-22
Re: Ensuring only one toggle is active in a profile
I'm not sure I fully understand everything, but I assume the toggle buttons are script buttons. As a generic "keep-only-one-button-active"-solution, you can use something like this:
[(init){@l_ID:"1,1"}]
[(init)(@g_activeID:*){state:#IF(@g_activeID=@l_ID, 1, 0)#}]
[(press){@g_activeID:#@l_ID#}{send something...}]
[(@g_activeID:*){state:#IF(@g_activeID=@l_ID, 1, 0)#}]
The script uses the new feature to store strings in variables. The plugin version that supports this was sent to Elgato a couple of days ago, so I assume it will be published soon. You can use numeric variables as well if the number of IDs is less than 127, but string IDs are more flexible.
The logic is like this:
You probably have additional requirements that affect the final scripts, but the script above works if put on several buttons on several pages and the @l_ID variable is set to a unique value for each button.
[(init){@l_ID:"1,1"}]
[(init)(@g_activeID:*){state:#IF(@g_activeID=@l_ID, 1, 0)#}]
[(press){@g_activeID:#@l_ID#}{send something...}]
[(@g_activeID:*){state:#IF(@g_activeID=@l_ID, 1, 0)#}]
The script uses the new feature to store strings in variables. The plugin version that supports this was sent to Elgato a couple of days ago, so I assume it will be published soon. You can use numeric variables as well if the number of IDs is less than 127, but string IDs are more flexible.
The logic is like this:
- You set a local variable @l_ID to a value unique to each button, e.g., "pagenr,buttonnr". All buttons can have the same name on this variable since it is local to the button.
- You have a global variable that stores the ID of the currently active button.
- In the press command, you set the global ID to the unique ID for the button and do whatever else needs to be done.
- When the global ID changes, all buttons fire the (@g_activeID:*) event and set the button state to 1 or 0, depending on whether the global ID is the same as the local ID.
- The second (init) command is to set the correct button state when you switch pages.
You probably have additional requirements that affect the final scripts, but the script above works if put on several buttons on several pages and the @l_ID variable is set to a unique value for each button.
jtints likes this post
Re: Ensuring only one toggle is active in a profile
Yes. It is a "Keep only one button on" idea that I would like to implement just for the range of buttons that will be used for the video-player toggles. This is what I am currently doing for these buttons:
[(init){image:%thumbs%\vidTN\T01_P02_B01_C01.jpg}]
[ (press) {cc:1,3,127} ][ (release) {text:ON} ]
[ (press) {cc:1,3,0} ][ (release) {text:#none#} ]
[ (cc:1,3,0) {text:#none#} {nextpress:1}]
[ (cc:1,3,127) {text:ON} {nextpress:2}]
Could I implement your ID system with this?
[(init){image:%thumbs%\vidTN\T01_P02_B01_C01.jpg}]
[ (press) {cc:1,3,127} ][ (release) {text:ON} ]
[ (press) {cc:1,3,0} ][ (release) {text:#none#} ]
[ (cc:1,3,0) {text:#none#} {nextpress:1}]
[ (cc:1,3,127) {text:ON} {nextpress:2}]
Could I implement your ID system with this?
jtints- Posts : 37
Join date : 2024-01-22
Re: Ensuring only one toggle is active in a profile
It should be possible, but it gets a bit more complicated. Some control questions:
- I assume you want to implement a latch key functionality. If you press one key to activate a specific clip, is it required to send the Off command for the previously activated clip?
- Are the On/Off commands (cc:1,3,x) in your script received from outside or only sent from the script?
- What is the reason for having the text actions in the release commands instead of in the press commands? (...not that it matters, I'm only curious)
Re: Ensuring only one toggle is active in a profile
You have a global variable that stores the ID of the currently active button.
I am excited about this functionality. It's very powerful and I will examine this more carefully. Will the global ID effect the buttons on other profiles? One of my requirements is to have a single toggle/latch on-state for each of the 4 profiles I will use. Thanks for your help. I will try to work through this some more this evening.
Last edited by jtints on Fri Feb 09, 2024 12:04 am; edited 1 time in total (Reason for editing : grammar)
jtints- Posts : 37
Join date : 2024-01-22
Re: Ensuring only one toggle is active in a profile
Thanks for your response.Admin wrote:It should be possible, but it gets a bit more complicated. Some control questions:
- I assume you want to implement a latch key functionality. If you press one key to activate a specific clip, is it required to send the Off command for the previously activated clip?
- Are the On/Off commands (cc:1,3,x) in your script received from outside or only sent from the script?
- What is the reason for having the text actions in the release commands instead of in the press commands? (...not that it matters, I'm only curious)
1. Yes. I would like to latch the active clip. I would need to send an off for the previous clip as the On will persist in the JSON without it.
2. I will also be sending midi from my host to the Streamdeck - for example, I am building a sequencer function that will shuffle clips programmaticly.
3. I just used your example in the scripting section of your website where you changed images on the release...it works nicely so I just used the same for the text marker.
Best, J
jtints- Posts : 37
Join date : 2024-01-22
Re: Ensuring only one toggle is active in a profile
The following script seems to work reasonably well:
This script does not send the off command for the previous clip.
Sending an off for the previous clip requires some very complex solution if the button for the previous clip is on another page since that script isn't active. If that is a requirement, I'm afraid you must go for a seriously complex background script solution...
The global variable (@g_activeID in my example) controls the scope of the toggle functionality it controls. If you want each profile to be self-contained and not affected by other profiles, you need a unique instance of such a variable for each profile, e.g., @g_activeID_P1, @g_activeID_P2, and so on.
- Code:
[ (config) {TriggerOnUnchangedVariables:No} ]
[(init){@l_ID:"1,3"}{@l_state:0}{image:%thumbs%\vidTN\T01_P02_B01_C01.jpg}]
[(init)(@g_activeID:*){state:#IF(@g_activeID=@l_ID, 1, 0)#}]
[ (press) {@g_activeID:#@l_ID#}{cc:1,3,127}]
[ (press) {@g_activeID:" "}{cc:1,3,0}]
[(@g_activeID:*){@l_state:#IF(@g_activeID=@l_ID, 1, 0)#}]
[(cc:1,3,0) {@l_state:0}]
[(cc:1,3,127){@l_state:1}]
[(@l_state:0){text:#none#} {nextpress:1}]
[(@l_state:1){text:ON} {nextpress:2}]
This script does not send the off command for the previous clip.
Sending an off for the previous clip requires some very complex solution if the button for the previous clip is on another page since that script isn't active. If that is a requirement, I'm afraid you must go for a seriously complex background script solution...
The global variable (@g_activeID in my example) controls the scope of the toggle functionality it controls. If you want each profile to be self-contained and not affected by other profiles, you need a unique instance of such a variable for each profile, e.g., @g_activeID_P1, @g_activeID_P2, and so on.
jtints likes this post
Re: Ensuring only one toggle is active in a profile
Amazing. Once the new plugin is released, I will work through this. I can figure out how to zero the other values in the JSON of my host application. The nice thing will be not having to send these values back to the streamdeck as that is where it gets complex in Isadora.
As always, I really appreciate your help. Thank-you.
As always, I really appreciate your help. Thank-you.
jtints- Posts : 37
Join date : 2024-01-22
Re: Ensuring only one toggle is active in a profile
The new version has been released. I don't know when it was released because I have not gotten any confirmation from Elgato, but I can see on Marketplace that it is live.
Re: Ensuring only one toggle is active in a profile
I am back working on these buttons. I programmed an only one on logic into Isadora in Javascript and it is working quite well. It means I no longer need to hold the toggle in the streamdeck so i have converted the buttons to 10ms holds. I would, however like to still use the only-one-on logic in the streamdeck so I don't need to send 80 button states back to the streamdeck everytime I change something programatically in isadora (for example a random sequence of clips.
I am trying to figure out the best way to work with the only one on script in the midi plugin. I put this together along with commenting how I understand each command. Currently, this allows several buttons to be active at a time. I know I have something wrong here. If you could point me in the right direction, I would be grateful.
I tried to simplify it further so that it is just about displaying the text or not:
The display toggle does not work here, though, and I could not figure out a way of assigning #none# within the IF() operation.
I am trying to figure out the best way to work with the only one on script in the midi plugin. I put this together along with commenting how I understand each command. Currently, this allows several buttons to be active at a time. I know I have something wrong here. If you could point me in the right direction, I would be grateful.
- Code:
\\unsure about how this works. Is this a global flag that determines when the script is triggered?
[ (config) {TriggerOnUnchangedVariables:No} ]
\\init local button ID, assign local state to 0, load button image
[(init){@l_ID:"T01_P02_B01_C02"}{@l_state:0}{image:%thumbs%\vidTN\T01_P02_B01_C02.jpg}]
\\retrieve global active ID, if it is this page set state to 1 else 0
[(init)(@g_activeID:*){state:#IF(@g_activeID=@l_ID, 1, 0)#}]
\\on button press assign global activeID to localID, send midi cc on, wait, send midi cc off
[ (press) {@g_activeID:#@l_ID#}{cc:1,4,1}{wait:10}{cc:1,4,0}]
\\retrieve global active ID, if it is this page set state to 1 else 0
[(@g_activeID:*){@l_state:#IF(@g_activeID=@l_ID, 1, 0)#}]
\\if button cc off recieved set state to 0
[(cc:1,4,0) {@l_state:0}]
\\if button cc on recieved set state to 1
[(cc:1,4,1){@l_state:1}]
\\state 0 text off
[(@l_state:0){text:#none#}]
\\state 1 text on
[(@l_state:1){text:--ON--}]
I tried to simplify it further so that it is just about displaying the text or not:
- Code:
[ (config) {TriggerOnUnchangedVariables:No} ]
[(init){@l_ID:"T01_P02_B01_C01"}{@l_disp:" "}{image:%thumbs%\vidTN\T01_P02_B01_C01.jpg}]
[(init)(@g_activeID:*){@l_disp:#IF(@g_activeID=@l_ID, "--ON--", " ")#}{text:#@l_disp#}]
[ (press) {@g_activeID:#@l_ID#}{cc:1,3,1}{wait:10}{cc:1,3,0}]
[(@g_activeID:*){@l_disp:#IF(@g_activeID=@l_ID, "--ON--", " ")#}{text:#@l_disp#}]
[(cc:1,3,0) {@l_disp:" "}{text:#@l_disp#}]
[(cc:1,3,1){@l_disp:"--ON--"}{@g_activeID:#@l_ID#}{text:#@l_disp#}]
The display toggle does not work here, though, and I could not figure out a way of assigning #none# within the IF() operation.
jtints- Posts : 37
Join date : 2024-01-22
Re: Ensuring only one toggle is active in a profile
I think the main problem is that I forgot to handle the new string variables when checking if a variable is changed.
Unfortunately, the command [ (config) {TriggerOnUnchangedVariables:No} ] will cause (@g_activeID:*) events to never be fired.
I see some other minor things besides that:
The command [(init)(@g_activeID:*){state:#IF(@g_activeID=@l_ID, 1, 0)#}] isn't really needed, I think. The (@g_activeID:*) is superfluous since it is supposed to be fulfilled regardless of variable content, and due to the bug, it will actually cause the command never to be fired. The command is also the only command that sets the button state; shouldn't it set @l_state? If that's the case, I'd suggest merging the (init) commands into one:
[(init){@l_ID:"T01_P02_B01_C02"}{@l_state:#IF(@g_activeID=@l_ID, 1, 0)#}{image:%thumbs%\vidTN\T01_P02_B01_C02.jpg}]
You would probably need to add this command to the script:
[ (config) {TriggerOnLocalMidiEvents:No} ]
Otherwise, the cc events will fire when you send CCs, causing the ON text to be visible for 10ms. (you can have a single (config) command with both actions).
I'll see if I can fix the string variable bug...
Unfortunately, the command [ (config) {TriggerOnUnchangedVariables:No} ] will cause (@g_activeID:*) events to never be fired.
I see some other minor things besides that:
The command [(init)(@g_activeID:*){state:#IF(@g_activeID=@l_ID, 1, 0)#}] isn't really needed, I think. The (@g_activeID:*) is superfluous since it is supposed to be fulfilled regardless of variable content, and due to the bug, it will actually cause the command never to be fired. The command is also the only command that sets the button state; shouldn't it set @l_state? If that's the case, I'd suggest merging the (init) commands into one:
[(init){@l_ID:"T01_P02_B01_C02"}{@l_state:#IF(@g_activeID=@l_ID, 1, 0)#}{image:%thumbs%\vidTN\T01_P02_B01_C02.jpg}]
You would probably need to add this command to the script:
[ (config) {TriggerOnLocalMidiEvents:No} ]
Otherwise, the cc events will fire when you send CCs, causing the ON text to be visible for 10ms. (you can have a single (config) command with both actions).
I'll see if I can fix the string variable bug...
jtints likes this post
Re: Ensuring only one toggle is active in a profile
Otherwise, the cc events will fire when you send CCs, causing the ON text to be visible for 10ms. (you can have a single (config) command with both actions)
Ah. So I should just leave the value at 1 even if my send and receive midi ports are different (FROM_SD_XL, TO_SD_XL)? It gets cleared in Isadora once another button is pressed, so the return to 0 is likely unnecessary. I have other parts of the patch to work on for now if that bug is a show stopper for this script.
jtints- Posts : 37
Join date : 2024-01-22
Re: Ensuring only one toggle is active in a profile
This version handles the variables better.
Version 3.8.0.9
In addition, three new reference variables may be of interest:
Version 3.8.0.9
In addition, three new reference variables may be of interest:
- @e_row and @e_column keep the row and column of the button. Top left button = (0,0)
- @e_id keeps the unique ID of the button. It's a GUID like "2ab472effdb1653c7dd82549a1b7009e" and can't be used for anything other than a unique ID. You could probably skip your @l_ID and use this instead.
jtints likes this post
Re: Ensuring only one toggle is active in a profile
Brilliant! I played with this a bit have it working very nicely:
- @e_id is a very powerful way of uniquly identifying a button. It greatly simplifies the work as there is no need to assign unique @l_ids to buttons.
- added @g_activeID assignments to the midi in logic
This is perfect for my usecase. Thank-you for all of your help. I has really made this build very efficient. Best, -J
- @e_id is a very powerful way of uniquly identifying a button. It greatly simplifies the work as there is no need to assign unique @l_ids to buttons.
- added @g_activeID assignments to the midi in logic
- Code:
[ (config) {TriggerOnUnchangedVariables:No} ]
[(init){@l_state:#IF(@g_activeID=@e_id, 1, 0)#}{image:%thumbs%\vidTN\T01_P02_B01_C03.jpg}]
[ (press) {@g_activeID:#@e_id#}{cc:1,5,127}]
[ (press) {@g_activeID:" "}{cc:1,5,0}]
[(@g_activeID:*){@l_state:#IF(@g_activeID=@e_id, 1, 0)#}]
[(cc:1,5,0) {@l_state:0}{@g_activeID:" "}]
[(cc:1,5,127){@l_state:1}{@g_activeID:#@e_id#}]
[(@l_state:0){text:#none#} {nextpress:1}]
[(@l_state:1){text:--ON--} {nextpress:2}]
This is perfect for my usecase. Thank-you for all of your help. I has really made this build very efficient. Best, -J
jtints- Posts : 37
Join date : 2024-01-22
Similar topics
» I am trying to toggle off a midi toggle button from outside the streamdeck
» DAW Mute toggle
» Button active only when value is selected
» Profile not loading in StreamDeck Properly
» Translate Channel values for a given profile.
» DAW Mute toggle
» Button active only when value is selected
» Profile not loading in StreamDeck Properly
» Translate Channel values for a given profile.
Page 1 of 1
Permissions in this forum:
You cannot reply to topics in this forum