[Bug]: DeviceManager doesn't work on Linux
Detailed steps on how to reproduce the bug
Summary
I'm unable to set the Midi In Device with dm.setDefaultMidiInDevice() on linux devices.
- The same code runs correctly on MacOS.
Context
My use case is playing virtual midi messages with:
int note = 60; // C3
te::MidiInputDevice *dev = engine_.getDeviceManager().getDefaultMidiInDevice();
dev->keyboardState.noteOn(1, note, 1.0);
Reproducing
I created a program fake_main.cc (below) in order to reproduce this behaviour.
Even though I'm setting the default midi in device, dm.getDefaultMidiInDevice() keeps returning nullptr
Here's my log from the github runner CI:
- I truncated the raylib init messages for clarity
JUCE v8.0.3
ALSA lib seq_hw.c:466:(snd_seq_hw_open) open /dev/snd/seq failed: No such file or directory
ALSA lib seq_hw.c:466:(snd_seq_hw_open) open /dev/snd/seq failed: No such file or directory
ALSA lib seq_hw.c:466:(snd_seq_hw_open) open /dev/snd/seq failed: No such file or directory
Audio block size: 256 Rate: 44100
Creating Default Controllers...
Edit loaded in: 2 ms
-----------
begin tests
ALSA::VirtualMidi begin
FakeMain: /home/runner/work/box/box/test/fake_main.cc:30: int main(): Assertion `ptr != nullptr' failed.
Aborted (core dumped)
Error: Process completed with exit code 134.
Solution?
I think this has to do with the line, since ALSA handles midi messages:
ALSA lib seq_hw.c:466:(snd_seq_hw_open) open /dev/snd/seq failed: No such file or directory
I saw the same error message on tracktion_engine:master.
Am I doing something wrong? Like not setting up the audio server correctly?
Note:
- I'm using int main() instead of the Juce application harness
- I would prefer to proceed this way because it's simpler. Especially since it works fine on macOS.
What is the expected behaviour?
The test should pass.
- On my Macbook (Air M1), the
FakeMainprogram runs without failing the assert.- It correctly prints out how many Midi Devices there are.
- I tested different linux platforms:
- my PC (x86 ubuntu 22.04)
- the github runner CI environment (x86 ubuntu 22.04)
- Raspberry Pi CM4 (ARM Raspberry Pi OS)
Unit test to reproduce the error?
// fake_main.cc
#include <filesystem>
#include <iostream>
#include <raylib.h>
#include <tracktion_engine/tracktion_engine.h>
namespace te = tracktion;
int main()
{
const juce::ScopedJuceInitialiser_GUI initialiser; // need this
te::Engine engine{"Tracktion Hello World"};
std::filesystem::path curr_path = std::filesystem::current_path();
juce::File my_file{juce::String{curr_path.string() + "/tmp.box"}};
std::unique_ptr<te::Edit> my_edit = createEmptyEdit(engine, my_file);
te::Edit &edit = *my_edit;
edit.ensureNumberOfAudioTracks(8);
edit.getTransport().ensureContextAllocated();
engine.getDeviceManager().rescanMidiDeviceList();
// need this line for the test to pass on macOS for some reason
InitWindow(512, 512, "fake main test");
std::cout << "-----------" << std::endl;
std::cout << "begin tests" << std::endl;
// test ALSA::VirtualMidi
{
std::cout << "ALSA::VirtualMidi begin" << std::endl;
engine.getDeviceManager().createVirtualMidiDevice("box_midi");
engine.getDeviceManager().setDefaultMidiInDevice("box_midi");
auto ptr = engine.getDeviceManager().getDefaultMidiInDevice();
assert(ptr != nullptr);
std::cout << "ALSA::VirtualMidi end" << std::endl;
}
std::cout << std::endl;
// test ALSA::PrintMidiIn
{
std::cout << "ALSA::PrintMidiIn begin:" << std::endl;
auto vec = engine.getDeviceManager().getMidiInDevices();
std::cout << "midiInputs.size(): " << vec.size() << std::endl;
for (auto &x : vec)
{
std::cout << "\t" << x->getName() << std::endl;
}
std::cout << "ALSA::PrintMidiIn end" << std::endl;
}
std::cout << "end tests" << std::endl;
std::cout << "-----------" << std::endl;
return 0;
}
Operating systems
Linux
What versions of the operating systems?
Ubuntu 22.04
Architectures
x86_64, ARM
Stacktrace
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
- [x] I agree to follow the Code of Conduct
Some the the functions you're calling there are asyncronous. You can't really run them in a straight procedural app like that.
Also, your ALSA::VirtualMidi I don't think is doing what you expect. In Tracktion Engine, a "VirtualMidiDevice" is local to the app, it's not a system device. More like an internal aggregate MIDI device that you can assign multiple MIDI devices to.
I would run the juce demo app first to see if that picks up your OS MIDI devices. If that does, TE should be able to find them.
Thank you. I will try that.
Just to clarify. By "juce demo app", do you mean this?
https://github.com/juce-framework/JUCE/blob/master/examples/CMake/GuiApp/Main.cpp
No, I think that's a template. It's this one: https://github.com/juce-framework/JUCE/blob/master/examples/DemoRunner/CMakeLists.txt
OK. I tried the tracktion_engine::DemoRunner on my ubuntu PC and it seemed to be working:
...
Default Wave Out: channel 1 + 2
Default MIDI Out:
Default Wave In: channel 1
Default MIDI In:
MIDI Input devices scanned in: 1 ms
Updating MIDI I/O devices
Found MIDI in: midiin_170f06 ("Midi Through Port-0") (enabled)
Found MIDI in: all_midi_in ("All MIDI Ins") (enabled)
Found MIDI out: out_c31d4a06 ("Midi Through Port-0") (enabled)
opening MIDI out device: out_c31d4a06 (Midi Through Port-0)
opening MIDI in device: midiin_170f06 (Midi Through Port-0)
closing MIDI output: Midi Through Port-0
Closing MIDI in device: Midi Through Port-0
...
How is this code compiled? I can't find an int main() or a START_JUCE_APPLICATION().
It's a PIP so I think the juce_add_pip function in cmake generates a cpp file which has that in.