1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-02-02 03:20:06 +00:00

Updated MidiKeyboardState to use nested Listener and fixed some thread safety issues

This commit is contained in:
ed 2020-06-12 09:26:28 +01:00
parent 3a9e26b26c
commit 5467c57e23
5 changed files with 50 additions and 64 deletions

View file

@ -65,7 +65,7 @@ struct MidiDeviceListEntry : ReferenceCountedObject
//==============================================================================
class MidiDemo : public Component,
private Timer,
private MidiKeyboardStateListener,
private MidiKeyboardState::Listener,
private MidiInputCallback,
private AsyncUpdater
{

View file

@ -76,9 +76,7 @@ void MidiKeyboardState::noteOnInternal (const int midiChannel, const int midiNo
if (isPositiveAndBelow (midiNoteNumber, 128))
{
noteStates[midiNoteNumber] = static_cast<uint16> (noteStates[midiNoteNumber] | (1 << (midiChannel - 1)));
for (int i = listeners.size(); --i >= 0;)
listeners.getUnchecked(i)->handleNoteOn (this, midiChannel, midiNoteNumber, velocity);
listeners.call ([&] (Listener& l) { l.handleNoteOn (this, midiChannel, midiNoteNumber, velocity); });
}
}
@ -101,9 +99,7 @@ void MidiKeyboardState::noteOffInternal (const int midiChannel, const int midiN
if (isNoteOn (midiChannel, midiNoteNumber))
{
noteStates[midiNoteNumber] = static_cast<uint16> (noteStates[midiNoteNumber] & ~(1 << (midiChannel - 1)));
for (int i = listeners.size(); --i >= 0;)
listeners.getUnchecked(i)->handleNoteOff (this, midiChannel, midiNoteNumber, velocity);
listeners.call ([&] (Listener& l) { l.handleNoteOff (this, midiChannel, midiNoteNumber, velocity); });
}
}
@ -166,16 +162,16 @@ void MidiKeyboardState::processNextMidiBuffer (MidiBuffer& buffer,
}
//==============================================================================
void MidiKeyboardState::addListener (MidiKeyboardStateListener* const listener)
void MidiKeyboardState::addListener (Listener* listener)
{
const ScopedLock sl (lock);
listeners.addIfNotAlreadyThere (listener);
listeners.add (listener);
}
void MidiKeyboardState::removeListener (MidiKeyboardStateListener* const listener)
void MidiKeyboardState::removeListener (Listener* listener)
{
const ScopedLock sl (lock);
listeners.removeFirstMatchingValue (listener);
listeners.remove (listener);
}
} // namespace juce

View file

@ -23,51 +23,6 @@
namespace juce
{
class MidiKeyboardState;
//==============================================================================
/**
Receives events from a MidiKeyboardState object.
@see MidiKeyboardState
@tags{Audio}
*/
class JUCE_API MidiKeyboardStateListener
{
public:
//==============================================================================
MidiKeyboardStateListener() = default;
virtual ~MidiKeyboardStateListener() = default;
//==============================================================================
/** Called when one of the MidiKeyboardState's keys is pressed.
This will be called synchronously when the state is either processing a
buffer in its MidiKeyboardState::processNextMidiBuffer() method, or
when a note is being played with its MidiKeyboardState::noteOn() method.
Note that this callback could happen from an audio callback thread, so be
careful not to block, and avoid any UI activity in the callback.
*/
virtual void handleNoteOn (MidiKeyboardState* source,
int midiChannel, int midiNoteNumber, float velocity) = 0;
/** Called when one of the MidiKeyboardState's keys is released.
This will be called synchronously when the state is either processing a
buffer in its MidiKeyboardState::processNextMidiBuffer() method, or
when a note is being played with its MidiKeyboardState::noteOff() method.
Note that this callback could happen from an audio callback thread, so be
careful not to block, and avoid any UI activity in the callback.
*/
virtual void handleNoteOff (MidiKeyboardState* source,
int midiChannel, int midiNoteNumber, float velocity) = 0;
};
//==============================================================================
/**
Represents a piano keyboard, keeping track of which keys are currently pressed.
@ -180,27 +135,62 @@ public:
bool injectIndirectEvents);
//==============================================================================
/** Receives events from a MidiKeyboardState object. */
class Listener
{
public:
//==============================================================================
virtual ~Listener() = default;
//==============================================================================
/** Called when one of the MidiKeyboardState's keys is pressed.
This will be called synchronously when the state is either processing a
buffer in its MidiKeyboardState::processNextMidiBuffer() method, or
when a note is being played with its MidiKeyboardState::noteOn() method.
Note that this callback could happen from an audio callback thread, so be
careful not to block, and avoid any UI activity in the callback.
*/
virtual void handleNoteOn (MidiKeyboardState* source,
int midiChannel, int midiNoteNumber, float velocity) = 0;
/** Called when one of the MidiKeyboardState's keys is released.
This will be called synchronously when the state is either processing a
buffer in its MidiKeyboardState::processNextMidiBuffer() method, or
when a note is being played with its MidiKeyboardState::noteOff() method.
Note that this callback could happen from an audio callback thread, so be
careful not to block, and avoid any UI activity in the callback.
*/
virtual void handleNoteOff (MidiKeyboardState* source,
int midiChannel, int midiNoteNumber, float velocity) = 0;
};
/** Registers a listener for callbacks when keys go up or down.
@see removeListener
*/
void addListener (MidiKeyboardStateListener* listener);
void addListener (Listener* listener);
/** Deregisters a listener.
@see addListener
*/
void removeListener (MidiKeyboardStateListener* listener);
void removeListener (Listener* listener);
private:
//==============================================================================
CriticalSection lock;
uint16 noteStates[128];
std::atomic<uint16> noteStates[128];
MidiBuffer eventsToAdd;
Array <MidiKeyboardStateListener*> listeners;
ListenerList<Listener> listeners;
void noteOnInternal (int midiChannel, int midiNoteNumber, float velocity);
void noteOnInternal (int midiChannel, int midiNoteNumber, float velocity);
void noteOffInternal (int midiChannel, int midiNoteNumber, float velocity);
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MidiKeyboardState)
};
using MidiKeyboardStateListener = MidiKeyboardState::Listener;
} // namespace juce

View file

@ -28,14 +28,14 @@ namespace juce
Collects incoming realtime MIDI messages and turns them into blocks suitable for
processing by a block-based audio callback.
The class can also be used as either a MidiKeyboardStateListener or a MidiInputCallback
The class can also be used as either a MidiKeyboardState::Listener or a MidiInputCallback
so it can easily use a midi input or keyboard component as its source.
@see MidiMessage, MidiInput
@tags{Audio}
*/
class JUCE_API MidiMessageCollector : public MidiKeyboardStateListener,
class JUCE_API MidiMessageCollector : public MidiKeyboardState::Listener,
public MidiInputCallback
{
public:

View file

@ -40,7 +40,7 @@ namespace juce
@tags{Audio}
*/
class JUCE_API MidiKeyboardComponent : public Component,
public MidiKeyboardStateListener,
public MidiKeyboardState::Listener,
public ChangeBroadcaster,
private Timer
{