git subrepo clone --branch=sono6good https://github.com/essej/JUCE.git deps/juce

subrepo:
  subdir:   "deps/juce"
  merged:   "b13f9084e"
upstream:
  origin:   "https://github.com/essej/JUCE.git"
  branch:   "sono6good"
  commit:   "b13f9084e"
git-subrepo:
  version:  "0.4.3"
  origin:   "https://github.com/ingydotnet/git-subrepo.git"
  commit:   "2f68596"
This commit is contained in:
essej
2022-04-18 17:51:22 -04:00
parent 63e175fee6
commit 25bd5d8adb
3210 changed files with 1045392 additions and 0 deletions

View File

@ -0,0 +1,153 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
The code included in this file is provided under the terms of the ISC license
http://www.isc.org/downloads/software-support-policy/isc-license. Permission
To use, copy, modify, and/or distribute this software for any purpose with or
without fee is hereby granted provided that the above copyright notice and
this permission notice appear in all copies.
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
MidiOutput::MidiOutput (const String& deviceName, const String& deviceIdentifier)
: Thread ("midi out"), deviceInfo (deviceName, deviceIdentifier)
{
}
void MidiOutput::sendBlockOfMessagesNow (const MidiBuffer& buffer)
{
for (const auto metadata : buffer)
sendMessageNow (metadata.getMessage());
}
void MidiOutput::sendBlockOfMessages (const MidiBuffer& buffer,
double millisecondCounterToStartAt,
double samplesPerSecondForBuffer)
{
// You've got to call startBackgroundThread() for this to actually work..
jassert (isThreadRunning());
// this needs to be a value in the future - RTFM for this method!
jassert (millisecondCounterToStartAt > 0);
auto timeScaleFactor = 1000.0 / samplesPerSecondForBuffer;
for (const auto metadata : buffer)
{
auto eventTime = millisecondCounterToStartAt + timeScaleFactor * metadata.samplePosition;
auto* m = new PendingMessage (metadata.data, metadata.numBytes, eventTime);
const ScopedLock sl (lock);
if (firstMessage == nullptr || firstMessage->message.getTimeStamp() > eventTime)
{
m->next = firstMessage;
firstMessage = m;
}
else
{
auto* mm = firstMessage;
while (mm->next != nullptr && mm->next->message.getTimeStamp() <= eventTime)
mm = mm->next;
m->next = mm->next;
mm->next = m;
}
}
notify();
}
void MidiOutput::clearAllPendingMessages()
{
const ScopedLock sl (lock);
while (firstMessage != nullptr)
{
auto* m = firstMessage;
firstMessage = firstMessage->next;
delete m;
}
}
void MidiOutput::startBackgroundThread()
{
startThread (9);
}
void MidiOutput::stopBackgroundThread()
{
stopThread (5000);
}
void MidiOutput::run()
{
while (! threadShouldExit())
{
auto now = Time::getMillisecondCounter();
uint32 eventTime = 0;
uint32 timeToWait = 500;
PendingMessage* message;
{
const ScopedLock sl (lock);
message = firstMessage;
if (message != nullptr)
{
eventTime = (uint32) roundToInt (message->message.getTimeStamp());
if (eventTime > now + 20)
{
timeToWait = eventTime - (now + 20);
message = nullptr;
}
else
{
firstMessage = message->next;
}
}
}
if (message != nullptr)
{
std::unique_ptr<PendingMessage> messageDeleter (message);
if (eventTime > now)
{
Time::waitForMillisecondCounter (eventTime);
if (threadShouldExit())
break;
}
if (eventTime > now - 200)
sendMessageNow (message->message);
}
else
{
jassert (timeToWait < 1000 * 30);
wait ((int) timeToWait);
}
}
clearAllPendingMessages();
}
} // namespace juce

View File

