I’m making a drum App that has touch pads on the screen. These work perfectly in Windows but are laggy and unstable on the iPad, unsuitable for live playing like other similar apps not made with Juce.
When running the App in the debugger, Xcode often displays this message:
<_UISystemGestureGateGestureRecognizer: 0x10111c500>: Gesture: Failed to receive system gesture state notification before next touch
I’ve tried different approaches, even tried to replace my pad components with the stock Juce keyboard and the result doesn’t change. Also went into the iPad’s settings and disabled all gestures, but to no avail.
My code is made up of two classes, one draws a pad, and another draws multiple pads on the screen, something like this:
struct MyDrumPad : public juce::Component
{
MyDrumPad(const String& name) : Component(name)
{
// give a shape to this path
path.addPolygon ( ... );
}
void paint(Graphics& g) override
{
// Draw the pad
g.setColour( /* set the color */ );
g.fillPath(path);
// ...
}
void resized() override
{
// Give the correct size to the path
path.applyTransform( ... );
}
juce::Path path;
int note = -1;
};
struct MyPadBoard : public juce::Component, public juce::MidiKeyboardState
{
MyPadBoard()
{
// Create the pad array...
StringArray padNames = { "Kick", "Snare", "etc...", ... };
for (int i = 0; i < 24; ++i)
{
auto* pad = new MyDrumPad(padNames[i]);
addAndMakeVisible(pad);
pad->note = 36 + i;
pad->addMouseListener(this, false); // this transfers the mouse interaction from each pad object to this class
pads.add(pad);
}
}
void resized() override
{
// Arrange the pads in a certain order...
for (auto* pad : pads)
{
pad->setBounds( ... );
// ...
}
}
void mouseDown(const MouseEvent& event) override
{
// This is where I trigger the note-on event whenever a pad is touched/clicked
if (auto* pad = dynamic_cast<MyDrumPad*>(event.eventComponent))
noteOn(1, pad->note, 1.f); // noteOn is a method of MidiKeyboardState
}
OwnedArray<MyDrumPad> pads;
};
Now that I have my custom keyboard (padboard) I can instantiate it from my caller class, typically the PluginEditor, and set the MidiKeyboardState::Listener
PadBoard.reset(new MyPadBoard());
addAndMakeVisible(PadBoard.get());
PadBoard->addListener(this);
Then the listener functions process the Midi Note events and transfer them to the processor class.
void handleNoteOn(MidiKeyboardState* source, int midiChannel, int midiNoteNumber, float velocity) override
{
MidiMessage m(0x90 | midiChannel - 1, midiNoteNumber, (int)(velocity * 127.f), 0);
audioProcessor.addKeyboardMessage(m);
}
I also tried a different approach using lambdas, but I just got the same results: snappy and precise on Windows, unstable on iPad.
This is with Juce 6.1.6.
Tried with two different iPads running iPadOS 15.7.
Not tried yet on macOS.
Anything I should know that I’m missing? Thanks in advance for your time.