A/B comparison



  • This has been asked for a few times. Here is one solution I have found, although I haven't tried it in a real world project so there may be some unintended effects.

    Originally I was thinking of exporting the state of the controls to a string and storing them in a panel but unfortunately HISE prevents us from getting a reference to the main interface from within the main interface script so that won't work.

    The method I'm using instead is to export as a preset XML outside of the usual preset system (I think).

    HiseSnippet 1083.3ocsV07aaaCEmJwpqVatXEnm1IhbRFI00tesglEjZ67AL5RhwbWv.JBJnknrIBEo.EcVLJx+J6xNtq6OncY22+AaORIYI24kEWfoKRuu3626GIeOMTICnooRExo9ammPQNeg6n4B8z9SILAZvAHm66RFqooZTu4IjzTZHxwYyiMVcpWCYe9y86Q3DQ.sTEBctjEP+NVLSWpc3qeCiyOhDReKKth2O+0CBjh9RtbFfjMcaiRHAWRlPOkXbaCWjy8NLjokpQZB.FjSsdxv4ilJ+IQl+myRYi4TiPGzHXgxTejjGZPr4aT+oLd3vhJNEAqxvx5eyr5+QtmvBYKzWxCeo0.tLhp7gyF2F757IBOmJvqVF7dn6n.EKQWZwfsO2cfPSUQDXKnJrx7EswOuoaeI3gP2JlbI8HEHrHB+W1t8N3Wztcyca30vyt82JjFQU8Ib9XXiH0WqlQyLqnSvL3KX+JUiuhnvi0ht8v6ge2Ef5HoB6y.o16hY3uE+T301a2rg2GZ3ggGqyuicA3QAhlP08kwIRAH3uUuYZsTr01LS5pFQqTieBsRxKvkuTXslqt4td2XfHSvYBJNZlHPyjB7xd4Gj8dG.7bnp.nYRSVxXQXeqZ7d6g6zLSYNzMObY.giYgWC32tnsXhP50mEUrpM2E+jmbLUi0SoXhRQlisdfkQVU.SM1VgfDA7RwlLgpng3f7ZpLW.dSkbZqDECHFHmELhEnFH.rLd+E7nBtjJUztbddklB6ywCA0TfW6tUS7qti91aKfJMY4lhz4cSE17Toldlvuo2G7p6ci2GaIJZUlxyCmpVkUS6.0sDluXV7XppXOy3mYqZ4sfLeZZ3kG2oIrOLXh.JxRNOMe+LunVvlYGwZeg4n34lD3aWjNUH2Olt5lVRr6fiH7TZU98e28dKbOmhg5Etcub6i6c2ZeDjksJNJECDL8YIzb4xFLcVQCFTNbMsZxQJ3p11n4A4MZFwYgTEhAKxm49FgbbGjcOHu48u+KI+w9neXvADMoXYfUDxRBUoYlhw4.5Uvnfr9W0cOfldoVl.IZwsdXoWNoYMArIstalPaz0HGWmG.4bt4iuB9PSuVapstHEIjIOVImkjUqojqnCDYbtoQHZsxUmrb8aqJW8VqbU6+jLsYZRQl9U6Tx+QWeX1iLbFmnWdfjYJbtA31xRc9Mc2EoL87pSoWioTsW4TpUdH5NB2G5NjoCltZ7twJvKbb5+a7lOyug6gQQz.cIXq4dzO9oNfeMfx2KmoYhImPf4.lCBmNKdD7KPAT.IBAkmZNSrg4hZlbairgYFQEgVg+BdxM1wH6jarSgQTLIPIee93IyeUbeqF.SB6OWU28DiLdw8ZCtige048AAFh3w.xWcDOcsi3YqcDOesi3EqcDubsi3qW6H9laIBy+U1clVFmcs.TL7Pa+TGmCED3Tk8DH5ugyQVSL
    


  • Actually it seems there is a problem with this method too, it only write the value the first time the state is exported. @Christoph-Hart is this intentional?



  • @d-healey Very good starting point.
    In A/B comparsion, There is an A to B copy button (so the user don't have to start a new preset from scratch, just continue from the A) and undo, redo options.

    Overloud-Comp-G.png



  • This solution is not working properly? Anyone didn't implement it yet?



  • Now that we have the ability to read/write JSON files I think that would probably be the direction to go in with this.



  • @d-healey hmm, but that would mean writing to the JSON file every time the user changed a UI element no?

    Given this is all transitory data - cant you just keep it all in an array? Or am I missing something obvious?



  • @Lindon You'd only need to read/write the JSON when the A or B button is pressed. I'm sure there was some reason why we couldn't just store it in an array but right now I can't remember what that is... perhaps it is doable!



  • @d-healey - maybe - but my thinking went like this:

    on init

    • read all the GUI element values - store them in Array_A and Array_B

    on ui change

    • store its value in Array_A (if A button = true) or store it in Array_B (if B button = true)

    on button A

    • set everyone to Array_A values and issue .changed()

    on Button B

    • set everyone to Array_B values and issue .changed()

    Or (as I say) I may be missing the point here...



  • @Lindon

    on ui change
    store its value in Array_A (if A button = true) or store it in Array_B (if B button = true)

    This might add some unnecessary overhead and extra code. Why not just store all values in array A once when button B is pressed? I'm also thinking we could avoid using an array and use a base64string using MidiProcessor.exportState() although I don't know if this function can be used from within the MIDI processor that is being exported/restored.



  • @d-healey sure that'd work too...



  • Has anyone explored this further? I'm experimenting with exportState() and restoreState() at the moment.

    HiseSnippet 1068.3ocsVEtaaaCDlx1paVadXEnO.b4W1.YNxaqcEnXXw1ItvnKIFyccCqnvfVhJlHRjBTTswKHOC6UZOB6QY+e+X6HkjkblRVpwl7OLOd22wu63wiblT3QSRDRjU6WtNlhr9X64q4pUiWQXbzziPV11CWLBMZcLIIg5irrZ9bsJq1sP4eiHgDtGs5TuRv7neGKhopL6gufEFNg3SeIKZKqm5I3iEghTfFMscQwDuKHmSOknMqgMx5AG6yTB4bEQQS.aFI7WOek3c7L6eEKgsLjpEFflCNJaZz3UrP+YEgXBBY0ZVY.2LKfej8ILe1l4KC7O0n.WhnZNvpw1Tp0VTZvsQoIhPesCtE5YUgdsxn2Csm6IYwpRMZt8Q1S4JpLf.o8pzJyVTi+ro8XAXAW0OhbAchDD1fn6Sbc2G+XW2dOqiSGmCN3bpBKoATIE1FwJANBxAXXSQA+SkcbfgIJ7aIRLTKf+FroDoO.yDBFot6Ap1qviF6VlpTBNlHkj0a4iQKFpmCbzqKXo1WhnXAGD.WsWu863fq8qdDvR+lh01rf5vHA1fnXyVDVDfGhGciPYwbvBnRSyjMvYblhQBY+BM2SuioVg8RkP5QgCEPArO3Zvocbp3iW69FvMvD8oWFKjJyx1UmPpZzfaynreLdHjwwAobOECxcZnSxE55UDt6C7OLk1qiyUYYoCNHKTMrByBvwoIqn9YJYAcKLWKdUYhMT3QBwL+K0bJeSoOi6Su7rfxUSytBDUCE.2sELZSuN6uBBJovZEVxPtPcSV9Y+WRy9RpImjQJ.bEd0tiy0lTdfP1krjrD1y234dX8L8SzkWbkTDNF38RniT2paF8d1l8HA+TghdFuaOmqbZ6bsC9lpBBpUWt+CoxZUq6RJuKfc4oQKoxhpgBCgVGa2a5A2udSdYGrpXnfOENKbVLMWtr60fZ5dgxOYB8wZlyPXjxzE6Sx6hMxzR.wLNYHxP7xaB9iuEcu.N5l.yW75.NOj4SkFfef8K3hkCpA7OL8Hhhna.mGCPbESkJlN8YcD8svsYYsiaaeDM4BkH1Dj4kdvkj2YXdIXf0uBqyZ8feFFHI9Lwykhz3hr48yWiz9Jm3+dxgqKihe7v6xms9WSJk9EGUwu+14Gh9mWJAWMJ7SCIpsuuT+vfbEPg5VWLou7gmvTqqta+dbIpasWhVaY38jtOzdFS4spd91nF9BkG+ey27mjzw93f.pmpjrsrm7S656OdOnx2KRUL94mPTRltn8zzn4vqx7n.S3bZXht9sg9zVlrqVVmYlS49Fg+B9xUNPKakqbPgRTDwSJV3kcbU+nmOzLCvIt48dssOQKi2bN011suKJBdK1BOOcp3yAtWOluXGv7k6.luZGv73c.yS1ALe8Nf4o2IF8yfGlpDQYGSfIlcroeok0wbBTkYpHQ+c3rG0t
    
    Content.makeFrontInterface(600, 500);
    
    //get reference to main container
    const var A_B = Synth.getChildSynth("A_B");
    
    // A_B button array
    const var AB_Array = [Content.getComponent("A"),
                          Content.getComponent("B")];
    
    // array to store State of A B
    const var A_B_Storage = [];
    
    // initialize array with current loaded state
    A_B_Storage[0] = A_B.exportState();
    A_B_Storage[1] = A_B.exportState();
    
    
    
    inline function A_B_Function(component, value)
    {
        //store state if pushed
        if(value)
        {
            local idx = AB_Array.indexOf(component);
            A_B_Storage[idx] = A_B.exportState();
        }
        
        //recall state if not pushed
        if(!value)
        {
            local idx = AB_Array.indexOf(component);
            A_B.restoreState(idx);
        }
    	
    };
    
    for(abab in AB_Array) abab.setControlCallback(A_B_Function);
    

    The exportState() appears to be working and I can store that value in an array, but restoreState() is questionable. At the moment, it only sets the master container volume to -100.



  • I spot an error in my function. in the second half idx is undefined.

        //recall state if not pushed
        if(!value)
        {
            local idx = AB_Array.indexOf(component);
            A_B.restoreState(idx);
        }
    

    it should be

        //recall state if not pushed
        if(!value)
        {
            local idx = AB_Array.indexOf(component);
            A_B.restoreState(A_B_Storage[idx]);
        }
    

    but changing to this value causes an instant crash.



  • @dustbro yeah I have A/B running in my synth - export and restore are not any use to me - as I want to be able to morph states a-to-B and to include/exclude voices in that process.. so it's all hand built.



  • @Lindon said in A/B comparison:

    it's all hand built

    Any hints on the method you used?



  • @dustbro see the post here from April 9th



  • @Lindon Are you using

    Content.storeAllControlsAsPreset()
    

    or

    Engine.dumpAsJSON()
    


  • @dustbro said in A/B comparison:

    @Lindon Are you using

    Content.storeAllControlsAsPreset()
    

    or

    Engine.dumpAsJSON()
    

    no. neither.

    I have a two array-dimensional array of "sound affecting controls"(lets call them slots) - and a button (in stateA or stateB).

    I save the array in the preset(panel.data) and depending on the button state I load one or other dimension.

    This allows me to :

    1. have a morph slider so I can move between slots
    2. Include or exclude any set of controls from this morph
    3. on preset load I can overwrite the loaded preset with these values if I wish

    So I have a 4-voice synth - the user can morph between Slot A and B - and include or exclude any voice, and they can include or exclude any voice from a preset load.



  • @Lindon Got it! 👍


Log in to reply
 

10
Online

813
Users

3.0k
Topics

25.5k
Posts