@ -0,0 +1,391 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
The code included in this file is provided under the terms of the ISC license
http://www.isc.org/downloads/software-support-policy/isc-license. Permission
To use, copy, modify, and/or distribute this software for any purpose with or
without fee is hereby granted provided that the above copyright notice and
this permission notice appear in all copies.
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
//==============================================================================
/**
This struct contains information about a MIDI input or output device.
You can get one of these structs by calling the static getAvailableDevices() or
getDefaultDevice() methods of MidiInput and MidiOutput or by calling getDeviceInfo()
on an instance of these classes. Devices can be opened by passing the identifier to
the openDevice() method.
@tags{Audio}
*/
struct MidiDeviceInfo
{
MidiDeviceInfo() = default;
MidiDeviceInfo (const String& deviceName, const String& deviceIdentifier)
: name (deviceName), identifier (deviceIdentifier)
{
}
/** The name of this device.
This will be provided by the OS unless the device has been created with the
createNewDevice() method.
Note that the name is not guaranteed to be unique and two devices with the
same name will be indistinguishable. If you want to address a specific device
it is better to use the identifier.
*/
String name;
/** The identifier for this device.
This will be provided by the OS and it's format will differ on different systems
e.g. on macOS it will be a number whereas on Windows it will be a long alphanumeric string.
*/
String identifier;
//==============================================================================
bool operator== (const MidiDeviceInfo& other) const noexcept { return name == other.name && identifier == other.identifier; }
bool operator!= (const MidiDeviceInfo& other) const noexcept { return ! operator== (other); }
};
class MidiInputCallback;
//==============================================================================
/**
Represents a midi input device.
To create one of these, use the static getAvailableDevices() method to find out what
inputs are available, and then use the openDevice() method to try to open one.
@see MidiOutput
@tags{Audio}
*/
class JUCE_API MidiInput final
{
public:
//==============================================================================
/** Returns a list of the available midi input devices.
You can open one of the devices by passing its identifier into the openDevice() method.
@see MidiDeviceInfo, getDevices, getDefaultDeviceIndex, openDevice
*/
static Array<MidiDeviceInfo> getAvailableDevices();
/** Returns the MidiDeviceInfo of the default midi input device to use. */
static MidiDeviceInfo getDefaultDevice();
/** Tries to open one of the midi input devices.
This will return a MidiInput object if it manages to open it, you can then
call start() and stop() on this device.
If the device can't be opened, this will return an empty object.
@param deviceIdentifier the ID of the device to open - use the getAvailableDevices() method to
find the available devices that can be opened
@param callback the object that will receive the midi messages from this device
@see MidiInputCallback, getDevices
*/
static std::unique_ptr<MidiInput> openDevice (const String& deviceIdentifier, MidiInputCallback* callback);
#if JUCE_LINUX || JUCE_BSD || JUCE_MAC || JUCE_IOS || DOXYGEN
/** This will try to create a new midi input device (only available on Linux, macOS and iOS).
This will attempt to create a new midi input device with the specified name for other
apps to connect to.
NB - if you are calling this method on iOS you must have enabled the "Audio Background Capability"
setting in the iOS exporter otherwise this method will fail.
Returns an empty object if a device can't be created.
@param deviceName the name of the device to create
@param callback the object that will receive the midi messages from this device
*/
static std::unique_ptr<MidiInput> createNewDevice (const String& deviceName, MidiInputCallback* callback);
#endif
//==============================================================================
/** Destructor. */
~MidiInput();
/** Starts the device running.
After calling this, the device will start sending midi messages to the MidiInputCallback
object that was specified when the openDevice() method was called.
@see stop
*/
void start();
/** Stops the device running.
@see start
*/
void stop();
/** Returns the MidiDeviceInfo struct containing some information about this device. */
MidiDeviceInfo getDeviceInfo() const noexcept { return deviceInfo; }
/** Returns the identifier of this device. */
String getIdentifier() const noexcept { return deviceInfo.identifier; }
/** Returns the name of this device. */
String getName() const noexcept { return deviceInfo.name; }
/** Sets a custom name for the device. */
void setName (const String& newName) noexcept { deviceInfo.name = newName; }
//==============================================================================
#ifndef DOXYGEN
[[deprecated ("Use getAvailableDevices instead.")]]
static StringArray getDevices();
[[deprecated ("Use getDefaultDevice instead.")]]
static int getDefaultDeviceIndex();
[[deprecated ("Use openDevice that takes a device identifier instead.")]]
static std::unique_ptr<MidiInput> openDevice (int, MidiInputCallback*);
#endif
/** @internal */
class Pimpl;
private:
//==============================================================================
explicit MidiInput (const String&, const String&);
MidiDeviceInfo deviceInfo;
std::unique_ptr<Pimpl> internal;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MidiInput)
};
//==============================================================================
/**
Receives incoming messages from a physical MIDI input device.
This class is overridden to handle incoming midi messages. See the MidiInput
class for more details.
@see MidiInput
@tags{Audio}
*/
class JUCE_API MidiInputCallback
{
public:
/** Destructor. */
virtual ~MidiInputCallback() = default;
/** Receives an incoming message.
A MidiInput object will call this method when a midi event arrives. It'll be
called on a high-priority system thread, so avoid doing anything time-consuming
in here, and avoid making any UI calls. You might find the MidiBuffer class helpful
for queueing incoming messages for use later.
@param source the MidiInput object that generated the message
@param message the incoming message. The message's timestamp is set to a value
equivalent to (Time::getMillisecondCounter() / 1000.0) to specify the
time when the message arrived
*/
virtual void handleIncomingMidiMessage (MidiInput* source,
const MidiMessage& message) = 0;
/** Notification sent each time a packet of a multi-packet sysex message arrives.
If a long sysex message is broken up into multiple packets, this callback is made
for each packet that arrives until the message is finished, at which point
the normal handleIncomingMidiMessage() callback will be made with the entire
message.
The message passed in will contain the start of a sysex, but won't be finished
with the terminating 0xf7 byte.
*/
virtual void handlePartialSysexMessage (MidiInput* source,
const uint8* messageData,
int numBytesSoFar,
double timestamp)
{
ignoreUnused (source, messageData, numBytesSoFar, timestamp);
}
};
//==============================================================================
/**
Represents a midi output device.
To create one of these, use the static getAvailableDevices() method to find out what
outputs are available, and then use the openDevice() method to try to open one.
@see MidiInput
@tags{Audio}
*/
class JUCE_API MidiOutput final : private Thread
{
public:
//==============================================================================
/** Returns a list of the available midi output devices.
You can open one of the devices by passing its identifier into the openDevice() method.
@see MidiDeviceInfo, getDevices, getDefaultDeviceIndex, openDevice
*/
static Array<MidiDeviceInfo> getAvailableDevices();
/** Returns the MidiDeviceInfo of the default midi output device to use. */
static MidiDeviceInfo getDefaultDevice();
/** Tries to open one of the midi output devices.
This will return a MidiOutput object if it manages to open it, you can then
send messages to this device.
If the device can't be opened, this will return an empty object.
@param deviceIdentifier the ID of the device to open - use the getAvailableDevices() method to
find the available devices that can be opened
@see getDevices
*/
static std::unique_ptr<MidiOutput> openDevice (const String& deviceIdentifier);
#if JUCE_LINUX || JUCE_BSD || JUCE_MAC || JUCE_IOS || DOXYGEN
/** This will try to create a new midi output device (only available on Linux, macOS and iOS).
This will attempt to create a new midi output device with the specified name that other
apps can connect to and use as their midi input.
NB - if you are calling this method on iOS you must have enabled the "Audio Background Capability"
setting in the iOS exporter otherwise this method will fail.
Returns an empty object if a device can't be created.
@param deviceName the name of the device to create
*/
static std::unique_ptr<MidiOutput> createNewDevice (const String& deviceName);
#endif
//==============================================================================
/** Destructor. */
~MidiOutput() override;
/** Returns the MidiDeviceInfo struct containing some information about this device. */
MidiDeviceInfo getDeviceInfo() const noexcept { return deviceInfo; }
/** Returns the identifier of this device. */
String getIdentifier() const noexcept { return deviceInfo.identifier; }
/** Returns the name of this device. */
String getName() const noexcept { return deviceInfo.name; }
/** Sets a custom name for the device. */
void setName (const String& newName) noexcept { deviceInfo.name = newName; }
//==============================================================================
/** Sends out a MIDI message immediately. */
void sendMessageNow (const MidiMessage& message);
/** Sends out a sequence of MIDI messages immediately. */
void sendBlockOfMessagesNow (const MidiBuffer& buffer);
/** This lets you supply a block of messages that will be sent out at some point
in the future.
The MidiOutput class has an internal thread that can send out timestamped
messages - this appends a set of messages to its internal buffer, ready for
sending.
This will only work if you've already started the thread with startBackgroundThread().
A time is specified, at which the block of messages should be sent. This time uses
the same time base as Time::getMillisecondCounter(), and must be in the future.
The samplesPerSecondForBuffer parameter indicates the number of samples per second
used by the MidiBuffer. Each event in a MidiBuffer has a sample position, and the
samplesPerSecondForBuffer value is needed to convert this sample position to a
real time.
*/
void sendBlockOfMessages (const MidiBuffer& buffer,
double millisecondCounterToStartAt,
double samplesPerSecondForBuffer);
/** Gets rid of any midi messages that had been added by sendBlockOfMessages(). */
void clearAllPendingMessages();
/** Starts up a background thread so that the device can send blocks of data.
Call this to get the device ready, before using sendBlockOfMessages().
*/
void startBackgroundThread();
/** Stops the background thread, and clears any pending midi events.
@see startBackgroundThread
*/
void stopBackgroundThread();
/** Returns true if the background thread used to send blocks of data is running.
@see startBackgroundThread, stopBackgroundThread
*/
bool isBackgroundThreadRunning() const noexcept { return isThreadRunning(); }
//==============================================================================
#ifndef DOXYGEN
[[deprecated ("Use getAvailableDevices instead.")]]
static StringArray getDevices();
[[deprecated ("Use getDefaultDevice instead.")]]
static int getDefaultDeviceIndex();
[[deprecated ("Use openDevice that takes a device identifier instead.")]]
static std::unique_ptr<MidiOutput> openDevice (int);
#endif
/** @internal */
class Pimpl;
private:
//==============================================================================
struct PendingMessage
{
PendingMessage (const void* data, int len, double timeStamp)
: message (data, len, timeStamp)
{
}
MidiMessage message;
PendingMessage* next;
};
//==============================================================================
explicit MidiOutput (const String&, const String&);
void run() override;
MidiDeviceInfo deviceInfo;
std::unique_ptr<Pimpl> internal;
CriticalSection lock;
PendingMessage* firstMessage = nullptr;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MidiOutput)
};
} // namespace juce

