PnS problem with output strings

Official support for: bluecataudio.com
Post Reply New Topic
RELATED
PRODUCTS

Post

Hi there Bluecats :-)

yes, I admit I am a menace :-D just found another thing with PnS that causes me some trouble.

This has to do with computeOutputData(), output strings and a output-parameter-bound kuiml action trigger that helps me to keep cxx and ui in synch.
The finding is that only output string 0 and output string 1 will find their way into kuiml action trigger in in the current cycle.
Very difficult to explain... here's some code (commented excerpts)



KUIML:
important is CLICKEDCHORDNAME, script_output_string2 and updateChords().
If certain changes occur in the DSP part, computeOutputData() will update values in script_output_string0 and script_output_string2 (proven that it does) and increase value of OP_CHORDCHANGETYPE, in order to trigger updateChords() in KUIML.

=================================

Code: Select all

	:
	:
  <STRING id="CLICKEDCHORDNAME" default="---"/>
  <STRING id="ARRCHORDNAME0" default="---" persistent="false"/>
  <STRING id="ARRCHORDNAME1" default="---" persistent="false"/>
  <STRING id="ARRCHORDNAME2" default="---" persistent="false"/>
  <STRING id="ARRCHORDNAME3" default="---" persistent="false"/>
  <STRING id="CHORDCANDIDATENAME0" default="---" persistent="false"/>
  <STRING id="CHORDCANDIDATENAME1" default="---" persistent="false"/>
  <STRING id="CHORDCANDIDATENAME2" default="---" persistent="false"/>
  <STRING id="CHORDCANDIDATENAME3" default="---" persistent="false"/>
  <PARAM id="CHORDCANDIDATEINFO0" type="integer" min="0" max="2147483647" default="0" exposed="false" persistent="false"/>
  <PARAM id="CHORDCANDIDATEINFO1" type="integer" min="0" max="2147483647" default="0" exposed="false" persistent="false"/>
  <PARAM id="CHORDCANDIDATEINFO2" type="integer" min="0" max="2147483647" default="0" exposed="false" persistent="false"/>
  <PARAM id="CHORDCANDIDATEINFO3" type="integer" min="0" max="2147483647" default="0" exposed="false" persistent="false"/>
  	:
  <ACTION_TRIGGER event_ids="custom_out_param6.value_changed"  script="updateChords(custom_out_param6);"/>		
														<=== gets triggered when computeOutputData() changes (increases) out param 6 value
	:
	:
  <SCRIPT  .....
  	:
      void updateChords( uint updateChordType ) 
      {
        CLICKEDCHORDNAME = $script_output_string2$;								<==== CORPUS DELICTI !! 
        														$script_output_string2$ always contains value from PREVIOUS computeOutputData()

		string arrChordNames=$script_output_string1$;							<==== SEEMS GOOD, BUT CANT PROVE THAT ITS GOOD IN ANY CASE
		array&lt;string> aChords=arrChordNames.split(&quot;,&quot;);
		if( aChords.length > 0) {
			firstAC= aChords[0];
			ARRCHORDNAME0=aChords[0];
			ARRCHORDNAME1=aChords[1];
			ARRCHORDNAME2=aChords[2];
			ARRCHORDNAME3=aChords[3];
		}

          firstCC = &quot;empty&quot;;
          string ccNames=$script_output_string0$;								<==== GOOD IN ANY CASE, contains always the value of CURRENT computeOutputData()
          chordCandidates = $script_output_string0$;
          array&lt;string> aCcChords=ccNames.split(&quot;,&quot;);
          if( aChords.length > 0) {
            firstCC= aCcChords[0].substr(5);;
            CHORDCANDIDATENAME0=aCcChords[0].substr(7);
            CHORDCANDIDATENAME1=aCcChords[1].substr(7);
            CHORDCANDIDATENAME2=aCcChords[2].substr(7);
            CHORDCANDIDATENAME3=aCcChords[3].substr(7);

            CHORDCANDIDATEINFO0 = parseInt(aCcChords[0].substr(0,7));
            CHORDCANDIDATEINFO1 = parseInt(aCcChords[1].substr(0,7));
            CHORDCANDIDATEINFO2 = parseInt(aCcChords[2].substr(0,7));
            CHORDCANDIDATEINFO3 = parseInt(aCcChords[3].substr(0,7));
          } else {
            /*firstCC = &quot;empty&quot;;*/
          }
          updatesMade = updatesMade+1;

      }



CXX:
=================================

Code: Select all

OP_CHORDCHANGETYPE = op("ChordChangeType", "", 0,65535,0,".0"); 				<== OUTPUT PARAM 6  (triggers kuiml action trigger)
	:
OPS_CHORDCANDIDATENAMES = ops("ChordCandidateNames");						<== OUTPUT STRING 0
OPS[OPS_CHORDCANDIDATENAMES] = "";
OPS_ARRCHORDNAMES = ops("ArrChordNames");							<== OUTPUT STRING 1
OPS[OPS_ARRCHORDNAMES] = "";
OPS_CHORDNAME = ops("ChordName");								<== OUTPUT STRING 2
OPS[OPS_CHORDNAME] = "";
	:
	:
