Remove minimp3

MP3 emulation already went through FFmpeg, leaving MiniMp3Audio dead.
The one live user was loading MP3 UI sound effects (custom achievement
sounds), which now splits the file into frames and decodes them with
the FFmpeg MP3 decoder.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
Henrik RydgårdandClaude Opus 5.5 committed 2026-09-28 10:57:02 -06:00
1 parent 87ad32d578
commit 761e2f3706
15 files changed
+115 -3397

No files matched your search

-2
View File
@@ -365,7 +365,6 @@
<ClInclude Include="..\ext\lzma-sdk\LzmaDec.h" />
<ClInclude Include="..\ext\lzma-sdk\Precomp.h" />
<ClInclude Include="..\ext\lzma-sdk\RotateDefs.h" />
<ClInclude Include="..\ext\minimp3\minimp3.h" />
<ClInclude Include="..\ext\naett-lib\naett.h" />
<ClInclude Include="..\ext\naett-lib\src\naett_internal.h" />
<ClInclude Include="..\ext\nanosvg\src\nanosvg.h" />
@@ -867,7 +866,6 @@
<ClCompile Include="..\ext\lzma-sdk\Delta.c" />
<ClCompile Include="..\ext\lzma-sdk\Lzma2Dec.c" />
<ClCompile Include="..\ext\lzma-sdk\LzmaDec.c" />
<ClCompile Include="..\ext\minimp3\minimp3.cpp" />
<ClCompile Include="..\ext\naett-lib\src\naett_core.c" />
<ClCompile Include="..\ext\naett-lib\src\naett_win.c" />
<ClCompile Include="..\ext\pugixml\pugixml.cpp" />
-9
View File
@@ -515,9 +515,6 @@
<ClInclude Include="Math\CrossSIMD.h">
<Filter>Math</Filter>
</ClInclude>
<ClInclude Include="..\ext\minimp3\minimp3.h">
<Filter>ext\minimp3</Filter>
</ClInclude>
<ClInclude Include="..\ext\at3_standalone\atrac3data.h">
<Filter>ext\at3_standalone</Filter>
</ClInclude>
@@ -1246,9 +1243,6 @@
<ClCompile Include="GPU\Vulkan\VulkanDescSet.cpp">
<Filter>GPU\Vulkan</Filter>
</ClCompile>
<ClCompile Include="..\ext\minimp3\minimp3.cpp">
<Filter>ext\minimp3</Filter>
</ClCompile>
<ClCompile Include="..\ext\at3_standalone\atrac3.cpp">
<Filter>ext\at3_standalone</Filter>
</ClCompile>
@@ -1588,9 +1582,6 @@
<Filter Include="ext\libchdr">
<UniqueIdentifier>{b681797d-7747-487f-b448-5ef5b2d2805b}</UniqueIdentifier>
</Filter>
<Filter Include="ext\minimp3">
<UniqueIdentifier>{83cd76d0-d1ac-4ed1-9bdc-11fb5a20e5d3}</UniqueIdentifier>
</Filter>
<Filter Include="ext\at3_standalone">
<UniqueIdentifier>{586da66e-922a-4479-9dac-9d608a1b9183}</UniqueIdentifier>
</Filter>
+1 -1
View File
@@ -735,7 +735,7 @@ endif()
list(APPEND CoreExtraLibs armips)
target_link_libraries(Core GPU Common chdr kirk cityhash sfmt19937 xbrz xxhash rcheevos minimp3 at3_standalone lua
target_link_libraries(Core GPU Common chdr kirk cityhash sfmt19937 xbrz xxhash rcheevos at3_standalone lua
aemu_postoffice_client ${CoreExtraLibs} ${CMAKE_DL_LIBS})
# Winsock
-54
View File
@@ -26,8 +26,6 @@
#include "Core/HW/BufferQueue.h"
#include "Core/HW/Atrac3Standalone.h"
#include "ext/minimp3/minimp3.h"
#ifdef USE_FFMPEG
extern "C" {
@@ -59,51 +57,6 @@ extern "C" {
// * https://github.com/meerkat-cv/h264_decoder
// * https://github.com/shengbinmeng/ffmpeg-h264-dec
// minimp3-based decoder.
class MiniMp3Audio : public AudioDecoder {
public:
MiniMp3Audio() {
mp3dec_init(&mp3_);
}
~MiniMp3Audio() {}
bool Decode(const uint8_t* inbuf, int inbytes, int *inbytesConsumed, int outputChannels, int16_t *outbuf, int *outSamples) override {
_dbg_assert_(outputChannels == 2);
// When used from sceMp3LowLevelDecode, this fails to parse the mp3 header!
// It's because minimp3 is a bit more sensitive than ffmpeg - if you give it a buffer that's larger than the frame size,
// it'll check that there's a second matching frame before accepting. But in our case we only get one frame,
// but we do not know the size. So this might need some modifications in minimp3.
mp3dec_frame_info_t info{};
int samplesWritten = mp3dec_decode_frame(&mp3_, inbuf, inbytes, (mp3d_sample_t *)temp_, &info);
_dbg_assert_(samplesWritten <= MINIMP3_MAX_SAMPLES_PER_FRAME);
_dbg_assert_(info.channels <= 2);
if (info.channels == 1) {
for (int i = 0; i < samplesWritten; i++) {
outbuf[i * 2] = temp_[i];
outbuf[i * 2 + 1] = temp_[i];
}
} else {
memcpy(outbuf, temp_, 4 * samplesWritten);
}
*inbytesConsumed = info.frame_bytes;
*outSamples = samplesWritten;
return true;
}
bool IsOK() const override { return true; }
void SetChannels(int channels) override {
// Hmm. ignore for now.
}
PSPAudioType GetAudioType() const override { return PSP_CODEC_MP3; }
private:
// We use the lowest-level API.
mp3dec_t mp3_{};
int16_t temp_[MINIMP3_MAX_SAMPLES_PER_FRAME]{};
};
// FFMPEG-based decoder. TODO: Replace with individual codecs.
// Based on http://ffmpeg.org/doxygen/trunk/doc_2examples_2decoding_encoding_8c-example.html#_a13
class FFmpegAudioDecoder : public AudioDecoder {
@@ -150,13 +103,6 @@ AudioDecoder *CreateAudioDecoder(PSPAudioType audioType, int sampleRateHz, int c
}
switch (audioType) {
// Our MiniMP3 backend has too many issues:
// * Doesn't accept sample rate
// * Doesn't accept data where there's only one valid frame if the buffer is bigger.
// This prevents sceMp3LowLevelDecode from working, since nothing passes us the frame size.
//
// case PSP_CODEC_MP3:
// return new MiniMp3Audio();
case PSP_CODEC_AT3:
return CreateAtrac3Audio(channels, blockAlign, extraData, extraDataSize);
case PSP_CODEC_AT3PLUS:
+114 -21
View File
@@ -1,9 +1,8 @@
#include <memory>
#include <string>
#include <mutex>
#include <algorithm>
#include "ext/minimp3/minimp3_ex.h"
#include "Common/File/VFS/VFS.h"
#include "Common/UI/Root.h"
@@ -434,6 +433,114 @@ inline int16_t ConvertU8ToI16(uint8_t value) {
return ivalue * 255;
}
// Returns the size of the MPEG-1/2/2.5 Layer III frame whose header is at p, or 0 if it isn't one.
static int Mp3FrameSize(const uint8_t *p, int *sampleRate) {
if (p[0] != 0xFF || (p[1] & 0xE0) != 0xE0 || (p[1] & 0x06) != 0x02) {
return 0;
}
static const int bitratesV1[16] = { 0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 0 };
static const int bitratesV2[16] = { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0 };
static const int sampleRatesV1[4] = { 44100, 48000, 32000, 0 };
const int version = (p[1] >> 3) & 3; // 3 = MPEG-1, 2 = MPEG-2, 0 = MPEG-2.5.
if (version == 1) {
return 0;
}
const int bitrate = (version == 3 ? bitratesV1 : bitratesV2)[p[2] >> 4] * 1000;
int rate = sampleRatesV1[(p[2] >> 2) & 3];
if (!bitrate || !rate) {
return 0;
}
rate >>= (version == 3 ? 0 : (version == 2 ? 1 : 2));
*sampleRate = rate;
const int padding = (p[2] >> 1) & 1;
return (version == 3 ? 144 : 72) * bitrate / rate + padding;
}
// Checks for a Xing/Info frame, which some encoders put first. If it carries a LAME tag,
// also returns the samples to trim from the start and end of the decoded stream.
static bool ParseXingFrame(const uint8_t *p, int frameSize, int *delay, int *padding) {
const int version = (p[1] >> 3) & 3;
const bool mono = (p[3] >> 6) == 3;
const int sideInfoSize = version == 3 ? (mono ? 17 : 32) : (mono ? 9 : 17);
const int tagPos = 4 + sideInfoSize;
if (tagPos + 8 > frameSize || (memcmp(p + tagPos, "Xing", 4) && memcmp(p + tagPos, "Info", 4))) {
return false;
}
const uint8_t flags = p[tagPos + 7];
// Skip the optional frame count, byte count, seek table and quality fields.
static const int fieldSizes[4] = { 4, 4, 100, 4 };
int lamePos = tagPos + 8;
for (int i = 0; i < 4; i++) {
if (flags & (1 << i)) {
lamePos += fieldSizes[i];
}
}
if (lamePos + 24 <= frameSize && (!memcmp(p + lamePos, "LAME", 4) || !memcmp(p + lamePos, "Lav", 3))) {
const uint8_t *t = p + lamePos + 21;
// The decoder adds 529 samples of its own delay (and so drops them from the padding).
const int decoderDelay = 529;
*delay = ((t[0] << 4) | (t[1] >> 4)) + decoderDelay;
*padding = std::max(0, (((t[1] & 0xF) << 8) | t[2]) - decoderDelay);
}
return true;
}
static Sample *LoadMp3(const uint8_t *data, size_t size) {
size_t pos = 0;
// Skip an ID3v2 tag.
if (size >= 10 && !memcmp(data, "ID3", 3)) {
pos = 10 + (((data[6] & 0x7F) << 21) | ((data[7] & 0x7F) << 14) | ((data[8] & 0x7F) << 7) | (data[9] & 0x7F));
if (data[5] & 0x10) {
pos += 10; // Footer.
}
}
std::unique_ptr<AudioDecoder> decoder;
std::vector<int16_t> samples;
int16_t frameBuf[1152 * 2];
int sampleRate = 0;
int delay = 0;
int padding = 0;
while (pos + 4 <= size) {
int frameRate = 0;
int frameSize = Mp3FrameSize(data + pos, &frameRate);
if (frameSize == 0 || pos + frameSize > size) {
// Resync, byte by byte.
pos++;
continue;
}
if (!decoder) {
sampleRate = frameRate;
decoder.reset(CreateAudioDecoder(PSP_CODEC_MP3, sampleRate, 2));
if (ParseXingFrame(data + pos, frameSize, &delay, &padding)) {
// It decodes to silence.
pos += frameSize;
continue;
}
}
int consumed = 0;
int outSamples = 0;
if (frameRate == sampleRate && decoder->Decode(data + pos, frameSize, &consumed, 2, frameBuf, &outSamples)) {
samples.insert(samples.end(), frameBuf, frameBuf + outSamples * 2);
}
pos += frameSize;
}
// Trim the encoder delay and padding, in stereo frames.
const size_t trim = (size_t)(delay + padding) * 2;
if (samples.size() > trim) {
samples.erase(samples.end() - padding * 2, samples.end());
samples.erase(samples.begin(), samples.begin() + delay * 2);
}
if (samples.empty()) {
return nullptr;
}
int16_t *sampleData = new int16_t[samples.size()];
memcpy(sampleData, samples.data(), samples.size() * sizeof(int16_t));
return new Sample(sampleData, 2, (int)samples.size() / 2, sampleRate);
}
Sample *Sample::Load(const std::string &path) {
size_t data_size = 0;
uint8_t *data = g_VFS.ReadFile(path.c_str(), &data_size);
@@ -442,7 +549,6 @@ Sample *Sample::Load(const std::string &path) {
return nullptr;
}
const char *mp3_magic = "ID3\03";
const char *wav_magic = "RIFF";
if (!memcmp(data, wav_magic, 4)) {
RIFFReader reader(data, (int)data_size);
@@ -476,25 +582,12 @@ Sample *Sample::Load(const std::string &path) {
return new Sample(samples, wave.num_channels, actualFrames, wave.sample_rate);
}
// Something else.
// Let's see if minimp3 can read it.
mp3dec_t mp3d;
mp3dec_init(&mp3d);
mp3dec_file_info_t mp3_info;
int retval = mp3dec_load_buf(&mp3d, data, data_size, &mp3_info, nullptr, nullptr);
if (retval < 0 || mp3_info.samples == 0) {
ERROR_LOG(Log::Audio, "Couldn't load MP3 for sound effect from %s", path.c_str());
return nullptr;
}
// mp3_info contains the decoded data.
int16_t *sample_data = new int16_t[mp3_info.samples];
memcpy(sample_data, mp3_info.buffer, mp3_info.samples * sizeof(int16_t));
Sample *sample = new Sample(sample_data, mp3_info.channels, (int)mp3_info.samples / mp3_info.channels, mp3_info.hz);
free(mp3_info.buffer);
// Something else, try MP3.
Sample *sample = LoadMp3(data, data_size);
delete[] data;
if (!sample) {
ERROR_LOG(Log::Audio, "Couldn't load MP3 for sound effect from %s", path.c_str());
}
return sample;
}
-1
View File
@@ -717,7 +717,6 @@ void CreditsScroller::Draw(UIContext &dc) {
"zstd",
"glew",
"libchdr",
"minimp3",
"xxhash",
"naett-http",
"PSP SDK",
-3
View File
@@ -291,8 +291,6 @@
<ClInclude Include="..\..\ext\lzma-sdk\LzmaDec.h" />
<ClInclude Include="..\..\ext\lzma-sdk\Precomp.h" />
<ClInclude Include="..\..\ext\lzma-sdk\RotateDefs.h" />
<ClInclude Include="..\..\ext\minimp3\minimp3.h" />
<ClInclude Include="..\..\ext\minimp3\minimp3_ex.h" />
<ClInclude Include="..\..\ext\naett-lib\naett.h" />
<ClInclude Include="..\..\ext\naett-lib\src\naett_internal.h" />
<ClInclude Include="..\..\ext\pugixml\pugiconfig.hpp" />
@@ -476,7 +474,6 @@
<ClCompile Include="..\..\ext\lzma-sdk\Delta.c" />
<ClCompile Include="..\..\ext\lzma-sdk\Lzma2Dec.c" />
<ClCompile Include="..\..\ext\lzma-sdk\LzmaDec.c" />
<ClCompile Include="..\..\ext\minimp3\minimp3.cpp" />
<ClCompile Include="..\..\ext\naett-lib\src\naett_core.c" />
<ClCompile Include="..\..\ext\naett-lib\src\naett_win.c" />
<ClCompile Include="..\..\ext\pugixml\pugixml.cpp" />
-12
View File
@@ -97,9 +97,6 @@
<Filter Include="ext\naett-lib">
<UniqueIdentifier>{403c3154-5e8a-4da1-ba82-8f69bef25e14}</UniqueIdentifier>
</Filter>
<Filter Include="ext\minimp3">
<UniqueIdentifier>{7b5c3ddc-225d-48d5-a829-9a1e71e304be}</UniqueIdentifier>
</Filter>
<Filter Include="ext\at3_standalone">
<UniqueIdentifier>{47e3b9c8-3a5f-4c78-b62b-3fa65bf23594}</UniqueIdentifier>
</Filter>
@@ -473,9 +470,6 @@
<ClCompile Include="..\..\ext\naett-lib\src\naett_win.c">
<Filter>ext\naett-lib</Filter>
</ClCompile>
<ClCompile Include="..\..\ext\minimp3\minimp3.cpp">
<Filter>ext\minimp3</Filter>
</ClCompile>
<ClCompile Include="..\..\ext\at3_standalone\atrac.cpp">
<Filter>ext\at3_standalone</Filter>
</ClCompile>
@@ -1006,12 +1000,6 @@
<ClInclude Include="..\..\Common\Math\CrossSIMD.h">
<Filter>Math</Filter>
</ClInclude>
<ClInclude Include="..\..\ext\minimp3\minimp3.h">
<Filter>ext\minimp3</Filter>
</ClInclude>
<ClInclude Include="..\..\ext\minimp3\minimp3_ex.h">
<Filter>ext\minimp3</Filter>
</ClInclude>
<ClInclude Include="..\..\ext\at3_standalone\aac_defines.h">
<Filter>ext\at3_standalone</Filter>
</ClInclude>
-4
View File
@@ -168,9 +168,6 @@ NAETT_FILES := \
${SRC}/ext/naett-lib/src/naett_core.c \
${SRC}/ext/naett-lib/src/naett_android.c
MINIMP3_FILES := \
${SRC}/ext/minimp3/minimp3.cpp
AT3_STANDALONE_FILES := \
${SRC}/ext/at3_standalone/atrac.cpp \
${SRC}/ext/at3_standalone/atrac3.cpp \
@@ -306,7 +303,6 @@ EXEC_AND_LIB_FILES := \
$(SPIRV_CROSS_FILES) \
$(RCHEEVOS_FILES) \
$(NAETT_FILES) \
$(MINIMP3_FILES) \
$(AT3_STANDALONE_FILES) \
$(EXT_FILES) \
$(NATIVE_FILES) \
-1
View File
@@ -31,7 +31,6 @@ set(ENABLE_GLSLANG_INSTALL OFF)
add_subdirectory(glslang EXCLUDE_FROM_ALL)
add_subdirectory(snappy)
add_subdirectory(lua-build)
add_subdirectory(minimp3)
add_subdirectory(at3_standalone)
add_subdirectory(udis86)
add_subdirectory(SPIRV-Cross-build)
-12
View File
@@ -1,12 +0,0 @@
cmake_minimum_required (VERSION 3.16)
project (minimp3)
set(SRC_DIR .)
# format
set(ALL_SOURCE_FILES
# rapi
${SRC_DIR}/minimp3.cpp
)
add_library(minimp3 STATIC ${ALL_SOURCE_FILES})
-11
View File
@@ -1,11 +0,0 @@
// Gotta define it somewhere.
#define MINIMP3_IMPLEMENTATION
#define MINIMP3_NO_STDIO
#ifdef _MSC_VER
#pragma warning(disable:4267)
#pragma warning(disable:4244)
#endif
#include "minimp3.h"
#include "minimp3_ex.h"
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
-4
View File
@@ -25,7 +25,6 @@ INCFLAGS += \
-I$(EXTDIR)/glslang \
-I$(EXTDIR)/glslang-build \
-I$(EXTDIR)/native \
-I$(EXTDIR)/minimp3 \
-I$(EXTDIR)/zlib \
-I$(EXTDIR)/cpu_features/include \
-I$(ZSTDDIR) \
@@ -174,9 +173,6 @@ endif
SOURCES_C += $(LIBRETRODIR)/ext/glew/glew.c
SOURCES_CXX += \
$(EXTDIR)/minimp3/minimp3.cpp
SOURCES_C += \
$(EXTDIR)/libkirk/AES.c \
$(EXTDIR)/libkirk/amctrl.c \