Unexpected behaviour of local vars

Yesterday I was fighting with my computer because Cubase opened with playback activated instead of opening with the transport stopped, as it should be.

Finally I found the solution, which is to initialize the local variables of the play button.

Although I found the solution, I don’t understand why play is triggered when I don’t initialize the local variables.

I had assumed that local variables have the value #none# or zero if they are not initialized, but maybe I have misunderstood.

Anyway, below I explain how to replicate it. Logs ID are after the codes.

Steps to reproduce this issue:

  1. Quit Cubase
  2. Copy the Background Script Code and paste it into a blank background script
  3. Copy the Play Button Code and paste it into a blank scripted button
  4. Both codes: Edit/change the global ports 5 and 6 for setting them to connect to Cubase (make sure you don’t use these ports in other background scripts)
  5. BG Script Code: Edit/change/set the note on/off midi messages for receiving STOP and REC messages from Cubase
  6. Play Button Code: Edit/change/set the cc message of the scripted button to send the order to play/pause the project of Cubase
  7. Play Button Code: set a midi message for triggering “play from last stop” command in Cubase instead of launching “Cubase_PlayFromLastStop.app“ (or remove this action to “noaction”)
  8. Restart the Stream Deck Software
  9. Launch Cubase
  10. When Cubase launches, it starts playing. The play button code triggers “play” even though it is not being pressed. This is the unexpected behaviour. It is important to note that the play is triggered without the need to open any project.
  11. Quit Cubase
  12. Quit the Stream Deck Software
  13. Play Button Code: Uncomment the code of “INIT LOCAL VARS“
  14. Launch the Stream Deck Software
  15. Launch Cubase
  16. Cubase launches as expected, stopped

BACKGROUND SCRIPT CODE:

PORTS
[(init)                         {outputport:GP5} {inputport:GP6}]

REC
[(noteon:1,95,0-127)            {@Recording:1}]--------> Rec ON
[(noteoff:1,95,0-127)           {@Recording:0}]--------> Rec OFF

STOP
[(noteoff:1,93,0-127)           {@Playing:1}]----------> Playing
[(noteon:1,93,0-127)            {@Playing:0}]----------> Stopped

DISPLAY PLAY BUTTON
[(@Playing:1) (@Recording:1)    {@DisplayPlayButton:3}]-----------------> Playing and Recording -----------------> DISPLAY STOP REC
[(@Playing:1) (@Recording:0)    {@DisplayPlayButton:2}]-----------------> Playing and Not Recording -------------> DISPLAY PLAYING
[(@Playing:0) (@Recording:0)    {@DisplayPlayButton:1}]-----------------> Stopped and Not Recording -------------> DISPLAY READY TO PLAY
[(@Playing:0) (@Recording:1)    {@DisplayPlayButton:4}]-----------------> Stopped and Recording -----------------> DISPLAY NOTHING

PLAY BUTTON CODE:

PORTS
[(init)                                                             {outputport:GP5} {inputport:GP6}]

/*
INIT LOCAL VARS
[(init)                                                             {@l_triggerAction:nothing} {@lt_localTimer:reset} {@l_pressedButton:0}]
*/

