Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MIDI: Ignore SysEx messages #710

Merged
merged 4 commits into from
Oct 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions RELEASENOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@
* Smooth Streaming Extension:
* RTSP Extension:
* Decoder Extensions (FFmpeg, VP9, AV1, MIDI, etc.):
* MIDI decoder: Ignore SysEx event messages
([#710](https://github.com/androidx/media/pull/710)).
* Leanback extension:
* Cast Extension:
* Test Utilities:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@
public static final int DATA_FIELD_UNSET = Integer.MIN_VALUE;

private static final int TICKS_UNSET = -1;
private static final int SYSEX_BEGIN_STATUS = 0xF0;
private static final int SYSEX_END_STATUS = 0xF7;
private static final int META_EVENT_STATUS = 0xFF;
private static final int META_END_OF_TRACK = 0x2F;
private static final int META_TEMPO_CHANGE = 0x51;
Expand Down Expand Up @@ -82,9 +84,40 @@ public boolean populateFrom(ParsableByteArray parsableTrackEventBytes, int previ
int firstByte = parsableTrackEventBytes.readUnsignedByte();
eventDecoderSizeBytes = 1;

if ((firstByte & 0xF0) != 0xF0) {
// Most significant nibble is not 0xF, this is a MIDI channel event.
if (firstByte == SYSEX_BEGIN_STATUS) {
// TODO(b/228838584): Handle this gracefully.
statusByte = firstByte;

int currentByte;
do { // Consume SysEx message.
currentByte = parsableTrackEventBytes.readUnsignedByte();
} while (currentByte != SYSEX_END_STATUS);
} else if (firstByte == META_EVENT_STATUS) { // This is a Meta event.
int metaEventMessageType = parsableTrackEventBytes.readUnsignedByte();
int eventLength = readVariableLengthInt(parsableTrackEventBytes);

statusByte = firstByte;

switch (metaEventMessageType) {
case META_TEMPO_CHANGE:
usPerQuarterNote = parsableTrackEventBytes.readUnsignedInt24();

if (usPerQuarterNote <= 0) {
throw ParserException.createForUnsupportedContainerFeature(
"Tempo event data value must be a non-zero positive value. Parsed value: "
+ usPerQuarterNote);
}

parsableTrackEventBytes.skipBytes(eventLength - /* tempoDataLength */ 3);
break;
case META_END_OF_TRACK:
parsableTrackEventBytes.setPosition(startingPosition);
reset();
return false;
default: // Ignore all other Meta events.
parsableTrackEventBytes.skipBytes(eventLength);
}
} else { // This is a MIDI channel event.
// Check for running status, an occurrence where the statusByte has been omitted from the
// bytes of this event. The standard expects us to assume that this command has the same
// statusByte as the last command.
Expand Down Expand Up @@ -113,37 +146,6 @@ public boolean populateFrom(ParsableByteArray parsableTrackEventBytes, int previ
}

statusByte = firstByte;
} else {
if (firstByte == META_EVENT_STATUS) { // This is a Meta event.
int metaEventMessageType = parsableTrackEventBytes.readUnsignedByte();
int eventLength = readVariableLengthInt(parsableTrackEventBytes);

statusByte = firstByte;

switch (metaEventMessageType) {
case META_TEMPO_CHANGE:
usPerQuarterNote = parsableTrackEventBytes.readUnsignedInt24();

if (usPerQuarterNote <= 0) {
throw ParserException.createForUnsupportedContainerFeature(
"Tempo event data value must be a non-zero positive value. Parsed value: "
+ usPerQuarterNote);
}

parsableTrackEventBytes.skipBytes(eventLength - /* tempoDataLength */ 3);
break;
case META_END_OF_TRACK:
parsableTrackEventBytes.setPosition(startingPosition);
reset();
return false;
default: // Ignore all other Meta events.
parsableTrackEventBytes.skipBytes(eventLength);
}
} else {
// TODO(b/228838584): Handle this gracefully.
throw ParserException.createForUnsupportedContainerFeature(
"SysEx track events are not yet supported.");
}
}

eventFileSizeBytes = parsableTrackEventBytes.getPosition() - startingPosition;
Expand All @@ -154,8 +156,7 @@ public boolean populateFrom(ParsableByteArray parsableTrackEventBytes, int previ
}

public boolean isMidiEvent() {
// TODO(b/228838584): Update with SysEx event check when implemented.
return statusByte != META_EVENT_STATUS;
return statusByte != META_EVENT_STATUS && statusByte != SYSEX_BEGIN_STATUS;
}

public boolean isNoteChannelEvent() {
Expand Down