Old 07-31-2010, 06:59 PM   #1
Geoff Waddington
Human being with feelings
 
Geoff Waddington's Avatar
 
Join Date: Mar 2009
Location: Dartmouth, Nova Scotia
Posts: 11,252
Default TrackFX_FormatParamValue failing intermittently

Am I doing some stupid thread tricks unknowingly, perhaps?

I'm working on support for the Mackie C4 plugin control and some sluggish VST's (notably LXP Native Reverb -- certain params, and almost everything in Kompakt) often leave the format string blank -- and hence the LCD display on the C4 gets left blank as well.

I've tried various combinations of Sleep() and retries after an adjustment through TrackFX_SetParam to no avail.

For instance the GUI on the Lexicon updates on the TrackFX_SetParam fine from the MIDI sent by the C4, but the subsequent call to update the display often comes up blank.

I am calling these functions from the MIDI handlers (don't know what thread they are on).

Any thoughts folks ?
Geoff Waddington is offline   Reply With Quote
Old 08-01-2010, 02:42 AM   #2
Jeffos
Mortal
 
Jeffos's Avatar
 
Join Date: Dec 2008
Location: France
Posts: 1,969
Default

Hi Geoff! I'm not sure I perfectly understood.. but it sounds like you're relying on a bug to clear the lcd what is the value you set when you say "TrackFX_SetParam to no avail" ? you're probably setting those already bad VSTs in an even more unpretictable state when doing this..

[EDIT] ok, I think I misunderstood, indeed. Geoff, you have to check TrackFX_FormatParamValue return value, see http://forum.cockos.com/showthread.php?t=43330

Last edited by Jeffos; 08-01-2010 at 02:55 AM.
Jeffos is offline   Reply With Quote
Old 08-01-2010, 02:57 AM   #3
Geoff Waddington
Human being with feelings
 
Geoff Waddington's Avatar
 
Join Date: Mar 2009
Location: Dartmouth, Nova Scotia
Posts: 11,252
Default

Thanks for the help, Jeffos.

I don't know how well you know the MCU and C4, I'll assume you do for now, and that you'll ask if you need clarification.

There are 2 functions:

PopulateC4 -- called when MCU is Plugins button is latched on and user presses Select for a channel (track).

OnC4MIDIEvent -- handles MIDI events for the C4.


If you note towards the end -- TrackFX_SetParam is called and you can see the GUI of the FX update just fine.

The problem is with the code just following that.

Sometimes TrackFX_FormatParamValue comes up with an empty string, which, of course is what gets displayed on the C4 (UpdateC4Display).

Sorry for the poor formatting, I need to learn how to embed code files properly.


void PopulateC4(MediaTrack *track, bool deselecting)
{
trackSelectedForC4 = 0;

// Hide floating FX windows
int commandId = plugin_register("command_id_lookup", "S&M_WNCLS3");
SendMessage(g_hwnd,WM_COMMAND,commandId,0);

UpdateC4Display(0, " ", 56 * 2, 0);
UpdateC4Display(0, " ", 56 * 2, 1);
UpdateC4Display(0, " ", 56 * 2, 2);
UpdateC4Display(0, " ", 56 * 2, 3);

for(int i = 0; i < 32; i++)
{
m_midiout->Send(0xB0, 0x20 + i, 0x00, -1);
Sleep(5);
}

if(deselecting)
{
return;
}

double value;
double min;
double max;

int trackFXCount = TrackFX_GetCount(track);

for(int i = 0; i < trackFXCount; i++)
{
TrackFX_GetFXName(track, i, FXInstances[i].FXName, sizeof(FXInstances[i].FXName));

FXInstances[i].numParameters = TrackFX_GetNumParams(track, i);

FXInstances[i].bias = 0;

if(!strncmp(FXInstances[i].FXName, "VST: LXP", 8))
{
FXInstances[i].bias = 6;
}

for(int j = 0; j < FXInstances[i].numParameters; j++)
{
if(j < FXInstances[i].bias)
{
continue;
}

int jVal = j - FXInstances[i].bias;

TrackFX_GetParamName(track, i, j, FXInstances[i].FXParameters[jVal].parameterName, sizeof(FXInstances[i].FXParameters[jVal].parameterName));

value = TrackFX_GetParam(track, i, j, &min, &max);

TrackFX_FormatParamValue(track, i, j, value, FXInstances[i].FXParameters[jVal].parameterValue, sizeof(FXInstances[i].FXParameters[jVal].parameterValue));

if(jVal < 8 )
{
UpdateC4Display(jVal * 7, FXInstances[i].FXParameters[jVal].parameterName, 6, i);
}

if(jVal < 8 )
{
UpdateC4Display(jVal * 7 + 56, FXInstances[i].FXParameters[jVal].parameterValue, 6, i);

int VPotRingVal = (int)((value / (max - min)) * 12.0);

m_midiout->Send(0xB0, 0x20 + jVal + (i * 8), 0x20 + VPotRingVal, -1);
}
}
}


// Show floating FX windows for selected track
commandId = plugin_register("command_id_lookup", "S&M_WNTSHW3");
SendMessage(g_hwnd,WM_COMMAND,commandId,0);

trackSelectedForC4 = track;
}














void OnC4MIDIEvent(MIDI_event_t *evt)
{
if(!trackSelectedForC4)
{
return;
}

int value = evt->midi_message[2];

int target = evt->midi_message[1];

int instance = target / 8;

int parameter = target % 8;

int biasedParameter = parameter + FXInstances[instance].bias;

double max;
double min;

double parameterValue = TrackFX_GetParam(trackSelectedForC4, instance, biasedParameter, &min, &max);

Sleep(5);

if(value > 0x00 && value < 0x40)
{
parameterValue += value * (max - min) / 100.0;

if(parameterValue > max)
{
parameterValue = max;
}
}
else
{
value = value - 0x40;

parameterValue -= value * (max - min) / 100.0;

if(parameterValue < min)
{
parameterValue = min;
}
}

TrackFX_SetParam(trackSelectedForC4, instance, biasedParameter, parameterValue);

Sleep(5);

TrackFX_FormatParamValue(trackSelectedForC4, instance, biasedParameter, parameterValue, FXInstances[instance].FXParameters[parameter].parameterValue, sizeof(FXInstances[instance].FXParameters[parameter].parameterValue));

Sleep(5);

UpdateC4Display(7 * parameter + 56, FXInstances[instance].FXParameters[parameter].parameterValue, 6, instance);

Sleep(5);

int VPotRingVal = (int)((parameterValue / (max - min)) * 12.0);

m_midiout->Send(0xB0, 0x20 + target, 0x20 + VPotRingVal, -1);

Sleep(5);
}
Geoff Waddington is offline   Reply With Quote
Old 08-01-2010, 03:08 AM   #4
Geoff Waddington
Human being with feelings
 
Geoff Waddington's Avatar
 
Join Date: Mar 2009
Location: Dartmouth, Nova Scotia
Posts: 11,252
Default

Quote:
[EDIT] ok, I think I misunderstood, indeed. Geoff, you have to check TrackFX_FormatParamValue return value, see http://forum.cockos.com/showthread.php?t=43330
Thanks, the problem is, it's intermittent for certain parameters -- I've tried recalling the function several times, with various timeout strategies to try and get things to "settle down" but it doesn't seem to make any difference, it's still hit or miss -- sometimes a good string, sometimes not.

Other parameters on the offending plug and other plugs are completely predictable and reliable, that's why I was guessing thread type issues.
Geoff Waddington is offline   Reply With Quote
Old 08-01-2010, 03:44 AM   #5
Jeffos
Mortal
 
Jeffos's Avatar
 
Join Date: Dec 2008
Location: France
Posts: 1,969
Default

yes, as it is said in the thread I linked, it's probably because TrackFX_FormatParamValue only returns true for VSTs implementing Cockos VST extensions (but you can build a "degraded" string if it returned false).
to put some code:
[ code] blabla [/code]
^ without space
Jeffos is offline   Reply With Quote
Old 08-01-2010, 04:09 AM   #6
Geoff Waddington
Human being with feelings
 
Geoff Waddington's Avatar
 
Join Date: Mar 2009
Location: Dartmouth, Nova Scotia
Posts: 11,252
Default

Quote:
Originally Posted by Jeffos
yes, as it is said in the thread I linked, it's probably because TrackFX_FormatParamValue only returns true for VSTs implementing Cockos VST extensions (but you can build a "degraded" string if it returned false).
I read that thread again, it looks like the behavior changes throughout the life of that thead -- notice how happy a couple of posters are towards the end of the thread

Thanks for the tip on how to embed code, I'm including some with the modifications as your suggestion of checking return value -- they are marked with "// New code....".

The update only happens if the call returns "true".

So now I now do not get blank strings, but the C4 surface values can get very "out of whack" with the GUI, until we get lucky enough that a call works.

A point of clarifiaction -- this call is intermittent on certain parameters, BUT IT WORKS SOMETIMES on those very same parameters -- so it is not, as the thread suggests a matter of the call supporting or not supporting the Cockos extensions -- because if it truly didn't we would ALWAYS get garbage -- but that is not the case -- we SOMETIMES get good values on a call to a certain parameter (with a return value of true), and then a few milliseconds / seconds later the call returns a blank string and false.

Here's the code that makes sure there are never blanks in the parameter on the LCD, but note that the value displayed on the LCD can vary widely from the actual value, until we are lucky enough to get a "good" return value, then everything is synched up (for the moment).

Sorry if I wasn't clear on the flakey nature of this thing earlier.

Please also note that the call to TrackFX_FormatParamValue in PopulateC4(the first function) ALWAYS works properly and sets a correct initial value on the display for ALL parameters, including the ones that are flakey later.

Here's the code

Code:
	void PopulateC4(MediaTrack *track, bool deselecting)
	{
		trackSelectedForC4 = 0;

		// Hide floating FX windows 
		int commandId = plugin_register("command_id_lookup", "S&M_WNCLS3");
		SendMessage(g_hwnd,WM_COMMAND,commandId,0);

		UpdateC4Display(0, " ", 56 * 2, 0);		
		UpdateC4Display(0, " ", 56 * 2, 1);		
		UpdateC4Display(0, " ", 56 * 2, 2);
		UpdateC4Display(0, " ", 56 * 2, 3);
		
		for(int i = 0; i < 32; i++)
		{
			m_midiout->Send(0xB0, 0x20 + i, 0x00, -1);
			Sleep(5);
		}

		if(deselecting)
		{
			return;
		}
		
		double value;
		double min;
		double max;

		int trackFXCount = TrackFX_GetCount(track);

		for(int i = 0; i < trackFXCount; i++)
		{
			TrackFX_GetFXName(track, i, FXInstances[i].FXName, sizeof(FXInstances[i].FXName));

			FXInstances[i].numParameters = TrackFX_GetNumParams(track, i);			
			
			FXInstances[i].bias = 0;

			if(!strncmp(FXInstances[i].FXName, "VST: LXP", 8))
			{
				FXInstances[i].bias = 6;
			}

			for(int j = 0; j < FXInstances[i].numParameters; j++)
			{
				if(j < FXInstances[i].bias)
				{
					continue;
				}

				int jVal = j - FXInstances[i].bias;

				TrackFX_GetParamName(track, i, j, FXInstances[i].FXParameters[jVal].parameterName, sizeof(FXInstances[i].FXParameters[jVal].parameterName));

				value = TrackFX_GetParam(track, i, j, &min, &max);

				TrackFX_FormatParamValue(track, i, j, value, FXInstances[i].FXParameters[jVal].parameterValue, sizeof(FXInstances[i].FXParameters[jVal].parameterValue));
				
				if(jVal < 8 )
				{
					UpdateC4Display(jVal * 7, FXInstances[i].FXParameters[jVal].parameterName, 6, i);
				}

				if(jVal < 8 )
				{
					UpdateC4Display(jVal * 7 + 56, FXInstances[i].FXParameters[jVal].parameterValue, 6, i);
							
					int VPotRingVal = (int)((value / (max - min)) * 12.0);

					m_midiout->Send(0xB0, 0x20 + jVal + (i * 8), 0x20 + VPotRingVal, -1);
				}
			}
		}


		// Show floating FX windows for selected track
		commandId = plugin_register("command_id_lookup", "S&M_WNTSHW3");
		SendMessage(g_hwnd,WM_COMMAND,commandId,0);

		trackSelectedForC4 = track;
	}

	void OnC4MIDIEvent(MIDI_event_t *evt)
	{
		if(!trackSelectedForC4)
		{
			return;
		}

		int value = evt->midi_message[2];

		int target = evt->midi_message[1];

		int instance = target / 8;

		int parameter = target % 8;

		int biasedParameter = parameter + FXInstances[instance].bias;

		double max;
		double min;

		double parameterValue = TrackFX_GetParam(trackSelectedForC4, instance, biasedParameter, &min, &max);

		Sleep(5);

		if(value > 0x00 && value < 0x40)
		{
			parameterValue += value * (max - min) / 100.0;

			if(parameterValue > max)
			{
				parameterValue = max;
			}
		}
		else
		{
			value = value - 0x40;

			parameterValue -= value * (max - min) / 100.0;

			if(parameterValue < min)
			{
				parameterValue = min;
			}
		}

		TrackFX_SetParam(trackSelectedForC4, instance, biasedParameter, parameterValue);

		Sleep(5);


		// New code -- we now check the return value of TrackFX_FormatParamValue and only update if true
		// The LCD no longer displays blanks
		// This has the unfortunate side effect that the GUI value can vary widely from the LCD value
		// until we are lucky enough to get a true return value

		if(TrackFX_FormatParamValue(trackSelectedForC4, instance, biasedParameter, parameterValue, FXInstances[instance].FXParameters[parameter].parameterValue, sizeof(FXInstances[instance].FXParameters[parameter].parameterValue)))
		{
			Sleep(5);

			UpdateC4Display(7 * parameter + 56, FXInstances[instance].FXParameters[parameter].parameterValue, 6, instance);

			Sleep(5);

			int VPotRingVal = (int)((parameterValue / (max - min)) * 12.0);

			m_midiout->Send(0xB0, 0x20 + target, 0x20 + VPotRingVal, -1);

			Sleep(5);
		}
	}

Last edited by Geoff Waddington; 08-01-2010 at 04:17 AM.
Geoff Waddington is offline   Reply With Quote
Old 08-01-2010, 05:35 AM   #7
Klinke
Human being with feelings
 
Klinke's Avatar
 
Join Date: Jul 2008
Location: Berlin / Germany
Posts: 832
Default

I find your arguments a little bit suspicious. What is the type of FXInstances[i].FXParameters[jVal].parameterValue? It should be a char*. And i think you should use strnlen in the sixth argument, and not sizeof.

And for VST-plugins it's important that you asked for the actual parameter value, the vst-interface doesn't support anything else. See my request in the thread Jeffos mentioned. Cockos was so nice and implemented my request.

Here is my code for getting the values as String for the MCU display:

Code:
String PlugAccess::getParamValueShort(ElementDesc::eType type, int channel) {
	double min, max;
	int id = getParamID(type, channel);
	if (id != NOT_ASSIGNED && id >= 0 && id < getNumParams()) {
		double val = TrackFX_GetParam(m_pPlugTrack, m_iSlot, id, &min, &max);

		char valueString[80];
		bool valid = TrackFX_FormatParamValue(m_pPlugTrack, m_iSlot, id, val, valueString, 79);
		if (valid) {
			return shortNameFromCString(valueString);
		} else {
			return String::formatted(JUCE_T("%1.3f"), getParamValueDouble(type, channel));
		}
	}

	return String::empty;
}

String PlugAccess::shortNameFromCString(const char* pName) {
	String name = pName;
	return name.substring(0, 6);
}
Klinke is offline   Reply With Quote
Old 08-01-2010, 05:59 AM   #8
Geoff Waddington
Human being with feelings
 
Geoff Waddington's Avatar
 
Join Date: Mar 2009
Location: Dartmouth, Nova Scotia
Posts: 11,252
Default

Quote:
Originally Posted by Klinke
I find your arguments a little bit suspicious
Code:
typedef struct FXParameter
{
	char parameterName[256];
	char parameterValue[256];
} FXParameter;

typedef struct FXInstance
{
	char FXName[256];
	int numParameters;
	int bias;
	FXParameter FXParameters[256];
} FXInstance;

FXInstance FXInstances[256];
Thanks, I think everything is OK with the code, because it works all the time on some parameters and some of the time on the flakey parameters.

I do have the fallback position that you have taken of just formatting the double value to a string, but that is sub-optimal for values that are actually states, like a meter function switch (e.g. Input, Output, Gain Reduction), so I'll keep trying to resolve this for a while more.

By the way, we haven't spoken in a while, congrats on the excellent reception your work is receiving !
Geoff Waddington is offline   Reply With Quote
Old 08-01-2010, 06:40 AM   #9
Klinke
Human being with feelings
 
Klinke's Avatar
 
Join Date: Jul 2008
Location: Berlin / Germany
Posts: 832
Default

Okay, your right, this should work. Are there other plugins then Kompakt and LXP Native Reverb that causes this problems?
Klinke is offline   Reply With Quote
Old 08-01-2010, 06:49 AM   #10
Geoff Waddington
Human being with feelings
 
Geoff Waddington's Avatar
 
Join Date: Mar 2009
Location: Dartmouth, Nova Scotia
Posts: 11,252
Default

Quote:
Originally Posted by Klinke
Are there other plugins then Kompakt and LXP Native Reverb that causes this problems?
I don't know, I posted a build in the stash for anyone who has an MCU and C4 to try out and see how widespread the problem is.
Geoff Waddington is offline   Reply With Quote
Old 08-01-2010, 09:29 AM   #11
Jeffos
Mortal
 
Jeffos's Avatar
 
Join Date: Dec 2008
Location: France
Posts: 1,969
Default

I see you're calling TrackFX_SetParam before TrackFX_FormatParamValue, not GetParam. For those "faulty" FXs, if you call SetParam and GetParam -immedialtely- after, do you have the same value ?
I now some of them are doing their stuff behind your back: ignore the set, round it their way, etc.. but sometimes it's normal too, e.g. with *some* toggle params, set(0.6) can imply get() == 1.0
Jeffos is offline   Reply With Quote
Old 08-01-2010, 11:17 AM   #12
Geoff Waddington
Human being with feelings
 
Geoff Waddington's Avatar
 
Join Date: Mar 2009
Location: Dartmouth, Nova Scotia
Posts: 11,252
Default

Thanks for the help so far guys, much appreciated !!

Jeffos, I put the call to TrackFX_GetParam in as you suggested, and when I stepped by it in the debugger that call didn't return for at least 4 seconds.

For my testing I have 4 FX windows open simultaneously.

After that call took so long, 2 of the FX GUI windows failed to repaint -- they remained with just a white background.

The FX in of those white windows never gave problems before, but now the update problem appeared on that window.

This whole thing feels very "thready" to me. I can't help but feel there's resource contention somewhere that's messing things up.

Thanks for the tip, at least we got different behaviour to examine.

The search continues...
Geoff Waddington is offline   Reply With Quote
Old 08-01-2010, 12:02 PM   #13
Geoff Waddington
Human being with feelings
 
Geoff Waddington's Avatar
 
Join Date: Mar 2009
Location: Dartmouth, Nova Scotia
Posts: 11,252
Default

AH HA !!!!

Jeffos, thanks for the tip to put the TrackFX_GetParam call in, it was necessary.

The other piece of the puzzle had to do with bridging / firewalling.

I had some plugs set up to run in a separate plug-in process.

I don't know if that was the exact cause, or if it was the mixed combination of models.

That's likely where my "thready / resource contention" feeling was coming from.

Anyway, once I set them all to Automatic Bridging, and added the TrackFX_GetParam it all came together nicely.
Geoff Waddington is offline   Reply With Quote
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -7. The time now is 07:17 PM.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2024, vBulletin Solutions Inc.