Skip to content

Commit

Permalink
Properly support parsing MP3 files without headers. (#264)
Browse files Browse the repository at this point in the history
* Properly support parsing MP3 files with no headers.

* Properly parse MP3 files without headers.
  • Loading branch information
psobot authored Oct 17, 2023
1 parent 977d969 commit 4012eba
Show file tree
Hide file tree
Showing 3 changed files with 19 additions and 6 deletions.
18 changes: 12 additions & 6 deletions pedalboard/juce_overrides/juce_PatchedMP3AudioFormat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2125,11 +2125,10 @@ struct PatchedMP3Stream {
auto oldPos = stream.getPosition();
int offset = -3;
uint32 header = 0;
bool isFirstScanAtThisPosition = true;
bool isParsingFirstFrame = oldPos == 0;

for (;;) {
auto streamPos = stream.getPosition();
bool isParsingFirstFrame = streamPos == 0;

if (stream.isExhausted() || streamPos > oldPos + 32768) {
offset = -1;
Expand All @@ -2156,15 +2155,22 @@ struct PatchedMP3Stream {
break;
}

if (isFirstScanAtThisPosition && isParsingFirstFrame) {
if (isParsingFirstFrame && offset == 0) {
// If we're parsing the first frame of a file/stream, that frame must be
// at the start of the stream. This prevents accidentally parsing .mp4
// files (among others) as MP3 files that start with junk.
// at the start of the stream (i.e.: the first four bytes must be a
// valid MP3 header).
//
// If the first four bytes were a valid MP3 header, the above `if (...
// isValidHeader)` check would have exited the `for` loop, and we'd
// never get here.
//
// This prevents accidentally parsing .mp4 files (among others) as MP3
// files that start with junk.
offset = -1;
break;
}

++offset;
isFirstScanAtThisPosition = false;
}

if (offset >= 0) {
Expand Down
Binary file added tests/audio/correct/no_header.mp3
Binary file not shown.
7 changes: 7 additions & 0 deletions tests/test_io.py
Original file line number Diff line number Diff line change
Expand Up @@ -1052,6 +1052,13 @@ def test_real_mp3_parsing_with_lyrics3():
assert f.read(f.frames).shape[1] == f.frames


def test_real_mp3_parsing_with_no_header():
filename = os.path.join(os.path.dirname(__file__), "audio", "correct", "no_header.mp3")
with pedalboard.io.AudioFile(filename) as f:
assert f.frames >= 40000 and f.frames <= 45000
assert f.read(f.frames).shape[1] == f.frames


@pytest.mark.parametrize("samplerate", [44100, 32000])
@pytest.mark.parametrize("chunk_size", [1, 2, 16])
@pytest.mark.parametrize("target_samplerate", [44100, 32000, 22050, 1234.56])
Expand Down

0 comments on commit 4012eba

Please sign in to comment.