mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-10 23:44:24 +00:00
MIDI-CI: Add module
This commit is contained in:
parent
387ab88c13
commit
8ebbc20311
85 changed files with 11013 additions and 16 deletions
|
|
@ -0,0 +1,152 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
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::midi_ci::detail
|
||||
{
|
||||
|
||||
PropertyDataMessageChunker::PropertyDataMessageChunker (std::vector<std::byte>& storageIn,
|
||||
int chunkSizeIn,
|
||||
const std::byte messageKindIn,
|
||||
const std::byte requestIdIn,
|
||||
Span<const std::byte> headerIn,
|
||||
MUID sourceIn,
|
||||
MUID destIn,
|
||||
InputStream& bodyIn)
|
||||
: header (headerIn),
|
||||
storage (&storageIn),
|
||||
body (&bodyIn),
|
||||
source (sourceIn),
|
||||
dest (destIn),
|
||||
chunkSize (chunkSizeIn),
|
||||
messageKind (messageKindIn),
|
||||
requestId (requestIdIn)
|
||||
{
|
||||
if (hasRoomForBody())
|
||||
{
|
||||
populateStorage();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Header too large! There's no way to fit this message into the requested chunk size.
|
||||
jassertfalse;
|
||||
*this = PropertyDataMessageChunker();
|
||||
}
|
||||
}
|
||||
|
||||
PropertyDataMessageChunker& PropertyDataMessageChunker::operator++() noexcept
|
||||
{
|
||||
if (*this != PropertyDataMessageChunker())
|
||||
{
|
||||
if (body->isExhausted())
|
||||
{
|
||||
*this = PropertyDataMessageChunker();
|
||||
}
|
||||
else
|
||||
{
|
||||
++thisChunk;
|
||||
populateStorage();
|
||||
}
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Span<const std::byte> PropertyDataMessageChunker::operator*() const noexcept
|
||||
{
|
||||
// The end of the stream was reached, no point dereferencing the iterator now!
|
||||
jassert (storage != nullptr && (int) storage->size() <= chunkSize);
|
||||
return *storage;
|
||||
}
|
||||
|
||||
Span<const std::byte> PropertyDataMessageChunker::getHeaderForBlock() const
|
||||
{
|
||||
return thisChunk == 1 ? header : Span<const std::byte>{};
|
||||
}
|
||||
|
||||
int PropertyDataMessageChunker::getRoomForBody() const
|
||||
{
|
||||
return chunkSize - (int) (getHeaderForBlock().size() + 22);
|
||||
}
|
||||
|
||||
bool PropertyDataMessageChunker::hasRoomForBody() const
|
||||
{
|
||||
const auto bodyRoom = getRoomForBody();
|
||||
return (0 < bodyRoom)
|
||||
|| (0 == bodyRoom && body->getNumBytesRemaining() == 0);
|
||||
}
|
||||
|
||||
void PropertyDataMessageChunker::populateStorage() const
|
||||
{
|
||||
storage->clear();
|
||||
storage->resize ((size_t) getRoomForBody());
|
||||
|
||||
// Read body data into buffer
|
||||
const auto numBytesRead = (uint16_t) jmax (ssize_t (0), body->read (storage->data(), storage->size()));
|
||||
|
||||
const auto [numChunks, thisChunkNum] = [&]() -> std::tuple<uint16_t, uint16_t>
|
||||
{
|
||||
if (body->isExhausted() || body->getNumBytesRemaining() == 0)
|
||||
return std::tuple (thisChunk, thisChunk);
|
||||
|
||||
const auto totalLength = body->getTotalLength();
|
||||
|
||||
if (totalLength < 0)
|
||||
return std::tuple ((uint16_t) 0, thisChunk); // 0 means "unknown number"
|
||||
|
||||
const auto roomForBody = getRoomForBody();
|
||||
|
||||
if (roomForBody != 0)
|
||||
return std::tuple ((uint16_t) ((totalLength + roomForBody - 1) / roomForBody), thisChunk);
|
||||
|
||||
// During construction, the input stream reported that it had no data remaining, so no
|
||||
// space was reserved for body content.
|
||||
// Now, the input stream reports that it has data remaining, but there's nowhere
|
||||
// to fit it in the message!
|
||||
jassertfalse;
|
||||
return std::tuple (thisChunk, (uint16_t) 0); // 0 means "data potentially unusable"
|
||||
}();
|
||||
|
||||
// Now we know how many bytes we managed to read, write the header at the end of the buffer
|
||||
const auto headerForBlock = getHeaderForBlock();
|
||||
detail::Marshalling::Writer writer { *storage };
|
||||
writer (Message::Header { ChannelInGroup::wholeBlock,
|
||||
messageKind,
|
||||
detail::MessageMeta::implementationVersion,
|
||||
source,
|
||||
dest },
|
||||
requestId,
|
||||
detail::MessageMeta::makeSpanWithSizeBytes<2> (headerForBlock),
|
||||
numChunks,
|
||||
thisChunkNum,
|
||||
numBytesRead);
|
||||
|
||||
// Finally, swap the header to the beginning of the buffer
|
||||
std::rotate (storage->begin(), storage->begin() + getRoomForBody(), storage->end());
|
||||
|
||||
// ...and bring the storage buffer down to size, if we didn't manage to fill it
|
||||
storage->resize (storage->size() + numBytesRead - (size_t) getRoomForBody());
|
||||
}
|
||||
|
||||
} // namespace juce::midi_ci::detail
|
||||
Loading…
Add table
Add a link
Reference in a new issue