mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-10 23:44:24 +00:00
Add simple Optional type
This commit is contained in:
parent
833c1e590f
commit
5d096b46d7
5 changed files with 1074 additions and 86 deletions
|
|
@ -46,18 +46,6 @@ namespace MidiFileHelpers
|
|||
}
|
||||
}
|
||||
|
||||
template <typename Value>
|
||||
struct Optional
|
||||
{
|
||||
Optional() = default;
|
||||
|
||||
Optional (const Value& v)
|
||||
: value (v), valid (true) {}
|
||||
|
||||
Value value = Value();
|
||||
bool valid = false;
|
||||
};
|
||||
|
||||
template <typename Integral>
|
||||
struct ReadTrait;
|
||||
|
||||
|
|
@ -100,23 +88,23 @@ namespace MidiFileHelpers
|
|||
|
||||
auto ch = tryRead<uint32> (data, remaining);
|
||||
|
||||
if (! ch.valid)
|
||||
if (! ch.hasValue())
|
||||
return {};
|
||||
|
||||
if (ch.value != ByteOrder::bigEndianInt ("MThd"))
|
||||
if (*ch != ByteOrder::bigEndianInt ("MThd"))
|
||||
{
|
||||
auto ok = false;
|
||||
|
||||
if (ch.value == ByteOrder::bigEndianInt ("RIFF"))
|
||||
if (*ch == ByteOrder::bigEndianInt ("RIFF"))
|
||||
{
|
||||
for (int i = 0; i < 8; ++i)
|
||||
{
|
||||
ch = tryRead<uint32> (data, remaining);
|
||||
|
||||
if (! ch.valid)
|
||||
if (! ch.hasValue())
|
||||
return {};
|
||||
|
||||
if (ch.value == ByteOrder::bigEndianInt ("MThd"))
|
||||
if (*ch == ByteOrder::bigEndianInt ("MThd"))
|
||||
{
|
||||
ok = true;
|
||||
break;
|
||||
|
|
@ -130,29 +118,29 @@ namespace MidiFileHelpers
|
|||
|
||||
const auto bytesRemaining = tryRead<uint32> (data, remaining);
|
||||
|
||||
if (! bytesRemaining.valid || bytesRemaining.value > remaining)
|
||||
if (! bytesRemaining.hasValue() || *bytesRemaining > remaining)
|
||||
return {};
|
||||
|
||||
const auto optFileType = tryRead<uint16> (data, remaining);
|
||||
|
||||
if (! optFileType.valid || 2 < optFileType.value)
|
||||
if (! optFileType.hasValue() || 2 < *optFileType)
|
||||
return {};
|
||||
|
||||
const auto optNumTracks = tryRead<uint16> (data, remaining);
|
||||
|
||||
if (! optNumTracks.valid || (optFileType.value == 0 && optNumTracks.value != 1))
|
||||
if (! optNumTracks.hasValue() || (*optFileType == 0 && *optNumTracks != 1))
|
||||
return {};
|
||||
|
||||
const auto optTimeFormat = tryRead<uint16> (data, remaining);
|
||||
|
||||
if (! optTimeFormat.valid)
|
||||
if (! optTimeFormat.hasValue())
|
||||
return {};
|
||||
|
||||
HeaderDetails result;
|
||||
|
||||
result.fileType = (short) optFileType.value;
|
||||
result.timeFormat = (short) optTimeFormat.value;
|
||||
result.numberOfTracks = (short) optNumTracks.value;
|
||||
result.fileType = (short) *optFileType;
|
||||
result.timeFormat = (short) *optTimeFormat;
|
||||
result.numberOfTracks = (short) *optNumTracks;
|
||||
result.bytesRead = maxSize - remaining;
|
||||
|
||||
return { result };
|
||||
|
|
@ -373,10 +361,10 @@ bool MidiFile::readFrom (InputStream& sourceStream,
|
|||
|
||||
const auto optHeader = MidiFileHelpers::parseMidiHeader (d, size);
|
||||
|
||||
if (! optHeader.valid)
|
||||
if (! optHeader.hasValue())
|
||||
return false;
|
||||
|
||||
const auto header = optHeader.value;
|
||||
const auto header = *optHeader;
|
||||
timeFormat = header.timeFormat;
|
||||
|
||||
d += header.bytesRead;
|
||||
|
|
@ -386,20 +374,20 @@ bool MidiFile::readFrom (InputStream& sourceStream,
|
|||
{
|
||||
const auto optChunkType = MidiFileHelpers::tryRead<uint32> (d, size);
|
||||
|
||||
if (! optChunkType.valid)
|
||||
if (! optChunkType.hasValue())
|
||||
return false;
|
||||
|
||||
const auto optChunkSize = MidiFileHelpers::tryRead<uint32> (d, size);
|
||||
|
||||
if (! optChunkSize.valid)
|
||||
if (! optChunkSize.hasValue())
|
||||
return false;
|
||||
|
||||
const auto chunkSize = optChunkSize.value;
|
||||
const auto chunkSize = *optChunkSize;
|
||||
|
||||
if (size < chunkSize)
|
||||
return false;
|
||||
|
||||
if (optChunkType.value == ByteOrder::bigEndianInt ("MTrk"))
|
||||
if (*optChunkType == ByteOrder::bigEndianInt ("MTrk"))
|
||||
readNextTrack (d, (int) chunkSize, createMatchingNoteOffs);
|
||||
|
||||
size -= chunkSize;
|
||||
|
|
@ -610,7 +598,7 @@ struct MidiFileTest : public UnitTest
|
|||
{
|
||||
// No data
|
||||
const auto header = parseHeader ([] (OutputStream&) {});
|
||||
expect (! header.valid);
|
||||
expect (! header.hasValue());
|
||||
}
|
||||
|
||||
{
|
||||
|
|
@ -620,7 +608,7 @@ struct MidiFileTest : public UnitTest
|
|||
writeBytes (os, { 0xff });
|
||||
});
|
||||
|
||||
expect (! header.valid);
|
||||
expect (! header.hasValue());
|
||||
}
|
||||
|
||||
{
|
||||
|
|
@ -630,7 +618,7 @@ struct MidiFileTest : public UnitTest
|
|||
writeBytes (os, { 'M', 'T', 'h', 'd' });
|
||||
});
|
||||
|
||||
expect (! header.valid);
|
||||
expect (! header.hasValue());
|
||||
}
|
||||
|
||||
{
|
||||
|
|
@ -640,7 +628,7 @@ struct MidiFileTest : public UnitTest
|
|||
writeBytes (os, { 'M', 'T', 'h', 'd', 0, 0, 0, 6, 0, 0, 0, 16, 0, 1 });
|
||||
});
|
||||
|
||||
expect (! header.valid);
|
||||
expect (! header.hasValue());
|
||||
}
|
||||
|
||||
{
|
||||
|
|
@ -650,7 +638,7 @@ struct MidiFileTest : public UnitTest
|
|||
writeBytes (os, { 'M', 'T', 'h', 'd', 0, 0, 0, 6, 0, 5, 0, 16, 0, 1 });
|
||||
});
|
||||
|
||||
expect (! header.valid);
|
||||
expect (! header.hasValue());
|
||||
}
|
||||
|
||||
{
|
||||
|
|
@ -660,12 +648,12 @@ struct MidiFileTest : public UnitTest
|
|||
writeBytes (os, { 'M', 'T', 'h', 'd', 0, 0, 0, 6, 0, 1, 0, 16, 0, 1 });
|
||||
});
|
||||
|
||||
expect (header.valid);
|
||||
expect (header.hasValue());
|
||||
|
||||
expectEquals (header.value.fileType, (short) 1);
|
||||
expectEquals (header.value.numberOfTracks, (short) 16);
|
||||
expectEquals (header.value.timeFormat, (short) 1);
|
||||
expectEquals ((int) header.value.bytesRead, 14);
|
||||
expectEquals (header->fileType, (short) 1);
|
||||
expectEquals (header->numberOfTracks, (short) 16);
|
||||
expectEquals (header->timeFormat, (short) 1);
|
||||
expectEquals ((int) header->bytesRead, 14);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -674,7 +662,7 @@ struct MidiFileTest : public UnitTest
|
|||
{
|
||||
// Empty input
|
||||
const auto file = parseFile ([] (OutputStream&) {});
|
||||
expect (! file.valid);
|
||||
expect (! file.hasValue());
|
||||
}
|
||||
|
||||
{
|
||||
|
|
@ -684,7 +672,7 @@ struct MidiFileTest : public UnitTest
|
|||
writeBytes (os, { 'M', 'T', 'h', 'd' });
|
||||
});
|
||||
|
||||
expect (! file.valid);
|
||||
expect (! file.hasValue());
|
||||
}
|
||||
|
||||
{
|
||||
|
|
@ -694,8 +682,8 @@ struct MidiFileTest : public UnitTest
|
|||
writeBytes (os, { 'M', 'T', 'h', 'd', 0, 0, 0, 6, 0, 1, 0, 0, 0, 1 });
|
||||
});
|
||||
|
||||
expect (file.valid);
|
||||
expectEquals (file.value.getNumTracks(), 0);
|
||||
expect (file.hasValue());
|
||||
expectEquals (file->getNumTracks(), 0);
|
||||
}
|
||||
|
||||
{
|
||||
|
|
@ -706,7 +694,7 @@ struct MidiFileTest : public UnitTest
|
|||
writeBytes (os, { 'M', 'T', 'r', '?' });
|
||||
});
|
||||
|
||||
expect (! file.valid);
|
||||
expect (! file.hasValue());
|
||||
}
|
||||
|
||||
{
|
||||
|
|
@ -717,9 +705,9 @@ struct MidiFileTest : public UnitTest
|
|||
writeBytes (os, { 'M', 'T', 'r', 'k', 0, 0, 0, 1, 0xff });
|
||||
});
|
||||
|
||||
expect (file.valid);
|
||||
expectEquals (file.value.getNumTracks(), 1);
|
||||
expectEquals (file.value.getTrack (0)->getNumEvents(), 0);
|
||||
expect (file.hasValue());
|
||||
expectEquals (file->getNumTracks(), 1);
|
||||
expectEquals (file->getTrack (0)->getNumEvents(), 0);
|
||||
}
|
||||
|
||||
{
|
||||
|
|
@ -730,7 +718,7 @@ struct MidiFileTest : public UnitTest
|
|||
writeBytes (os, { 'M', 'T', 'r', 'k', 0x0f, 0, 0, 0, 0xff });
|
||||
});
|
||||
|
||||
expect (! file.valid);
|
||||
expect (! file.hasValue());
|
||||
}
|
||||
|
||||
{
|
||||
|
|
@ -744,10 +732,10 @@ struct MidiFileTest : public UnitTest
|
|||
writeBytes (os, { 0x80, 0x00, 0x00 });
|
||||
});
|
||||
|
||||
expect (file.valid);
|
||||
expectEquals (file.value.getNumTracks(), 1);
|
||||
expect (file.hasValue());
|
||||
expectEquals (file->getNumTracks(), 1);
|
||||
|
||||
auto& track = *file.value.getTrack (0);
|
||||
auto& track = *file->getTrack (0);
|
||||
expectEquals (track.getNumEvents(), 1);
|
||||
expect (track.getEventPointer (0)->message.isNoteOff());
|
||||
expectEquals (track.getEventPointer (0)->message.getTimeStamp(), (double) 0x0f);
|
||||
|
|
@ -766,7 +754,7 @@ struct MidiFileTest : public UnitTest
|
|||
}
|
||||
|
||||
template <typename Fn>
|
||||
static MidiFileHelpers::Optional<MidiFileHelpers::HeaderDetails> parseHeader (Fn&& fn)
|
||||
static Optional<MidiFileHelpers::HeaderDetails> parseHeader (Fn&& fn)
|
||||
{
|
||||
MemoryOutputStream os;
|
||||
fn (os);
|
||||
|
|
@ -776,7 +764,7 @@ struct MidiFileTest : public UnitTest
|
|||
}
|
||||
|
||||
template <typename Fn>
|
||||
static MidiFileHelpers::Optional<MidiFile> parseFile (Fn&& fn)
|
||||
static Optional<MidiFile> parseFile (Fn&& fn)
|
||||
{
|
||||
MemoryOutputStream os;
|
||||
fn (os);
|
||||
|
|
|
|||
|
|
@ -306,63 +306,56 @@ void MidiMessageSequence::deleteSysExMessages()
|
|||
//==============================================================================
|
||||
class OptionalPitchWheel
|
||||
{
|
||||
int value = 0;
|
||||
bool valid = false;
|
||||
Optional<int> value;
|
||||
|
||||
public:
|
||||
void emit (int channel, Array<MidiMessage>& out) const
|
||||
{
|
||||
if (valid)
|
||||
out.add (MidiMessage::pitchWheel (channel, value));
|
||||
if (value.hasValue())
|
||||
out.add (MidiMessage::pitchWheel (channel, *value));
|
||||
}
|
||||
|
||||
void set (int v)
|
||||
{
|
||||
value = v;
|
||||
valid = true;
|
||||
}
|
||||
};
|
||||
|
||||
class OptionalControllerValues
|
||||
{
|
||||
int values[128];
|
||||
Optional<char> values[128];
|
||||
|
||||
public:
|
||||
OptionalControllerValues()
|
||||
{
|
||||
std::fill (std::begin (values), std::end (values), -1);
|
||||
}
|
||||
|
||||
void emit (int channel, Array<MidiMessage>& out) const
|
||||
{
|
||||
for (auto it = std::begin (values); it != std::end (values); ++it)
|
||||
if (*it != -1)
|
||||
out.add (MidiMessage::controllerEvent (channel, (int) std::distance (std::begin (values), it), *it));
|
||||
if (it->hasValue())
|
||||
out.add (MidiMessage::controllerEvent (channel, (int) std::distance (std::begin (values), it), **it));
|
||||
}
|
||||
|
||||
void set (int controller, int value)
|
||||
{
|
||||
values[controller] = value;
|
||||
values[controller] = (char) value;
|
||||
}
|
||||
};
|
||||
|
||||
class OptionalProgramChange
|
||||
{
|
||||
int value = -1, bankLSB = -1, bankMSB = -1;
|
||||
Optional<char> value, bankLSB, bankMSB;
|
||||
|
||||
public:
|
||||
void emit (int channel, double time, Array<MidiMessage>& out) const
|
||||
{
|
||||
if (value == -1)
|
||||
if (! value.hasValue())
|
||||
return;
|
||||
|
||||
if (bankLSB != -1 && bankMSB != -1)
|
||||
if (bankLSB.hasValue() && bankMSB.hasValue())
|
||||
{
|
||||
out.add (MidiMessage::controllerEvent (channel, 0x00, bankMSB).withTimeStamp (time));
|
||||
out.add (MidiMessage::controllerEvent (channel, 0x20, bankLSB).withTimeStamp (time));
|
||||
out.add (MidiMessage::controllerEvent (channel, 0x00, *bankMSB).withTimeStamp (time));
|
||||
out.add (MidiMessage::controllerEvent (channel, 0x20, *bankLSB).withTimeStamp (time));
|
||||
}
|
||||
|
||||
out.add (MidiMessage::programChange (channel, value).withTimeStamp (time));
|
||||
out.add (MidiMessage::programChange (channel, *value).withTimeStamp (time));
|
||||
}
|
||||
|
||||
// Returns true if this is a bank number change, and false otherwise.
|
||||
|
|
@ -370,22 +363,21 @@ public:
|
|||
{
|
||||
switch (controller)
|
||||
{
|
||||
case 0x00: bankMSB = v; return true;
|
||||
case 0x20: bankLSB = v; return true;
|
||||
case 0x00: bankMSB = (char) v; return true;
|
||||
case 0x20: bankLSB = (char) v; return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void setProgram (int v) { value = v; }
|
||||
void setProgram (int v) { value = (char) v; }
|
||||
};
|
||||
|
||||
class ParameterNumberState
|
||||
{
|
||||
enum class Kind { rpn, nrpn };
|
||||
|
||||
int newestRpnLsb = -1, newestRpnMsb = -1, newestNrpnLsb = -1, newestNrpnMsb = -1;
|
||||
int lastSentLsb = -1, lastSentMsb = -1;
|
||||
Optional<char> newestRpnLsb, newestRpnMsb, newestNrpnLsb, newestNrpnMsb, lastSentLsb, lastSentMsb;
|
||||
Kind lastSentKind = Kind::rpn, newestKind = Kind::rpn;
|
||||
|
||||
public:
|
||||
|
|
@ -401,11 +393,11 @@ public:
|
|||
auto lastSent = std::tie (lastSentKind, lastSentMsb, lastSentLsb);
|
||||
const auto newest = std::tie (newestKind, newestMsb, newestLsb);
|
||||
|
||||
if (lastSent == newest || newestMsb == -1 || newestLsb == -1)
|
||||
if (lastSent == newest || ! newestMsb.hasValue() || ! newestLsb.hasValue())
|
||||
return;
|
||||
|
||||
out.add (MidiMessage::controllerEvent (channel, newestKind == Kind::rpn ? 0x65 : 0x63, newestMsb).withTimeStamp (time));
|
||||
out.add (MidiMessage::controllerEvent (channel, newestKind == Kind::rpn ? 0x64 : 0x62, newestLsb).withTimeStamp (time));
|
||||
out.add (MidiMessage::controllerEvent (channel, newestKind == Kind::rpn ? 0x65 : 0x63, *newestMsb).withTimeStamp (time));
|
||||
out.add (MidiMessage::controllerEvent (channel, newestKind == Kind::rpn ? 0x64 : 0x62, *newestLsb).withTimeStamp (time));
|
||||
|
||||
lastSent = newest;
|
||||
}
|
||||
|
|
@ -415,10 +407,10 @@ public:
|
|||
{
|
||||
switch (controller)
|
||||
{
|
||||
case 0x65: newestRpnMsb = value; newestKind = Kind::rpn; return true;
|
||||
case 0x64: newestRpnLsb = value; newestKind = Kind::rpn; return true;
|
||||
case 0x63: newestNrpnMsb = value; newestKind = Kind::nrpn; return true;
|
||||
case 0x62: newestNrpnLsb = value; newestKind = Kind::nrpn; return true;
|
||||
case 0x65: newestRpnMsb = (char) value; newestKind = Kind::rpn; return true;
|
||||
case 0x64: newestRpnLsb = (char) value; newestKind = Kind::rpn; return true;
|
||||
case 0x63: newestNrpnMsb = (char) value; newestKind = Kind::nrpn; return true;
|
||||
case 0x62: newestNrpnLsb = (char) value; newestKind = Kind::nrpn; return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue