How to display the last played midi note on the UI

I started with the basic project.

  • added juce::Label midiSignLabel; to PluginEditor.cpp
  • in processBlock() I’d like to refresh the UI (midiSignLabel) on every midi note
    for (const auto metadata : midiMessages)
    {
        auto message = metadata.getMessage();
        const auto time = metadata.samplePosition;

        if (message.isNoteOn())
        {
            refreshUI() ???
        }
    }

how can I do this? there’s a reference for the audioprocessor in the editor class but I’d need it in the opposite way (or only the C++ sytax confused me). what kind of listeners shall I use and in which class?

That is a surprisingly complicated problem and Juce doesn’t have particularly good ready to use tools to solve it.

But a basic simple solution would be that you have an atomic member variable in your audio processor class and a timer in your GUI editor class. In your processBlock code you would set that atomic variable based on your MIDI message. The timer callback in the GUI editor would poll the value from the processor and do repaints of the GUI. Obviously that solution works only for very simple use cases. Anything more complicated could require using things like lock free ring buffers. Juce doesn’t provide an easy to use one, unfortunately. It does have the AbstractFIFO class but that is quite painful to use.

hey, thanks for the help!
I tried the following based on your answer, but I can’t see the midi notes on the GUI.

what do I miss?

It looks like you only grab the midi note value in the editor when you construct it. You need to call setText, with the current value, in the timer callback. I minor optimization would be to only call repaint if the value has changed. ‘midiNote’ should also be an atomic. Depending on your intention, this seems like a weak implementation. But it will get you something, ie. The last midi note played, at 1 second intervals.

that if you create a slider with a range from 0 to 127 that only shows the value, and update it with setValue?

@Marcusonic
sorry, I don’t get what you wrote. I would not like to use a slider…

hey @cpr2323 ,

I’ve pushed new changes but still does not work.

    void timerCallback() final {
        midiNotesLabel.setText(juce::String(audioProcessor.getMidiNote()), juce::dontSendNotification);
    }
juce::String MidiDiffAudioProcessor::getMidiNote()
{
    return juce::String(midiNote);
}
    for (const auto midiMessage : midiMessages)
    {
        auto* channelData = buffer.getWritePointer (channel);
        if (midiMessage.getMessage().isNoteOn()) {
            midiNote = midiMessage.getMessage().getNoteNumber();
        }
    }

I expected to see the last midi note on the GUI, but that is still 0

    int midiNote = 0;

@xenakios
could you have a look at my changes? I think I have a typical beginner C++ mistake (I know almost nothing about C++)

Time to debug. Use juce::Logger::outputDebugString in the timeCallback to help narrow diwn the issue. Ie, verify you are getting updated values for the backend. I’m in the hospital recovering from surgery, so I can’t run any code to verify things myself :mask::grin::nerd_face:

1 Like

there is a nice solution but as such IS NOT THREAD SAFE, which is to associate a value of the processor

label.getTextValue().referTo(audioProcessor.lastNote);

in the processor

juce:Value lastNote;

lastNote.setValue(numNote);

I’ve tried it because I currently use a timer, and I wanted to know if this was better and get rid of the timer,

it works fine, but I get an exception after 10 seconds, I guess when the collision occurs.

maybe someone knows how to make it safe,

Yes, bad design. But do you get a crash or an assert? Ie. Juce will assert for most UI related calls if not done on the MessageManager thread. Regardless, don’t do this. :stuck_out_tongue:

crash of read access in atomic file

Interesting. I use ValueTrees a ton, but I haven’t used ‘referTo’, so I can’t give an educated theory. I am interested in what the actual line of code is that is crashing. A read access crash sounds more like using memory that has been freed, or gone out of scope.

That is not going to work because of the thread safety issue.

The speed at which the label is updated I have never seen before, even so this time I needed to wait more than a minute to replicate the error. I wonder if a usual timer of 50 or 100 ms is just as dangerous but with the difference that a collision occurs is minimal.

It seems that it is possible if there is synchronization.

Important note! The Value class is not thread-safe! If you’re accessing one from multiple threads, then you’ll need to use your own synchronization around any code that accesses it.

maybe an atomic could be used as a flag?

I am still wondering if this is a lifetime bug. Read access violations aren’t usually the result of a threading issue.

And yes, slowing the timer down just reduces the frequency of opportunities for the crash, it doesn’t solve it.

It is an error that occurs always after a while updating the label from the audio thread with setValue

You should just move on to a more acceptable method that is thread safe, for this problem. Such as using ValueTrees properly. :nerd_face:

@cpr2323 @Marcusonic @xenakios
are you still talking about my question?
sorry but I don’t understand the last few messages…

could you propose anything for my MR? have you tried it?

this is my first try to create a VST plugin and refreshing a label would be only my first step, not my final goal