Add support for loading mp3 files as UI sound.

Fixes #18136
This commit is contained in:
Henrik Rydgård
2024-04-09 17:29:57 +02:00
parent fd91611f4f
commit 862fb951f1
10 changed files with 79 additions and 40 deletions
+1 -1
View File
@@ -2363,7 +2363,7 @@ endif()
include_directories(ext/libchdr/include)
target_link_libraries(${CoreLibName} Common native chdr kirk cityhash sfmt19937 xbrz xxhash rcheevos ${GlslangLibs}
target_link_libraries(${CoreLibName} Common native chdr kirk cityhash sfmt19937 xbrz xxhash rcheevos minimp3 ${GlslangLibs}
${CoreExtraLibs} ${OPENGL_LIBRARIES} ${X11_LIBRARIES} ${CMAKE_DL_LIBS})
if(NOT HTTPS_NOT_AVAILABLE)
+3 -1
View File
@@ -399,6 +399,7 @@
<ClInclude Include="..\ext\libpng17\pnglibconf.h" />
<ClInclude Include="..\ext\libpng17\pngpriv.h" />
<ClInclude Include="..\ext\libpng17\pngstruct.h" />
<ClInclude Include="..\ext\minimp3\minimp3.h" />
<ClInclude Include="..\ext\naett\naett.h" />
<ClInclude Include="..\ext\vma\vk_mem_alloc.h" />
<ClInclude Include="ABI.h" />
@@ -832,6 +833,7 @@
<ForcedIncludeFiles Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
</ForcedIncludeFiles>
</ClCompile>
<ClCompile Include="..\ext\minimp3\minimp3.cpp" />
<ClCompile Include="..\ext\naett\naett.c" />
<ClCompile Include="..\ext\vma\vk_mem_alloc.cpp" />
<ClCompile Include="ABI.cpp" />
@@ -1039,4 +1041,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>
+9
View File
@@ -521,6 +521,9 @@
<ClInclude Include="Math\CrossSIMD.h">
<Filter>Math</Filter>
</ClInclude>
<ClInclude Include="..\ext\minimp3\minimp3.h">
<Filter>ext\minimp3</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="ABI.cpp" />
@@ -975,6 +978,9 @@
<ClCompile Include="GPU\Vulkan\VulkanDescSet.cpp">
<Filter>GPU\Vulkan</Filter>
</ClCompile>
<ClCompile Include="..\ext\minimp3\minimp3.cpp">
<Filter>ext\minimp3</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Filter Include="Crypto">
@@ -1085,6 +1091,9 @@
<Filter Include="ext\libchdr">
<UniqueIdentifier>{b681797d-7747-487f-b448-5ef5b2d2805b}</UniqueIdentifier>
</Filter>
<Filter Include="ext\minimp3">
<UniqueIdentifier>{83cd76d0-d1ac-4ed1-9bdc-11fb5a20e5d3}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<Text Include="..\ext\libpng17\CMakeLists.txt">
+1 -1
View File
@@ -316,7 +316,7 @@ bool MainUI::HandleCustomEvent(QEvent *e) {
filter = "DB files (*.db)";
break;
case BrowseFileType::SOUND_EFFECT:
filter = "WAVE files (*.wav)";
filter = "WAVE files (*.wav *.mp3)";
break;
case BrowseFileType::ZIP:
filter = "ZIP files (*.zip)";
+57 -34
View File
@@ -1,6 +1,8 @@
#include <string>
#include <mutex>
#include "ext/minimp3/minimp3_ex.h"
#include "Common/File/VFS/VFS.h"
#include "Common/UI/Root.h"
@@ -36,7 +38,7 @@ struct WavData {
int raw_data_size = 0;
u8 at3_extradata[16];
void Read(RIFFReader &riff);
bool Read(RIFFReader &riff);
~WavData() {
free(raw_data);
@@ -49,7 +51,7 @@ struct WavData {
}
};
void WavData::Read(RIFFReader &file_) {
bool WavData::Read(RIFFReader &file_) {
// If we have no loop start info, we'll just loop the entire audio.
raw_offset_loop_start = 0;
raw_offset_loop_end = 0;
@@ -72,7 +74,7 @@ void WavData::Read(RIFFReader &file_) {
break;
default:
ERROR_LOG(SCEAUDIO, "Unexpected wave format %04x", format);
return;
return false;
}
num_channels = temp >> 16;
@@ -97,7 +99,7 @@ void WavData::Read(RIFFReader &file_) {
} else {
ERROR_LOG(AUDIO, "Error - no format chunk in wav");
file_.Ascend();
return;
return false;
}
if (file_.Descend('smpl')) {
@@ -157,20 +159,21 @@ void WavData::Read(RIFFReader &file_) {
ERROR_LOG(AUDIO, "Error - bad blockalign or channels");
free(raw_data);
raw_data = nullptr;
return;
return false;
}
file_.Ascend();
} else {
ERROR_LOG(AUDIO, "Error - no data chunk in wav");
file_.Ascend();
return;
return false;
}
file_.Ascend();
} else {
ERROR_LOG(AUDIO, "Could not descend into RIFF file.");
return;
return false;
}
sample_rate = samplesPerSec;
return true;
}
// Really simple looping in-memory AT3 player that also takes care of reading the file format.
@@ -380,40 +383,60 @@ inline int16_t ConvertU8ToI16(uint8_t value) {
}
Sample *Sample::Load(const std::string &path) {
size_t bytes = 0;
uint8_t *data = g_VFS.ReadFile(path.c_str(), &bytes);
if (!data || bytes > 100000000) {
size_t data_size = 0;
uint8_t *data = g_VFS.ReadFile(path.c_str(), &data_size);
if (!data || data_size > 100000000) {
WARN_LOG(AUDIO, "Failed to load sample '%s'", path.c_str());
return nullptr;
}
RIFFReader reader(data, (int)bytes);
WavData wave;
wave.Read(reader);
delete[] data;
if (!wave.IsSimpleWAV()) {
ERROR_LOG(AUDIO, "Wave format not supported for mixer playback. Must be 8-bit or 16-bit raw mono or stereo. '%s'", path.c_str());
return nullptr;
}
int16_t *samples = new int16_t[wave.num_channels * wave.numFrames];
if (wave.raw_bytes_per_frame == wave.num_channels * 2) {
// 16-bit
memcpy(samples, wave.raw_data, wave.numFrames * wave.raw_bytes_per_frame);
} else if (wave.raw_bytes_per_frame == wave.num_channels) {
// 8-bit. Convert.
for (int i = 0; i < wave.num_channels * wave.numFrames; i++) {
samples[i] = ConvertU8ToI16(wave.raw_data[i]);
const char *mp3_magic = "ID3\03";
const char *wav_magic = "RIFF";
if (!memcmp(data, wav_magic, 4)) {
RIFFReader reader(data, (int)data_size);
WavData wave;
if (!wave.Read(reader)) {
delete[] data;
return nullptr;
}
// A wav file.
delete[] data;
if (!wave.IsSimpleWAV()) {
ERROR_LOG(AUDIO, "Wave format not supported for mixer playback. Must be 8-bit or 16-bit raw mono or stereo. '%s'", path.c_str());
return nullptr;
}
int16_t *samples = new int16_t[wave.num_channels * wave.numFrames];
if (wave.raw_bytes_per_frame == wave.num_channels * 2) {
// 16-bit
memcpy(samples, wave.raw_data, wave.numFrames * wave.raw_bytes_per_frame);
} else if (wave.raw_bytes_per_frame == wave.num_channels) {
// 8-bit. Convert.
for (int i = 0; i < wave.num_channels * wave.numFrames; i++) {
samples[i] = ConvertU8ToI16(wave.raw_data[i]);
}
}
// Protect against bad metadata.
int actualFrames = std::min(wave.numFrames, wave.raw_data_size / wave.raw_bytes_per_frame);
return new Sample(samples, wave.num_channels, actualFrames, wave.sample_rate);
}
// Protect against bad metadata.
int actualFrames = std::min(wave.numFrames, wave.raw_data_size / wave.raw_bytes_per_frame);
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 samples = mp3dec_load_buf(&mp3d, data, data_size, &mp3_info, nullptr, 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, mp3_info.samples, mp3_info.hz);
free(mp3_info.buffer);
delete[] data;
return sample;
}
static inline int16_t Clamp16(int32_t sample) {
+1 -1
View File
@@ -11,7 +11,7 @@
class AT3PlusReader;
struct Sample {
// data must be new-ed.
// data must be new[]-ed.
Sample(int16_t *data, int channels, int length, int rateInHz) : channels_(channels), data_(data), length_(length), rateInHz_(rateInHz) {}
~Sample() {
delete[] data_;
+1 -1
View File
@@ -514,7 +514,7 @@ bool System_MakeRequest(SystemRequestType type, int requestId, const std::string
supportedExtensions = { ".db" };
break;
case BrowseFileType::SOUND_EFFECT:
supportedExtensions = { ".wav" };
supportedExtensions = { ".wav", ".mp3" };
break;
case BrowseFileType::ANY:
// 'ChooseFile' will added '*' by default when there are no extensions assigned
+1 -1
View File
@@ -578,7 +578,7 @@ bool System_MakeRequest(SystemRequestType type, int requestId, const std::string
filter = MakeFilter(L"Cheat db files (*.db)|*.db|All files (*.*)|*.*||");
break;
case BrowseFileType::SOUND_EFFECT:
filter = MakeFilter(L"WAVE files (*.wav)|*.wav|All files (*.*)|*.*||");
filter = MakeFilter(L"Sound effect files (*.wav *.mp3)|*.wav;*.mp3|All files (*.*)|*.*||");
break;
case BrowseFileType::ANY:
filter = MakeFilter(L"All files (*.*)|*.*||");
+4
View File
@@ -109,6 +109,9 @@ SPIRV_CROSS_FILES := \
NAETT_FILES := \
${SRC}/ext/naett/naett.c
MINIMP3_FILES := \
${SRC}/ext/minimp3/minimp3.cpp
RCHEEVOS_FILES := \
${SRC}/ext/rcheevos/src/rapi/rc_api_common.c \
${SRC}/ext/rcheevos/src/rapi/rc_api_editor.c \
@@ -217,6 +220,7 @@ EXEC_AND_LIB_FILES := \
$(SPIRV_CROSS_FILES) \
$(RCHEEVOS_FILES) \
$(NAETT_FILES) \
$(MINIMP3_FILES) \
$(EXT_FILES) \
$(NATIVE_FILES) \
$(SRC)/Common/Buffer.cpp \
+1
View File
@@ -28,6 +28,7 @@ set(SKIP_GLSLANG_INSTALL ON CACHE BOOL "" FORCE)
set(ENABLE_GLSLANG_INSTALL OFF)
add_subdirectory(glslang EXCLUDE_FROM_ALL)
add_subdirectory(snappy)
add_subdirectory(minimp3)
add_subdirectory(udis86)
add_subdirectory(SPIRV-Cross-build)
add_subdirectory(rcheevos-build)