Notifying host not working properly


#1

Hello everybody,

I’m experiencing something weird with my plugin. I’m receiving OSC messages from touchOSC that moves the sliders on my GUI, everything is working great for that part except that the host doesn’t get anything I’m doing when the parameters are modified through the OSC messages.
What I’ve done is that I’ve created three different “setParameters” in my PluginProcessor to avoid infinite loop, so I have :

setParameterFromUI() -> used by the main window to change my internal parameters. This one also send an OSC message to replicate the modification on touchOSC and calls “sendParamChangesToListeners()” that seems to be necessary to notify the host about the changes occuring. This method is working as expected, when I move a slider on my GUI, the internal value is updated, the OSC message is transmitted and received on the iPad and the slider is also moving in my host (Ableton Live in my case, but I’ve also tried on Reaper it works great with both).

[code]void MyPlugin::SetParameterFromUI(int index,float newValue)
{
// Internal parameter change
parameterTable[index].value = newValue;

// Sending information to OSC only
oscSender->updateOsc(index,newValue);

// Sending information to the Host
sendParamChangeMessageToListeners(index, newValue);
}[/code]

setParameter() -> original juce method from the AudioProcessor, this one is called when the slider is moved from the host, it sends an OSC message to the iPad and notify the main window about the change. No problem here, everything’s working great too.

[code]void MyPlugin::SetParameter(int index,float newValue)
{
// Internal parameter change
parameterTable[index].value = newValue;

// Sending information to UI only
/* here I create a string saying that a value has change on my processor
and that the UI should update the corresponding slider */
sendActionMessage(string);

// Sending information to OSC only
oscSender->updateOsc(index,newValue);
}[/code]

Where it gets complicated is when I receive and OSC message.

setParameterFromOSC() -> uses the same instruction as setParameterFromUI() except that instead of sending a notification to the OSC it sends to the main window. In this case, the GUI and the internal value are updated but the host slider won’t move at all even though I call explicitly the “sendParamChangesToListeners()” method.

[code]void MyPlugin::SetParameterFromOSC(int index,float newValue)
{
// Internal parameter change
parameterTable[index].value = newValue;

// Sending information to UI only
/* here I create a string saying that a value has change on my processor
and that the UI should update the corresponding slider */
sendActionMessage(string);

// Sending information to the Host
sendParamChangeMessageToListeners(index, newValue);
}[/code]

I suspect something that as to do with my threads : it’s the OSC Receiver in one of its method that calls the setParameterFromOSC() method from the PluginProcessor. The thing is the OSC Receiver has its own thread because it needs to be continuously listening to the udp port to receive osc messages.

Another thing, is that this bug is only appearing in the VST version of my plugin (mac or win). In the AU version, the setParameterFromOSC() works as expected and I get to see the host slider moving regardless of where the notification comes from (OSC or GUI), but that’s not happening in VST where only the UI get to move the host slider. I don’t know why it’s working in AU but I can’t get it to work in VST.

Is there something I’m doing wrong ? What should be the good thing to do for this kind of scenario ?

Thanks a lot for your time !
Adrien


#2

Hi Adrien,

I assume that when your GUI acts on the action message that it doesn’t send another notification to the host (i.e. slider values are set using dontSendNotification)?

Also, how does the OSC bit of your code find out about parameter changes? That’s not clear from your post.

-Andrew


#3

You’re assuming right, the gui callBack updates the sliders with the dontSendNotification flag so they don’t create a loop.

From which side ? Parameter changes on the UI or on the iPad ?

From the UI as you see in the code I posted above, the setParameterFromUI() calls oscSender->updateOsc() with the index of the value that has changed and the new value. The oscSender then uses the index to retrieve the parameter name and create an OSC message using this information and the value. I don’t have my code here but it looks like that :

void OSCSender::updateOsc(int index,float newValue){ juce::String paramName = processor->getParameterName(index); juce::MemoryBlock data = OSCMessage::createOscMessage(paramName,newValue); socket->writeOnPort(data); }

It’s not exactly like that but you get the idea, the OSCSender has got a pointer to the processor which I use to retrieve the parameter name, then I create an osc message and finally send it through the udp socket.

