MidiMessage datasize exception

Hello everyone,

I have a plugin that is using the MidiKeyboardState noteOn and noteOff methods.

At the end of the timercallback method I placed in the editor I use keyboardState.processNextMidiBuffer() to send all the note on and off events to a buffer I created in the plugin processor. This buffer then gets swapped with the midiMessages buffer in the processBlock message of the processor.

Every now and then I get a MidiMessage exception if the plugin runs for more than a minute and in debugging the following code appears:

MidiMessage::MidiMessage (const void* const d, const int dataSize, const double t)
   : timeStamp (t), size (dataSize)
{
    jassert (dataSize > 0);

What determines the datasize of the midiMessage?
Should I be locking the midibuffer at any point to avoid this?
The timerCallback() method in the plugin processor is refreshing at a rate of 100Hz.
Any suggestions?

What’s the trace of the exception?

That assertion is raised when the parameter dataSize is zero or less, so I imagine at some point you are attempting to create a MidiMessage with sizeof used to determine dataSize. But are you checking to make sure sizeof is greater than zero before creating the message?

Could it be the intermittency of the error is not time-based, but input-based - it happens when you stop passing midi input in?

1 Like

This is likely the cause of the problem. Normally the MidiKeyboardState would be a member of the AudioProcessor, and you’d call processNextMidiBuffer directly inside AudioProcessor::processBlock.

1 Like

I will rewrite the code and rethink the logic and give feedback tomorrow it’s late where I am (Australia). Sounds correct but I will confirm tomorrow.

@reuk and anyone else who would like to help which I appreciate so much, I have declared the keyboardState in the pluginprocessornow.

I used the following function to pass a pointer to the plugineditor:

juce::MidiKeyboardState& getKeyboardState()
    {
        return keyboardState;
    }

I called this method in the constructor of the PluginEditor.

As you advised I called processNextMidiBuffer directly inside AudioProcessor::processBlock

This compiles but fails to run with a ‘DeleteCriticalSection’ exception.

Any suggestions on how to proceed?

1 Like

It’s not clear what might be causing the problem. What’s the call stack at the point of the exception?

Hello again @reuk ,

Call stack breaks at:

Exception thrown at 0x00007FFEC20BFAAD (ntdll.dll) in JucePresetManager.exe: 0xC0000005: Access violation reading location 0xFFFFFFFFFFFFFFFF.

I believe this is pointer related but the problem is the MidiKeyboardComponent contructor in the PluginEditor is not accepting a std::unique_ptrjuce::MidiKeyboardState

A brief outline of what I have:

In PluginProcessor.h declared keyboardstate as a private variable.

juce::MidiKeyboardState keyboardState;

In PluginProcessor.cpp processBlock():

getKeyboardState().processNextMidiBuffer (midiMessages, 0, buffer.getNumSamples(), true);

Method for PluginEditor to access thekeyboardState member

juce::MidiKeyboardState& getKeyboardState()
{
        return keyboardState;
}

In PluginEditor:

midiKeyboard (audioProcessor.getKeyboardState(), juce::MidiKeyboardComponent::Orientation::horizontalKeyboard)

Any thoughts?

Could you post the whole call stack? not just the crash point? this may contain the forensic evidence needed to reason about this problem. you know, this kind of thing…

 	A8Manager.exe!juce::detail::dispatchNextMessageOnSystemQueue(bool returnIfNoPendingMessages) Line 263	C++
 	A8Manager.exe!juce::MessageManager::runDispatchLoop() Line 112	C++
 	A8Manager.exe!juce::JUCEApplicationBase::main() Line 269	C++
 	A8Manager.exe!WinMain(HINSTANCE__ * __formal, HINSTANCE__ * __formal, char * __formal, int __formal) Line 288	C++
 	[External Code]	

Hello @cpr2323 I appreciate you looking at this.

Here it is:

| |ntdll.dll!00007ffec20bfaad()|Unknown|
|---|---|---|
|>|JucePresetManager.exe!juce::CriticalSection::enter() Line 46|C++|
| |JucePresetManager.exe!juce::GenericScopedLock<juce::CriticalSection>::GenericScopedLock<juce::CriticalSection>(const juce::CriticalSection & lock) Line 67|C++|
| |JucePresetManager.exe!juce::MidiKeyboardState::addListener(juce::MidiKeyboardState::Listener * listener) Line 167|C++|
| |JucePresetManager.exe!juce::CustomMidiKeyboardComponent::CustomMidiKeyboardComponent(juce::MidiKeyboardState & s, juce::CustomMidiKeyboardComponent::Orientation o) Line 99|C++|
| |JucePresetManager.exe!JucePresetManagerAudioProcessorEditor::JucePresetManagerAudioProcessorEditor(JucePresetManagerAudioProcessor & p) Line 9|C++|
| |JucePresetManager.exe!JucePresetManagerAudioProcessor::createEditor() Line 563|C++|
| |JucePresetManager.exe!juce::AudioProcessor::createEditorIfNeeded() Line 829|C++|
| |JucePresetManager.exe!juce::StandaloneFilterWindow::MainContentComponent::MainContentComponent(juce::StandaloneFilterWindow & filterWindow) Line 712|C++|
| |JucePresetManager.exe!juce::StandaloneFilterWindow::StandaloneFilterWindow(const juce::String & title, juce::Colour backgroundColour, juce::PropertySet * settingsToUse, bool takeOwnershipOfSettings, const juce::String & preferredDefaultDeviceName, const juce::AudioDeviceManager::AudioDeviceSetup * preferredSetupOptions, const juce::Array<juce::StandalonePluginHolder::PluginInOuts,juce::DummyCriticalSection,0> & constrainToConfiguration, bool autoOpenMidiDevices) Line 599|C++|
| |JucePresetManager.exe!juce::StandaloneFilterApp::createWindow() Line 81|C++|
| |JucePresetManager.exe!juce::StandaloneFilterApp::initialise(const juce::String & __formal) Line 99|C++|
| |JucePresetManager.exe!juce::JUCEApplicationBase::initialiseApp() Line 297|C++|
| |JucePresetManager.exe!juce::JUCEApplication::initialiseApp() Line 92|C++|
| |JucePresetManager.exe!juce::JUCEApplicationBase::main() Line 256|C++|
| |JucePresetManager.exe!WinMain(HINSTANCE__ * __formal, HINSTANCE__ * __formal, char * __formal, int __formal) Line 45|C++|
| |[External Code]||

CustomMidiKeyboardComponent is my own version of MidiKeyboardComponent.

Any thoughts?

If you break in the debugger at the beginning of the CustomMidiKeyboardComponent constructor, does the MidiKeyboardState argument definitely reference a valid object? Is it possible that you’re passing dereferencing a null pointer and passing that accidentally?

1 Like

@reuk let me check that out I’ll reply tomorrow with the results.

@reuk I have gone for a unique pointer declared in the header of the PluginEditor:

std::unique_ptr<juce::MidiKeyboardState> keyboardState;

In the PluginProcessor I created the method:

juce::MidiKeyboardState& JucePresetManagerAudioProcessor::getKeyboardState()
{
        return *keyboardState.get();
}

In the constructor of CustomMidiKeyboard I have same as before:

midiKeyboard (audioProcessor.getKeyboardState(), juce::CustomMidiKeyboardComponent::Orientation::horizontalKeyboard)

This gives a different exception than before with the following call stack that breaks at:

|>|JucePresetManager.exe!std::unique_ptr<juce::MidiKeyboardState,std::default_delete<juce::MidiKeyboardState>>::get() Line 3219|C++

I don’t fully understand pointers to be honest I have just referenced and deferenced until I got something that ran and I cannot find any example in these forums of the constructor of a midiKeyboardComponent in a PluginEditor which I feel is all I need to know now.

Any thoughts?

Allright so I’ve decided to go back to my original setup of having the keyboardState in the editor. This gives a datasize exception after some time fo running the plugin. I may need to override the keyboardstate methods involved to check for the datasize of the message. I know ideally the keyboardstate should be in the processor but the results of this structure are different exceptions. The only JUCE example I see is one of an audio app and there is no official example of a plugin using keyboardState that I can find so I’ll have to wing it. Thanks for everyone who reached out I’ve got something that works but is by no means the textbook way to do things.

The AudioPluginDemo has an onscreen keyboard that shows the MIDI notes passed into the plugin, and that also allows the user to trigger notes.

1 Like

@reuk , that’s helped me a lot. In the PluginEditor I was using audioProcessor.keyboardState to access the keyboardState in the PluginProcessor but this did not work in the contructor of the PluginEditor. Replacing this with p.keyboardState worked for some reason my guess is the audioProcessor identifier isn’t defined yet at that point. Thanks for everyone’s help. All good now.

1 Like