void computeOutputData()
{
    chordTypesToUpdate = 0;
    if( chordChanged ) {
        if( chordDetector.hasResults()) {
            chordTypesToUpdate |= 1;						
            OPS[OPS_CHORDNAME] = curChordInfoName;						<=== CORPUS DELICTY  
            											(output string 2) I can prove from logs that it actually gets changed each expected time
            											to a current value,  but in kuiml (action trigger) always arrives the PREVIOUSLY computed
            											value.
        }
        chordChanged=false;
    }

    if( arrChordsChanged ) {
        string arrChordNames;
        for( uint i=0; i<15;i++) {
            arrChordNames+=curArrChordNames[i]+",";
        }
        arrChordNames+=curArrChordNames[15];
        OPS[OPS_ARRCHORDNAMES] = arrChordNames;							<=== (output string 1) Seems to work (but cant prove if always, cause this changes only once in a while)
        chordTypesToUpdate |= 2;
        arrChordsChanged = false;
    }


    if( chordCandidatesChanged ) {
        string arrChordNames;
        for( uint i=0; i<3;i++) {
            arrChordNames += formatInt(int64(curChordCandidatesInfo[i]), "0", 7);
            arrChordNames += curChordCandidateNames[i]+",";
        }
        arrChordNames += formatInt(int64(curChordCandidatesInfo[3]), "0", 7);
        arrChordNames+=curChordCandidateNames[3];
        OPS[OPS_CHORDCANDIDATENAMES] = arrChordNames;						<=== (output string 0) Can prove that this gets updated each expected time along with output string 2,
               																 output string 0 gets into kuiml action trigger with this CURRENT value 
        chordTypesToUpdate |= 4;
        chordCandidatesChanged = false;
    }

    uint uiUpdateMsg = (chordTypesToUpdate > 0 ? (chordTypesToUpdate << 8 | nrOfUIUpdates) : 0);
    if( (KittyDSP::Utils::roundDoubleToInt(OP[OP_CHORDCHANGETYPE]) != uiUpdateMsg) && chordTypesToUpdate>0) {
        nrOfUIUpdates = (nrOfUIUpdates+1) % 256;
        OP[OP_CHORDCHANGETYPE] = uiUpdateMsg;							<=== if i want tht UI to update, 
         																	 put a new value into OP[OP_CHORDCHANGETYPE] (out param 6), so kuiml triggers
    }
}

Conclusion is that output string 0 and output string 1 will have their most current values when KUIML triggers updateChords(...), but output string 2 still has the value of the previous computeOutputData() cycle.

The funny thing is that I've swapped output string indexes. Before, output string 0 was OPS_CHORDNAME and output string 2 was OPS_CHORDCANDIDATENAMES (now 2 and 0).
And guess what ... before, OPS_CHORDNAME was always good and OPS_CHORDCANDIDATENAMES contained always the value of the previous computeOutputData() cycle.... the same thing that now happens to OPS_CHORDNAME at OPS position 2.

So.... this seems to me as if only a certain amount of output strings gets updated INTO kuiml before action trigger (in this case OPS_0 and OPS_1 ; OPS_2 stays behind)...
or if updateChords() gets triggered BEFORE kuiml finished the update of all changed OPS.


I am not sure if all this explains the problem properly. My code is still an experimental mess, but if it helps to find out what happens, just give me a ping and i'll send it.


Have a nice weekend
Cheers
Rudi
http://www.pulpoaudio.com
Virtual Percussion Instruments
email: pulpo@pulpoaudio.com

Post

The communication between GUI and DSP is a rather complex thing, full of asynchronous updates between multiple threads and event loops, so it may indeed happen at some point in time that some output strings are up to date and some are not yet. So if you need to make sure that several pieces of data are absolutely in sync in the GUI, you should probably save them all in a single string (as a data structure), or make sure that you update the chords every time an output string is modified.

Post

yes, I've already figured out this solution... now, I sync DSP and GUI with a input_string (command from GUI to DSP) and only one output_string (all results in one string from DSP to GUI).

A rather steep learning curve :-D

Just to let you know a bit about the challenge:
In a earlier state of development I was exchanging out_params and in_params between DSP and GUI, each containing all info about a chord (gender, key, etc.) in a bit coded manner (4 bit for gender, 4 bit for key, etc.), which worked fine so far. Then I had to add a 8bit "chord type" info to that number .... and exceeded the possible 24 bit. The params are real and won't resolve integers > 24 bit ... huh huh :-D
So I started to assemble out_strings with these infos, one out_string for each of the different chord sections on the UI. But they wouldn't come in all at the same time, which made me call for help...
Seems to be solved now...

However, it would be great If in a future version of PnS there was a possibility to ensure that all params/strings come in to the GUI at the same time, so they'll all be updated when the first "value-changed" action trigger fires... It's just a though, don't know if it'll be possible, but it may be worth thinking about it.

Thanks for your support !

Cheers
http://www.pulpoaudio.com
Virtual Percussion Instruments
email: pulpo@pulpoaudio.com

Post

It is a rather complex topic, especially when you have large data structures and many different objects. Forcing them to be always in sync in the GUI could result in freezing the GUI everytime you have an update.

Post Reply

Return to “Blue Cat Audio”