From the iPad now, I’ve got an OSCReceiver that inherite from the juce::Thread class. In the run() method I listen to the UDP socket and wait for data. Something like that :

void OSCReceiver::run(){ while(!threadHasToStop){ if(we get something from the udp port){ OSCMessage mes = new OSCMessage(memory block received) int index = /* here I use a corresponding table I created inside the OSCReceiver to retrive the parameter index with the parameter name received from OSC. It also validate if the packet received is valid */ processor->setParameterFromOsc(index,mem->getFloatValue()) } } }

That’s pretty much it. As you see the receiver also got a pointer to the processor. I think it’s not really thread safe but I’ve tried sending actionMessage to the processor, it doesn’t change anything, the host won’t udate.


#4

Looks OK to me - so I don’t know what’s going wrong :frowning: Can only suggest to step through the sendParamChangeMessageToListeners() as you call it from SetParameterFromOSC().


#5

Hi, sorry I haven’t been around this weekend to answer your post.

So I did some debugging today to dig on that. The strange thing is that everything seems to be running ok but it just doesn’t and it’s pretty frustrating. The only difference there is between changing a parameter from the GUI or changing it from OSC is that it doesn’t happen in the same thread. The same instructions are executed, the same function are called with the same parameters, the objects have the same references, but it just doesn’t work.

Here is how it goes : we saw that sendParamChangeMessageToListeners(index, newValue) is called in the AudioProcessor when we want to update the host about a parameter being modified.

void AudioProcessor::sendParamChangeMessageToListeners (const int parameterIndex, const float newValue) { jassert (isPositiveAndBelow (parameterIndex, getNumParameters())); for (int i = listeners.size(); --i >= 0;) if (AudioProcessorListener* l = getListenerLocked (i)) l->audioProcessorParameterChanged (this, parameterIndex, newValue); }
After validating the parameter index, it sends a parameter change on the plugin wrapper (AudioProcessorListener) which is either a JuceAU or a JuceVSTWrapper depending on the version used. Next is what the VSTWrapper does since I’m having trouble with the VST version.

void audioProcessorParameterChanged (AudioProcessor*, int index, float newValue) { if (audioMaster != nullptr) audioMaster (&cEffect, audioMasterAutomate, index, 0, 0, newValue); }
Nothing was different when I got there from OSC or from the GUI but in one case, getting out of this function updates the host and in the other it just doesn’t.
I also found this in the juce_AudioProcessorListener.h

