Accesso rapido:  

Forum: VirtualDJ Plugins

Topic: user button firing vdjscript event without press/click
Hi, I recently started experimenting with DeclareParameterCommand and I've noticed two things when creating a custom user button within VDJ

1) when typing vdjscript into the button editor the script is being fired while typing.
2) once saved, the vdjscript for the custom button is fired continuously without the button being pressed. I'm guessing at a rate of a few hounded times per second, maybe more.

Is this normal behavior?

vdjscript
effect_command 'MYPLUGIN8' 1 'TEST COMMAND'


plugin
HRESULT VDJ_API CMyPlugin8::OnLoad()
{
// ADD YOUR CODE HERE WHEN THE PLUGIN IS CALLED
DeclareParameterCommand(m_transitionCommand, ID_CMD_1, "Command", "CMD", sizeof(m_transitionCommand));

return S_OK;
}

HRESULT VDJ_API CMyPlugin8::OnParameter(int id)
{
std::string t_command = m_transitionCommand;

const char* c_SendString;
char genre[2048];

std::string SendString;

switch (id)
{
case ID_CMD_1:

char param_msg[256];

GetStringInfo("get_browsed_song 'genre'", genre, 100);

sprintf(param_msg, "ID: %d, effect_command text var: '%s', getstringinfo ret: '%s'\n", id, t_command, genre);

err_write(param_msg, strlen(param_msg));

SendString = "browsed_song 'genre' 'test'";
c_SendString = SendString.c_str();

SendCommand(c_SendString);

break;

}
return 0;
}
 

Inviato Sun 09 Jul 23 @ 12:21 am
That's on Windows 11, VDJ v2023 (I think 8.5.7555.0 - that's what Windows says)
 

Inviato Sun 09 Jul 23 @ 12:29 am
locoDogPRO InfinityModeratorMember since 2013
Others will be able to give you better info but what I see is, you're not querying the effect_command sent, so it's really just...

is the command something or even nothing ? then I'll do stuff.

It's been a while since I wrote c++ for effect_command but I remember doing an old v current comparison, to check if the command had changed, and also a else is the command was an unknown or empty string which made it do nothing [except update old variable to current]

but I might be remembering wrong or I might have been working in a stupid way back then.
 

Inviato Sun 09 Jul 23 @ 1:23 am
I'm not sure I fully understand your reply. I'm not querying effect_command from the plugin, I'm attempting to call the vdjscript function from within VDJ as a means to send an event into my plugin. Right now I have it working as expected by assigning "effect_command 'MYPLUGIN8' 1 'TEST COMMAND'" to key '1' on my keyboard. However if I add the same vdjscript to either a user button or a pad the vdjscript is called continuously before I finish typing into the editor. It had me entirely flummoxed for around an hour because it was crashing VDJ each time I tried adding the vdjscript into the editor. I'd type "effect_command 'MYPLUGIN8'" and then the second I typed "1" into the editor VDJ would crash.

The "err_write(param_msg, strlen(param_msg));" function in my code writes to a file, and the file would show hundreds of writes after each time I typed "1" in the editor. More than once the file was over 100 kb. I'm not sure if it's a bug, but it appears to be entering an infinite loop and crashing.
 

Inviato Sun 09 Jul 23 @ 4:46 pm
I'm still learning VDJ as a platform so I'm sure there's a great deal I don't understand, but what gets me is that It's doing this while entering the script into the editor. It's awesome if there's a way to run a well made gem of vdjscript continuously in the background, but it appears to be attempting this before the script is finished being typed within the editor.
 

Inviato Sun 09 Jul 23 @ 5:03 pm
AdionPRO InfinityCTOMember since 2006
effect_command is indeed a bit tricky, in that it works both ways (query and execute)
So when mapped on a custom button or pad, it is also queried ~60 times per second to update the skin on/off button.

I agree that this behavior is not ideal, as there's also no way to know if OnParameter was called because of a button press or because of a query, but unfortunately that's a leftover from older VirtualDJ versions, so it's not easy to change. (although perhaps a new command type could be added to fix this)

As a workaround, there are currently two options
-In your mapper, use "on & effect_command". The single '&' would make the query stop trying after seeing 'on', so effect_command would only be called when pressing the button.
-Change to using a string with DeclareParameterString and effect_string . Querying a string does not use OnParameter, it simply compares the value in your provided pointer with the parameter of effect_string.
 

Inviato Sun 09 Jul 23 @ 5:21 pm
Thank you Adion. Is this normal behavior from within the editor? If I understand you correctly I can see where this may take place when a button is pressed/clicked, however I haven't been able to make it that far as VDJ crashes, and when VDJ is brought back up the vdjscript is not saved within the buttton. If I paste the whole string "effect_command 'MYPLUGIN8' 1 'TEST'" into the editor it crashes as soon as a press "CTRL+V", and if typed it crashed as soon as I enter the event number '1'. It won't allow me to type any further to complete the command.
 

Inviato Sun 09 Jul 23 @ 6:17 pm
AdionPRO InfinityCTOMember since 2006
There is a crash logged, but it appears to be within your plugin, so best to use the debugger with your plugin to find out more about the crash.
Keep in mind that query might be from a different thread, in case any of the code you use is not thread safe.
 

Inviato Sun 09 Jul 23 @ 6:22 pm
I'm working in that direction now.
 

Inviato Sun 09 Jul 23 @ 7:25 pm
I'm going to post my code and exactly what I'm seeing. Not trying to make your day harder, just for those who may follow and see these issues. BTW the plugin code was found on github.com but I trimmed most of it away:

MyPlugin8.cpp
#include "MyPlugin8.h"

#include <string>
#include <ctime>
#include <map>

#include <iostream>
#include <vector>
#include <functional>
#include <algorithm>
#include <sstream>
#include <regex>

#include <mutex>
#include <thread>

std::mutex onp_mutex;

HRESULT VDJ_API CMyPlugin8::OnLoad()
{
char param_msg[256];

sprintf_s(param_msg, "In onload");
OutputDebugStringA(param_msg);

DeclareParameterCommand(m_transitionCommand, ID_CMD_1, "Command", "CMD", sizeof(m_transitionCommand));
return S_OK;
}

HRESULT VDJ_API CMyPlugin8::OnGetPluginInfo(TVdjPluginInfo8* infos)
{
infos->PluginName = "MyPlugin8";
infos->Author = "Atomix Productions";
infos->Description = "My first VirtualDJ 8 plugin";
infos->Version = "1.0";
infos->Flags = 0x00;
infos->Bitmap = NULL;

return S_OK;
}

ULONG VDJ_API CMyPlugin8::Release()
{
delete this;
return 0;
}


HRESULT VDJ_API CMyPlugin8::OnGetUserInterface(TVdjPluginInterface8* pluginInterface)
{
pluginInterface->Type = VDJINTERFACE_DEFAULT;

return S_OK;
}

HRESULT VDJ_API CMyPlugin8::OnParameter(int id)
{
std::scoped_lock lock{ onp_mutex };

std::string t_command(m_transitionCommand);
counter++;
switch (id)
{
case ID_CMD_1:

char param_msg[256];

if (counter % 100 == 0 && counter != 0)
{
sprintf_s(param_msg, "CMyPlugin8::OnParameter() called [%d] times: id: %d, command: %s\n", counter, id, t_command.c_str());
OutputDebugStringA(param_msg);
}

break;

}
return 0;
}

HRESULT VDJ_API CMyPlugin8::OnGetParameterString(int id, char* outParam, int outParamSize)
{
return S_OK;
}


MyPlugin.h
#ifndef MYPLUGIN8_H
#define MYPLUGIN8_H

#define _CRT_SECURE_NO_WARNINGS

#include "vdjPlugin8.h"

class CMyPlugin8 : public IVdjPlugin8
{
public:
HRESULT VDJ_API OnLoad();
HRESULT VDJ_API OnGetPluginInfo(TVdjPluginInfo8* infos);
ULONG VDJ_API Release();
HRESULT VDJ_API OnGetUserInterface(TVdjPluginInterface8* pluginInterface);
HRESULT VDJ_API OnParameter(int id);
HRESULT VDJ_API OnGetParameterString(int id, char* outParam, int outParamSize);

private:
#define STRMAX 200
char m_transitionCommand[STRMAX]{};
int counter = 0;


protected:
typedef enum _ID_Interface
{
ID_CMD_1 = 1

} ID_Interface;

};

#endif


While running this plugin in the VS Studio debugger I first observe that this behavior starts as soon as I type 'effect_command'. As you can see there is a counter, and the pluggin prints to the debugger every 100 times which occurs around each second, maybe a second and a half. The results of 'effect_command' alone

