Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug]: Simple TE v3.0 program hanging on "Creating Default Controllers..." #219

Open
1 task done
debrisapron opened this issue Jul 21, 2024 · 11 comments
Open
1 task done

Comments

@debrisapron
Copy link

Detailed steps on how to reproduce the bug

On macOS, go to https://github.com/debrisapron/tracktion-engine-hello-world/tree/upgrade-tracktion_engine and follow instructions in README. Should build successfully, print the block size & samplerate, then hang when it gets to "Creating Default Controllers...". This is against the v3.0 tag but I've also checked against the latest develop & same error. Note that I don't have any loopbacks or other exotic drivers installed.

What is the expected behaviour?

It should play the demo, as it does with the previous version.

Unit test to reproduce the error?

No response

Operating systems

macOS

What versions of the operating systems?

Sonoma 14.2.1 on M1 Max

Architectures

ARM

Stacktrace

No response

Plug-in formats (if applicable)

No response

Plug-in host applications (DAWs) (if applicable)

No response

Testing on the develop branch

The bug is present on the develop branch

Code of Conduct

  • I agree to follow the Code of Conduct
@drowaudio
Copy link
Contributor

drowaudio commented Jul 22, 2024

I just tried this on macOS and got the following:

[100%] Built target TracktionHelloWorld
Finding MIDI I/O
MIDI output: IAC Driver Bus 1 (enabled)
opening MIDI out device:IAC Driver Bus 1
MIDI input: IAC Driver Bus 1 (enabled)
opening MIDI in device: IAC Driver Bus 1
Audio block size: 512  Rate: 44100
Rebuilding Wave Device List...
Wave In: New Label (enabled): 0 (L)
Wave Out: Output 1 + 2 (enabled): 0 (L), 1 (R)
Default Wave Out: Output 1 + 2
Default MIDI Out: IAC Driver Bus 1
Default Wave In: New Label
Default MIDI In: IAC Driver Bus 1
Creating Default Controllers...

but it was playing the audio.

I'm not quite sure what the reported problem is here? It looks like Creating Default Controllers is just the last message to be logged?

But have you run this in debug? You'll get assertions because you've not actually started the JUCE MessageManager.
Tracktion Engine requires this to be running and you're not really supposed to block the message thread as there could be all kinds of async messages piling up behind your blocking while loop.

@debrisapron
Copy link
Author

Huh that's interesting, was definitely not producing sound for me but good to know it's not just hanging. I actually thought I was running this in debug but looking at the code I forgot to put it in lol. To the point about the blocking while what else should I do here? I found that without it the program would simply exit before any audio had been emitted, but I'm sure there's a standard construct I should be using here. This is very much a learning process for me!

Anyway thanks for the reply! Will do a bit more investigation & probably close this soon.

@drowaudio
Copy link
Contributor

It's a bit tricky as you really want to be creating a juce::JUCEApplication rather than a console app.

However, you might get away with adding a ScopedJuceInitialiser_GUI instance at the top of your main function (see our TestRunner.h for an example) and then manually run the message loop afterwards instead of your while loop:

    JUCE_TRY
    {
        // loop until a quit message is received..
        MessageManager::getInstance()->runDispatchLoop();
    }
    JUCE_CATCH_EXCEPTION

@debrisapron
Copy link
Author

Hello again! Sorry, I let this hang for a while, but trying to get it working again with TE V3. So I followed your suggestion and added the lines you mentioned, now my main.cpp looks like this:

#include <tracktion_engine/tracktion_engine.h>
#include <memory>

using namespace std;
namespace te = tracktion;
using namespace std::literals;
using namespace te::literals;

static void addNoteToClip(
    te::MidiClip *midiClip,
    int noteNumber,
    int velocity,
    te::BeatPosition start,
    te::BeatDuration duration)
{
    midiClip->getSequence().addNote(
        noteNumber,
        start,
        duration,
        velocity,
        0,
        nullptr);
}

