2
votes

I am using RtMidi library to handle midi message in my Qt application and I am facing problem with slot trigger:

My PhMidiInput object is emiting signal from the RtMidi callback upon specific midi message but the slots are not always triggered.

Here is a part of the PhMidiInput class:

class PhMidiInput : QObject
{
    Q_OBJECT
public:
    void PhMidiInput() {}
signals:
    void quarterFrame(unsigned char data);
private:
    static void callback(double, std::vector< unsigned char > *message, void *userData ) {
        PhMidiInput *midiInput = (PhMidiInput*)userData;
        if(midiInput)
            midiInput->onMessage(message);
    }

    void onMessage(std::vector<unsigned char> *message) {
        ...
        emit quarterFrame(data);
        ...
    }

}

Connecting to a lambda functor works:

PhMidiInput midiIn;
int quarterFrameCount;

connect(&midiIn, &PhMidiInput::quarterFrame, [&](unsigned char data) {
    quarterFrameCount++;
});

Connecting to my application window works to:

// MyWindow inherits from QMainWindow
connect(_midiIn, &PhMidiInput::quarterFrame, this, &MyWindow::onQuarterFrame);

When trying to connect to a custom class (MidiTest) inheriting from QObject it does'nt trigger:

connect(_midiIn, &PhMidiInput::quarterFrame, this, &MidiTest::onQuarterFrame);

I was wondering if there was something around QObject::moveToThread() but since I don't create the thread myself (the signal is sent from a callback) I don't know if I need to use it or not.

2

2 Answers

1
votes

It is as simple as calling emit obj->quarterFrame(data); from the callback. If the connection type is default then this will be perfectly thread safe.

Though you should create a QByteArray from data to pass around as data will likely not be valid by the time the slots get called.

void callback(..., void* user){
    //user is the standard void* in most callbacks passed as reinterpret_cast<void*>(this)
    unsigned char* data = ...;
    QByteArray bytes(data);
    emit reinterpret_cast<PhMidiInput>(user)->quarterFrame(bytes);//calling the signal which will behave as you'd expect

}
0
votes

In the last connect() call you pass this and MidiTest::onQuarterFrame as the receiver object and method. I bet this is not an instance of MidiTest, is it?

The problem here is that you're passing SLOT method from MidiTest, while the receiver object is this, which is not instance of MidiTest. Change receiver from this to some instance of MidiTest.

I'm surprised this code doesn't crash your application when running.