View File

@ -0,0 +1,158 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
The code included in this file is provided under the terms of the ISC license
http://www.isc.org/downloads/software-support-policy/isc-license. Permission
To use, copy, modify, and/or distribute this software for any purpose with or
without fee is hereby granted provided that the above copyright notice and
this permission notice appear in all copies.
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
MidiMessageCollector::MidiMessageCollector()
{
}
MidiMessageCollector::~MidiMessageCollector()
{
}
//==============================================================================
void MidiMessageCollector::reset (const double newSampleRate)
{
const ScopedLock sl (midiCallbackLock);
jassert (newSampleRate > 0);
#if JUCE_DEBUG
hasCalledReset = true;
#endif
sampleRate = newSampleRate;
incomingMessages.clear();
lastCallbackTime = Time::getMillisecondCounterHiRes();
}
void MidiMessageCollector::addMessageToQueue (const MidiMessage& message)
{
const ScopedLock sl (midiCallbackLock);
#if JUCE_DEBUG
jassert (hasCalledReset); // you need to call reset() to set the correct sample rate before using this object
#endif
// the messages that come in here need to be time-stamped correctly - see MidiInput
// for details of what the number should be.
jassert (message.getTimeStamp() != 0);
auto sampleNumber = (int) ((message.getTimeStamp() - 0.001 * lastCallbackTime) * sampleRate);
incomingMessages.addEvent (message, sampleNumber);
// if the messages don't get used for over a second, we'd better
// get rid of any old ones to avoid the queue getting too big
if (sampleNumber > sampleRate)
incomingMessages.clear (0, sampleNumber - (int) sampleRate);
}
void MidiMessageCollector::removeNextBlockOfMessages (MidiBuffer& destBuffer,
const int numSamples)
{
const ScopedLock sl (midiCallbackLock);
#if JUCE_DEBUG
jassert (hasCalledReset); // you need to call reset() to set the correct sample rate before using this object
#endif
jassert (numSamples > 0);
auto timeNow = Time::getMillisecondCounterHiRes();
auto msElapsed = timeNow - lastCallbackTime;
lastCallbackTime = timeNow;
if (! incomingMessages.isEmpty())
{
int numSourceSamples = jmax (1, roundToInt (msElapsed * 0.001 * sampleRate));
int startSample = 0;
int scale = 1 << 16;
if (numSourceSamples > numSamples)
{
// if our list of events is longer than the buffer we're being
// asked for, scale them down to squeeze them all in..
const int maxBlockLengthToUse = numSamples << 5;
auto iter = incomingMessages.cbegin();
if (numSourceSamples > maxBlockLengthToUse)
{
startSample = numSourceSamples - maxBlockLengthToUse;
numSourceSamples = maxBlockLengthToUse;
iter = incomingMessages.findNextSamplePosition (startSample);
}
scale = (numSamples << 10) / numSourceSamples;
std::for_each (iter, incomingMessages.cend(), [&] (const MidiMessageMetadata& meta)
{
const auto pos = ((meta.samplePosition - startSample) * scale) >> 10;
destBuffer.addEvent (meta.data, meta.numBytes, jlimit (0, numSamples - 1, pos));
});
}
else
{
// if our event list is shorter than the number we need, put them
// towards the end of the buffer
startSample = numSamples - numSourceSamples;
for (const auto metadata : incomingMessages)
destBuffer.addEvent (metadata.data, metadata.numBytes,
jlimit (0, numSamples - 1, metadata.samplePosition + startSample));
}
incomingMessages.clear();
}
}
void MidiMessageCollector::ensureStorageAllocated (size_t bytes)
{
incomingMessages.ensureSize (bytes);
}
//==============================================================================
void MidiMessageCollector::handleNoteOn (MidiKeyboardState*, int midiChannel, int midiNoteNumber, float velocity)
{
MidiMessage m (MidiMessage::noteOn (midiChannel, midiNoteNumber, velocity));
m.setTimeStamp (Time::getMillisecondCounterHiRes() * 0.001);
addMessageToQueue (m);
}
void MidiMessageCollector::handleNoteOff (MidiKeyboardState*, int midiChannel, int midiNoteNumber, float velocity)
{
MidiMessage m (MidiMessage::noteOff (midiChannel, midiNoteNumber, velocity));
m.setTimeStamp (Time::getMillisecondCounterHiRes() * 0.001);
addMessageToQueue (m);
}
void MidiMessageCollector::handleIncomingMidiMessage (MidiInput*, const MidiMessage& message)
{
addMessageToQueue (message);
}
} // namespace juce

View File

@ -0,0 +1,113 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
The code included in this file is provided under the terms of the ISC license
http://www.isc.org/downloads/software-support-policy/isc-license. Permission
To use, copy, modify, and/or distribute this software for any purpose with or
without fee is hereby granted provided that the above copyright notice and
this permission notice appear in all copies.
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
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 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 MidiKeyboardState::Listener,
public MidiInputCallback
{
public:
//==============================================================================
/** Creates a MidiMessageCollector. */
MidiMessageCollector();
/** Destructor. */
~MidiMessageCollector() override;
//==============================================================================
/** Clears any messages from the queue.
You need to call this method before starting to use the collector, so that
it knows the correct sample rate to use.
*/
void reset (double sampleRate);
/** Takes an incoming real-time message and adds it to the queue.
The message's timestamp is taken, and it will be ready for retrieval as part
of the block returned by the next call to removeNextBlockOfMessages().
This method is fully thread-safe when overlapping calls are made with
removeNextBlockOfMessages().
*/
void addMessageToQueue (const MidiMessage& message);
/** Removes all the pending messages from the queue as a buffer.
This will also correct the messages' timestamps to make sure they're in
the range 0 to numSamples - 1.
This call should be made regularly by something like an audio processing
callback, because the time that it happens is used in calculating the
midi event positions.
This method is fully thread-safe when overlapping calls are made with
addMessageToQueue().
Precondition: numSamples must be greater than 0.
*/
void removeNextBlockOfMessages (MidiBuffer& destBuffer, int numSamples);
/** Preallocates storage for collected messages.
This can be called before audio processing begins to ensure that there
is sufficient space for the expected MIDI messages, in order to avoid
allocations within the audio callback.
*/
void ensureStorageAllocated (size_t bytes);
//==============================================================================
/** @internal */
void handleNoteOn (MidiKeyboardState*, int midiChannel, int midiNoteNumber, float velocity) override;
/** @internal */
void handleNoteOff (MidiKeyboardState*, int midiChannel, int midiNoteNumber, float velocity) override;
/** @internal */
void handleIncomingMidiMessage (MidiInput*, const MidiMessage&) override;
private:
//==============================================================================
double lastCallbackTime = 0;
CriticalSection midiCallbackLock;
MidiBuffer incomingMessages;
double sampleRate = 44100.0;
#if JUCE_DEBUG
bool hasCalledReset = false;
#endif
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MidiMessageCollector)
};
} // namespace juce