int main()
{
    juce::ScopedJuceInitialiser_GUI init;

    // Create the engine
    te::Engine engine{"Tracktion Hello World"};

    // Create an edit
    auto edit = std::make_unique<te::Edit>(
        engine,
        te::Edit::forEditing);

    // Create a track
    edit->ensureNumberOfAudioTracks(1);
    auto track = te::getAudioTracks(*edit)[0];

    // Get length of 1 bar
    const tracktion::TimeRange oneBarTimeRange(
        0s,
        edit->tempoSequence.toTime({1, tracktion::BeatDuration()}));

    // Insert a 1 bar long Midi clip
    auto clip = track->insertNewClip(
        te::TrackItem::Type::midi,
        "Midi Clip",
        oneBarTimeRange,
        nullptr);
    auto midiClip = static_cast<te::MidiClip *>(clip);

    // Add a 4-note C-E-G-C sequence to the clip
    // Note the use of Tracktion's beat position/duration literals
    addNoteToClip(midiClip, 60, 100, 0_bp, 0.5_bd);
    addNoteToClip(midiClip, 64, 100, 1_bp, 0.5_bd);
    addNoteToClip(midiClip, 67, 100, 2_bp, 0.5_bd);
    addNoteToClip(midiClip, 72, 100, 3_bp, 0.5_bd);

    // Create a built-in synth plugin instance to play the sequence on
    auto plugin = edit->getPluginCache()
                      .createNewPlugin(te::FourOscPlugin::xmlTypeName, {})
                      .get();
    auto fourOscPlugin = static_cast<te::FourOscPlugin *>(plugin);

    // Insert the plugin to the track
    track->pluginList.insertPlugin(*fourOscPlugin, 0, nullptr);

    // Get the transport & set it to the start of the edit
    auto &transport = edit->getTransport();
    transport.setPosition(0s);

    // Set the transport to loop our clip
    transport.setLoopRange(clip->getEditTimeRange());
    transport.looping = true;

    // Begin playback
    transport.play(false);

    // loop until a quit message is received..
    juce::MessageManager::getInstance()->runDispatchLoop();
}

This builds and runs fine, but all it does is print out the following & then immediately exits:

Audio block size: 512  Rate: 44100
Creating Default Controllers...
Cleaning up temp files...

For the sake of completeness here is my CMakeLists.txt:

cmake_minimum_required(VERSION 3.22)

project(TRACKTION_HELLO_WORLD VERSION 0.0.1)

add_subdirectory(tracktion_engine/modules/juce)
add_subdirectory(tracktion_engine/modules)

juce_add_console_app(TracktionHelloWorld
    PRODUCT_NAME "Tracktion Hello World")

target_sources(TracktionHelloWorld
    PRIVATE
        main.cpp)

target_compile_definitions(TracktionHelloWorld
    PRIVATE
        JUCE_WEB_BROWSER=0
        JUCE_USE_CURL=0)

target_link_libraries(TracktionHelloWorld
    PRIVATE
        tracktion::tracktion_engine
        juce::juce_core
    PUBLIC
        juce::juce_recommended_config_flags
        juce::juce_recommended_warning_flags)

set_property(TARGET TracktionHelloWorld PROPERTY CXX_STANDARD 20)

if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
  target_link_libraries(TracktionHelloWorld PRIVATE "-latomic")
endif()

I know I could probably get it working if I just change it to a regular JUCE GUI App, but I'd really like to boil it down to the fewest possible moving parts if I can! Also I have an interest in using TE for a headless audio app and it would be great to know if this is actually possible. Thanks in advance if you have any thoughts!

@drowaudio
Copy link
Contributor

Is it actually quitting?

If so, is a quit message being posted to the message queue?

You should be able to put a breakpoint in the juce::application/message_manager classes to see where that is coming from.

@debrisapron
Copy link
Author

OK this is good stuff! So I registered an ActionListener that just prints any received messages to stdout and it never receives anything! Which is super weird because runDispatchLoop should block forever if it doesn't get a quit message right?

@debrisapron
Copy link
Author

I added a bunch of logging and it's not silently crapping out early or anything. It runs all the way through to the end and returns. So runDispatchLoop isn't blocking at all.

@drowaudio
Copy link
Contributor

So it's working as you hoped?

@debrisapron
Copy link
Author

No, because it doesn't play audio and exits immediately. With TE 2 it plays audio endlessly until I kill it, now it just exits without playing anything.

@drowaudio
Copy link
Contributor

Right, but you must be able to debug why it's quitting?
But a breakpoint in MessageManager::runDispatchLoop() and step through it. Is the quitMessageReceived equal to 1?

If so, look at the line quitMessageReceived = true, is that being hit at all? Or MessageManager::stopDispatchLoop() being hit?

This isn't really a supported use case so I can't spend a bunch of time debugging it myself I'm afraid but I'm happy to help if you can debug it and find out what's actually happening. But you'll need to be able to use the debugger and breakpoints etc. to step in to the juce code.

@debrisapron
Copy link
Author

OK will try breakpointing it, thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants