HISE Logo Forum
    • Categories
    • Register
    • Login

    Multiple Global Data Cables - only the first one gets a runtime target

    Scheduled Pinned Locked Moved Solved Bug Reports
    10 Posts 3 Posters 86 Views
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • O
      Orvillain
      last edited by

      Custom c++ node:

      #pragma once
      #include <JuceHeader.h>
      
      namespace project
      {
      using namespace juce;
      using namespace hise;
      using namespace scriptnode;
      
      enum class GlobalCables
      {
      	dataCable = 0,
      	otherDataCable = 1
      };
      
      using cable_manager_t = routing::global_cable_cpp_manager<
      														SN_GLOBAL_CABLE(-389806413),
      														SN_GLOBAL_CABLE(-389806400)
      														>;
      
      template <int NV> struct custom_node: public data::base,
      								    public cable_manager_t
      {
      	SNEX_NODE(custom_node);
      	
      	struct MetadataClass
      	{
      		SN_NODE_ID("custom_node");
      	};
      	
      	static constexpr bool isModNode() { return false; };
      	static constexpr bool isPolyphonic() { return NV > 1; };
      	static constexpr bool hasTail() { return false; };
      	static constexpr bool isSuspendedOnSilence() { return false; };
      	static constexpr int getFixChannelAmount() { return 2; };
      	
      	static constexpr int NumTables = 0;
      	static constexpr int NumSliderPacks = 0;
      	static constexpr int NumAudioFiles = 1;
      	static constexpr int NumFilters = 0;
      	static constexpr int NumDisplayBuffers = 0;
      
      	custom_node()
      	{
      		// this doesn't do anything, but if you want the communication the other way around
      		// (from HISE to your C++ node, this is the way to register callbacks).
      		this->registerDataCallback<GlobalCables::dataCable>([](const var& funky)
      		{
      			jassertfalse;
      		});
      		
      		this->registerDataCallback<GlobalCables::otherDataCable>([](const var& funky)
      		{
      			jassertfalse;
      		});
      	}
      
      	// We don't need any of the DSP callbacks for this example so we can use these macros to
      	// define empty methods
      	SN_EMPTY_PREPARE;
      	SN_EMPTY_HANDLE_EVENT;
      	SN_EMPTY_PROCESS;
      	SN_EMPTY_PROCESS_FRAME;
      	SN_EMPTY_MOD;
      	SN_EMPTY_RESET;
      
      	void setExternalData(const ExternalData& data, int index)
      	{
      		if(data.isNotEmpty())
      		{
      			// convert the data to the juce::AudioSampleBuffer class
      			auto buffer = data.toAudioSampleBuffer();
      
      			// fetch a few properties from the buffer
      			// (this is the place where you could do your custom processing
      			auto magnitude = buffer.getMagnitude(0, 0, buffer.getNumSamples());
      			auto rms = buffer.getRMSLevel(0, 0, buffer.getNumSamples());
      			auto length = buffer.getNumSamples();
      			auto channels = buffer.getNumChannels();
      
      			hise::JSONObject obj;
      
      			// write the values into the JSON object
      			obj[String("magnitude")] = magnitude;
      			obj[String("RMS")] = rms;
      			obj[String("length")] = length;
      			obj[String("numChannels")] = channels;
      
      			// just attach the current knob position so you know it's working.
      			obj[String("knobValue")] = value;
      
      			// send the JSON object back to HISE
      			this->sendDataToGlobalCable<GlobalCables::dataCable>(obj);
      			this->sendDataToGlobalCable<GlobalCables::otherDataCable>(obj);
      		}
      	}
      	
      	template <int P> void setParameter(double v)
      	{
      		// just save the parameter to be send in the JSON object later.
      		value = v;
      	}
      
      	double value = 0.0;
      
      	void createParameters(ParameterDataList& data)
      	{
      		{
      			parameter::data p("MyParameter", { 0.0, 1.0 });
      			registerCallback<0>(p);
      			p.setDefaultValue(0.5);
      			data.add(std::move(p));
      		}
      	}
      };
      }
      
      

      Then the interface script:

      Content.makeFrontInterface(600, 600);
      
      reg rm = Engine.getGlobalRoutingManager();
      
      reg dataCable = rm.getCable("dataCable");
      reg otherDataCable = rm.getCable("otherDataCable");
      
      dataCable.registerDataCallback(function(data)
      {
      	Console.print(trace(data));
      });
      
      otherDataCable.registerDataCallback(function(data)
      {
      	Console.print("We could have other data here from the same node");
      });
      
      
      
      

      Here's the project snippet:

      HiseSnippet 1238.3ocuWs0SibCE1SfY2R5tRck19Z0HdJTQiRfvsspp.IDZTKPDgR2GPB43wCwEO1i73AHsZk5i8ma+GzdNyLIYlRX2UQsKHglyU+4i+NGa5azLdbr1Pbpdw3HNw4EtCFqriZOhJTjdcHNegaXhzJhjbFcnjGSNbbDMNl6SbbV5XzKmUVlj9ye88GRkTEiOSEgboVv3+jHTXmos+9+nPJ6R84WHBK3cq86wzp1ZoNAPzRtMHQT1sza3mRQ2p3R9AZ7HhyW6t0FaxZ4ui+Far0daynay2KfFDzbS+Vs1d28Zt4dzV6tMuwVDmmcjuvpMCrTK.dmkOT6OdvH88prE3RQr.1VnPSx.XkyT2UK8wsHpkzdjP52eRoJl.Yo+rB2RYEtW6dhvWLUewBHZvaVDEKfNUJCukJAulEgWiBvaNPxo.jVNCRuxc.yHhryrf34yc6orbS.ENmJBkLeIU9pJts0fGJa8P5s7tFPXZD01tQi08f+r12VspgeimIz667NRciPwqeC2drTOjJOWmXEpaNgpfyNSsI95Ssz1HIBBwDhtmJUa0oFVEbE8TaGwMcdJ2KaEio5zLTGBWDamXWJGBLnZAIJlUnU0P+Vq5uWcEXKFqA2iLBksl0f6sTiP1dGlwxKxhk1U+EtGSmH88FQuimsqRqBdvGbu.iNzCz4ECzaOk1Ocujt5UmjZOs5TskelpVZ9q9tpd+aSAAy0FdHZzRId.LGyXmm48EXMUR3PtYcu6nxD9TGA1UYJq6SSYK1Qwx3TEbTq5oD1yh3pmpOijSDgu94dXkG4445.+h3Fq.gfSG9cvTlLV+Jtc3w2Z0QvblG0R.MiZ+DI0VtCEmika.pAkZKPpuJVXGWbN2+YsserP7Ut8EV1n4iwJyAiPk5+CLlOr6ktGEDvY1Y.bY2tu8S2jsp4S1f0DW7WjK508sMm2LMm+zcFAOxvinF9E59R53ZPqGb014.FW2anTytcf323OtqHJCBGhdTiMhpTbY7hz77rO5pRy2+gxzYrVi3AnK7zjvAv0lLd6bzA5bpf8PYxMPYjWLfq7SE9a3mbiMQYmbiMmXrP62ob68ZysoGG4eSbddVsuSbzDUWxMwH4z44tMpC+RNPJ022VGFIxosvgRpt9Z43nQZkfgpx7XBzOHTm.qZN9gq7ufJjHOePRLLsv+L0.v4z2Yf7rSgAmPgsKkAE1w8o1QX+BNuAHmbSc1TRZIrNimfU3rWXTxALuSdKRVoCfYHVOvWh3rDZOqfjA.bEdoKKI1pCuFmlSJAouzEHQ+JzzTunKyCEkSxGBFXsSxeXx3wCR7E5tBYFzlJAsN8T97GvN0uoI4Hfc5CuvIMJm8cO9MW0AFnNT+vUGmHrTy4hff1ZSTR7U.rsPWmuHdmFWEl.71q5zyC+nVilqU+d5cjSDpKQh9DDdB8gox+waVAFgPMvVCt+LqgdhDXuPnHmoXntMA4rp5IimESA22hzgGPg2mVRGovcCkW5RVRGrfRvXyJYzidwWhVYT4jUAnfGp02FRSI+K10PeJZUCoLi9ZV1zGby8YoZ.9gJkSsh6InrWSxcYarYWTDBOO8ZFqbpdTfarnAt4hFXqEMvsVz.2dQCbmEMvc+vAh+2CGj.iCxFfBMW8OJqs04HE91zza5H+C7L.wuK
      

      You'll need to compile the custom node as "custom_node".

      So what I am seeing here, and I have no idea why .... the "otherDataCable" does not get a "Runtime Target" entry in the list of targets, so its callback never seems to run.

      This is using two cables with a single node.

      Is this not supported?

      Christoph HartC 1 Reply Last reply Reply Quote 1
      • Christoph HartC
        Christoph Hart @Orvillain
        last edited by

        Have you created the boilerplate code with the correct IDs? The hashes look suspiciously similar.

        Christoph HartC 1 Reply Last reply Reply Quote 0
        • Christoph HartC
          Christoph Hart @Christoph Hart
          last edited by

          If I'm using the global cable code creator with your Ids I get:

          // Use this enum to refer to the cables, eg. this->setGlobalCableValue<GlobalCables::dataCable>(0.4)
          enum class GlobalCables
          {
          	dataCable = 0,
          	otherDataCable = 1
          };
          // Subclass your node from this
          using cable_manager_t = routing::global_cable_cpp_manager<SN_GLOBAL_CABLE(-389806413),
                                                                    SN_GLOBAL_CABLE(165255555)>;
          
          
          O 1 Reply Last reply Reply Quote 0
          • O
            Orvillain @Christoph Hart
            last edited by

            @Christoph-Hart Dannngg!!! I knew I cocked something up!!!! baaaahhh!!

            Thanks Chris. No bug here. You're 100% right.

            griffinboyG 1 Reply Last reply Reply Quote 1
            • O Orvillain marked this topic as a question
            • O Orvillain has marked this topic as solved
            • griffinboyG
              griffinboy @Orvillain
              last edited by

              @Orvillain

              Oh yeah i made this mistake a while ago XD

              I use a template for my c++ nodes and it has a helper baked in with temp IDs for the cables. I forgot you have to generate the IDs from the project!

              O 2 Replies Last reply Reply Quote 1
              • O
                Orvillain @griffinboy
                last edited by

                @griffinboy Yep - I can't even plead ignorance either. I knew about the hashing and just totally forgot! So I'm an idiot!

                1 Reply Last reply Reply Quote 0
                • O
                  Orvillain @griffinboy
                  last edited by

                  @griffinboy @Christoph-Hart

                  Do you know if DataCables work in Scriptnode Synthesizers? Because I've just taken my node and put it into one, and now I no longer get the runtime target showing up, and the data callback no longer fires.

                  Nothing has changed, and I only have a single instance of the node in the entire project.

                  If I delete the scriptnode synthesizer and re-add the script FX, then it immediately begins to work.

                  griffinboyG 1 Reply Last reply Reply Quote 0
                  • griffinboyG
                    griffinboy @Orvillain
                    last edited by

                    @Orvillain

                    It should work fine. I think it works. I might be wrong though, I haven't used them in a synth recently.

                    Process() only runs when voices are playing in a scriptnode synth. But that shouldn't affect the callbacks.

                    O 1 Reply Last reply Reply Quote 0
                    • O
                      Orvillain @griffinboy
                      last edited by

                      @griffinboy Hmmmm, that might be what I ran into. Can't remember now. But basically my c++ as an effect works well... and I'm able to update the UI any time I turn a parameter.

                      But when I tried to convert it to a synth... it wasn't working.

                      This actually makes sense, because my sendData function gets triggered from within processFrame, which gets triggered from within process()

                      griffinboyG 1 Reply Last reply Reply Quote 1
                      • griffinboyG
                        griffinboy @Orvillain
                        last edited by griffinboy

                        @Orvillain

                        Yep that'll be it.

                        I actually wish it worked differently, but currently scriptnode c++ synth nodes only call process() per active voice. So if there are no voices it won't call process (or subsequently process frame).

                        Additionally say there are 3 voices playing, that will mean your process script gets called 3 times as frequently... Each voice will run it's own process.

                        You can check which voice the process() is currently running for, using polydata, which allows you to do different processing per voice

                        1 Reply Last reply Reply Quote 0
                        • First post
                          Last post

                        16

                        Online

                        1.7k

                        Users

                        11.8k

                        Topics

                        102.6k

                        Posts