[code]/** Receives a callback when a parameter is changed.

IMPORTANT NOTE: this will be called synchronously when a parameter changes, and
many audio processors will change their parameter during their audio callback.
This means that not only has your handler code got to be completely thread-safe,
but it’s also got to be VERY fast, and avoid blocking. If you need to handle
this event on your message thread, use this callback to trigger an AsyncUpdater
or ChangeBroadcaster which you can respond to on the message thread.
/
virtual void audioProcessorParameterChanged (AudioProcessor
processor, int parameterIndex, float newValue) = 0;[/code]
But I’m not really sure what it means.
Anyway, I’m not sure why it does work in the AU version but imo it really shouldn’t. There may be some sorcery involved. I’m going to try some things to get around the potential thread problem, if you have any idea I’ll take it !


#6

I’ve tried something but it doesn’t change much. Now my OSCReceiver is filling a vector in the AudioProcessor with the new values it receives from the network. This vector is read at every process block iteration and if there are some value stored in it, they are applied to their corresponding parameters using the previous setParameterFromOSC(). After that, the vector is cleared. I used a ScopedLock to prevent crash if we are in the situation of reading and writing on the same variable at the same time, but anyway … The host won’t update ! Doing the paramChange in the processBlock’s thread didn’t change anything.


#7

Are you completely sure you passed a reference to the existing AudioProcessor to the OSCReceiver and didn’t create a new AudioProcessor by accident? I know you mentioned the objects have the same references, but I’m asking anyway :wink:

Another thing to play around with: try getting the OSCReceiver to talk to your plugin GUI instead. Ultimately, that’s poor design - but it may be useful as a step in figuring out where things are going wrong.


#8

I verified the id by printing all the references involved, I double checked this morning, I’m using the same AudioProcessor.

I tried that, and good news : it worked ! It’s indeed poor design but at least I’ve got something !
I checked the thread and as expected, I’m in the same thread as I was when I updated by using the GUI.
I feel like the sendParamChangesToListeners() has to be called from the thread 1 to work, the process block has it own thread (17 on the picture) as well as my receiver (22) and the method won’t work if I call it from those threads. Or maybe it has nothing to do with the threads at all but I don’t know what it might be …
[attachment=0]Capture d’écran 2013-05-21 à 13.54.56.png[/attachment]

I’m not sure thread1 is the GUI thread … But if it is and if my problem has to do with the threads, how come the host can’t be updated if the gui doesn’t exist, that seems pretty unlikely.


#9

OK, now that we seem to have eliminated some potential gotchas, I agree it looks like a threading issue. Only problem is I don’t understand exactly what the issue is (especially why it’s OK for AU but not for VST).

Anyhow, if you want to revert back to having the OSCReceiver independent of your GUI, then you probably ought to take a look at Vinnie’s threading stuff in VFLib. There’s some useful discussion about it in this thread.


#10

I’ve got something new … And I’m not sure it’s good news … Both AU & VST are working fine in Reaper with the ‘write’ mode (not with the GUI workaround). I think it means that it’s the way Ableton handles the VSTs that’s messing up with everything …

I can’t really figure out how to workaround this, but I’m not sure adding a new dependency to Vinnie’s VFLib is the best solution. There should be a way to resolve this without it.

Maybe it has to do with the fact that OSC messages do not send “beginParameterChangeGesture” and that it’s messing up with ableton and juce’s vst wrapper or whatever. I think reaper is getting it because it has multiple automation ‘mode’ … Anyway I’m digging this way now to see if I can get it to work in Ableton.


#11

At least there’s a possible explanation for the problem - I was a bit worried I couldn’t figure out what was going wrong :roll:

Are you going to try implementing parameter change gesture notifications from your OSCReceiver?


#12

Yes, the thing is touchOSC doesn’t send when a parameter is “touched”, so I may have to try something with timers I guess. When a slider is moved I send a beginGesture and after a certain amount of time, if the slider’s value hasn’t change I’ll send the endGesture. Maybe that’ll change something …


#13

That didn’t work either …


#14

Bugger :frowning:


#15

Maybe this is related?

http://www.juce.com/comment/298108#comment-298108


#16

I am experiencing a similar issue with the jassert isAboveorBelow in the AudioBuffer getSampleData().  When this:


inline bool isPositiveAndBelow (const int valueToTest, const int upperLimit) noexcept
{
    jassert (upperLimit >= 0); // makes no sense to call this if the upper limit is itself below zero..
    return static_cast <unsigned int> (valueToTest) < static_cast <unsigned int> (upperLimit);
}

gets called in MathFunctions and the debugger Locals says valueToTest and upperLimit are both = 1

jassert still fails and isPositiveAndBelow returns false to the getSampleData jassert. 

What is strange is that the debugger steps over the return static_casts like it should be returning both of them. 

**EDIT** To clarify, I am unsure whether the jassert in the code above is returning true or false, but I assume it to be true becuase the return statement executes. isPositiveAndBelow returning valuetoTest and upperLimit doesn't seem to be translating to true. 

**EDIT** Upon further investigation, I discovered that in my PluginProcessor.cpp


void FrameworkAudioProcessor::processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages)
{
    float* sampleData = buffer.getSampleData(0);
    for(long i=0; i<buffer.getNumSamples();i++)
    {
        PluginProcessor.ClockProcess(&sampleData[i]);
    }

I was passing a 1 instead of 0 to getSampleData and my plug, being mono, had nothing to return. 
 


#17

You seem a little confused.. What happens in this function is irrelevant without looking at the stack trace that called it. The assertion just tells you that something called it with a duff argument - you need to look at the stack to see where that bad input came from.