Creating a basic rack and adding to master track

Hi,

I can’t seem to be able to find any documentation or examples for creating basic rack.

This is what i managed to put together, it compiles and runs however there is no audio output:


void MainComponent::createPluginRack()
{
    if (auto masterTrack = edit.getMasterTrack())
    {
        // Add the rack type to the edit
        auto rackType = edit.getRackList().addNewRack();
        
        if (rackType != nullptr)
        {
            // Create and add the rack instance with the rack type ID
            juce::ValueTree rackValueTree(te::IDs::PLUGIN);
            rackValueTree.setProperty(te::IDs::type, te::RackInstance::xmlTypeName, nullptr);
            rackValueTree.setProperty(te::IDs::rackType, rackType->itemID, nullptr);
            auto rackInstancePlugin = edit.getPluginCache().createNewPlugin(rackValueTree);
            
            if (rackInstancePlugin != nullptr)
            {
                masterTrack->pluginList.insertPlugin(rackInstancePlugin, -1, nullptr);
                DBG("Successfully created rack");
            }
        }
    }
}

I can see in the logs that the rack as created successfully. If i remove this line then the audio works again:

masterTrack->pluginList.insertPlugin(rackInstancePlugin, -1, nullptr);

From what i can tell in the documentation the rack should automatically create input and output nodes, i don’t need to configure that? I should just be able to call addPlugin on the rack type to start adding plugins.

P.S. I’m using a plugin rack on the master to get around the limit of 4 plugins for the master track.

It doesn’t automatically create connections. So that’s probably the problem.

There is a helper function which will probably do what you want though:

RackType::Ptr RackType::createTypeToWrapPlugins (const Plugin::Array& plugins, Edit& sourceEdit)

Check if rack instance requires explicit input/output node configuration.

I get this error when i’m trying to add the rack to the plugins list of the master track:

/Applications/JUCE/modules/juce_core/memory/juce_ReferenceCountedObject.h:310:11 Cannot initialize a member subobject of type 'ReferencedType *' (aka 'tracktion::Plugin *') with an rvalue of type 'ReferencedType *' (aka 'tracktion::RackType *')
void MainComponent::createPluginRack()
{
    if (auto masterTrack = edit.getMasterTrack())
    {
        tracktion_engine::Plugin::Array plugins;

        tracktion::engine::RackType::Ptr rack = tracktion_engine::RackType::createTypeToWrapPlugins (plugins, edit);
        
        masterTrack->pluginList.insertPlugin(rack, 0, nullptr);
    }
}

Actually so I could get it to compile, i found the solution in one of the test files. However when I go to play audio I get this error:

JUCE Assertion failure in tracktion_ConnectedNode.h:235

inline void ConnectedNode::process (ProcessContext& pc)
{
    auto destAudio = pc.buffers.audio;
    auto& destMIDI = pc.buffers.midi;

    const int numSamples = (int) pc.referenceSampleRange.getLength();
    juce::ignoreUnused (numSamples);
    jassert (destAudio.getNumChannels() == 0 || numSamples == (int) destAudio.getNumFrames());

This is my current working code:

void MainComponent::createPluginRack()
{
    if (auto masterTrack = edit.getMasterTrack())
    {
        tracktion_engine::Plugin::Array plugins;
            
        // Create the rack type with proper channel connections
        if (auto rack = tracktion_engine::RackType::createTypeToWrapPlugins(plugins, edit))
        {
            masterTrack->pluginList.insertPlugin(tracktion_engine::RackInstance::create(*rack), 0);
        }
    }
}

That’s just an empty Rack though?
You haven’t added any plugins to it.

Ah yes i removed my plugin creation code, even something simple like this causes the same error.

void MainComponent::createPluginRack()
{
    if (auto masterTrack = edit.getMasterTrack())
    {
        tracktion_engine::Plugin::Array plugins;
        
        // Create internal reverb plugin
        if (auto reverbPlugin = edit.getPluginCache().createNewPlugin(tracktion_engine::ReverbPlugin::xmlTypeName, {}))
        {
            plugins.add(reverbPlugin.get());
        }

        // Create the rack type with proper channel connections
        if (auto rack = tracktion_engine::RackType::createTypeToWrapPlugins(plugins, edit))
        {
            masterTrack->pluginList.insertPlugin(tracktion_engine::RackInstance::create(*rack), 0);
        }
    }
}

When the assertion triggers, can you check which part of it is failing?
What is numSamples and what is destAudio.getNumFrames()? You can check the latter just by examining the destAudio members.

channels is 0, numSamples is 513, numFrames is 512,

Can you look up the stack and see where the 513 is coming from? Seems like a strange number…

It comes from ProcessContext& pc method pc.referenceSampleRange.getLength() it’s returning 513 even though pc.numSamples is 512

If i modify the ConnectedNode::process function to use pc.numSamples then it compiles and plays audio with them being processed through the effects rack as expected. But not sure what side effects that has.

Right, but can you see where pc.referenceSampleRange is getting a length of 513 from? Do you have any EditPlaybackContext stretching going on?

I’ve tried to follow it but i’m not really the best at debugging c++ but I see that the process function is called in certain places. the EditPlaybackContext being one of them.

I do use time stretching (setTempoAdjustment) in my application, and after disabling all the time stretching functionality then the rack works as expected (but without time stretch of course).