DISPLAY PLAY BUTTON
[(init+) (@DisplayPlayButton:1)                                     {state:1} {text:▷}]-------> STOPPED & READY TO PLAY
[(init+) (@DisplayPlayButton:2)                                     {state:1} {text:▶︎}]-------> PLAYING
[(init+) (@DisplayPlayButton:3)                                     {state:1} {text:✔︎🟥 }]----> STOP REC
[(init+) (@DisplayPlayButton:4)                                     {state:1} {text:#none#}]--> NOTHING

PRESS & RELEASE LOGIC
[(press)                                                            {@l_triggerAction:nothing} {@lt_localTimer:restart} {@l_pressedButton:1}]
[(release)            (@l_pressedButton:1)                          {@l_pressedButton:0}       {@lt_localTimer:reset}   {@l_triggerAction:playPauseRecstop}]
[(@lt_localTimer:450) (@l_pressedButton:1)                          {@l_pressedButton:0}       {@lt_localTimer:reset}   {@l_triggerAction:playFromLastStop}]

PRESS & RELEASE ACTIONS
[(@l_triggerAction:playPauseRecstop) (@Recording:0)                 {@l_triggerAction:nothing} {cc:1,31,127}]--------------------------> PLAY PAUSE
[(@l_triggerAction:playPauseRecstop) (@Recording:1)                 {@l_triggerAction:nothing} {cc:1,31,127}]----------------------------> STOP REC

[(@l_triggerAction:playFromLastStop) (@Recording:0)                 {@l_triggerAction:nothing} {launch:"Cubase_PlayFromLastStop.app"}]
[(@l_triggerAction:playFromLastStop) (@Recording:1)                 {@l_triggerAction:nothing} {cc:1,31,127}]----------------------------> STOP REC

Log ID when local vars are not initialized (Cubase launches playing):
f5c41eb3-b8b2-4aa6-b917-71d8c0cbaa66

Log ID when local vars are initialized (Cubase launches stopped, as expected):
5131fa4f-070b-46dd-8cd4-15617fc52234

I am a bit confused.

I can’t reproduce the issue. With the scripts you list, Stream Deck sends nothing when Cubase starts. The first log file (f5c41eb3-b8b2-4aa6-b917-71d8c0cbaa66) does not handle these scripts at all.

Do you use the Generic Remote or the MIDI Remote in Cubase?

The three midi messages involved (note 93, note 95, cc31) are configured with the Generic Remote.

To reproduce the issue, try to remove all background scripts from the Global Settings. Leave only the background script I have sent you.

Hope you can reproduce it.

What is this log showing? Any differences versus the other log?

Since the log files don’t handle the same scripts, it’s pointless to compare them.

But I’ve found the problem, deep in the script handler. The event test didn’t work well when the variable type didn’t match the test value.

When the INIT LOCAL VARS section is commented out, @l_triggerAction is never initialized.

When it should test whether (@l_triggerAction:playPauseRecstop) is fulfilled, it must first create the variable so there is something to test against. This is standard procedure in the script engine: the first access to a variable (even if it’s a read access) creates the variable as a numeric variable with the value 0.

The test if (@l_triggerAction:playPauseRecstop) is fulfilled can then proceed. It should have tested whether the current variable value 0 was equal to “playPauseRecstop”, but instead it compared the variable’s numerical value 0 to the event’s numerical value (which was 0 because the event has a string value).

So, all in all, the (@l_triggerAction:playPauseRecstop) event was considered fulfilled when the variable was uninitialized, which was an error. This led to the script command being executed and sent to Cubase.

When the (init) section was included, the variable was initialized as a string before the event test was run, resulting in the correct outcome.

This is a somewhat breaking change, which I must include in the upgrade popup.

As a side note, I recommend avoiding Note commands for remote control. With CC, you use the same command with different values. With notes, you have two commands, Note On and Note Off, and different applications handle them differently. Cubase, for example, doesn’t send Note Off; it sends Note On with a velocity of 0, which, according to the MIDI specifications, should be treated as a Note Off. Relying on receiving a Note Off message is risky. The plugin tries to follow the MIDI Spec, but I can’t guarantee it works in every case.

I’ll do additional tests before publishing an update.

Great. Thanks for the explanation. It’s a pretty complicated issue, great that you found why this was happening. Yesterday I went crazy looking for why it was happening and how to fix it.

Thanks also for the recommendation to not use on/off notes. I also prefer to use CCs. The only notes I use are four: these two that I gave you and two more for punch in and punch out. For now they work well and have never given me any problems, so I’ll keep them for now.

What I don’t understand is that you find that in the two logs I sent you different scripts are executed. I made the two logs in a row, one after the other, doing exactly the same things and with the same configuration (a background script and a scripted button). The only difference between the two logs should be that in the scripted button the initialization of the variables is commented and in the other it is not.

The first file has 48000+ entries. I can’t just read the file; I must search for potential places of interest. I don’t remember what I searched for now, but I found it in the second file, not the first. So I concluded that a comparison wasn’t possible. Maybe I was wrong, but it doesn’t matter now.

The first log is the log where Cubase triggers the PLAY unexpectadly.

When PLAY is triggered, the Mackie protocol starts sending a lot of information per second of the position of the cursor. That could be the reason of the qty of lines. I will keep this in mind for disconnecting the mackie protocol from Cubase when saving a log.

Anyway, if you want to check again the 1st log, you only need to check the first midi messages that are sent to the port “IAC Everybody > CubaseMidi“. You should find a cc1,31,127 at the very beginning. That is the unexpecte play. Just before this message, you should find the received notes on/off 93 and 95 from the port “IAC CubaseMidi > Everybody“. All subsequent midi events are dispensable (they are those of unexpected playback).

I can save another log with video if you need it, disconnecting the mackie protocol.

I have found the error. Why are the log files important?

The logs have the importance that you give them. I am only offering you help and information IF YOU NEED IT.

If you don’t need more logs or more videos, that’s fine with me.

I really appreciate the time and effort you put in helping me find issues with the plugin.

I assumed that reporting that I had found and corrected the issue meant the log files were no longer needed. I will be clearer in the future. Sorry. :flushed_face:

1 Like