CMyPlugin8::OnParameter() called [100] times: id: 1, command: 
CMyPlugin8::OnParameter() called [200] times: id: 1, command:
CMyPlugin8::OnParameter() called [300] times: id: 1, command:
CMyPlugin8::OnParameter() called [400] times: id: 1, command:
CMyPlugin8::OnParameter() called [500] times: id: 1, command:
CMyPlugin8::OnParameter() called [600] times: id: 1, command:
CMyPlugin8::OnParameter() called [700] times: id: 1, command:
CMyPlugin8::OnParameter() called [800] times: id: 1, command:


As you can see the 'id' within the plugin is set to '1' even though no id is provided by the 'effect_command' scriptlet. If I continue within the editor, modifying the button with the script 'effect_command 'MYPLUGIN'' (which is the incorrect plugin identifier) I begin to see in the debugger:
CMyPlugin8::OnParameter() called [5400] times: id: 1, command: MYPLUGIN
CMyPlugin8::OnParameter() called [5500] times: id: 1, command: MYPLUGIN
CMyPlugin8::OnParameter() called [5600] times: id: 1, command: MYPLUGIN
CMyPlugin8::OnParameter() called [5700] times: id: 1, command: MYPLUGIN
CMyPlugin8::OnParameter() called [5800] times: id: 1, command: MYPLUGIN


Note this is well into the 5,000s without clicking the button. If I enter the correct name I see this:
In onloadCMyPlugin8::OnParameter() called [5900] times: id: 1, command: 
CMyPlugin8::OnParameter() called [100] times: id: 1, command:
CMyPlugin8::OnParameter() called [6000] times: id: 1, command:
CMyPlugin8::OnParameter() called [200] times: id: 1, command:
CMyPlugin8::OnParameter() called [6100] times: id: 1, command:
CMyPlugin8::OnParameter() called [300] times: id: 1, command:
CMyPlugin8::OnParameter() called [6200] times: id: 1, command:
CMyPlugin8::OnParameter() called [400] times: id: 1, command:
CMyPlugin8::OnParameter() called [6300] times: id: 1, command:
CMyPlugin8::OnParameter() called [500] times: id: 1, command:
CMyPlugin8::OnParameter() called [6400] times: id: 1, command:
CMyPlugin8::OnParameter() called [600] times: id: 1, command:
CMyPlugin8::OnParameter() called [6500] times: id: 1, command:
CMyPlugin8::OnParameter() called [700] times: id: 1, command:
CMyPlugin8::OnParameter() called [6600] times: id: 1, command:
CMyPlugin8::OnParameter() called [800] times: id: 1, command:
CMyPlugin8::OnParameter() called [6700] times: id: 1, command:


The print from onload indicates that a second instance of my plugin, the two counts indicate that they are in fact separate instances and not shared. After more playiing when I finly entered the full statement of 'effect_command 'MYPLUGIN8' 1 'TEST' I see
In onloadCMyPlugin8::OnParameter() called [18400] times: id: 1, command: 
CMyPlugin8::OnParameter() called [100] times: id: 1, command:
CMyPlugin8::OnParameter() called [18500] times: id: 1, command: TEST
CMyPlugin8::OnParameter() called [200] times: id: 1, command: TEST
CMyPlugin8::OnParameter() called [18600] times: id: 1, command: TEST
CMyPlugin8::OnParameter() called [300] times: id: 1, command: TEST
CMyPlugin8::OnParameter() called [18700] times: id: 1, command: TEST
CMyPlugin8::OnParameter() called [400] times: id: 1, command: TEST
CMyPlugin8::OnParameter() called [18800] times: id: 1, command: TEST
CMyPlugin8::OnParameter() called [500] times: id: 1, command: TEST
CMyPlugin8::OnParameter() called [18900] times: id: 1, command: TEST


 

Inviato Sun 09 Jul 23 @ 8:25 pm
I noticed that once I entered a correct statement that the same button also showed on the opposite deck. Is this where the second instance comes in?
 

Inviato Sun 09 Jul 23 @ 8:42 pm
At any rate I was able to solve my problem 👍
 

Inviato Sun 09 Jul 23 @ 8:49 pm
AdionPRO InfinityCTOMember since 2006
If you don't specify a deck, the effect will be called from the calling deck. Custom buttons on the default skin are indeed present on both decks, so each would have its own effect instance.
You can use "deck master effect_command ..." to load the plugin as a master plugin instead, which will be independent of any deck.

When effect_command is used without any parameters, it would be calling the first command of the plugin currently selected in the first slot. So probably you selected your plugin in the first effect slot on the deck, which is how VDJ called it without you specifying the name.
 

Inviato Mon 10 Jul 23 @ 4:27 am
Thank you,
 

Inviato Mon 10 Jul 23 @ 4:15 pm