1
0
Fork 0
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:
reuk 2022-03-16 13:35:04 +00:00
parent 833c1e590f
commit 5d096b46d7
No known key found for this signature in database
GPG key ID: 9ADCD339CFC98A11
5 changed files with 1074 additions and 86 deletions

View file

@ -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);

View file

@ -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;