View File

@ -0,0 +1,140 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
The code included in this file is provided under the terms of the ISC license
http://www.isc.org/downloads/software-support-policy/isc-license. Permission
To use, copy, modify, and/or distribute this software for any purpose with or
without fee is hereby granted provided that the above copyright notice and
this permission notice appear in all copies.
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
namespace universal_midi_packets
{
/**
A base class for classes which convert bytestream midi to other formats.
@tags{Audio}
*/
struct BytestreamInputHandler
{
virtual ~BytestreamInputHandler() noexcept = default;
virtual void reset() = 0;
virtual void pushMidiData (const void* data, int bytes, double time) = 0;
};
/**
Parses a continuous bytestream and emits complete MidiMessages whenever a full
message is received.
@tags{Audio}
*/
struct BytestreamToBytestreamHandler : public BytestreamInputHandler
{
BytestreamToBytestreamHandler (MidiInput& i, MidiInputCallback& c)
: input (i), callback (c), concatenator (2048) {}
/**
Provides an `operator()` which can create an input handler for a given
MidiInput.
All handler classes should have a similar Factory to facilitate
creation of handlers in generic contexts.
*/
class Factory
{
public:
explicit Factory (MidiInputCallback* c)
: callback (c) {}
std::unique_ptr<BytestreamToBytestreamHandler> operator() (MidiInput& i) const
{
if (callback != nullptr)
return std::make_unique<BytestreamToBytestreamHandler> (i, *callback);
jassertfalse;
return {};
}
private:
MidiInputCallback* callback = nullptr;
};
void reset() override { concatenator.reset(); }
void pushMidiData (const void* data, int bytes, double time) override
{
concatenator.pushMidiData (data, bytes, time, &input, callback);
}
MidiInput& input;
MidiInputCallback& callback;
MidiDataConcatenator concatenator;
};
/**
Parses a continuous MIDI 1.0 bytestream, and emits full messages in the requested
UMP format.
@tags{Audio}
*/
struct BytestreamToUMPHandler : public BytestreamInputHandler
{
BytestreamToUMPHandler (PacketProtocol protocol, Receiver& c)
: recipient (c), dispatcher (protocol, 2048) {}
/**
Provides an `operator()` which can create an input handler for a given
MidiInput.
All handler classes should have a similar Factory to facilitate
creation of handlers in generic contexts.
*/
class Factory
{
public:
Factory (PacketProtocol p, Receiver& c)
: protocol (p), callback (c) {}
std::unique_ptr<BytestreamToUMPHandler> operator() (MidiInput&) const
{
return std::make_unique<BytestreamToUMPHandler> (protocol, callback);
}
private:
PacketProtocol protocol;
Receiver& callback;
};
void reset() override { dispatcher.reset(); }
void pushMidiData (const void* data, int bytes, double time) override
{
const auto* ptr = static_cast<const uint8_t*> (data);
dispatcher.dispatch (ptr, ptr + bytes, time, [&] (const View& v)
{
recipient.packetReceived (v, time);
});
}
Receiver& recipient;
BytestreamToUMPDispatcher dispatcher;
};
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,151 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
The code included in this file is provided under the terms of the ISC license
http://www.isc.org/downloads/software-support-policy/isc-license. Permission
To use, copy, modify, and/or distribute this software for any purpose with or
without fee is hereby granted provided that the above copyright notice and
this permission notice appear in all copies.
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
namespace universal_midi_packets
{
/**
A base class for classes which convert Universal MIDI Packets to other
formats.
@tags{Audio}
*/
struct U32InputHandler
{
virtual ~U32InputHandler() noexcept = default;
virtual void reset() = 0;
virtual void pushMidiData (const uint32_t* begin, const uint32_t* end, double time) = 0;
};
/**
Parses a continuous stream of U32 words and emits complete MidiMessages whenever a full
message is received.
@tags{Audio}
*/
struct U32ToBytestreamHandler : public U32InputHandler
{
U32ToBytestreamHandler (MidiInput& i, MidiInputCallback& c)
: input (i), callback (c), dispatcher (2048) {}
/**
Provides an `operator()` which can create an input handler for a given
MidiInput.
All handler classes should have a similar Factory to facilitate
creation of handlers in generic contexts.
*/
class Factory
{
public:
explicit Factory (MidiInputCallback* c)
: callback (c) {}
std::unique_ptr<U32ToBytestreamHandler> operator() (MidiInput& i) const
{
if (callback != nullptr)
return std::make_unique<U32ToBytestreamHandler> (i, *callback);
jassertfalse;
return {};
}
private:
MidiInputCallback* callback = nullptr;
};
void reset() override { dispatcher.reset(); }
void pushMidiData (const uint32_t* begin, const uint32_t* end, double time) override
{
dispatcher.dispatch (begin, end, time, [this] (const MidiMessage& m)
{
callback.handleIncomingMidiMessage (&input, m);
});
}
MidiInput& input;
MidiInputCallback& callback;
ToBytestreamDispatcher dispatcher;
};
/**
Parses a continuous stream of U32 words and emits full messages in the requested
UMP format.
@tags{Audio}
*/
struct U32ToUMPHandler : public U32InputHandler
{
U32ToUMPHandler (PacketProtocol protocol, Receiver& c)
: recipient (c), converter (protocol) {}
/**
Provides an `operator()` which can create an input handler for a given
MidiInput.
All handler classes should have a similar Factory to facilitate
creation of handlers in generic contexts.
*/
class Factory
{
public:
Factory (PacketProtocol p, Receiver& c)
: protocol (p), callback (c) {}
std::unique_ptr<U32ToUMPHandler> operator() (MidiInput&) const
{
return std::make_unique<U32ToUMPHandler> (protocol, callback);
}
private:
PacketProtocol protocol;
Receiver& callback;
};
void reset() override
{
dispatcher.reset();
converter.reset();
}
void pushMidiData (const uint32_t* begin, const uint32_t* end, double time) override
{
dispatcher.dispatch (begin, end, time, [this] (const View& view, double thisTime)
{
converter.convert (view, [&] (const View& converted)
{
recipient.packetReceived (converted, thisTime);
});
});
}
Receiver& recipient;
Dispatcher dispatcher;
GenericUMPConverter converter;
};
}
}