No internet connection
  1. Home
  2. How to

How can I use a deck to enter user input in a larger macro / script?

By Stephan Wunderlich @Stephan_Wunderlich
    2022-10-21 16:36:08.025Z

    Hello everyone!

    The script I'm creating seems simple enough to execute, but I'm confused as to why one small aspect doesn't work as expected. The script involves two decks and (when working) would operate as follows ...

    On a deck I call 'Plugins' I select a plugin I would like to load. This then calls up a deck called 'Numbers' where I select the insert number I would like the plugin instantiated on. This would then automatically navigate to the previous deck to show the 'Plugins' deck once again.

    At the moment everything works except for the part where I use the 'Numbers' deck to enter the insert number -- HOWEVER -- I AM able to enter the insert number using my physical keyboard. Additionally, the scripts inside the 'Numbers' deck work fine on their own typing or pressing whatever keys I would like, the disconnect seems to be entirely with being able to use the deck to enter the text into a prompt.

    Here's an example of the script that would occur when using the 'Numbers' deck:

    // Types the number 7 and then presses 'enter'
    sf.keyboard.press({
        keys: "numpad 7, numpad enter",
    });
    
    // Calling command "Navigate to Previous Deck" from package "undefined" (installed from user/pkg/version "srAasovvDiQacRZ2mcId4RrOA8R2/ckp49i4j60000a2100yfwywgf/cl7ifcvv10000cz108r31chrd")
    sf.soundflow.runCommand({
        commandId: 'user:ckp49i4j60000a2100yfwywgf:cku7lmnhe00010t101ef24isa',
        props: {}
    });
    

    So, pretty simple.

    The 'Plugin' deck runs slightly more dynamic bits of code as can be seen below: in this example I've 'picked' Pro-Q 3 as my plugin of choice

    // Calling command "Numbers" from package "Basic Production"
    sf.soundflow.runCommand({
        commandId: 'user:cl98wudnr0000u910n7hkulfz:cl9bwsx9q000cq910lwm8q6kc',
        props: {}
    });
    
    // Prompts you for an 'insert' number and stores it in 'myVariable'
    var myVariable = prompt("Insert Number?");
    
    // converts the String to a number variable
    var numVariable = Number(myVariable);
    
    // Inserts the selected plugin on the selected track at the user selected insert
    sf.ui.proTools.selectedTrack.trackInsertOrSendSelect({
        insertOrSend: "Insert",
    
        pluginNumber: Number = numVariable,
        pluginPath: ["multichannel plug-in","FabFilter","FabFilter Pro-Q 3 (stereo)"],
        selectForAllSelectedTracks: false,
    });
    

    Also seems pretty simple.

    The part I can't wrap my head around is why I AM able to enter a value using my typing keyboard, but AM NOT able to use the 'Numbers' deck to do the same thing in this specific workflow. Since I'm new to this I have a few ideas about what could be going wrong, but I'm at a loss for what direction to head to figure it out.

    I would love any insight this forum might have to offer, and I also want to say that these tools and this forum have already been invaluable to me in creating workflows that are significantly changing my day-to-day life for the better -- so thank you all!

    Best, -Stephan

    Solved in post #11, click to view
    • 13 replies

    There are 13 replies. Estimated reading time: 19 minutes

    1. I'm thinking that your numbers script isn't doing anything. It's pressing the "7" key but the number 7 isn't being stored anywhere (unless theres a text field/ window that I'm not aware of).

      Also, once your numbers deck script has been run, then any data / variables / constants that are assigned during that script are cleared.

      Your best bet is to store the number 7 into a global state variable which persist even when a script is finished. Instead of

      // Types the number 7 and then presses 'enter'
      sf.keyboard.press({
          keys: "numpad 7, numpad enter",
      });
      

      i would do this:

      globalState.swInsertNumber = 7;
      
      // Calling command "Navigate to Previous Deck" from package "undefined" (installed from user/pkg/version "srAasovvDiQacRZ2mcId4RrOA8R2/ckp49i4j60000a2100yfwywgf/cl7ifcvv10000cz108r31chrd")
      sf.soundflow.runCommand({
          commandId: 'user:ckp49i4j60000a2100yfwywgf:cku7lmnhe00010t101ef24isa',
          props: {}
      });
      

      (Note: I'm using your initials in front of the variable name to help insure that your insert variable name is unique - lots of scripts use the global state)

      then back in your plug-ins deck you'd just do this:

      // Inserts the selected plugin on the selected track at the user selected insert
      sf.ui.proTools.selectedTrack.trackInsertOrSendSelect({
          insertOrSend: "Insert",
          pluginNumber: globalState.swInsertNumber,
          pluginPath: ["multichannel plug-in", "FabFilter", "FabFilter Pro-Q 3 (stereo)"],
          selectForAllSelectedTracks: false,
      });
      
      
      1. Chris Shaw @Chris_Shaw2022-10-21 23:27:43.091Z2022-10-21 23:48:11.870Z

        on second thought this would be a better workflow:

        • your plugin deck stores the menu path for the selected plugin into the global state
        • globalState.swPluginPath = ["multichannel plug-in","FabFilter","FabFilter Pro-Q 3 (stereo)"]
        • then it switches to the numbers deck.
        • the user picks the insert number by pressing the button on the deck (in this case 7)
        • then the script in the numbers deck reads the insert path from the global state, instantiates the plugin, and switches back to the plugin deck
        // Inserts the selected plugin on the selected track at the user selected insert
        sf.ui.proTools.selectedTrack.trackInsertOrSendSelect({
            insertOrSend: "Insert",
            pluginNumber: 7,
            pluginPath: globalState.swPluginPath,
            selectForAllSelectedTracks: false,
        });
        // this is the easiest way to navigate to the previous deck:
        event.deck.device.goBack()
        
        1. Hello again!

          I was responding to your other post before seeing this one -- I'll give this a try in a moment. One more round of thanks yous!

        2. In reply toChris_Shaw:

          Hi Chris,

          Thanks for your response!

          After typing up the longer response below the main issue seems like there's some disconnect between the 'prompt' and being able to use things like sf.keyboard.press or sf.keyboard.type to fill it in. Short example that, for whatever reason, does not work ...

          var myVariable = prompt("Insert Number?");
          
          sf.keyboard.press({
              keys: "numpad 7",
          });
          


          Which is counterintuitive to what I assumed would happen.

          I'll experiment with globalState and see if I can get something running. Cheers.

          ::::: ::::: ::::: ::::: ::::: ::::: ::::: ::::: MY ORIGINAL RESPONSE ::::: ::::: ::::: ::::: ::::: ::::: ::::: :::::

          There is in fact a text field for entry that shows up on the screen with my call as follows ...

          var myVariable = prompt("Insert Number?");
          


          It also comes AFTER my 'Numbers' deck is accessible on the Stream Deck, so I'm not sure a globalState is needed, although I'll give it a try.

          To further clarify the workflow I'm attempting, I'm starting at the following screen ...


          I would then click on the plugin I would like to load (Pro-Q 3 in this instance) which would launch the code ...

          // Calling command "Numbers" from package "Basic Production"
          sf.soundflow.runCommand({
              commandId: 'user:cl98wudnr0000u910n7hkulfz:cl9bwsx9q000cq910lwm8q6kc',
              props: {}
          });
          
          // Prompts you for an 'insert' number and stores it in 'myVariable'
          var myVariable = prompt("Insert Number?");
          
          // converts the String to a number variable
          var numVariable = Number(myVariable);
          
          // Inserts the selected plugin on the selected track at the user selected insert
          sf.ui.proTools.selectedTrack.trackInsertOrSendSelect({
              insertOrSend: "Insert",
          
              pluginNumber: Number = numVariable,
              pluginPath: ["multichannel plug-in","FabFilter","FabFilter Pro-Q 3 (stereo)"],
              selectForAllSelectedTracks: false,
          });
          


          The first action in the code pulls up my 'Numbers' deck which looks like this ...


          Each of these numbered buttons has a simple script in it that types a number and then presses enter as well as goes back to the previous deck -- Using number 7 as the example would do the following ...

          // Types the number 7 and then presses 'enter'
          sf.keyboard.press({
              keys: "numpad 7, numpad enter",
          });
          
          // Calling command "Navigate to Previous Deck" from package "undefined" (installed from user/pkg/version "srAasovvDiQacRZ2mcId4RrOA8R2/ckp49i4j60000a2100yfwywgf/cl7ifcvv10000cz108r31chrd")
          sf.soundflow.runCommand({
              commandId: 'user:ckp49i4j60000a2100yfwywgf:cku7lmnhe00010t101ef24isa',
              props: {}
          });
          


          Before I've pressed any button on my 'Numbers' deck, the code has brought up the myVariable prompt which looks like this ...


          I'm able to manually enter the number 7 and then hit enter on my typing keyboard, but the 'Numbers' deck which is also available to me on the Stream Deck in that moment acts as though it cannot be pressed.

          ::::: ::::: ::::: ::::: ::::: ::::: ::::: ::::: END OF ORIGINAL RESPONSE ::::: ::::: ::::: ::::: ::::: ::::: ::::: :::::

          Thanks again for your help so far!

          1. Chris Shaw @Chris_Shaw2022-10-22 00:35:02.867Z2022-10-22 01:13:17.764Z

            You’re trying to get your numbers script to fill in a prompt dialog which isn’t necessary. When the user presses 7 then you already know what the insert number is. The prompt is redundant.
            Also you can’t use SF to automate filling in a dialog / prompt because a dialog box pauses a script until it is dismissed.

            1. If you want to prompt the user to press a key on the numbers deck just use
              log(“Select insert slot for plugin via the deck”,””)
              to show a SF notification which will allow the script to continue

              1. Awesome, I'll give that a try -- and thanks again!

              2. In reply toChris_Shaw:

                EDIT: You had already offered other advice while I was typing this -- so this is likely irrelevant

                ::::: ::::: ::::: :::::

                Just want to clarify the order in which I'm trying to do things just to make sure we're imagining the same workflow -- I'm attempting to pick the plugin first and THEN pick the insert number. In your suggestions it seems like the pluginNumber is pre-defined, or else I'm misinterpreting the code in this moment (which is completely plausible).

                Side Note: The entirety of my script works aside from me being able to define the plugin insert number using the Numbers deck. If I select the plugin I want but then use my physical keyboard to type '7' then hit 'enter' Pro Q shows up on insert 7, or whatever insert number position I just typed in.

                And again, thank you -- I really appreciate your input here.

          2. S

            @Chris_Shaw , thank you so very very much for your input and patience.

            At this point I've been able to use globalState variables in one script and have them impact the other, but for some reason the pushing of buttons on the SD within my script doesn't do anything even though their sole purpose is to define a global state -- it's as if the buttons cannot be pushed.

            However I did find an additional thread that discussed a similar workflow (and that you had participated in) which added some helpful context for me: Can I use multi-touch on the deck?

            So here's where I'm at. I select the plugin I want on the first deck, in this case Pro-Q 3, which starts to run the following script ...

            globalState.myInsertNumber = undefined
            
            // Show the 'Numbers' deck
            sf.soundflow.runCommand({
                commandId: 'user:cl98wudnr0000u910n7hkulfz:cl9bwsx9q000cq910lwm8q6kc',
                props: {}
            });
            
            if (globalState.myInsertNumber == undefined) {
            
            
            /* 
            OF NOTE: 
            None of the alert, log, or waitForPress scripts alter the outcome 
            of not being able to change the global state via the SD, so I've bypassed 
            them in this example 
            */
            
            
                //alert("Please Select a Slot.")
                //sf.devices.streamDeck.getDeviceBySerialNumber('AL06L2C58493').waitForPress();
                //log("Select insert slot for plugin via the deck")
            
            } else {
            
                // Inserts the selected plugin on the selected track at the user selected insert
                sf.ui.proTools.selectedTrack.trackInsertOrSendSelect({
                    insertOrSend: "Insert",
            
                    pluginNumber: globalState.myInsertNumber,
                    pluginPath: ["multichannel plug-in","FabFilter","FabFilter Pro-Q 3 (stereo)"],
                    selectForAllSelectedTracks: false,
                });
            
                globalState.myInsertNumber = undefined
            }
            


            The scripts contained within the buttons on the 'Numbers' deck are the simplest things they could possibly be -- button number 7 contains ...

            // Sets the globalState variable 'myInsertNumber' to 7
            globalState.myInsertNumber = 7
            


            Although this code is simpler and uses globalState variables, I have the same hiccup as I did previously which is that the buttons on the SD act as though they cannot be pushed when running the script.

            BTW, globalState is a significantly more elegant way of doing what I'm attempting to do, so thank you for sharing that with me as I'm going to use that a lot going forward.

            1. Chris Shaw @Chris_Shaw2022-10-22 18:21:23.334Z2022-10-22 19:20:24.370Z

              Your EQ button script starts with globalState.myInsertNumber = undefined: this is unnecessary. In javascript you cannot "undefine" a globalState variable you can only change its value or delete it.


              The concept that I think you're not getting is that your EQ button script is only telling SF to display your numbers deck on your stream deck - that's all that command is doing. Once it shows your numbers deck the eq script continues on - it's not waiting for you to press a button so your global state variable globalState.myInsertNumber does't get defined. Because globalState.myInsertNumber is undefined nothing else happens in the EQ script - the if statement is empty and the else statement won't run. The script stops and all you're left with is a numbers deck that seems unresponsive (it actually is doing something - it's changing the globalState.myInsertNumber value but that's all)


              Instead, the eq button should set the path for the desired plugin in globalState.myPluginPath then the numbers deck button script will read the plugin path from globalState.myPluginPath , instantiate the plugin, then display/go back to the plugin deck.

              This should be the workflow:
              The script for your eq button should be this :

              globalState.myPluginPath = ["multichannel plug-in","FabFilter","FabFilter Pro-Q 3 (stereo)"]
              
              // Notify the user to pick an insert slot for the plugin
              log ("Please pick an insert slot on the deck","(1-10)")
              
              // Show the 'Numbers' deck
              sf.soundflow.runCommand({
                  commandId: 'user:cl98wudnr0000u910n7hkulfz:cl9bwsx9q000cq910lwm8q6kc',
                  props: {}
              });
              

              (This will store the plugin you want to instantiate into the global state, then open the numbers deck. )

              The script for the 7 button on the numbers deck should be:

              // Insert the selected plugin on the selected track at the user selected insert (number button)
              sf.ui.proTools.selectedTrack.trackInsertOrSendSelect({
                  insertOrSend: "Insert",
                  pluginNumber: 7,
                  pluginPath: globalState.myPluginPath,
                  selectForAllSelectedTracks: false,
              });
              
              // Now display the previous / plugin deck
              event.deck.device.goBack();
              

              This instantiates the plugin and returns you back to the plugins deck

              Reply1 LikeSolution
              1. Chris Shaw @Chris_Shaw2022-10-22 18:23:49.343Z2022-10-22 18:54:53.915Z

                Now all you have to do is duplicate the above numbers script for each button (1-10) and just change pluginNumber:.

                1. Chris Shaw @Chris_Shaw2022-10-22 18:32:39.469Z2022-10-22 19:26:10.542Z

                  Instead of using the log statement to prompt the user to pick a number on the numbers deck (lines 3 & 4 in the EQ button script) you could just label the top 5 buttons "Choose", "insert", and "slot." and give them all a color background by pasting a solid color for the button icon.

                  Then create a script with just this:

                  event.deck.device.goBack()
                  

                  assign it to a button called "Cancel / Go back" - it's always good to be able to cancel an operation

                2. In reply toChris_Shaw:

                  Ahhhhh, I see it now!

                  And I really appreciate the commentary on the order in which things were happening since I was definitely missing where things were stopping and starting -- as you could tell I was assuming the 'if' was keeping me in a holding pattern until I could update the 'myInsertNumber' value.

                  What you've shared and how you've explained it makes total sense now and truly appreciate it. Thank you very, very much Chris.

                  I'm also happy to be walking away feeling like I understand how to ask better and more focused questions if / when I might need to again on this forum, so again -- thank you.

                  -Stephan