Is there a way to pickup host transport messages directly within a custom node??
-
I'd like to be able to poll transport start/stop and tempo changes from within a node. Is that possible, or do I have to use a data cable to feed messages from the top Hise layer?
-
I'd like to be able to poll transport start/stop and tempo changes from within a node. Is that possible, or do I have to use a data cable to feed messages from the top Hise layer?
+1 Would really like to know about how to do this.
Definitley a good place to start experimenting is the tempo_sync node and the tempo_sync_base class it inherits from.
-
@HISEnberg https://forum.hise.audio/topic/11486/c-transport-handler/4
I just came across this too, which seems relevant.
-
@Orvillain Nice find.
Honestly up until now I have just been placing my C++ nodes inside of scriptnode and using that for interacting with transport/tempo information. Not always the most ideal solution but it does work in most scenarios.
-
@HISEnberg If in doubt, stalk @griffinboy

So following Chris's comment in that thread, it sounds like the node needs to inherit from:
public hise::TempoListenerAnd then you write a custom callback. Something like:
void tempoChanged(double newTempo) override { // yo bro, do a thing here innit fam bruv dudemeister for (auto& t : data) { t.bpm = newTempo; t.refresh(); } }But I haven't tried it yet.
-
#pragma once #include <JuceHeader.h> namespace project { using namespace juce; using namespace hise; using namespace scriptnode; using namespace snex; /** Smallest possible BPM listener example. Demonstrates: - TempoListener registration - tempoChanged() callback - BPM flowing into the audio graph */ struct MinimalBPMListener : public data::base, public hise::TempoListener { SNEX_NODE(MinimalBPMListener); struct MetadataClass { SN_NODE_ID("MinimalBPMListener"); }; static constexpr bool isModNode() { return true; } static constexpr bool isPolyphonic() { return false; } static constexpr bool hasTail() { return false; } static constexpr bool isSuspendedOnSilence() { return false; } static constexpr int getFixChannelAmount() { return 1; } // --- Tempo sync --- hise::DllBoundaryTempoSyncer* tempoSyncer = nullptr; double bpm = 120.0; // Exposed modulation value double lastOut = 120.0; // --- TempoListener --- void tempoChanged(double newTempo) override { bpm = newTempo; lastOut = bpm; // make it observable } // --- Lifecycle --- void prepare(PrepareSpecs specs) { if (tempoSyncer == nullptr && specs.voiceIndex != nullptr) { tempoSyncer = specs.voiceIndex->getTempoSyncer(); if (tempoSyncer != nullptr) tempoSyncer->registerItem(this); } // Initialize output lastOut = bpm; } void reset() {} ~MinimalBPMListener() override { if (tempoSyncer != nullptr) { tempoSyncer->deregisterItem(this); tempoSyncer = nullptr; } } // --- Processing --- template <typename T> void process(T& data) { static constexpr int NumChannels = getFixChannelAmount(); auto& fixData = data.template as<ProcessData<NumChannels>>(); auto fd = fixData.toFrameData(); while (fd.next()) fd.toSpan()[0] = (float)lastOut; } int handleModulation(double& value) { value = lastOut; return 1; } void setExternalData(const ExternalData&, int) {} }; }This is a minimal example of how to get your custom C++ node to listen to the host BPM. Code above doesn't actually DO anything with the BPM information. But it proves the concept.